zink: EXT_vertex_input_dynamic_state

this eliminates vertex attributes from the pipeline state, massively
deduplicating the number of pipelines needed

Reviewed-by: Dave Airlie <airlied@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/12009>
This commit is contained in:
Mike Blumenkrantz
2021-05-13 15:55:43 -04:00
committed by Marge Bot
parent 907e4a0f02
commit 6691a48bcc
9 changed files with 111 additions and 50 deletions

View File

@@ -945,7 +945,7 @@ zink_set_vertex_buffers(struct pipe_context *pctx,
if (buffers) {
if (!zink_screen(pctx->screen)->info.have_EXT_extended_dynamic_state)
ctx->gfx_pipeline_state.vertex_state_dirty = true;
ctx->vertex_state_changed = true;
for (unsigned i = 0; i < num_buffers; ++i) {
const struct pipe_vertex_buffer *vb = buffers + i;
struct pipe_vertex_buffer *ctx_vb = &ctx->vertex_buffers[start_slot + i];
@@ -971,7 +971,7 @@ zink_set_vertex_buffers(struct pipe_context *pctx,
}
} else {
if (!zink_screen(pctx->screen)->info.have_EXT_extended_dynamic_state)
ctx->gfx_pipeline_state.vertex_state_dirty = true;
ctx->vertex_state_changed = true;
for (unsigned i = 0; i < num_buffers; ++i) {
update_existing_vbo(ctx, start_slot + i);
pipe_resource_reference(&ctx->vertex_buffers[start_slot + i].buffer.resource, NULL);

View File

@@ -303,6 +303,7 @@ struct zink_context {
bool have_timelines;
bool is_device_lost;
bool vertex_state_changed : 1;
bool blend_state_changed : 1;
bool rast_state_changed : 1;
bool dsa_state_changed : 1;

View File

@@ -176,6 +176,10 @@ EXTENSIONS = [
alias="line_rast",
properties=True,
features=True),
Extension("VK_EXT_vertex_input_dynamic_state",
alias="vertex_input",
features=True,
conditions=["$feats.vertexInputDynamicState"]),
Extension("VK_KHR_dedicated_allocation",
alias="dedicated"),
]

View File

@@ -130,7 +130,7 @@ zink_bind_vertex_buffers(struct zink_batch *batch, struct zink_context *ctx)
VkBuffer buffers[PIPE_MAX_ATTRIBS];
VkDeviceSize buffer_offsets[PIPE_MAX_ATTRIBS];
VkDeviceSize buffer_strides[PIPE_MAX_ATTRIBS];
const struct zink_vertex_elements_state *elems = ctx->element_state;
struct zink_vertex_elements_state *elems = ctx->element_state;
struct zink_screen *screen = zink_screen(ctx->base.screen);
if (!elems->hw_state.num_bindings)
@@ -143,12 +143,16 @@ zink_bind_vertex_buffers(struct zink_batch *batch, struct zink_context *ctx)
if (vb->buffer.resource) {
buffers[i] = ctx->vbufs[buffer_id];
assert(buffers[i]);
if (screen->info.have_EXT_vertex_input_dynamic_state)
elems->hw_state.dynbindings[i].stride = vb->stride;
buffer_offsets[i] = ctx->vbuf_offsets[buffer_id];
buffer_strides[i] = vb->stride;
} else {
buffers[i] = zink_resource(ctx->dummy_vertex_buffer)->obj->buffer;
buffer_offsets[i] = 0;
buffer_strides[i] = 0;
if (screen->info.have_EXT_vertex_input_dynamic_state)
elems->hw_state.dynbindings[i].stride = 0;
}
}
@@ -160,6 +164,13 @@ zink_bind_vertex_buffers(struct zink_batch *batch, struct zink_context *ctx)
vkCmdBindVertexBuffers(batch->state->cmdbuf, 0,
elems->hw_state.num_bindings,
buffers, buffer_offsets);
if (screen->info.have_EXT_vertex_input_dynamic_state)
screen->vk.CmdSetVertexInputEXT(batch->state->cmdbuf,
elems->hw_state.num_bindings, elems->hw_state.dynbindings,
elems->hw_state.num_attribs, elems->hw_state.dynattribs);
ctx->vertex_state_changed = false;
ctx->vertex_buffers_dirty = false;
}

View File

@@ -51,19 +51,23 @@ zink_create_gfx_pipeline(struct zink_screen *screen,
struct zink_gfx_pipeline_state *state,
VkPrimitiveTopology primitive_topology)
{
VkPipelineVertexInputStateCreateInfo vertex_input_state = {0};
vertex_input_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertex_input_state.pVertexBindingDescriptions = state->element_state->bindings;
vertex_input_state.vertexBindingDescriptionCount = state->element_state->num_bindings;
vertex_input_state.pVertexAttributeDescriptions = state->element_state->attribs;
vertex_input_state.vertexAttributeDescriptionCount = state->element_state->num_attribs;
VkPipelineVertexInputStateCreateInfo vertex_input_state;
if (!screen->info.have_EXT_vertex_input_dynamic_state) {
memset(&vertex_input_state, 0, sizeof(vertex_input_state));
vertex_input_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertex_input_state.pVertexBindingDescriptions = state->element_state->b.bindings;
vertex_input_state.vertexBindingDescriptionCount = state->element_state->num_bindings;
vertex_input_state.pVertexAttributeDescriptions = state->element_state->attribs;
vertex_input_state.vertexAttributeDescriptionCount = state->element_state->num_attribs;
}
VkPipelineVertexInputDivisorStateCreateInfoEXT vdiv_state = {0};
if (state->element_state->divisors_present) {
VkPipelineVertexInputDivisorStateCreateInfoEXT vdiv_state;
if (!screen->info.have_EXT_vertex_input_dynamic_state && state->element_state->b.divisors_present) {
memset(&vdiv_state, 0, sizeof(vdiv_state));
vertex_input_state.pNext = &vdiv_state;
vdiv_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
vdiv_state.vertexBindingDivisorCount = state->element_state->divisors_present;
vdiv_state.pVertexBindingDivisors = state->element_state->divisors;
vdiv_state.vertexBindingDivisorCount = state->element_state->b.divisors_present;
vdiv_state.pVertexBindingDivisors = state->element_state->b.divisors;
}
VkPipelineInputAssemblyStateCreateInfo primitive_state = {0};
@@ -202,6 +206,9 @@ zink_create_gfx_pipeline(struct zink_screen *screen,
dynamicStateEnables[state_count++] = VK_DYNAMIC_STATE_VIEWPORT;
dynamicStateEnables[state_count++] = VK_DYNAMIC_STATE_SCISSOR;
}
if (screen->info.have_EXT_vertex_input_dynamic_state) {
dynamicStateEnables[state_count++] = VK_DYNAMIC_STATE_VERTEX_INPUT_EXT;
}
VkPipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo = {0};
pipelineDynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
@@ -212,7 +219,8 @@ zink_create_gfx_pipeline(struct zink_screen *screen,
pci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pci.layout = prog->base.layout;
pci.renderPass = state->render_pass->render_pass;
pci.pVertexInputState = &vertex_input_state;
if (!screen->info.have_EXT_vertex_input_dynamic_state)
pci.pVertexInputState = &vertex_input_state;
pci.pInputAssemblyState = &primitive_state;
pci.pRasterizationState = &rast_state;
pci.pColorBlendState = &blend_state;

View File

@@ -69,7 +69,6 @@ struct zink_gfx_pipeline_state {
bool combined_dirty;
struct zink_vertex_elements_hw_state *element_state;
bool vertex_state_dirty;
uint32_t final_hash;

View File

@@ -764,41 +764,49 @@ zink_get_gfx_pipeline(struct zink_context *ctx,
struct zink_gfx_pipeline_state *state,
enum pipe_prim_type mode)
{
if (!state->dirty && !state->combined_dirty && !state->vertex_state_dirty && mode == state->mode)
struct zink_screen *screen = zink_screen(ctx->base.screen);
const bool have_EXT_vertex_input_dynamic_state = screen->info.have_EXT_vertex_input_dynamic_state;
if (!state->dirty && !state->combined_dirty && mode == state->mode &&
(have_EXT_vertex_input_dynamic_state || !ctx->vertex_state_changed))
return state->pipeline;
struct zink_screen *screen = zink_screen(ctx->base.screen);
VkPrimitiveTopology vkmode = primitive_topology(mode);
assert(vkmode <= ARRAY_SIZE(prog->pipelines));
struct hash_entry *entry = NULL;
if (state->dirty) {
state->vertex_state_dirty = state->combined_dirty = true;
if (!have_EXT_vertex_input_dynamic_state)
ctx->vertex_state_changed = true;
state->combined_dirty = true;
state->hash = hash_gfx_pipeline_state(state);
state->dirty = false;
}
if (state->combined_dirty) {
state->vertex_state_dirty = true;
if (!have_EXT_vertex_input_dynamic_state)
ctx->vertex_state_changed = true;
state->combined_hash = XXH32(&state->module_hash, sizeof(uint32_t), state->hash);
state->combined_dirty = false;
}
if (state->vertex_state_dirty) {
uint32_t hash = state->combined_hash;
if (!state->have_EXT_extended_dynamic_state) {
/* if we don't have dynamic states, we have to hash the enabled vertex buffer bindings */
uint32_t vertex_buffers_enabled_mask = state->vertex_buffers_enabled_mask;
hash = XXH32(&vertex_buffers_enabled_mask, sizeof(uint32_t), hash);
if (have_EXT_vertex_input_dynamic_state)
state->final_hash = state->combined_hash;
else
if (ctx->vertex_state_changed) {
uint32_t hash = state->combined_hash;
if (!state->have_EXT_extended_dynamic_state) {
/* if we don't have dynamic states, we have to hash the enabled vertex buffer bindings */
uint32_t vertex_buffers_enabled_mask = state->vertex_buffers_enabled_mask;
hash = XXH32(&vertex_buffers_enabled_mask, sizeof(uint32_t), hash);
for (unsigned i = 0; i < state->element_state->num_bindings; i++) {
struct pipe_vertex_buffer *vb = ctx->vertex_buffers + ctx->element_state->binding_map[i];
state->vertex_strides[i] = vb->buffer.resource ? vb->stride : 0;
hash = XXH32(&state->vertex_strides[i], sizeof(uint32_t), hash);
for (unsigned i = 0; i < state->element_state->num_bindings; i++) {
struct pipe_vertex_buffer *vb = ctx->vertex_buffers + ctx->element_state->binding_map[i];
state->vertex_strides[i] = vb->buffer.resource ? vb->stride : 0;
hash = XXH32(&state->vertex_strides[i], sizeof(uint32_t), hash);
}
}
state->final_hash = XXH32(&state->element_state, sizeof(void*), hash);
ctx->vertex_state_changed = false;
}
state->final_hash = XXH32(&state->element_state, sizeof(void*), hash);
state->vertex_state_dirty = false;
}
entry = _mesa_hash_table_search_pre_hashed(prog->pipelines[vkmode], state->final_hash, state);
if (!entry) {

View File

@@ -66,23 +66,45 @@ zink_create_vertex_elements_state(struct pipe_context *pctx,
ves->divisor[binding] = elem->instance_divisor;
assert(elem->instance_divisor <= screen->info.vdiv_props.maxVertexAttribDivisor);
ves->hw_state.attribs[i].binding = binding;
ves->hw_state.attribs[i].location = i;
ves->hw_state.attribs[i].format = zink_get_format(screen,
elem->src_format);
assert(ves->hw_state.attribs[i].format != VK_FORMAT_UNDEFINED);
ves->hw_state.attribs[i].offset = elem->src_offset;
if (screen->info.have_EXT_vertex_input_dynamic_state) {
ves->hw_state.dynattribs[i].sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT;
ves->hw_state.dynattribs[i].binding = binding;
ves->hw_state.dynattribs[i].location = i;
ves->hw_state.dynattribs[i].format = zink_get_format(screen,
elem->src_format);
assert(ves->hw_state.dynattribs[i].format != VK_FORMAT_UNDEFINED);
ves->hw_state.dynattribs[i].offset = elem->src_offset;
} else {
ves->hw_state.attribs[i].binding = binding;
ves->hw_state.attribs[i].location = i;
ves->hw_state.attribs[i].format = zink_get_format(screen,
elem->src_format);
assert(ves->hw_state.attribs[i].format != VK_FORMAT_UNDEFINED);
ves->hw_state.attribs[i].offset = elem->src_offset;
}
}
ves->hw_state.num_bindings = num_bindings;
ves->hw_state.num_attribs = num_elements;
for (int i = 0; i < num_bindings; ++i) {
ves->hw_state.bindings[i].binding = ves->bindings[i].binding;
ves->hw_state.bindings[i].inputRate = ves->bindings[i].inputRate;
if (ves->divisor[i]) {
ves->hw_state.divisors[ves->hw_state.divisors_present].divisor = ves->divisor[i];
ves->hw_state.divisors[ves->hw_state.divisors_present].binding = ves->bindings[i].binding;
ves->hw_state.divisors_present++;
if (screen->info.have_EXT_vertex_input_dynamic_state) {
for (int i = 0; i < num_bindings; ++i) {
ves->hw_state.dynbindings[i].sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT;
ves->hw_state.dynbindings[i].binding = ves->bindings[i].binding;
ves->hw_state.dynbindings[i].inputRate = ves->bindings[i].inputRate;
if (ves->divisor[i])
ves->hw_state.dynbindings[i].divisor = ves->divisor[i];
else
ves->hw_state.dynbindings[i].divisor = 1;
}
} else {
for (int i = 0; i < num_bindings; ++i) {
ves->hw_state.b.bindings[i].binding = ves->bindings[i].binding;
ves->hw_state.b.bindings[i].inputRate = ves->bindings[i].inputRate;
if (ves->divisor[i]) {
ves->hw_state.b.divisors[ves->hw_state.b.divisors_present].divisor = ves->divisor[i];
ves->hw_state.b.divisors[ves->hw_state.b.divisors_present].binding = ves->bindings[i].binding;
ves->hw_state.b.divisors_present++;
}
}
}
return ves;
@@ -97,7 +119,7 @@ zink_bind_vertex_elements_state(struct pipe_context *pctx,
ctx->element_state = cso;
if (cso) {
if (state->element_state != &ctx->element_state->hw_state) {
state->vertex_state_dirty = true;
ctx->vertex_state_changed = true;
ctx->vertex_buffers_dirty = ctx->element_state->hw_state.num_bindings > 0;
}
state->element_state = &ctx->element_state->hw_state;

View File

@@ -29,11 +29,19 @@
#include "pipe/p_state.h"
struct zink_vertex_elements_hw_state {
VkVertexInputAttributeDescription attribs[PIPE_MAX_ATTRIBS];
VkVertexInputBindingDivisorDescriptionEXT divisors[PIPE_MAX_ATTRIBS];
VkVertexInputBindingDescription bindings[PIPE_MAX_ATTRIBS]; // combination of element_state and stride
union {
VkVertexInputAttributeDescription attribs[PIPE_MAX_ATTRIBS];
VkVertexInputAttributeDescription2EXT dynattribs[PIPE_MAX_ATTRIBS];
};
union {
struct {
VkVertexInputBindingDivisorDescriptionEXT divisors[PIPE_MAX_ATTRIBS];
VkVertexInputBindingDescription bindings[PIPE_MAX_ATTRIBS]; // combination of element_state and stride
uint8_t divisors_present;
} b;
VkVertexInputBindingDescription2EXT dynbindings[PIPE_MAX_ATTRIBS];
};
uint32_t num_bindings, num_attribs;
uint8_t divisors_present;
};
struct zink_vertex_elements_state {