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 (buffers) {
|
||||||
if (!zink_screen(pctx->screen)->info.have_EXT_extended_dynamic_state)
|
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) {
|
for (unsigned i = 0; i < num_buffers; ++i) {
|
||||||
const struct pipe_vertex_buffer *vb = buffers + i;
|
const struct pipe_vertex_buffer *vb = buffers + i;
|
||||||
struct pipe_vertex_buffer *ctx_vb = &ctx->vertex_buffers[start_slot + 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 {
|
} else {
|
||||||
if (!zink_screen(pctx->screen)->info.have_EXT_extended_dynamic_state)
|
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) {
|
for (unsigned i = 0; i < num_buffers; ++i) {
|
||||||
update_existing_vbo(ctx, start_slot + i);
|
update_existing_vbo(ctx, start_slot + i);
|
||||||
pipe_resource_reference(&ctx->vertex_buffers[start_slot + i].buffer.resource, NULL);
|
pipe_resource_reference(&ctx->vertex_buffers[start_slot + i].buffer.resource, NULL);
|
||||||
|
@@ -303,6 +303,7 @@ struct zink_context {
|
|||||||
bool have_timelines;
|
bool have_timelines;
|
||||||
|
|
||||||
bool is_device_lost;
|
bool is_device_lost;
|
||||||
|
bool vertex_state_changed : 1;
|
||||||
bool blend_state_changed : 1;
|
bool blend_state_changed : 1;
|
||||||
bool rast_state_changed : 1;
|
bool rast_state_changed : 1;
|
||||||
bool dsa_state_changed : 1;
|
bool dsa_state_changed : 1;
|
||||||
|
@@ -176,6 +176,10 @@ EXTENSIONS = [
|
|||||||
alias="line_rast",
|
alias="line_rast",
|
||||||
properties=True,
|
properties=True,
|
||||||
features=True),
|
features=True),
|
||||||
|
Extension("VK_EXT_vertex_input_dynamic_state",
|
||||||
|
alias="vertex_input",
|
||||||
|
features=True,
|
||||||
|
conditions=["$feats.vertexInputDynamicState"]),
|
||||||
Extension("VK_KHR_dedicated_allocation",
|
Extension("VK_KHR_dedicated_allocation",
|
||||||
alias="dedicated"),
|
alias="dedicated"),
|
||||||
]
|
]
|
||||||
|
@@ -130,7 +130,7 @@ zink_bind_vertex_buffers(struct zink_batch *batch, struct zink_context *ctx)
|
|||||||
VkBuffer buffers[PIPE_MAX_ATTRIBS];
|
VkBuffer buffers[PIPE_MAX_ATTRIBS];
|
||||||
VkDeviceSize buffer_offsets[PIPE_MAX_ATTRIBS];
|
VkDeviceSize buffer_offsets[PIPE_MAX_ATTRIBS];
|
||||||
VkDeviceSize buffer_strides[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);
|
struct zink_screen *screen = zink_screen(ctx->base.screen);
|
||||||
|
|
||||||
if (!elems->hw_state.num_bindings)
|
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) {
|
if (vb->buffer.resource) {
|
||||||
buffers[i] = ctx->vbufs[buffer_id];
|
buffers[i] = ctx->vbufs[buffer_id];
|
||||||
assert(buffers[i]);
|
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_offsets[i] = ctx->vbuf_offsets[buffer_id];
|
||||||
buffer_strides[i] = vb->stride;
|
buffer_strides[i] = vb->stride;
|
||||||
} else {
|
} else {
|
||||||
buffers[i] = zink_resource(ctx->dummy_vertex_buffer)->obj->buffer;
|
buffers[i] = zink_resource(ctx->dummy_vertex_buffer)->obj->buffer;
|
||||||
buffer_offsets[i] = 0;
|
buffer_offsets[i] = 0;
|
||||||
buffer_strides[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,
|
vkCmdBindVertexBuffers(batch->state->cmdbuf, 0,
|
||||||
elems->hw_state.num_bindings,
|
elems->hw_state.num_bindings,
|
||||||
buffers, buffer_offsets);
|
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;
|
ctx->vertex_buffers_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -51,19 +51,23 @@ zink_create_gfx_pipeline(struct zink_screen *screen,
|
|||||||
struct zink_gfx_pipeline_state *state,
|
struct zink_gfx_pipeline_state *state,
|
||||||
VkPrimitiveTopology primitive_topology)
|
VkPrimitiveTopology primitive_topology)
|
||||||
{
|
{
|
||||||
VkPipelineVertexInputStateCreateInfo vertex_input_state = {0};
|
VkPipelineVertexInputStateCreateInfo vertex_input_state;
|
||||||
vertex_input_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
if (!screen->info.have_EXT_vertex_input_dynamic_state) {
|
||||||
vertex_input_state.pVertexBindingDescriptions = state->element_state->bindings;
|
memset(&vertex_input_state, 0, sizeof(vertex_input_state));
|
||||||
vertex_input_state.vertexBindingDescriptionCount = state->element_state->num_bindings;
|
vertex_input_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||||
vertex_input_state.pVertexAttributeDescriptions = state->element_state->attribs;
|
vertex_input_state.pVertexBindingDescriptions = state->element_state->b.bindings;
|
||||||
vertex_input_state.vertexAttributeDescriptionCount = state->element_state->num_attribs;
|
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};
|
VkPipelineVertexInputDivisorStateCreateInfoEXT vdiv_state;
|
||||||
if (state->element_state->divisors_present) {
|
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;
|
vertex_input_state.pNext = &vdiv_state;
|
||||||
vdiv_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
|
vdiv_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
|
||||||
vdiv_state.vertexBindingDivisorCount = state->element_state->divisors_present;
|
vdiv_state.vertexBindingDivisorCount = state->element_state->b.divisors_present;
|
||||||
vdiv_state.pVertexBindingDivisors = state->element_state->divisors;
|
vdiv_state.pVertexBindingDivisors = state->element_state->b.divisors;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkPipelineInputAssemblyStateCreateInfo primitive_state = {0};
|
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_VIEWPORT;
|
||||||
dynamicStateEnables[state_count++] = VK_DYNAMIC_STATE_SCISSOR;
|
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};
|
VkPipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo = {0};
|
||||||
pipelineDynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
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.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||||
pci.layout = prog->base.layout;
|
pci.layout = prog->base.layout;
|
||||||
pci.renderPass = state->render_pass->render_pass;
|
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.pInputAssemblyState = &primitive_state;
|
||||||
pci.pRasterizationState = &rast_state;
|
pci.pRasterizationState = &rast_state;
|
||||||
pci.pColorBlendState = &blend_state;
|
pci.pColorBlendState = &blend_state;
|
||||||
|
@@ -69,7 +69,6 @@ struct zink_gfx_pipeline_state {
|
|||||||
bool combined_dirty;
|
bool combined_dirty;
|
||||||
|
|
||||||
struct zink_vertex_elements_hw_state *element_state;
|
struct zink_vertex_elements_hw_state *element_state;
|
||||||
bool vertex_state_dirty;
|
|
||||||
|
|
||||||
uint32_t final_hash;
|
uint32_t final_hash;
|
||||||
|
|
||||||
|
@@ -764,41 +764,49 @@ zink_get_gfx_pipeline(struct zink_context *ctx,
|
|||||||
struct zink_gfx_pipeline_state *state,
|
struct zink_gfx_pipeline_state *state,
|
||||||
enum pipe_prim_type mode)
|
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;
|
return state->pipeline;
|
||||||
|
|
||||||
struct zink_screen *screen = zink_screen(ctx->base.screen);
|
|
||||||
VkPrimitiveTopology vkmode = primitive_topology(mode);
|
VkPrimitiveTopology vkmode = primitive_topology(mode);
|
||||||
assert(vkmode <= ARRAY_SIZE(prog->pipelines));
|
assert(vkmode <= ARRAY_SIZE(prog->pipelines));
|
||||||
|
|
||||||
struct hash_entry *entry = NULL;
|
struct hash_entry *entry = NULL;
|
||||||
|
|
||||||
if (state->dirty) {
|
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->hash = hash_gfx_pipeline_state(state);
|
||||||
state->dirty = false;
|
state->dirty = false;
|
||||||
}
|
}
|
||||||
if (state->combined_dirty) {
|
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_hash = XXH32(&state->module_hash, sizeof(uint32_t), state->hash);
|
||||||
state->combined_dirty = false;
|
state->combined_dirty = false;
|
||||||
}
|
}
|
||||||
if (state->vertex_state_dirty) {
|
if (have_EXT_vertex_input_dynamic_state)
|
||||||
uint32_t hash = state->combined_hash;
|
state->final_hash = state->combined_hash;
|
||||||
if (!state->have_EXT_extended_dynamic_state) {
|
else
|
||||||
/* if we don't have dynamic states, we have to hash the enabled vertex buffer bindings */
|
if (ctx->vertex_state_changed) {
|
||||||
uint32_t vertex_buffers_enabled_mask = state->vertex_buffers_enabled_mask;
|
uint32_t hash = state->combined_hash;
|
||||||
hash = XXH32(&vertex_buffers_enabled_mask, sizeof(uint32_t), 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++) {
|
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];
|
struct pipe_vertex_buffer *vb = ctx->vertex_buffers + ctx->element_state->binding_map[i];
|
||||||
state->vertex_strides[i] = vb->buffer.resource ? vb->stride : 0;
|
state->vertex_strides[i] = vb->buffer.resource ? vb->stride : 0;
|
||||||
hash = XXH32(&state->vertex_strides[i], sizeof(uint32_t), hash);
|
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);
|
entry = _mesa_hash_table_search_pre_hashed(prog->pipelines[vkmode], state->final_hash, state);
|
||||||
|
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
|
@@ -66,23 +66,45 @@ zink_create_vertex_elements_state(struct pipe_context *pctx,
|
|||||||
ves->divisor[binding] = elem->instance_divisor;
|
ves->divisor[binding] = elem->instance_divisor;
|
||||||
assert(elem->instance_divisor <= screen->info.vdiv_props.maxVertexAttribDivisor);
|
assert(elem->instance_divisor <= screen->info.vdiv_props.maxVertexAttribDivisor);
|
||||||
|
|
||||||
ves->hw_state.attribs[i].binding = binding;
|
if (screen->info.have_EXT_vertex_input_dynamic_state) {
|
||||||
ves->hw_state.attribs[i].location = i;
|
ves->hw_state.dynattribs[i].sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT;
|
||||||
ves->hw_state.attribs[i].format = zink_get_format(screen,
|
ves->hw_state.dynattribs[i].binding = binding;
|
||||||
elem->src_format);
|
ves->hw_state.dynattribs[i].location = i;
|
||||||
assert(ves->hw_state.attribs[i].format != VK_FORMAT_UNDEFINED);
|
ves->hw_state.dynattribs[i].format = zink_get_format(screen,
|
||||||
ves->hw_state.attribs[i].offset = elem->src_offset;
|
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_bindings = num_bindings;
|
||||||
ves->hw_state.num_attribs = num_elements;
|
ves->hw_state.num_attribs = num_elements;
|
||||||
for (int i = 0; i < num_bindings; ++i) {
|
if (screen->info.have_EXT_vertex_input_dynamic_state) {
|
||||||
ves->hw_state.bindings[i].binding = ves->bindings[i].binding;
|
for (int i = 0; i < num_bindings; ++i) {
|
||||||
ves->hw_state.bindings[i].inputRate = ves->bindings[i].inputRate;
|
ves->hw_state.dynbindings[i].sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT;
|
||||||
if (ves->divisor[i]) {
|
ves->hw_state.dynbindings[i].binding = ves->bindings[i].binding;
|
||||||
ves->hw_state.divisors[ves->hw_state.divisors_present].divisor = ves->divisor[i];
|
ves->hw_state.dynbindings[i].inputRate = ves->bindings[i].inputRate;
|
||||||
ves->hw_state.divisors[ves->hw_state.divisors_present].binding = ves->bindings[i].binding;
|
if (ves->divisor[i])
|
||||||
ves->hw_state.divisors_present++;
|
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;
|
return ves;
|
||||||
@@ -97,7 +119,7 @@ zink_bind_vertex_elements_state(struct pipe_context *pctx,
|
|||||||
ctx->element_state = cso;
|
ctx->element_state = cso;
|
||||||
if (cso) {
|
if (cso) {
|
||||||
if (state->element_state != &ctx->element_state->hw_state) {
|
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;
|
ctx->vertex_buffers_dirty = ctx->element_state->hw_state.num_bindings > 0;
|
||||||
}
|
}
|
||||||
state->element_state = &ctx->element_state->hw_state;
|
state->element_state = &ctx->element_state->hw_state;
|
||||||
|
@@ -29,11 +29,19 @@
|
|||||||
#include "pipe/p_state.h"
|
#include "pipe/p_state.h"
|
||||||
|
|
||||||
struct zink_vertex_elements_hw_state {
|
struct zink_vertex_elements_hw_state {
|
||||||
VkVertexInputAttributeDescription attribs[PIPE_MAX_ATTRIBS];
|
union {
|
||||||
VkVertexInputBindingDivisorDescriptionEXT divisors[PIPE_MAX_ATTRIBS];
|
VkVertexInputAttributeDescription attribs[PIPE_MAX_ATTRIBS];
|
||||||
VkVertexInputBindingDescription bindings[PIPE_MAX_ATTRIBS]; // combination of element_state and stride
|
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;
|
uint32_t num_bindings, num_attribs;
|
||||||
uint8_t divisors_present;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct zink_vertex_elements_state {
|
struct zink_vertex_elements_state {
|
||||||
|
Reference in New Issue
Block a user