anv: Only re-emit non-dynamic state that has changed.
authorRafael Antognolli <rafael.antognolli@intel.com>
Tue, 20 Aug 2019 00:01:10 +0000 (17:01 -0700)
committerRafael Antognolli <rafael.antognolli@intel.com>
Fri, 23 Aug 2019 22:55:18 +0000 (15:55 -0700)
On commit f6e7de41d7b, we started emitting 3DSTATE_LINE_STIPPLE as part
of the non-dynamic state. That gets re-emitted every time we bind a new
VkPipeline. But that instruction is non-pipelined, and it caused a perf
regression of about 9-10% on Dota2.

This commit makes anv_dynamic_state_copy() return a mask with only the
state that has changed when copying it. 3DSTATE_LINE_STIPPLE won't be
emitted anymore unless it has changed, fixing the problem above.

v2: Improve commit message and add documentation about skipped checks
(Jason)

Fixes: f6e7de41d7b ("anv: Implement VK_EXT_line_rasterization")
Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
src/intel/vulkan/anv_cmd_buffer.c
src/intel/vulkan/anv_private.h

index 96c75e0..59a281d 100644 (file)
@@ -78,46 +78,72 @@ const struct anv_dynamic_state default_dynamic_state = {
    },
 };
 
-void
+/**
+ * Copy the dynamic state from src to dest based on the copy_mask.
+ *
+ * Avoid copying states that have not changed, except for VIEWPORT, SCISSOR and
+ * BLEND_CONSTANTS (always copy them if they are in the copy_mask).
+ *
+ * Returns a mask of the states which changed.
+ */
+anv_cmd_dirty_mask_t
 anv_dynamic_state_copy(struct anv_dynamic_state *dest,
                        const struct anv_dynamic_state *src,
                        anv_cmd_dirty_mask_t copy_mask)
 {
+   anv_cmd_dirty_mask_t changed = 0;
+
    if (copy_mask & ANV_CMD_DIRTY_DYNAMIC_VIEWPORT) {
       dest->viewport.count = src->viewport.count;
       typed_memcpy(dest->viewport.viewports, src->viewport.viewports,
                    src->viewport.count);
+      changed |= ANV_CMD_DIRTY_DYNAMIC_VIEWPORT;
    }
 
    if (copy_mask & ANV_CMD_DIRTY_DYNAMIC_SCISSOR) {
       dest->scissor.count = src->scissor.count;
       typed_memcpy(dest->scissor.scissors, src->scissor.scissors,
                    src->scissor.count);
+      changed |= ANV_CMD_DIRTY_DYNAMIC_SCISSOR;
    }
 
-   if (copy_mask & ANV_CMD_DIRTY_DYNAMIC_LINE_WIDTH)
-      dest->line_width = src->line_width;
+   if (copy_mask & ANV_CMD_DIRTY_DYNAMIC_BLEND_CONSTANTS) {
+      typed_memcpy(dest->blend_constants, src->blend_constants, 4);
+      changed |= ANV_CMD_DIRTY_DYNAMIC_BLEND_CONSTANTS;
+   }
 
-   if (copy_mask & ANV_CMD_DIRTY_DYNAMIC_DEPTH_BIAS)
-      dest->depth_bias = src->depth_bias;
+#define ANV_CMP_COPY(field, flag)                                 \
+   if (copy_mask & flag) {                                        \
+      if (dest->field != src->field) {                            \
+         dest->field = src->field;                                \
+         changed |= flag;                                         \
+      }                                                           \
+   }
 
-   if (copy_mask & ANV_CMD_DIRTY_DYNAMIC_BLEND_CONSTANTS)
-      typed_memcpy(dest->blend_constants, src->blend_constants, 4);
+   ANV_CMP_COPY(line_width, ANV_CMD_DIRTY_DYNAMIC_LINE_WIDTH);
+
+   ANV_CMP_COPY(depth_bias.bias, ANV_CMD_DIRTY_DYNAMIC_DEPTH_BIAS);
+   ANV_CMP_COPY(depth_bias.clamp, ANV_CMD_DIRTY_DYNAMIC_DEPTH_BIAS);
+   ANV_CMP_COPY(depth_bias.slope, ANV_CMD_DIRTY_DYNAMIC_DEPTH_BIAS);
+
+   ANV_CMP_COPY(depth_bounds.min, ANV_CMD_DIRTY_DYNAMIC_DEPTH_BOUNDS);
+   ANV_CMP_COPY(depth_bounds.max, ANV_CMD_DIRTY_DYNAMIC_DEPTH_BOUNDS);
+
+   ANV_CMP_COPY(stencil_compare_mask.front, ANV_CMD_DIRTY_DYNAMIC_STENCIL_COMPARE_MASK);
+   ANV_CMP_COPY(stencil_compare_mask.back, ANV_CMD_DIRTY_DYNAMIC_STENCIL_COMPARE_MASK);
 
-   if (copy_mask & ANV_CMD_DIRTY_DYNAMIC_DEPTH_BOUNDS)
-      dest->depth_bounds = src->depth_bounds;
+   ANV_CMP_COPY(stencil_write_mask.front, ANV_CMD_DIRTY_DYNAMIC_STENCIL_WRITE_MASK);
+   ANV_CMP_COPY(stencil_write_mask.back, ANV_CMD_DIRTY_DYNAMIC_STENCIL_WRITE_MASK);
 
-   if (copy_mask & ANV_CMD_DIRTY_DYNAMIC_STENCIL_COMPARE_MASK)
-      dest->stencil_compare_mask = src->stencil_compare_mask;
+   ANV_CMP_COPY(stencil_reference.front, ANV_CMD_DIRTY_DYNAMIC_STENCIL_REFERENCE);
+   ANV_CMP_COPY(stencil_reference.back, ANV_CMD_DIRTY_DYNAMIC_STENCIL_REFERENCE);
 
-   if (copy_mask & ANV_CMD_DIRTY_DYNAMIC_STENCIL_WRITE_MASK)
-      dest->stencil_write_mask = src->stencil_write_mask;
+   ANV_CMP_COPY(line_stipple.factor, ANV_CMD_DIRTY_DYNAMIC_LINE_STIPPLE);
+   ANV_CMP_COPY(line_stipple.pattern, ANV_CMD_DIRTY_DYNAMIC_LINE_STIPPLE);
 
-   if (copy_mask & ANV_CMD_DIRTY_DYNAMIC_STENCIL_REFERENCE)
-      dest->stencil_reference = src->stencil_reference;
+#undef ANV_CMP_COPY
 
-   if (copy_mask & ANV_CMD_DIRTY_DYNAMIC_LINE_STIPPLE)
-      dest->line_stipple = src->line_stipple;
+   return changed;
 }
 
 static void
