anv: More carefully dirty state in BindDescriptorSets
authorJason Ekstrand <jason@jlekstrand.net>
Thu, 7 Nov 2019 17:44:08 +0000 (11:44 -0600)
committerJason Ekstrand <jason@jlekstrand.net>
Mon, 18 Nov 2019 18:35:14 +0000 (18:35 +0000)
Instead of dirtying all graphics or all compute based on binding point,
we're now much more careful.  We first check to see if the actual
descriptor set changed and then only dirty the stages used by that
descriptor set.  For dynamic offsets, we keep a bitfield per-stage of
which offsets are actually used in that stage and we only dirty push
constants and descriptors if that stage has dynamic offsets AND those
offsets actually change.

Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
src/intel/vulkan/anv_cmd_buffer.c
src/intel/vulkan/anv_descriptor_set.c
src/intel/vulkan/anv_private.h
src/intel/vulkan/genX_cmd_buffer.c

index f14225b963ae39f5f2f70ab695e718258da1ee97..2a555f1d2be1eef14d9220cd8c6277254fcc8f0d 100644 (file)
@@ -572,53 +572,65 @@ anv_cmd_buffer_bind_descriptor_set(struct anv_cmd_buffer *cmd_buffer,
    struct anv_descriptor_set_layout *set_layout =
       layout->set[set_index].layout;
 
-   struct anv_cmd_pipeline_state *pipe_state;
+   VkShaderStageFlags stages = set_layout->shader_stages &
+      (bind_point == VK_PIPELINE_BIND_POINT_COMPUTE ?
+       VK_SHADER_STAGE_COMPUTE_BIT : VK_SHADER_STAGE_ALL_GRAPHICS);
+
+   VkShaderStageFlags dirty_stages = 0;
    if (bind_point == VK_PIPELINE_BIND_POINT_COMPUTE) {
-      pipe_state = &cmd_buffer->state.compute.base;
+      if (cmd_buffer->state.compute.base.descriptors[set_index] != set) {
+         cmd_buffer->state.compute.base.descriptors[set_index] = set;
+         dirty_stages |= stages;
+      }
    } else {
       assert(bind_point == VK_PIPELINE_BIND_POINT_GRAPHICS);
-      pipe_state = &cmd_buffer->state.gfx.base;
+      if (cmd_buffer->state.gfx.base.descriptors[set_index] != set) {
+         cmd_buffer->state.gfx.base.descriptors[set_index] = set;
+         dirty_stages |= stages;
+      }
    }
-   pipe_state->descriptors[set_index] = set;
+
+   /* If it's a push descriptor set, we have to flag things as dirty
+    * regardless of whether or not the CPU-side data structure changed as we
+    * may have edited in-place.
+    */
+   if (set->pool == NULL)
+      dirty_stages |= stages;
 
    if (dynamic_offsets) {
       if (set_layout->dynamic_offset_count > 0) {
          uint32_t dynamic_offset_start =
             layout->set[set_index].dynamic_offset_start;
 
-         anv_foreach_stage(stage, set_layout->shader_stages) {
+         anv_foreach_stage(stage, stages) {
             struct anv_push_constants *push =
                &cmd_buffer->state.push_constants[stage];
+            uint32_t *push_offsets =
+               &push->dynamic_offsets[dynamic_offset_start];
 
             /* Assert that everything is in range */
             assert(set_layout->dynamic_offset_count <= *dynamic_offset_count);
             assert(dynamic_offset_start + set_layout->dynamic_offset_count <=
                    ARRAY_SIZE(push->dynamic_offsets));
 
-            typed_memcpy(&push->dynamic_offsets[dynamic_offset_start],
-                         *dynamic_offsets, set_layout->dynamic_offset_count);
+            unsigned mask = set_layout->stage_dynamic_offsets[stage];
+            STATIC_ASSERT(MAX_DYNAMIC_BUFFERS <= sizeof(mask) * 8);
+            while (mask) {
+               int i = u_bit_scan(&mask);
+               if (push_offsets[i] != (*dynamic_offsets)[i]) {
+                  push_offsets[i] = (*dynamic_offsets)[i];
+                  dirty_stages |= mesa_to_vk_shader_stage(stage);
+               }
+            }
          }
 
          *dynamic_offsets += set_layout->dynamic_offset_count;
          *dynamic_offset_count -= set_layout->dynamic_offset_count;
-
-         if (bind_point == VK_PIPELINE_BIND_POINT_COMPUTE) {
-            cmd_buffer->state.push_constants_dirty |=
-               VK_SHADER_STAGE_COMPUTE_BIT;
-         } else {
-            cmd_buffer->state.push_constants_dirty |=
-               VK_SHADER_STAGE_ALL_GRAPHICS;
-         }
       }
    }
 
-   if (bind_point == VK_PIPELINE_BIND_POINT_COMPUTE) {
-      cmd_buffer->state.descriptors_dirty |= VK_SHADER_STAGE_COMPUTE_BIT;
-   } else {
-      assert(bind_point == VK_PIPELINE_BIND_POINT_GRAPHICS);
-      cmd_buffer->state.descriptors_dirty |=
-         set_layout->shader_stages & VK_SHADER_STAGE_ALL_GRAPHICS;
-   }
+   cmd_buffer->state.descriptors_dirty |= dirty_stages;
+   cmd_buffer->state.push_constants_dirty |= dirty_stages;
 }
 
 void anv_CmdBindDescriptorSets(
index 2f7b32b1b82f99556ff4469edd9c593cdc429b5f..af8fa40a0a966117dc493e811aaef5d757182ca0 100644 (file)
@@ -469,7 +469,15 @@ VkResult anv_CreateDescriptorSetLayout(
       case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
       case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
          set_layout->binding[b].dynamic_offset_index = dynamic_offset_count;
+         anv_foreach_stage(s, binding->stageFlags) {
+            STATIC_ASSERT(MAX_DYNAMIC_BUFFERS <=
+                          sizeof(set_layout->stage_dynamic_offsets[s]) * 8);
+            set_layout->stage_dynamic_offsets[s] |=
+               BITFIELD_RANGE(set_layout->binding[b].dynamic_offset_index,
+                              binding->descriptorCount);
+         }
          dynamic_offset_count += binding->descriptorCount;
+         assert(dynamic_offset_count < MAX_DYNAMIC_BUFFERS);
          break;
 
       default:
@@ -603,6 +611,7 @@ VkResult anv_CreatePipelineLayout(
          dynamic_offset_count += set_layout->binding[b].array_size;
       }
    }
+   assert(dynamic_offset_count < MAX_DYNAMIC_BUFFERS);
 
    struct mesa_sha1 ctx;
    _mesa_sha1_init(&ctx);
index 3ad4a5971e20c95fa6cc107f5fd0d069ed46bfa4..ec403acd41665726bd6ada733649ccc0d6c7507a 100644 (file)
@@ -1803,6 +1803,9 @@ struct anv_descriptor_set_layout {
    /* Number of dynamic offsets used by this descriptor set */
    uint16_t dynamic_offset_count;
 
+   /* For each shader stage, which offsets apply to that stage */
+   uint16_t stage_dynamic_offsets[MESA_SHADER_STAGES];
+
    /* Size of the descriptor buffer for this descriptor set */
    uint32_t descriptor_buffer_size;
 
index 9f143180d73a3224cebb5103b9428e1be1ce91cb..d4ed49263de42a8b9c28b2d501e7af745f43a440 100644 (file)
@@ -3544,6 +3544,11 @@ genX(cmd_buffer_flush_compute_state)(struct anv_cmd_buffer *cmd_buffer)
       genX(cmd_buffer_apply_pipe_flushes)(cmd_buffer);
 
       anv_batch_emit_batch(&cmd_buffer->batch, &pipeline->batch);
+
+      /* The workgroup size of the pipeline affects our push constant layout
+       * so flag push constants as dirty if we change the pipeline.
+       */
+      cmd_buffer->state.push_constants_dirty |= VK_SHADER_STAGE_COMPUTE_BIT;
    }
 
    if ((cmd_buffer->state.descriptors_dirty & VK_SHADER_STAGE_COMPUTE_BIT) ||