svga: avoid emitting redundant SetShaderResources and SetVertexBuffers
authorCharmaine Lee <charmainel@vmware.com>
Tue, 1 Aug 2017 22:58:50 +0000 (15:58 -0700)
committerBrian Paul <brianp@vmware.com>
Tue, 5 Sep 2017 16:31:18 +0000 (10:31 -0600)
Minor performance improvement in avoiding binding the same shader resource
or the same vertex buffer for the same slot.

Tested with MTT glretrace.

v2: Per Brian's suggestion, add a helper function to do vertex buffer
    comparision.
v3: Change the helper function to vertex_buffers_equal().

Reviewed-by: Brian Paul <brianp@vmware.com>
src/gallium/drivers/svga/svga_draw.c
src/gallium/drivers/svga/svga_state_sampler.c

index 5919bd35daeae8214efd029003878a7a949f5f28..0639d5eaebe1fbba07537f7fca9067d444d36e8f 100644 (file)
@@ -489,6 +489,24 @@ last_command_was_draw(const struct svga_context *svga)
 }
 
 
+/**
+ * A helper function to compare vertex buffers.
+ * They are equal if the vertex buffer attributes and the vertex buffer
+ * resources are identical.
+ */
+static boolean
+vertex_buffers_equal(unsigned count,
+                     SVGA3dVertexBuffer *pVBufAttr1,
+                     struct pipe_resource **pVBuf1,
+                     SVGA3dVertexBuffer *pVBufAttr2,
+                     struct pipe_resource **pVBuf2)
+{
+   return (memcmp(pVBufAttr1, pVBufAttr2,
+                  count * sizeof(*pVBufAttr1)) == 0) &&
+          (memcmp(pVBuf1, pVBuf2, count * sizeof(*pVBuf1)) == 0);
+}
+
+
 static enum pipe_error
 draw_vgpu10(struct svga_hwtnl *hwtnl,
             const SVGA3dPrimitiveRange *range,
@@ -607,10 +625,11 @@ draw_vgpu10(struct svga_hwtnl *hwtnl,
        */
       if (((hwtnl->cmd.swc->hints & SVGA_HINT_FLAG_CAN_PRE_FLUSH) == 0) ||
           vbuf_count != svga->state.hw_draw.num_vbuffers ||
-          memcmp(vbuffer_attrs, svga->state.hw_draw.vbuffer_attrs,
-                 vbuf_count * sizeof(vbuffer_attrs[0])) ||
-          memcmp(vbuffers, svga->state.hw_draw.vbuffers,
-                 vbuf_count * sizeof(vbuffers[0]))) {
+          !vertex_buffers_equal(vbuf_count,
+                                vbuffer_attrs,
+                                vbuffers,
+                                svga->state.hw_draw.vbuffer_attrs,
+                                svga->state.hw_draw.vbuffers)) {
 
          unsigned num_vbuffers;
 
@@ -631,13 +650,52 @@ draw_vgpu10(struct svga_hwtnl *hwtnl,
          }
 
          if (num_vbuffers > 0) {
+            SVGA3dVertexBuffer *pbufAttrs = vbuffer_attrs;
+            struct svga_winsys_surface **pbufHandles = vbuffer_handles;
+            unsigned numVBuf = 0;
 
-            ret = SVGA3D_vgpu10_SetVertexBuffers(svga->swc, num_vbuffers,
-                                                 0,    /* startBuffer */
-                                                 vbuffer_attrs,
-                                                 vbuffer_handles);
-            if (ret != PIPE_OK)
-               return ret;
+            /* Loop through the vertex buffer lists to only emit
+             * those vertex buffers that are not already in the
+             * corresponding entries in the device's vertex buffer list.
+             */
+            for (i = 0; i < num_vbuffers; i++) {
+               boolean emit;
+
+               emit = vertex_buffers_equal(1,
+                                           &vbuffer_attrs[i],
+                                           &vbuffers[i],
+                                           &svga->state.hw_draw.vbuffer_attrs[i],
+                                           &svga->state.hw_draw.vbuffers[i]);
+                                               
+               if (!emit && i == num_vbuffers-1) {
+                  /* Include the last vertex buffer in the next emit
+                   * if it is different.
+                   */
+                  emit = TRUE;
+                  numVBuf++;
+                  i++;
+               }
+
+               if (emit) {
+                  /* numVBuf can only be 0 if the first vertex buffer
+                   * is the same as the one in the device's list.
+                   * In this case, there is nothing to send yet.
+                   */
+                  if (numVBuf) {
+                     ret = SVGA3D_vgpu10_SetVertexBuffers(svga->swc,
+                                                          numVBuf,
+                                                          i - numVBuf,
+                                                          pbufAttrs, pbufHandles);
+                     if (ret != PIPE_OK)
+                        return ret;
+                  }
+                  pbufAttrs += (numVBuf + 1);
+                  pbufHandles += (numVBuf + 1);
+                  numVBuf = 0;
+               }
+               else
+                  numVBuf++;
+            }
 
             /* save the number of vertex buffers sent to the device, not
              * including trailing unbound vertex buffers.
index c361dba676a4e83ccae27d736584307942280f19..763437d9b87a579ea0eb6024fed64994c8d56719 100644 (file)
@@ -278,14 +278,54 @@ update_sampler_resources(struct svga_context *svga, unsigned dirty)
          if (count != svga->state.hw_draw.num_sampler_views[shader] ||
              memcmp(sampler_views, svga->state.hw_draw.sampler_views[shader],
                     count * sizeof(sampler_views[0])) != 0) {
-            ret = SVGA3D_vgpu10_SetShaderResources(svga->swc,
-                                                svga_shader_type(shader),
-                                                0, /* startView */
-                                                nviews,
-                                                ids,
-                                                surfaces);
-            if (ret != PIPE_OK)
-               return ret;
+            SVGA3dShaderResourceViewId *pIds = ids;
+            struct svga_winsys_surface **pSurf = surfaces;
+            unsigned numSR = 0;
+
+            /* Loop through the sampler view list to only emit
+             * the sampler views that are not already in the
+             * corresponding entries in the device's
+             * shader resource list.
+             */
+            for (i = 0; i < nviews; i++) {
+                boolean emit;
+
+                emit = sampler_views[i] ==
+                       svga->state.hw_draw.sampler_views[shader][i];
+
+                if (!emit && i == nviews-1) {
+                   /* Include the last sampler view in the next emit
+                    * if it is different.
+                    */
+                   emit = TRUE;
+                   numSR++;
+                   i++;
+                }
+                if (emit) {
+                   /* numSR can only be 0 if the first entry of the list
+                    * is the same as the one in the device list.
+                    * In this case, * there is nothing to send yet.
+                    */
+                   if (numSR) {
+                      ret = SVGA3D_vgpu10_SetShaderResources(
+                               svga->swc,
+                               svga_shader_type(shader),
+                               i - numSR, /* startView */
+                               numSR,
+                               pIds,
+                               pSurf);
+
+                      if (ret != PIPE_OK)
+                         return ret;
+                   }
+                   pIds += (numSR + 1);
+                   pSurf += (numSR + 1);
+                   numSR = 0;
+                }
+                else
+                   numSR++;
+            }
 
             /* Save referenced sampler views in the hw draw state.  */
             svga->state.hw_draw.num_sampler_views[shader] = count;