@@ -378,10 +404,10 @@ void anv_CmdBindPipeline(
       cmd_buffer->state.descriptors_dirty |= pipeline->active_stages;
 
       /* Apply the dynamic state from the pipeline */
-      cmd_buffer->state.gfx.dirty |= pipeline->dynamic_state_mask;
-      anv_dynamic_state_copy(&cmd_buffer->state.gfx.dynamic,
-                             &pipeline->dynamic_state,
-                             pipeline->dynamic_state_mask);
+      cmd_buffer->state.gfx.dirty |=
+         anv_dynamic_state_copy(&cmd_buffer->state.gfx.dynamic,
+                                &pipeline->dynamic_state,
+                                pipeline->dynamic_state_mask);
       break;
 
    default:
index 78b5b07..b6bb201 100644 (file)
@@ -2275,9 +2275,9 @@ struct anv_dynamic_state {
 
 extern const struct anv_dynamic_state default_dynamic_state;
 
-void anv_dynamic_state_copy(struct anv_dynamic_state *dest,
-                            const struct anv_dynamic_state *src,
-                            uint32_t copy_mask);
+uint32_t anv_dynamic_state_copy(struct anv_dynamic_state *dest,
+                                const struct anv_dynamic_state *src,
+                                uint32_t copy_mask);
 
 struct anv_surface_state {
    struct anv_state state;