mesa,st/mesa: add a fast path for non-static VAOs
authorMarek Olšák <marek.olsak@amd.com>
Fri, 27 Mar 2020 09:07:02 +0000 (05:07 -0400)
committerMarge Bot <eric+marge@anholt.net>
Thu, 30 Apr 2020 22:01:55 +0000 (22:01 +0000)
Skip most of _mesa_update_vao_derived_arrays if the VAO is not static.
Drivers need a separate codepath for this.

This increases performance by 7% with glthread and the game "torcs".

The reason is that glthread uploads vertices and sets vertex buffers
every draw call, so the overhead is very noticable. glthread doesn't
hide the overhead, because the driver thread is the busiest thread.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/4314>

src/mesa/main/arrayobj.c
src/mesa/main/attrib.c
src/mesa/main/mtypes.h
src/mesa/state_tracker/st_atom_array.c
src/mesa/state_tracker/st_extensions.c

index 3ebcedea4e9c63ce34e8c2042ccda5826a206c3f..a4c15cfe36928825983f27e9073c72dd29785978 100644 (file)
@@ -546,6 +546,17 @@ _mesa_update_vao_derived_arrays(struct gl_context *ctx,
    vao->_EffEnabledVBO = _mesa_vao_enable_to_vp_inputs(mode, enabled & vbos);
    vao->_EffEnabledNonZeroDivisor =
       _mesa_vao_enable_to_vp_inputs(mode, enabled & divisor_is_nonzero);
+
+   /* Fast path when the VAO is updated too often. */
+   if (vao->IsDynamic)
+      return;
+
+   /* More than 4 updates turn the VAO to dynamic. */
+   if (ctx->Const.AllowDynamicVAOFastPath && ++vao->NumUpdates > 4) {
+      vao->IsDynamic = true;
+      return;
+   }
+
    /* Walk those enabled arrays that have a real vbo attached */
    GLbitfield mask = enabled;
    while (mask) {
index 74c449bfbcb2df076fc8fcceab6bd02c11e37439..45018188168690760762db628fdfa48699fa0c53 100644 (file)
@@ -1589,6 +1589,8 @@ copy_array_object(struct gl_context *ctx,
    dest->NonZeroDivisorMask = src->NonZeroDivisorMask;
    dest->_AttributeMapMode = src->_AttributeMapMode;
    dest->NewArrays = src->NewArrays;
+   dest->NumUpdates = src->NumUpdates;
+   dest->IsDynamic = src->IsDynamic;
 }
 
 /**
index c99d6b97f005f51edd1f325ecafeae783e4aac4f..f7cccbcc0a0c87950ce1fec2926a495003e92ec2 100644 (file)
@@ -1539,6 +1539,14 @@ struct gl_vertex_array_object
     */
    GLboolean EverBound;
 
+   /**
+    * Whether the VAO is changed by the application so often that some of
+    * the derived fields are not updated at all to decrease overhead.
+    * Also, interleaved arrays are not detected, because it's too expensive
+    * to do that before every draw call.
+    */
+   bool IsDynamic;
+
    /**
     * Marked to true if the object is shared between contexts and immutable.
     * Then reference counting is done using atomics and thread safe.
@@ -1546,6 +1554,12 @@ struct gl_vertex_array_object
     */
    bool SharedAndImmutable;
 
+   /**
+    * Number of updates that were done by the application. This is used to
+    * decide whether the VAO is static or dynamic.
+    */
+   unsigned NumUpdates;
+
    /** Vertex attribute arrays */
    struct gl_array_attributes VertexAttrib[VERT_ATTRIB_MAX];
 
@@ -4164,6 +4178,9 @@ struct gl_constants
    /** Whether out-of-order draw (Begin/End) optimizations are allowed. */
    bool AllowDrawOutOfOrder;
 
+   /** Whether to allow the fast path for frequently updated VAOs. */
+   bool AllowDynamicVAOFastPath;
+
    /** GL_ARB_gl_spirv */
    struct spirv_supported_capabilities SpirVCapabilities;
 
index 0b5909ba11aab484ae33e1ecbcdca155743c998a..1faf72b0db5e706dccdb496d47917dc7526bc1be 100644 (file)
@@ -149,6 +149,38 @@ st_setup_arrays(struct st_context *st,
    st->draw_needs_minmax_index =
       (userbuf_attribs & ~_mesa_draw_nonzero_divisor_bits(ctx)) != 0;
 
+   if (vao->IsDynamic) {
+      while (mask) {
+         const gl_vert_attrib attr = u_bit_scan(&mask);
+         const struct gl_array_attributes *const attrib =
+            _mesa_draw_array_attrib(vao, attr);
+         const struct gl_vertex_buffer_binding *const binding =
+            &vao->BufferBinding[attrib->BufferBindingIndex];
+         const unsigned bufidx = (*num_vbuffers)++;
+
+         /* Set the vertex buffer. */
+         if (binding->BufferObj) {
+            struct st_buffer_object *stobj = st_buffer_object(binding->BufferObj);
+
+            vbuffer[bufidx].buffer.resource = stobj ? stobj->buffer : NULL;
+            vbuffer[bufidx].is_user_buffer = false;
+            vbuffer[bufidx].buffer_offset = binding->Offset +
+                                            attrib->RelativeOffset;
+         } else {
+            vbuffer[bufidx].buffer.user = attrib->Ptr;
+            vbuffer[bufidx].is_user_buffer = true;
+            vbuffer[bufidx].buffer_offset = 0;
+         }
+         vbuffer[bufidx].stride = binding->Stride; /* in bytes */
+
+         /* Set the vertex element. */
+         init_velement(vp, velements->velems, &attrib->Format, 0,
+                       binding->InstanceDivisor, bufidx,
+                       input_to_index[attr]);
+      }
+      return;
+   }
+
    while (mask) {
       /* The attribute index to start pulling a binding */
       const gl_vert_attrib i = ffs(mask) - 1;
index 386b035a052e1bada4280ab98c70283784129f8b..5ddb55f053dfe93ed814565b52df1c1a0f72e372 100644 (file)
@@ -583,6 +583,8 @@ void st_init_limits(struct pipe_screen *screen,
    c->MultiDrawWithUserIndices =
       screen->get_param(screen, PIPE_CAP_DRAW_INFO_START_WITH_USER_INDICES);
 
+   c->AllowDynamicVAOFastPath = true;
+
    c->glBeginEndBufferSize =
       screen->get_param(screen, PIPE_CAP_GL_BEGIN_END_BUFFER_SIZE);
 }