st/mesa: simplify determination whether a draw needs min/max index
[mesa.git] / src / mesa / main / arrayobj.c
index 4977009f6f5a962e66eecd32a407693718e0f1c9..6dbd09b39ec431ceb936b3aef7343f6d02e289af 100644 (file)
@@ -229,12 +229,17 @@ _mesa_lookup_vao(struct gl_context *ctx, GLuint id)
 /**
  * Looks up the array object for the given ID.
  *
- * Unlike _mesa_lookup_vao, this function generates a GL_INVALID_OPERATION
+ * While _mesa_lookup_vao doesn't generate an error if the object does not
+ * exist, this function comes in two variants.
+ * If is_ext_dsa is false, this function generates a GL_INVALID_OPERATION
  * error if the array object does not exist. It also returns the default
  * array object when ctx is a compatibility profile context and id is zero.
+ * If is_ext_dsa is true, 0 is not a valid name. If the name exists but
+ * the object has never been bound, it is initialized.
  */
 struct gl_vertex_array_object *
-_mesa_lookup_vao_err(struct gl_context *ctx, GLuint id, const char *caller)
+_mesa_lookup_vao_err(struct gl_context *ctx, GLuint id,
+                     bool is_ext_dsa, const char *caller)
 {
    /* The ARB_direct_state_access specification says:
     *
@@ -243,10 +248,11 @@ _mesa_lookup_vao_err(struct gl_context *ctx, GLuint id, const char *caller)
     *     the name of the vertex array object."
     */
    if (id == 0) {
-      if (ctx->API == API_OPENGL_CORE) {
+      if (is_ext_dsa || ctx->API == API_OPENGL_CORE) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "%s(zero is not valid vaobj name in a core profile "
-                     "context)", caller);
+                     "%s(zero is not valid vaobj name%s)",
+                     caller,
+                     is_ext_dsa ? "" : " in a core profile context");
          return NULL;
       }
 
@@ -267,12 +273,23 @@ _mesa_lookup_vao_err(struct gl_context *ctx, GLuint id, const char *caller)
           *     [compatibility profile: zero or] the name of an existing
           *     vertex array object."
           */
-         if (!vao || !vao->EverBound) {
+         if (!vao || (!is_ext_dsa && !vao->EverBound)) {
             _mesa_error(ctx, GL_INVALID_OPERATION,
                         "%s(non-existent vaobj=%u)", caller, id);
             return NULL;
          }
 
+         /* The EXT_direct_state_access specification says:
+         *
+         *    "If the vertex array object named by the vaobj parameter has not
+         *     been previously bound but has been generated (without subsequent
+         *     deletion) by GenVertexArrays, the GL first creates a new state
+         *     vector in the same manner as when BindVertexArray creates a new
+         *     vertex array object."
+         */
+         if (vao && is_ext_dsa && !vao->EverBound)
+            vao->EverBound = true;
+
          _mesa_reference_vao(ctx, &ctx->Array.LastLookedUpVAO, vao);
       }
 
