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.
This commit is contained in:
Kristian Høgsberg Kristensen 2016-01-07 16:25:49 -08:00
parent a18b5e642c
commit 1b1dca75a4
4 changed files with 68 additions and 51 deletions

View 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);

View 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);

View 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);

View 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);