From 1b1dca75a401b2d885ae7583837a63c3f66da022 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Kristian=20H=C3=B8gsberg=20Kristensen?= Date: Thu, 7 Jan 2016 16:25:49 -0800 Subject: [PATCH] vk: Make sure we emit binding table pointers after push constants 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 | 8 +++- src/vulkan/anv_private.h | 6 ++- src/vulkan/gen7_cmd_buffer.c | 76 ++++++++++++++++++++---------------- src/vulkan/gen8_cmd_buffer.c | 29 +++++++------- 4 files changed, 68 insertions(+), 51 deletions(-) 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); -- 2.30.2