+/**
+ * Copy gl_array_object from src to dest.
+ * 'dest' must be in an initialized state.
+ */
+static void
+copy_array_object(struct gl_context *ctx,
+ struct gl_array_object *dest,
+ struct gl_array_object *src)
+{
+ GLuint i;
+
+ /* skip Name */
+ /* skip RefCount */
+
+ /* In theory must be the same anyway, but on recreate make sure it matches */
+ dest->ARBsemantics = src->ARBsemantics;
+
+ for (i = 0; i < Elements(src->VertexAttrib); i++)
+ _mesa_copy_client_array(ctx, &dest->VertexAttrib[i], &src->VertexAttrib[i]);
+
+ /* _Enabled must be the same than on push */
+ dest->_Enabled = src->_Enabled;
+ dest->_MaxElement = src->_MaxElement;
+}
+
+/**
+ * Copy gl_array_attrib from src to dest.
+ * 'dest' must be in an initialized state.
+ */
+static void
+copy_array_attrib(struct gl_context *ctx,
+ struct gl_array_attrib *dest,
+ struct gl_array_attrib *src,
+ bool vbo_deleted)
+{
+ /* skip ArrayObj */
+ /* skip DefaultArrayObj, Objects */
+ dest->ActiveTexture = src->ActiveTexture;
+ dest->LockFirst = src->LockFirst;
+ dest->LockCount = src->LockCount;
+ dest->PrimitiveRestart = src->PrimitiveRestart;
+ dest->RestartIndex = src->RestartIndex;
+ /* skip NewState */
+ /* skip RebindArrays */
+
+ if (!vbo_deleted)
+ copy_array_object(ctx, dest->ArrayObj, src->ArrayObj);
+
+ /* skip ArrayBufferObj */
+ /* skip ElementArrayBufferObj */
+}
+
+/**
+ * Save the content of src to dest.
+ */
+static void
+save_array_attrib(struct gl_context *ctx,
+ struct gl_array_attrib *dest,
+ struct gl_array_attrib *src)
+{
+ /* Set the Name, needed for restore, but do never overwrite.
+ * Needs to match value in the object hash. */
+ dest->ArrayObj->Name = src->ArrayObj->Name;
+ /* And copy all of the rest. */
+ copy_array_attrib(ctx, dest, src, false);
+
+ /* Just reference them here */
+ _mesa_reference_buffer_object(ctx, &dest->ArrayBufferObj,
+ src->ArrayBufferObj);
+ _mesa_reference_buffer_object(ctx, &dest->ArrayObj->ElementArrayBufferObj,
+ src->ArrayObj->ElementArrayBufferObj);
+}
+
+/**
+ * Restore the content of src to dest.
+ */
+static void
+restore_array_attrib(struct gl_context *ctx,
+ struct gl_array_attrib *dest,
+ struct gl_array_attrib *src)
+{
+ /* The ARB_vertex_array_object spec says:
+ *
+ * "BindVertexArray fails and an INVALID_OPERATION error is generated
+ * if array is not a name returned from a previous call to
+ * GenVertexArrays, or if such a name has since been deleted with
+ * DeleteVertexArrays."
+ *
+ * Therefore popping a deleted VAO cannot magically recreate it.
+ *
+ * The semantics of objects created using APPLE_vertex_array_objects behave
+ * differently. These objects expect to be recreated by pop. Alas.
+ */
+ const bool arb_vao = (src->ArrayObj->Name != 0
+ && src->ArrayObj->ARBsemantics);
+
+ if (arb_vao && !_mesa_IsVertexArray(src->ArrayObj->Name))
+ return;
+
+ _mesa_BindVertexArrayAPPLE(src->ArrayObj->Name);
+
+ /* Restore or recreate the buffer objects by the names ... */
+ if (!arb_vao
+ || src->ArrayBufferObj->Name == 0
+ || _mesa_IsBuffer(src->ArrayBufferObj->Name)) {
+ /* ... and restore its content */
+ copy_array_attrib(ctx, dest, src, false);
+
+ _mesa_BindBuffer(GL_ARRAY_BUFFER_ARB,
+ src->ArrayBufferObj->Name);
+ } else {
+ copy_array_attrib(ctx, dest, src, true);
+ }
+
+ if (!arb_vao
+ || src->ArrayObj->ElementArrayBufferObj->Name == 0
+ || _mesa_IsBuffer(src->ArrayObj->ElementArrayBufferObj->Name))
+ _mesa_BindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB,
+ src->ArrayObj->ElementArrayBufferObj->Name);
+}
+
+/**
+ * init/alloc the fields of 'attrib'.
+ * Needs to the init part matching free_array_attrib_data below.
+ */
+static void
+init_array_attrib_data(struct gl_context *ctx,
+ struct gl_array_attrib *attrib)
+{
+ /* Get a non driver gl_array_object. */
+ attrib->ArrayObj = CALLOC_STRUCT( gl_array_object );
+ _mesa_initialize_array_object(ctx, attrib->ArrayObj, 0);
+}
+
+/**
+ * Free/unreference the fields of 'attrib' but don't delete it (that's
+ * done later in the calling code).
+ * Needs to the cleanup part matching init_array_attrib_data above.
+ */
+static void
+free_array_attrib_data(struct gl_context *ctx,
+ struct gl_array_attrib *attrib)
+{
+ /* We use a non driver array object, so don't just unref since we would
+ * end up using the drivers DeleteArrayObject function for deletion. */
+ _mesa_delete_array_object(ctx, attrib->ArrayObj);
+ attrib->ArrayObj = 0;
+ _mesa_reference_buffer_object(ctx, &attrib->ArrayBufferObj, NULL);
+}
+