Module: Mesa Branch: main Commit: 86eb1549efded1e6209b65d2b90a0d270d076824 URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=86eb1549efded1e6209b65d2b90a0d270d076824
Author: Mike Blumenkrantz <[email protected]> Date: Fri Nov 5 12:00:25 2021 -0400 zink: implement pipe_context::draw_vertex_state rough implementation, but it should be a decent start Reviewed-by: Dave Airlie <[email protected]> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/13692> --- src/gallium/drivers/zink/zink_context.h | 8 +- src/gallium/drivers/zink/zink_draw.cpp | 130 ++++++++++++++++++++++++++------ src/gallium/drivers/zink/zink_inlines.h | 2 + src/gallium/drivers/zink/zink_screen.c | 8 ++ src/gallium/drivers/zink/zink_screen.h | 2 + src/gallium/drivers/zink/zink_state.c | 93 +++++++++++++++++++++++ src/gallium/drivers/zink/zink_state.h | 40 +++++++++- 7 files changed, 258 insertions(+), 25 deletions(-) diff --git a/src/gallium/drivers/zink/zink_context.h b/src/gallium/drivers/zink/zink_context.h index 65aaf02c00f..9e017c7d9bc 100644 --- a/src/gallium/drivers/zink/zink_context.h +++ b/src/gallium/drivers/zink/zink_context.h @@ -160,7 +160,12 @@ typedef void (*pipe_draw_vbo_func)(struct pipe_context *pipe, const struct pipe_draw_indirect_info *indirect, const struct pipe_draw_start_count_bias *draws, unsigned num_draws); - +typedef void (*pipe_draw_vertex_state_func)(struct pipe_context *ctx, + struct pipe_vertex_state *vstate, + uint32_t partial_velem_mask, + struct pipe_draw_vertex_state_info info, + const struct pipe_draw_start_count_bias *draws, + unsigned num_draws); typedef void (*pipe_launch_grid_func)(struct pipe_context *pipe, const struct pipe_grid_info *info); typedef enum { @@ -183,6 +188,7 @@ struct zink_context { struct blitter_context *blitter; pipe_draw_vbo_func draw_vbo[2]; //batch changed + pipe_draw_vertex_state_func draw_state[2]; //batch changed pipe_launch_grid_func launch_grid[2]; //batch changed struct pipe_device_reset_callback reset; diff --git a/src/gallium/drivers/zink/zink_draw.cpp b/src/gallium/drivers/zink/zink_draw.cpp index 2be1085048b..532aeb4814f 100644 --- a/src/gallium/drivers/zink/zink_draw.cpp +++ b/src/gallium/drivers/zink/zink_draw.cpp @@ -171,6 +171,28 @@ zink_bind_vertex_buffers(struct zink_batch *batch, struct zink_context *ctx) ctx->vertex_buffers_dirty = false; } +static void +zink_bind_vertex_state(struct zink_batch *batch, struct zink_context *ctx, + struct pipe_vertex_state *vstate, uint32_t partial_velem_mask) +{ + if (!vstate->input.vbuffer.buffer.resource) + return; + + const struct zink_vertex_elements_hw_state *hw_state = zink_vertex_state_mask(vstate, partial_velem_mask, true); + assert(hw_state); + + struct zink_resource *res = zink_resource(vstate->input.vbuffer.buffer.resource); + zink_batch_resource_usage_set(&ctx->batch, res, false); + VkDeviceSize offset = vstate->input.vbuffer.buffer_offset; + VKCTX(CmdBindVertexBuffers)(batch->state->cmdbuf, 0, + hw_state->num_bindings, + &res->obj->buffer, &offset); + + VKCTX(CmdSetVertexInputEXT)(batch->state->cmdbuf, + hw_state->num_bindings, hw_state->dynbindings, + hw_state->num_attribs, hw_state->dynattribs); +} + static void update_gfx_program(struct zink_context *ctx) { @@ -452,14 +474,16 @@ hack_conditional_render(struct pipe_context *pctx, return true; } -template <zink_multidraw HAS_MULTIDRAW, zink_dynamic_state DYNAMIC_STATE, bool BATCH_CHANGED> +template <zink_multidraw HAS_MULTIDRAW, zink_dynamic_state DYNAMIC_STATE, bool BATCH_CHANGED, bool DRAW_STATE> void -zink_draw_vbo(struct pipe_context *pctx, - const struct pipe_draw_info *dinfo, - unsigned drawid_offset, - const struct pipe_draw_indirect_info *dindirect, - const struct pipe_draw_start_count_bias *draws, - unsigned num_draws) +zink_draw(struct pipe_context *pctx, + const struct pipe_draw_info *dinfo, + unsigned drawid_offset, + const struct pipe_draw_indirect_info *dindirect, + const struct pipe_draw_start_count_bias *draws, + unsigned num_draws, + struct pipe_vertex_state *vstate, + uint32_t partial_velem_mask) { struct zink_context *ctx = zink_context(pctx); struct zink_screen *screen = zink_screen(pctx->screen); @@ -734,7 +758,9 @@ zink_draw_vbo(struct pipe_context *pctx, } ctx->blend_state_changed = false; - if (BATCH_CHANGED || ctx->vertex_buffers_dirty) + if (DRAW_STATE) + zink_bind_vertex_state(batch, ctx, vstate, partial_velem_mask); + else if (BATCH_CHANGED || ctx->vertex_buffers_dirty) zink_bind_vertex_buffers<DYNAMIC_STATE>(batch, ctx); zink_query_update_gs_states(ctx); @@ -859,6 +885,47 @@ zink_draw_vbo(struct pipe_context *pctx, pctx->flush(pctx, NULL, 0); } +template <zink_multidraw HAS_MULTIDRAW, zink_dynamic_state DYNAMIC_STATE, bool BATCH_CHANGED> +static void +zink_draw_vbo(struct pipe_context *pctx, + const struct pipe_draw_info *info, + unsigned drawid_offset, + const struct pipe_draw_indirect_info *indirect, + const struct pipe_draw_start_count_bias *draws, + unsigned num_draws) +{ + zink_draw<HAS_MULTIDRAW, DYNAMIC_STATE, BATCH_CHANGED, false>(pctx, info, drawid_offset, indirect, draws, num_draws, NULL, 0); +} + +template <zink_multidraw HAS_MULTIDRAW, zink_dynamic_state DYNAMIC_STATE, bool BATCH_CHANGED> +static void +zink_draw_vertex_state(struct pipe_context *pctx, + struct pipe_vertex_state *vstate, + uint32_t partial_velem_mask, + struct pipe_draw_vertex_state_info info, + const struct pipe_draw_start_count_bias *draws, + unsigned num_draws) +{ + struct pipe_draw_info dinfo = {}; + + dinfo.mode = info.mode; + dinfo.index_size = 4; + dinfo.instance_count = 1; + dinfo.index.resource = vstate->input.indexbuf; + struct zink_context *ctx = zink_context(pctx); + struct zink_resource *res = zink_resource(vstate->input.vbuffer.buffer.resource); + zink_resource_buffer_barrier(ctx, res, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, + VK_PIPELINE_STAGE_VERTEX_INPUT_BIT); + struct zink_vertex_elements_hw_state *hw_state = ctx->gfx_pipeline_state.element_state; + ctx->gfx_pipeline_state.element_state = &((struct zink_vertex_state*)vstate)->velems.hw_state; + + zink_draw<HAS_MULTIDRAW, DYNAMIC_STATE, BATCH_CHANGED, true>(pctx, &dinfo, 0, NULL, draws, num_draws, vstate, partial_velem_mask); + ctx->gfx_pipeline_state.element_state = hw_state; + + if (info.take_vertex_state_ownership) + pipe_vertex_state_reference(&vstate, NULL); +} + template <bool BATCH_CHANGED> static void zink_launch_grid(struct pipe_context *pctx, const struct pipe_grid_info *info) @@ -928,35 +995,35 @@ zink_launch_grid(struct pipe_context *pctx, const struct pipe_grid_info *info) template <zink_multidraw HAS_MULTIDRAW, zink_dynamic_state DYNAMIC_STATE, bool BATCH_CHANGED> static void -init_batch_changed_functions(struct zink_context *ctx, pipe_draw_vbo_func draw_vbo_array[2][4][2]) +init_batch_changed_functions(struct zink_context *ctx, pipe_draw_vbo_func draw_vbo_array[2][4][2], pipe_draw_vertex_state_func draw_state_array[2][4][2]) { - draw_vbo_array[HAS_MULTIDRAW][DYNAMIC_STATE][BATCH_CHANGED] = - zink_draw_vbo<HAS_MULTIDRAW, DYNAMIC_STATE, BATCH_CHANGED>; + draw_vbo_array[HAS_MULTIDRAW][DYNAMIC_STATE][BATCH_CHANGED] = zink_draw_vbo<HAS_MULTIDRAW, DYNAMIC_STATE, BATCH_CHANGED>; + draw_state_array[HAS_MULTIDRAW][DYNAMIC_STATE][BATCH_CHANGED] = zink_draw_vertex_state<HAS_MULTIDRAW, DYNAMIC_STATE, BATCH_CHANGED>; } template <zink_multidraw HAS_MULTIDRAW, zink_dynamic_state DYNAMIC_STATE> static void -init_dynamic_state_functions(struct zink_context *ctx, pipe_draw_vbo_func draw_vbo_array[2][4][2]) +init_dynamic_state_functions(struct zink_context *ctx, pipe_draw_vbo_func draw_vbo_array[2][4][2], pipe_draw_vertex_state_func draw_state_array[2][4][2]) { - init_batch_changed_functions<HAS_MULTIDRAW, DYNAMIC_STATE, false>(ctx, draw_vbo_array); - init_batch_changed_functions<HAS_MULTIDRAW, DYNAMIC_STATE, true>(ctx, draw_vbo_array); + init_batch_changed_functions<HAS_MULTIDRAW, DYNAMIC_STATE, false>(ctx, draw_vbo_array, draw_state_array); + init_batch_changed_functions<HAS_MULTIDRAW, DYNAMIC_STATE, true>(ctx, draw_vbo_array, draw_state_array); } template <zink_multidraw HAS_MULTIDRAW> static void -init_multidraw_functions(struct zink_context *ctx, pipe_draw_vbo_func draw_vbo_array[2][4][2]) +init_multidraw_functions(struct zink_context *ctx, pipe_draw_vbo_func draw_vbo_array[2][4][2], pipe_draw_vertex_state_func draw_state_array[2][4][2]) { - init_dynamic_state_functions<HAS_MULTIDRAW, ZINK_NO_DYNAMIC_STATE>(ctx, draw_vbo_array); - init_dynamic_state_functions<HAS_MULTIDRAW, ZINK_DYNAMIC_STATE>(ctx, draw_vbo_array); - init_dynamic_state_functions<HAS_MULTIDRAW, ZINK_DYNAMIC_STATE2>(ctx, draw_vbo_array); - init_dynamic_state_functions<HAS_MULTIDRAW, ZINK_DYNAMIC_VERTEX_INPUT>(ctx, draw_vbo_array); + init_dynamic_state_functions<HAS_MULTIDRAW, ZINK_NO_DYNAMIC_STATE>(ctx, draw_vbo_array, draw_state_array); + init_dynamic_state_functions<HAS_MULTIDRAW, ZINK_DYNAMIC_STATE>(ctx, draw_vbo_array, draw_state_array); + init_dynamic_state_functions<HAS_MULTIDRAW, ZINK_DYNAMIC_STATE2>(ctx, draw_vbo_array, draw_state_array); + init_dynamic_state_functions<HAS_MULTIDRAW, ZINK_DYNAMIC_VERTEX_INPUT>(ctx, draw_vbo_array, draw_state_array); } static void -init_all_draw_functions(struct zink_context *ctx, pipe_draw_vbo_func draw_vbo_array[2][4][2]) +init_all_draw_functions(struct zink_context *ctx, pipe_draw_vbo_func draw_vbo_array[2][4][2], pipe_draw_vertex_state_func draw_state_array[2][4][2]) { - init_multidraw_functions<ZINK_NO_MULTIDRAW>(ctx, draw_vbo_array); - init_multidraw_functions<ZINK_MULTIDRAW>(ctx, draw_vbo_array); + init_multidraw_functions<ZINK_NO_MULTIDRAW>(ctx, draw_vbo_array, draw_state_array); + init_multidraw_functions<ZINK_MULTIDRAW>(ctx, draw_vbo_array, draw_state_array); } template <bool BATCH_CHANGED> @@ -984,6 +1051,17 @@ zink_invalid_draw_vbo(struct pipe_context *pipe, unreachable("vertex shader not bound"); } +static void +zink_invalid_draw_vertex_state(struct pipe_context *pipe, + struct pipe_vertex_state *vstate, + uint32_t partial_velem_mask, + struct pipe_draw_vertex_state_info info, + const struct pipe_draw_start_count_bias *draws, + unsigned num_draws) +{ + unreachable("vertex shader not bound"); +} + static void zink_invalid_launch_grid(struct pipe_context *pctx, const struct pipe_grid_info *info) { @@ -1043,6 +1121,8 @@ zink_init_draw_functions(struct zink_context *ctx, struct zink_screen *screen) { pipe_draw_vbo_func draw_vbo_array[2][4] //multidraw, zink_dynamic_state [2]; //batch changed + pipe_draw_vertex_state_func draw_state_array[2][4] //multidraw, zink_dynamic_state + [2]; //batch changed zink_dynamic_state dynamic; if (screen->info.have_EXT_extended_dynamic_state) { if (screen->info.have_EXT_extended_dynamic_state2) { @@ -1056,15 +1136,19 @@ zink_init_draw_functions(struct zink_context *ctx, struct zink_screen *screen) } else { dynamic = ZINK_NO_DYNAMIC_STATE; } - init_all_draw_functions(ctx, draw_vbo_array); + init_all_draw_functions(ctx, draw_vbo_array, draw_state_array); memcpy(ctx->draw_vbo, &draw_vbo_array[screen->info.have_EXT_multi_draw] [dynamic], sizeof(ctx->draw_vbo)); + memcpy(ctx->draw_state, &draw_state_array[screen->info.have_EXT_multi_draw] + [dynamic], + sizeof(ctx->draw_state)); /* Bind a fake draw_vbo, so that draw_vbo isn't NULL, which would skip * initialization of callbacks in upper layers (such as u_threaded_context). */ ctx->base.draw_vbo = zink_invalid_draw_vbo; + ctx->base.draw_vertex_state = zink_invalid_draw_vertex_state; _mesa_hash_table_init(&ctx->program_cache[0], ctx, hash_gfx_program<0>, equals_gfx_program<0>); _mesa_hash_table_init(&ctx->program_cache[1], ctx, hash_gfx_program<1>, equals_gfx_program<1>); diff --git a/src/gallium/drivers/zink/zink_inlines.h b/src/gallium/drivers/zink/zink_inlines.h index fe873828423..44d4474d99a 100644 --- a/src/gallium/drivers/zink/zink_inlines.h +++ b/src/gallium/drivers/zink/zink_inlines.h @@ -6,7 +6,9 @@ static inline void zink_select_draw_vbo(struct zink_context *ctx) { ctx->base.draw_vbo = ctx->draw_vbo[ctx->pipeline_changed[0]]; + ctx->base.draw_vertex_state = ctx->draw_state[ctx->pipeline_changed[0]]; assert(ctx->base.draw_vbo); + assert(ctx->base.draw_vertex_state); } static inline void diff --git a/src/gallium/drivers/zink/zink_screen.c b/src/gallium/drivers/zink/zink_screen.c index 11814e25a9a..45ae6c4b5b2 100644 --- a/src/gallium/drivers/zink/zink_screen.c +++ b/src/gallium/drivers/zink/zink_screen.c @@ -363,6 +363,9 @@ zink_get_param(struct pipe_screen *pscreen, enum pipe_cap param) case PIPE_CAP_TGSI_PACK_HALF_FLOAT: return 1; + case PIPE_CAP_DRAW_VERTEX_STATE: + return screen->info.have_EXT_vertex_input_dynamic_state; + case PIPE_CAP_SURFACE_SAMPLE_COUNT: return screen->vk_version >= VK_MAKE_VERSION(1,2,0); @@ -2068,6 +2071,11 @@ zink_internal_create_screen(const struct pipe_screen_config *config) zink_screen_init_descriptor_funcs(screen, false); util_idalloc_mt_init_tc(&screen->buffer_ids); + util_vertex_state_cache_init(&screen->vertex_state_cache, + zink_create_vertex_state, zink_vertex_state_destroy); + screen->base.create_vertex_state = zink_cache_create_vertex_state; + screen->base.vertex_state_destroy = zink_cache_vertex_state_destroy; + return screen; fail: diff --git a/src/gallium/drivers/zink/zink_screen.h b/src/gallium/drivers/zink/zink_screen.h index 6bb14fc4545..7df140b078f 100644 --- a/src/gallium/drivers/zink/zink_screen.h +++ b/src/gallium/drivers/zink/zink_screen.h @@ -37,6 +37,7 @@ #include "util/simple_mtx.h" #include "util/u_queue.h" #include "util/u_live_shader_cache.h" +#include "util/u_vertex_state_cache.h" #include "pipebuffer/pb_cache.h" #include "pipebuffer/pb_slab.h" #include <vulkan/vulkan.h> @@ -120,6 +121,7 @@ struct zink_screen { VkPhysicalDevice pdev; uint32_t vk_version, spirv_version; struct util_idalloc_mt buffer_ids; + struct util_vertex_state_cache vertex_state_cache; struct zink_device_info info; struct nir_shader_compiler_options nir_options; diff --git a/src/gallium/drivers/zink/zink_state.c b/src/gallium/drivers/zink/zink_state.c index 68e8d413ff9..313c78cc396 100644 --- a/src/gallium/drivers/zink/zink_state.c +++ b/src/gallium/drivers/zink/zink_state.c @@ -31,6 +31,7 @@ #include "compiler/shader_enums.h" #include "util/u_dual_blend.h" #include "util/u_memory.h" +#include "util/u_helpers.h" #include <math.h> @@ -714,6 +715,98 @@ zink_delete_rasterizer_state(struct pipe_context *pctx, void *rs_state) FREE(rs_state); } +struct pipe_vertex_state * +zink_create_vertex_state(struct pipe_screen *pscreen, + struct pipe_vertex_buffer *buffer, + const struct pipe_vertex_element *elements, + unsigned num_elements, + struct pipe_resource *indexbuf, + uint32_t full_velem_mask) +{ + struct zink_vertex_state *zstate = CALLOC_STRUCT(zink_vertex_state); + _mesa_set_init(&zstate->masks, NULL, NULL, _mesa_key_pointer_equal); + + util_init_pipe_vertex_state(pscreen, buffer, elements, num_elements, indexbuf, full_velem_mask, + &zstate->b); + + /* Initialize the vertex element state in state->element. + * Do it by creating a vertex element state object and copying it there. + */ + struct zink_context ctx; + ctx.base.screen = pscreen; + struct zink_vertex_elements_state *elems = zink_create_vertex_elements_state(&ctx.base, num_elements, elements); + for (unsigned i = 0; i < elems->hw_state.num_bindings; i++) { + if (zink_screen(pscreen)->info.have_EXT_vertex_input_dynamic_state) + elems->hw_state.dynbindings[i].stride = buffer->stride; + } + zstate->velems = *elems; + zink_delete_vertex_elements_state(&ctx.base, elems); + + return &zstate->b; +} + +void +zink_vertex_state_destroy(struct pipe_screen *pscreen, struct pipe_vertex_state *vstate) +{ + struct zink_vertex_state *zstate = (struct zink_vertex_state *)vstate; + ralloc_free(zstate->masks.table); + pipe_vertex_buffer_unreference(&vstate->input.vbuffer); + pipe_resource_reference(&vstate->input.indexbuf, NULL); + FREE(vstate); +} + +const struct zink_vertex_elements_hw_state * +zink_vertex_state_mask(struct pipe_vertex_state *vstate, uint32_t partial_velem_mask, bool have_EXT_vertex_input_dynamic_state) +{ + struct zink_vertex_state *zstate = (struct zink_vertex_state *)vstate; + + if (partial_velem_mask == vstate->input.full_velem_mask) + return &zstate->velems.hw_state; + struct set_entry *he = _mesa_set_search_pre_hashed(&zstate->masks, partial_velem_mask, (void*)(uintptr_t)partial_velem_mask); + if (he) + return he->key; + + struct zink_vertex_elements_hw_state *hw_state = rzalloc(zstate->masks.table, struct zink_vertex_elements_hw_state); + unsigned i = 0; + if (have_EXT_vertex_input_dynamic_state) { + u_foreach_bit(elem, vstate->input.full_velem_mask & partial_velem_mask) { + unsigned idx = util_bitcount(vstate->input.full_velem_mask & BITFIELD_MASK(elem)); + hw_state->dynattribs[i] = zstate->velems.hw_state.dynattribs[idx]; + hw_state->dynattribs[i].location = i; + i++; + } + memcpy(hw_state->dynbindings, zstate->velems.hw_state.dynbindings, + zstate->velems.hw_state.num_bindings * sizeof(VkVertexInputBindingDescription2EXT)); + } else { + } + hw_state->num_attribs = i; + hw_state->num_bindings = zstate->velems.hw_state.num_bindings; + _mesa_set_add_pre_hashed(&zstate->masks, partial_velem_mask, hw_state); + return hw_state; +} + +struct pipe_vertex_state * +zink_cache_create_vertex_state(struct pipe_screen *pscreen, + struct pipe_vertex_buffer *buffer, + const struct pipe_vertex_element *elements, + unsigned num_elements, + struct pipe_resource *indexbuf, + uint32_t full_velem_mask) +{ + struct zink_screen *screen = zink_screen(pscreen); + + return util_vertex_state_cache_get(pscreen, buffer, elements, num_elements, indexbuf, + full_velem_mask, &screen->vertex_state_cache); +} + +void +zink_cache_vertex_state_destroy(struct pipe_screen *pscreen, struct pipe_vertex_state *vstate) +{ + struct zink_screen *screen = zink_screen(pscreen); + + util_vertex_state_destroy(pscreen, &screen->vertex_state_cache, vstate); +} + void zink_context_state_init(struct pipe_context *pctx) { diff --git a/src/gallium/drivers/zink/zink_state.h b/src/gallium/drivers/zink/zink_state.h index 1254498377c..27011903fe4 100644 --- a/src/gallium/drivers/zink/zink_state.h +++ b/src/gallium/drivers/zink/zink_state.h @@ -27,9 +27,11 @@ #include <vulkan/vulkan.h> #include "pipe/p_state.h" +#include "util/set.h" struct zink_vertex_elements_hw_state { uint32_t hash; + uint32_t num_bindings, num_attribs; union { VkVertexInputAttributeDescription attribs[PIPE_MAX_ATTRIBS]; VkVertexInputAttributeDescription2EXT dynattribs[PIPE_MAX_ATTRIBS]; @@ -42,7 +44,6 @@ struct zink_vertex_elements_hw_state { } b; VkVertexInputBindingDescription2EXT dynbindings[PIPE_MAX_ATTRIBS]; }; - uint32_t num_bindings, num_attribs; }; struct zink_vertex_elements_state { @@ -59,6 +60,12 @@ struct zink_vertex_elements_state { struct zink_vertex_elements_hw_state hw_state; }; +struct zink_vertex_state { + struct pipe_vertex_state b; + struct zink_vertex_elements_state velems; + struct set masks; +}; + struct zink_rasterizer_hw_state { unsigned polygon_mode : 2; //VkPolygonMode unsigned cull_mode : 2; //VkCullModeFlags @@ -115,7 +122,38 @@ struct zink_depth_stencil_alpha_state { struct zink_depth_stencil_alpha_hw_state hw_state; }; +#ifdef __cplusplus +extern "C" { +#endif + void zink_context_state_init(struct pipe_context *pctx); + +struct pipe_vertex_state * +zink_create_vertex_state(struct pipe_screen *pscreen, + struct pipe_vertex_buffer *buffer, + const struct pipe_vertex_element *elements, + unsigned num_elements, + struct pipe_resource *indexbuf, + uint32_t full_velem_mask); +void +zink_vertex_state_destroy(struct pipe_screen *pscreen, struct pipe_vertex_state *vstate); +struct pipe_vertex_state * +zink_cache_create_vertex_state(struct pipe_screen *pscreen, + struct pipe_vertex_buffer *buffer, + const struct pipe_vertex_element *elements, + unsigned num_elements, + struct pipe_resource *indexbuf, + uint32_t full_velem_mask); +void +zink_cache_vertex_state_destroy(struct pipe_screen *pscreen, struct pipe_vertex_state *vstate); + +const struct zink_vertex_elements_hw_state * +zink_vertex_state_mask(struct pipe_vertex_state *vstate, uint32_t partial_velem_mask, bool have_EXT_vertex_input_dynamic_state); + +#ifdef __cplusplus +} +#endif + #endif
