diff --git a/src/vulkan/anv_cmd_buffer.c b/src/vulkan/anv_cmd_buffer.c index 49bb298a188..0407ad92fba 100644 --- a/src/vulkan/anv_cmd_buffer.c +++ b/src/vulkan/anv_cmd_buffer.c @@ -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); diff --git a/src/vulkan/anv_private.h b/src/vulkan/anv_private.h index 0cd8ab6facd..ded2d9a5e24 100644 --- a/src/vulkan/anv_private.h +++ b/src/vulkan/anv_private.h @@ -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); diff --git a/src/vulkan/gen7_cmd_buffer.c b/src/vulkan/gen7_cmd_buffer.c index 85eec0b055e..e69bf47782e 100644 --- a/src/vulkan/gen7_cmd_buffer.c +++ b/src/vulkan/gen7_cmd_buffer.c @@ -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); diff --git a/src/vulkan/gen8_cmd_buffer.c b/src/vulkan/gen8_cmd_buffer.c index 0ba9beac9c8..308b72b3d7b 100644 --- a/src/vulkan/gen8_cmd_buffer.c +++ b/src/vulkan/gen8_cmd_buffer.c @@ -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);