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:

committed by
Marge Bot

parent
907e4a0f02
commit
6691a48bcc
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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"),
|
||||
]
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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) {
|
||||
|
@@ -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;
|
||||
|
@@ -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 {
|
||||
|
Reference in New Issue
Block a user