vk: Make sure we emit binding table pointers after push constants
authorKristian Høgsberg Kristensen <krh@owl.jf.intel.com>
Fri, 8 Jan 2016 00:25:49 +0000 (16:25 -0800)
committerKristian Høgsberg Kristensen <krh@owl.jf.intel.com>
Fri, 8 Jan 2016 00:31:57 +0000 (16:31 -0800)
SKL needs this to make sure we flush the push constants. It gets a
little tricky, since we also need to emit binding tables before push
constants, since that may affect the push constants (dynamic buffer
offsets and storage image parameters).  This patch splits emitting
binding tables from emitting the pointers so that we can emit push
constants after binding tables but before emitting binding table
pointers.

src/vulkan/anv_cmd_buffer.c
src/vulkan/anv_private.h
src/vulkan/gen7_cmd_buffer.c
src/vulkan/gen8_cmd_buffer.c

index 49bb298a1884a84469fcee08fb9ef073e5ae66b6..0407ad92fba2ad1adfa24c3578ae11c781a33479 100644 (file)
@@ -636,8 +636,10 @@ anv_cmd_buffer_emit_binding_table(struct anv_cmd_buffer *cmd_buffer,
     * targets. */
    uint32_t surface_count = layout ? layout->stage[stage].surface_count : 0;
 
-   if (color_count + surface_count == 0)
+   if (color_count + surface_count == 0) {
+      *bt_state = (struct anv_state) { 0, };
       return VK_SUCCESS;
+   }
 
    *bt_state = anv_cmd_buffer_alloc_binding_table(cmd_buffer,
                                                   bias + surface_count,
@@ -781,8 +783,10 @@ anv_cmd_buffer_emit_samplers(struct anv_cmd_buffer *cmd_buffer,
       layout = cmd_buffer->state.pipeline->layout;
 
    sampler_count = layout ? layout->stage[stage].sampler_count : 0;
-   if (sampler_count == 0)
+   if (sampler_count == 0) {
+      *state = (struct anv_state) { 0, };
       return VK_SUCCESS;
+   }
 
    uint32_t size = sampler_count * 16;
    *state = anv_cmd_buffer_alloc_dynamic_state(cmd_buffer, size, 32);
index 0cd8ab6facdd453fa59087ae22147638b279d9c1..ded2d9a5e2407602b636ec8feda77f2e98850457 100644 (file)
@@ -1079,6 +1079,8 @@ struct anv_cmd_state {
    struct anv_vertex_binding                    vertex_bindings[MAX_VBS];
    struct anv_descriptor_set *                  descriptors[MAX_SETS];
    struct anv_push_constants *                  push_constants[MESA_SHADER_STAGES];
+   struct anv_state                             binding_tables[MESA_SHADER_STAGES];
+   struct anv_state                             samplers[MESA_SHADER_STAGES];
    struct anv_dynamic_state                     dynamic;
 
    struct {
@@ -1176,7 +1178,9 @@ VkResult anv_cmd_buffer_emit_binding_table(struct anv_cmd_buffer *cmd_buffer,
                                            unsigned stage, struct anv_state *bt_state);
 VkResult anv_cmd_buffer_emit_samplers(struct anv_cmd_buffer *cmd_buffer,
                                       unsigned stage, struct anv_state *state);
-void gen7_cmd_buffer_flush_descriptor_sets(struct anv_cmd_buffer *cmd_buffer);
+uint32_t gen7_cmd_buffer_flush_descriptor_sets(struct anv_cmd_buffer *cmd_buffer);
+void gen7_cmd_buffer_emit_descriptor_pointers(struct anv_cmd_buffer *cmd_buffer,
+                                              uint32_t stages);
 
 struct anv_state anv_cmd_buffer_emit_dynamic(struct anv_cmd_buffer *cmd_buffer,
                                              const void *data, uint32_t size, uint32_t alignment);
index 85eec0b055e6bba407d6e0f1d00a53a8519a59bb..e69bf47782e05d4369938e7bcb5cb076e5aab480 100644 (file)
@@ -32,7 +32,7 @@
 #include "gen7_pack.h"
 #include "gen75_pack.h"
 
-static void
+static uint32_t
 cmd_buffer_flush_push_constants(struct anv_cmd_buffer *cmd_buffer)
 {
    static const uint32_t push_constant_opcodes[] = {
@@ -63,21 +63,14 @@ cmd_buffer_flush_push_constants(struct anv_cmd_buffer *cmd_buffer)
    }
 
    cmd_buffer->state.push_constants_dirty &= ~flushed;
+
+   return flushed;
 }
 
-static VkResult
-flush_descriptor_set(struct anv_cmd_buffer *cmd_buffer, gl_shader_stage stage)
+GENX_FUNC(GEN7, GEN7) void
+genX(cmd_buffer_emit_descriptor_pointers)(struct anv_cmd_buffer *cmd_buffer,
+                                          uint32_t stages)
 {
-   struct anv_state surfaces = { 0, }, samplers = { 0, };
-   VkResult result;
-
-   result = anv_cmd_buffer_emit_samplers(cmd_buffer, stage, &samplers);
-   if (result != VK_SUCCESS)
-      return result;
-   result = anv_cmd_buffer_emit_binding_table(cmd_buffer, stage, &surfaces);
-   if (result != VK_SUCCESS)
-      return result;
-
    static const uint32_t sampler_state_opcodes[] = {
       [MESA_SHADER_VERTEX]                      = 43,
       [MESA_SHADER_TESS_CTRL]                   = 44, /* HS */
@@ -96,24 +89,24 @@ flush_descriptor_set(struct anv_cmd_buffer *cmd_buffer, gl_shader_stage stage)
       [MESA_SHADER_COMPUTE]                     = 0,
    };
 
-   if (samplers.alloc_size > 0) {
-      anv_batch_emit(&cmd_buffer->batch,
-                     GEN7_3DSTATE_SAMPLER_STATE_POINTERS_VS,
-                     ._3DCommandSubOpcode  = sampler_state_opcodes[stage],
-                     .PointertoVSSamplerState = samplers.offset);
-   }
+   anv_foreach_stage(s, stages) {
+      if (cmd_buffer->state.samplers[s].alloc_size > 0) {
+         anv_batch_emit(&cmd_buffer->batch,
+                        GEN7_3DSTATE_SAMPLER_STATE_POINTERS_VS,
+                        ._3DCommandSubOpcode  = sampler_state_opcodes[s],
+                        .PointertoVSSamplerState = cmd_buffer->state.samplers[s].offset);
+      }
 
-   if (surfaces.alloc_size > 0) {
+      /* Always emit binding table pointers if we're asked to, since on SKL
+       * this is what flushes push constants. */
       anv_batch_emit(&cmd_buffer->batch,
                      GEN7_3DSTATE_BINDING_TABLE_POINTERS_VS,
-                     ._3DCommandSubOpcode  = binding_table_opcodes[stage],
-                     .PointertoVSBindingTable = surfaces.offset);
+                     ._3DCommandSubOpcode  = binding_table_opcodes[s],
+                     .PointertoVSBindingTable = cmd_buffer->state.binding_tables[s].offset);
    }
-
-   return VK_SUCCESS;
 }
 
-GENX_FUNC(GEN7, GEN7) void
+GENX_FUNC(GEN7, GEN7) uint32_t
 genX(cmd_buffer_flush_descriptor_sets)(struct anv_cmd_buffer *cmd_buffer)
 {
    VkShaderStageFlags dirty = cmd_buffer->state.descriptors_dirty &
@@ -121,7 +114,12 @@ genX(cmd_buffer_flush_descriptor_sets)(struct anv_cmd_buffer *cmd_buffer)
 
    VkResult result = VK_SUCCESS;
    anv_foreach_stage(s, dirty) {
-      result = flush_descriptor_set(cmd_buffer, s);
+      result = anv_cmd_buffer_emit_samplers(cmd_buffer, s,
+                                            &cmd_buffer->state.samplers[s]);
+      if (result != VK_SUCCESS)
+         break;
+      result = anv_cmd_buffer_emit_binding_table(cmd_buffer, s,
+                                                 &cmd_buffer->state.binding_tables[s]);
       if (result != VK_SUCCESS)
          break;
    }
@@ -138,15 +136,22 @@ genX(cmd_buffer_flush_descriptor_sets)(struct anv_cmd_buffer *cmd_buffer)
       anv_cmd_buffer_emit_state_base_address(cmd_buffer);
 
       /* Re-emit all active binding tables */
-      anv_foreach_stage(s, cmd_buffer->state.pipeline->active_stages) {
-         result = flush_descriptor_set(cmd_buffer, s);
-
-         /* It had better succeed this time */
-         assert(result == VK_SUCCESS);
+      dirty |= cmd_buffer->state.pipeline->active_stages;
+      anv_foreach_stage(s, dirty) {
+         result = anv_cmd_buffer_emit_samplers(cmd_buffer, s,
+                                               &cmd_buffer->state.samplers[s]);
+         if (result != VK_SUCCESS)
+            return result;
+         result = anv_cmd_buffer_emit_binding_table(cmd_buffer, s,
+                                                    &cmd_buffer->state.binding_tables[s]);
+         if (result != VK_SUCCESS)
+            return result;
       }
    }
 
-   cmd_buffer->state.descriptors_dirty &= ~cmd_buffer->state.pipeline->active_stages;
+   cmd_buffer->state.descriptors_dirty &= ~dirty;
+
+   return dirty;
 }
 
 static inline int64_t
@@ -389,8 +394,11 @@ cmd_buffer_flush_state(struct anv_cmd_buffer *cmd_buffer)
                      .Address = { &cmd_buffer->device->workaround_bo, 0 });
    }
 
-   if (cmd_buffer->state.descriptors_dirty)
-      gen7_cmd_buffer_flush_descriptor_sets(cmd_buffer);
+   uint32_t dirty = 0;
+   if (cmd_buffer->state.descriptors_dirty) {
+      dirty = gen7_cmd_buffer_flush_descriptor_sets(cmd_buffer);
+      gen7_cmd_buffer_emit_descriptor_pointers(cmd_buffer, dirty);
+   }
 
    if (cmd_buffer->state.push_constants_dirty)
       cmd_buffer_flush_push_constants(cmd_buffer);
index 0ba9beac9c8240996684cded781cd7ac6b967268..308b72b3d7b0f1813b068e42fae149bbd1ee243b 100644 (file)
@@ -32,7 +32,7 @@
 #include "gen8_pack.h"
 #include "gen9_pack.h"
 
-static void
+static uint32_t
 cmd_buffer_flush_push_constants(struct anv_cmd_buffer *cmd_buffer)
 {
    static const uint32_t push_constant_opcodes[] = {
@@ -66,6 +66,8 @@ cmd_buffer_flush_push_constants(struct anv_cmd_buffer *cmd_buffer)
    }
 
    cmd_buffer->state.push_constants_dirty &= ~flushed;
+
+   return flushed;
 }
 
 #if ANV_GEN == 8
@@ -205,23 +207,22 @@ cmd_buffer_flush_state(struct anv_cmd_buffer *cmd_buffer)
       anv_batch_emit_batch(&cmd_buffer->batch, &pipeline->batch);
    }
 
-#if ANV_GEN >= 9
-   /* On SKL+ the new constants don't take effect until the next corresponding
-    * 3DSTATE_BINDING_TABLE_POINTER_* command is parsed so we need to ensure
-    * that is sent. As it is, we re-emit binding tables but we could hold on
-    * to the offset of the most recent binding table and only re-emit the
-    * 3DSTATE_BINDING_TABLE_POINTER_* command.
+   /* We emit the binding tables and sampler tables first, then emit push
+    * constants and then finally emit binding table and sampler table
+    * pointers.  It has to happen in this order, since emitting the binding
+    * tables may change the push constants (in case of storage images). After
+    * emitting push constants, on SKL+ we have to emit the corresponding
+    * 3DSTATE_BINDING_TABLE_POINTER_* for the push constants to take effect.
     */
-   cmd_buffer->state.descriptors_dirty |=
-      cmd_buffer->state.push_constants_dirty &
-      cmd_buffer->state.pipeline->active_stages;
-#endif
-
+   uint32_t dirty = 0;
    if (cmd_buffer->state.descriptors_dirty)
-      gen7_cmd_buffer_flush_descriptor_sets(cmd_buffer);
+      dirty = gen7_cmd_buffer_flush_descriptor_sets(cmd_buffer);
 
    if (cmd_buffer->state.push_constants_dirty)
-      cmd_buffer_flush_push_constants(cmd_buffer);
+      dirty |= cmd_buffer_flush_push_constants(cmd_buffer);
+
+   if (dirty)
+      gen7_cmd_buffer_emit_descriptor_pointers(cmd_buffer, dirty);
 
    if (cmd_buffer->state.dirty & ANV_CMD_DIRTY_DYNAMIC_VIEWPORT)
       gen8_cmd_buffer_emit_viewport(cmd_buffer);