@@ -385,22 +402,17 @@ init_array(struct gl_context *ctx,
    assert(index < ARRAY_SIZE(vao->BufferBinding));
    struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[index];
 
-   array->Size = size;
-   array->Type = type;
-   array->Format = GL_RGBA; /* only significant for GL_EXT_vertex_array_bgra */
+   _mesa_set_vertex_format(&array->Format, size, type, GL_RGBA,
+                           GL_FALSE, GL_FALSE, GL_FALSE);
    array->Stride = 0;
    array->Ptr = NULL;
    array->RelativeOffset = 0;
-   array->Normalized = GL_FALSE;
-   array->Integer = GL_FALSE;
-   array->Doubles = GL_FALSE;
-   array->_ElementSize = size * _mesa_sizeof_type(type);
    ASSERT_BITFIELD_SIZE(struct gl_array_attributes, BufferBindingIndex,
                         VERT_ATTRIB_MAX - 1);
    array->BufferBindingIndex = index;
 
    binding->Offset = 0;
-   binding->Stride = array->_ElementSize;
+   binding->Stride = array->Format._ElementSize;
    binding->BufferObj = NULL;
    binding->_BoundArrays = BITFIELD_BIT(index);
 
@@ -441,7 +453,7 @@ _mesa_initialize_vao(struct gl_context *ctx,
          init_array(ctx, vao, VERT_ATTRIB_COLOR_INDEX, 1, GL_FLOAT);
          break;
       case VERT_ATTRIB_EDGEFLAG:
-         init_array(ctx, vao, VERT_ATTRIB_EDGEFLAG, 1, GL_BOOL);
+         init_array(ctx, vao, VERT_ATTRIB_EDGEFLAG, 1, GL_UNSIGNED_BYTE);
          break;
       case VERT_ATTRIB_POINT_SIZE:
          init_array(ctx, vao, VERT_ATTRIB_POINT_SIZE, 1, GL_FLOAT);
@@ -599,9 +611,12 @@ _mesa_update_vao_derived_arrays(struct gl_context *ctx,
    const GLbitfield enabled = vao->Enabled;
    /* VBO array bits. */
    const GLbitfield vbos = vao->VertexAttribBufferMask;
+   const GLbitfield divisor_is_nonzero = vao->NonZeroDivisorMask;
 
    /* Compute and store effectively enabled and mapped vbo arrays */
    vao->_EffEnabledVBO = _mesa_vao_enable_to_vp_inputs(mode, enabled & vbos);
+   vao->_EffEnabledNonZeroDivisor =
+      _mesa_vao_enable_to_vp_inputs(mode, enabled & divisor_is_nonzero);
    /* Walk those enabled arrays that have a real vbo attached */
    GLbitfield mask = enabled;
    while (mask) {
@@ -756,7 +771,7 @@ _mesa_update_vao_derived_arrays(struct gl_context *ctx,
          GLbitfield eff_bound_arrays = bound;
 
          const GLubyte *ptr = attrib->Ptr;
-         unsigned vertex_end = attrib->_ElementSize;
+         unsigned vertex_end = attrib->Format._ElementSize;
 
          /* Walk other user space arrays and see which are interleaved
           * using the same binding parameters.
@@ -778,9 +793,10 @@ _mesa_update_vao_derived_arrays(struct gl_context *ctx,
             if (binding->InstanceDivisor != binding2->InstanceDivisor)
                continue;
             if (ptr <= attrib2->Ptr) {
-               if (ptr + binding->Stride < attrib2->Ptr + attrib2->_ElementSize)
+               if (ptr + binding->Stride < attrib2->Ptr +
+                   attrib2->Format._ElementSize)
                   continue;
-               unsigned end = attrib2->Ptr + attrib2->_ElementSize - ptr;
+               unsigned end = attrib2->Ptr + attrib2->Format._ElementSize - ptr;
                vertex_end = MAX2(vertex_end, end);
             } else {
                if (attrib2->Ptr + binding->Stride < ptr + vertex_end)
@@ -823,7 +839,8 @@ _mesa_update_vao_derived_arrays(struct gl_context *ctx,
       /* Query the original api defined attrib/binding information ... */
       const unsigned char *const map =_mesa_vao_attribute_map[mode];
       if (vao->Enabled & VERT_BIT(map[attr])) {
-         const struct gl_array_attributes *attrib = &vao->VertexAttrib[map[attr]];
+         const struct gl_array_attributes *attrib =
+            &vao->VertexAttrib[map[attr]];
          const struct gl_vertex_buffer_binding *binding =
             &vao->BufferBinding[attrib->BufferBindingIndex];
          /* ... and compare that with the computed attrib/binding */
@@ -916,6 +933,90 @@ _mesa_all_buffers_are_unmapped(const struct gl_vertex_array_object *vao)
    return true;
 }
 
+
+/**
+ * Map buffer objects used in attribute arrays.
+ */
+void
+_mesa_vao_map_arrays(struct gl_context *ctx, struct gl_vertex_array_object *vao,
+                     GLbitfield access)
+{
+   GLbitfield mask = vao->Enabled & vao->VertexAttribBufferMask;
+   while (mask) {
+      /* Do not use u_bit_scan as we can walk multiple attrib arrays at once */
+      const gl_vert_attrib attr = ffs(mask) - 1;
+      const GLubyte bindex = vao->VertexAttrib[attr].BufferBindingIndex;
+      struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[bindex];
+      mask &= ~binding->_BoundArrays;
+
+      struct gl_buffer_object *bo = binding->BufferObj;
+      assert(_mesa_is_bufferobj(bo));
+      if (_mesa_bufferobj_mapped(bo, MAP_INTERNAL))
+         continue;
+
+      ctx->Driver.MapBufferRange(ctx, 0, bo->Size, access, bo, MAP_INTERNAL);
+   }
+}
+
+
+/**
+ * Map buffer objects used in the vao, attribute arrays and index buffer.
+ */
+void
+_mesa_vao_map(struct gl_context *ctx, struct gl_vertex_array_object *vao,
+              GLbitfield access)
+{
+   struct gl_buffer_object *bo = vao->IndexBufferObj;
+
+   /* map the index buffer, if there is one, and not already mapped */
+   if (_mesa_is_bufferobj(bo) && !_mesa_bufferobj_mapped(bo, MAP_INTERNAL))
+      ctx->Driver.MapBufferRange(ctx, 0, bo->Size, access, bo, MAP_INTERNAL);
+
+   _mesa_vao_map_arrays(ctx, vao, access);
+}
+
+
+/**
+ * Unmap buffer objects used in attribute arrays.
+ */
+void
+_mesa_vao_unmap_arrays(struct gl_context *ctx,
+                       struct gl_vertex_array_object *vao)
+{
+   GLbitfield mask = vao->Enabled & vao->VertexAttribBufferMask;
+   while (mask) {
+      /* Do not use u_bit_scan as we can walk multiple attrib arrays at once */
+      const gl_vert_attrib attr = ffs(mask) - 1;
+      const GLubyte bindex = vao->VertexAttrib[attr].BufferBindingIndex;
+      struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[bindex];
+      mask &= ~binding->_BoundArrays;
+
+      struct gl_buffer_object *bo = binding->BufferObj;
+      assert(_mesa_is_bufferobj(bo));
+      if (!_mesa_bufferobj_mapped(bo, MAP_INTERNAL))
+         continue;
+
+      ctx->Driver.UnmapBuffer(ctx, bo, MAP_INTERNAL);
+   }
+}
+
+
+/**
+ * Unmap buffer objects used in the vao, attribute arrays and index buffer.
+ */
+void
+_mesa_vao_unmap(struct gl_context *ctx, struct gl_vertex_array_object *vao)
+{
+   struct gl_buffer_object *bo = vao->IndexBufferObj;
+
+   /* unmap the index buffer, if there is one, and still mapped */
+   if (_mesa_is_bufferobj(bo) && _mesa_bufferobj_mapped(bo, MAP_INTERNAL))
+      ctx->Driver.UnmapBuffer(ctx, bo, MAP_INTERNAL);
+
+   _mesa_vao_unmap_arrays(ctx, vao);
+}
+
+
 /**********************************************************************/
 /* API Functions                                                      */
 /**********************************************************************/
@@ -968,7 +1069,6 @@ bind_vertex_array(struct gl_context *ctx, GLuint id, bool no_error)
     */
    _mesa_set_draw_vao(ctx, ctx->Array._EmptyVAO, 0);
 
-   ctx->NewState |= _NEW_ARRAY;
    _mesa_reference_vao(ctx, &ctx->Array.VAO, newObj);
 }
 
@@ -1193,7 +1293,7 @@ vertex_array_element_buffer(struct gl_context *ctx, GLuint vaobj, GLuint buffer,
        *     VertexArrayElementBuffer if <vaobj> is not [compatibility profile:
        *     zero or] the name of an existing vertex array object."
        */
-      vao =_mesa_lookup_vao_err(ctx, vaobj, "glVertexArrayElementBuffer");
+      vao =_mesa_lookup_vao_err(ctx, vaobj, false, "glVertexArrayElementBuffer");
       if (!vao)
          return;
    } else {
@@ -1216,8 +1316,10 @@ vertex_array_element_buffer(struct gl_context *ctx, GLuint vaobj, GLuint buffer,
       bufObj = ctx->Shared->NullBufferObj;
    }
 
-   if (bufObj)
+   if (bufObj) {
+      bufObj->UsageHistory |= USAGE_ELEMENT_ARRAY_BUFFER;
       _mesa_reference_buffer_object(ctx, &vao->IndexBufferObj, bufObj);
+   }
 }
 
 
@@ -1251,7 +1353,7 @@ _mesa_GetVertexArrayiv(GLuint vaobj, GLenum pname, GLint *param)
     *    [compatibility profile: zero or] the name of an existing
     *    vertex array object."
     */
-   vao =_mesa_lookup_vao_err(ctx, vaobj, "glGetVertexArrayiv");
+   vao = _mesa_lookup_vao_err(ctx, vaobj, false, "glGetVertexArrayiv");
    if (!vao)
       return;