diff --git a/docs/vulkan/graphics-state.rst b/docs/vulkan/graphics-state.rst index b74857c7a1a..278a5985031 100644 --- a/docs/vulkan/graphics-state.rst +++ b/docs/vulkan/graphics-state.rst @@ -82,6 +82,32 @@ together but store the final state on the stack for immediate consumption: .. doxygenfunction:: vk_graphics_pipeline_state_merge + +Dynamic state +------------- + +All dynamic states in Vulkan, regardless of which API version or extension +introduced them, are represented by the +:cpp:enum:`mesa_vk_dynamic_graphics_state` enum. This corresponds to the +:cpp:type:`VkDynamicState` enum in the Vulkan API only it's compact (has no +holes due to extension namespacing) and a bit better organized. Each +enumerant is named with the name of the state group to which the dynamic +state belongs as well as the name of the dynamic state itself. The fact +that it's compact allows us to use to index bitsets. + +.. doxygenfunction:: vk_get_dynamic_graphics_states + +We also provide a :cpp:struct:`vk_dynamic_graphics_state` structure which +contains all the dynamic graphics states, regardless of which API version +or extension introduced them. This structure can be populated from a +:cpp:struct:`vk_graphics_pipeline_state` via +:cpp:func:`vk_dynamic_graphics_state_init`. + +.. doxygenfunction:: vk_dynamic_graphics_state_init + +.. doxygenfunction:: vk_dynamic_graphics_state_copy + + Reference --------- @@ -133,3 +159,7 @@ Reference .. doxygenstruct:: vk_render_pass_state :members: +.. doxygenenum:: mesa_vk_dynamic_graphics_state + +.. doxygenstruct:: vk_dynamic_graphics_state + :members: diff --git a/src/vulkan/runtime/vk_graphics_state.c b/src/vulkan/runtime/vk_graphics_state.c index 3a8341da920..2a6344b4d1f 100644 --- a/src/vulkan/runtime/vk_graphics_state.c +++ b/src/vulkan/runtime/vk_graphics_state.c @@ -180,6 +180,9 @@ vk_get_dynamic_graphics_states(BITSET_WORD *dynamic, #define IS_DYNAMIC(STATE) \ BITSET_TEST(dynamic, MESA_VK_DYNAMIC_##STATE) +#define IS_NEEDED(STATE) \ + BITSET_TEST(needed, MESA_VK_DYNAMIC_##STATE) + static void vk_vertex_input_state_init(struct vk_vertex_input_state *vi, const BITSET_WORD *dynamic, @@ -236,6 +239,24 @@ vk_vertex_input_state_init(struct vk_vertex_input_state *vi, } } +static void +vk_dynamic_graphics_state_init_vi(struct vk_dynamic_graphics_state *dst, + const BITSET_WORD *needed, + const struct vk_vertex_input_state *vi) +{ + if (IS_NEEDED(VI)) + *dst->vi = *vi; + + if (IS_NEEDED(VI_BINDING_STRIDES)) { + for (uint32_t b = 0; b < MESA_VK_MAX_VERTEX_BINDINGS; b++) { + if (vi->bindings_valid & BITFIELD_BIT(b)) + dst->vi_binding_strides[b] = vi->bindings[b].stride; + else + dst->vi_binding_strides[b] = 0; + } + } +} + static void vk_input_assembly_state_init(struct vk_input_assembly_state *ia, const BITSET_WORD *dynamic, @@ -251,6 +272,14 @@ vk_input_assembly_state_init(struct vk_input_assembly_state *ia, ia->primitive_restart_enable = ia_info->primitiveRestartEnable; } +static void +vk_dynamic_graphics_state_init_ia(struct vk_dynamic_graphics_state *dst, + const BITSET_WORD *needed, + const struct vk_input_assembly_state *ia) +{ + dst->ia = *ia; +} + static void vk_tessellation_state_init(struct vk_tessellation_state *ts, const BITSET_WORD *dynamic, @@ -274,6 +303,14 @@ vk_tessellation_state_init(struct vk_tessellation_state *ts, } } +static void +vk_dynamic_graphics_state_init_ts(struct vk_dynamic_graphics_state *dst, + const BITSET_WORD *needed, + const struct vk_tessellation_state *ts) +{ + dst->ts.patch_control_points = ts->patch_control_points; +} + static void vk_viewport_state_init(struct vk_viewport_state *vp, const BITSET_WORD *dynamic, @@ -310,6 +347,20 @@ vk_viewport_state_init(struct vk_viewport_state *vp, vp->negative_one_to_one = vp_dcc_info->negativeOneToOne; } +static void +vk_dynamic_graphics_state_init_vp(struct vk_dynamic_graphics_state *dst, + const BITSET_WORD *needed, + const struct vk_viewport_state *vp) +{ + dst->vp.viewport_count = vp->viewport_count; + if (IS_NEEDED(VP_VIEWPORTS)) + typed_memcpy(dst->vp.viewports, vp->viewports, vp->viewport_count); + + dst->vp.scissor_count = vp->scissor_count; + if (IS_NEEDED(VP_SCISSORS)) + typed_memcpy(dst->vp.scissors, vp->scissors, vp->scissor_count); +} + static void vk_discard_rectangles_state_init(struct vk_discard_rectangles_state *dr, const BITSET_WORD *dynamic, @@ -330,6 +381,15 @@ vk_discard_rectangles_state_init(struct vk_discard_rectangles_state *dr, } } +static void +vk_dynamic_graphics_state_init_dr(struct vk_dynamic_graphics_state *dst, + const BITSET_WORD *needed, + const struct vk_discard_rectangles_state *dr) +{ + dst->dr.rectangle_count = dr->rectangle_count; + typed_memcpy(dst->dr.rectangles, dr->rectangles, dr->rectangle_count); +} + static void vk_rasterization_state_init(struct vk_rasterization_state *rs, const BITSET_WORD *dynamic, @@ -427,6 +487,23 @@ vk_rasterization_state_init(struct vk_rasterization_state *rs, } } +static void +vk_dynamic_graphics_state_init_rs(struct vk_dynamic_graphics_state *dst, + const BITSET_WORD *needed, + const struct vk_rasterization_state *rs) +{ + dst->rs.rasterizer_discard_enable = rs->rasterizer_discard_enable; + dst->rs.cull_mode = rs->cull_mode; + dst->rs.front_face = rs->front_face; + dst->rs.depth_bias.enable = rs->depth_bias.enable; + dst->rs.depth_bias.constant = rs->depth_bias.constant; + dst->rs.depth_bias.clamp = rs->depth_bias.clamp; + dst->rs.depth_bias.slope = rs->depth_bias.slope; + dst->rs.line.width = rs->line.width; + dst->rs.line.stipple.factor = rs->line.stipple.factor; + dst->rs.line.stipple.pattern = rs->line.stipple.pattern; +} + static void vk_fragment_shading_rate_state_init( struct vk_fragment_shading_rate_state *fsr, @@ -444,6 +521,15 @@ vk_fragment_shading_rate_state_init( } } +static void +vk_dynamic_graphics_state_init_fsr( + struct vk_dynamic_graphics_state *dst, + const BITSET_WORD *needed, + const struct vk_fragment_shading_rate_state *fsr) +{ + dst->fsr = *fsr; +} + static void vk_sample_locations_state_init(struct vk_sample_locations_state *sl, const VkSampleLocationsInfoEXT *sl_info) @@ -529,6 +615,15 @@ vk_multisample_sample_locations_state_init( } } +static void +vk_dynamic_graphics_state_init_ms(struct vk_dynamic_graphics_state *dst, + const BITSET_WORD *needed, + const struct vk_multisample_state *ms) +{ + if (IS_NEEDED(MS_SAMPLE_LOCATIONS)) + *dst->ms.sample_locations = *ms->sample_locations; +} + static void vk_stencil_test_face_state_init(struct vk_stencil_test_face_state *face, const VkStencilOpState *info) @@ -561,6 +656,14 @@ vk_depth_stencil_state_init(struct vk_depth_stencil_state *ds, vk_stencil_test_face_state_init(&ds->stencil.back, &ds_info->back); } +static void +vk_dynamic_graphics_state_init_ds(struct vk_dynamic_graphics_state *dst, + const BITSET_WORD *needed, + const struct vk_depth_stencil_state *ds) +{ + dst->ds = *ds; +} + static void vk_color_blend_state_init(struct vk_color_blend_state *cb, const BITSET_WORD *dynamic, @@ -605,6 +708,18 @@ vk_color_blend_state_init(struct vk_color_blend_state *cb, } } +static void +vk_dynamic_graphics_state_init_cb(struct vk_dynamic_graphics_state *dst, + const BITSET_WORD *needed, + const struct vk_color_blend_state *cb) +{ + dst->cb.logic_op = cb->logic_op; + dst->cb.color_write_enables = cb->color_write_enables; + + if (IS_NEEDED(CB_BLEND_CONSTANTS)) + typed_memcpy(dst->cb.blend_constants, cb->blend_constants, 4); +} + static bool vk_render_pass_state_is_complete(const struct vk_render_pass_state *rp) { @@ -696,6 +811,12 @@ vk_render_pass_state_init(struct vk_render_pass_state *rp, } } +static void +vk_dynamic_graphics_state_init_rp(struct vk_dynamic_graphics_state *dst, + const BITSET_WORD *needed, + const struct vk_render_pass_state *rp) +{ } + #define FOREACH_STATE_GROUP(f) \ f(MESA_VK_GRAPHICS_STATE_VERTEX_INPUT_BIT, \ vk_vertex_input_state, vi); \ @@ -1061,6 +1182,7 @@ vk_graphics_pipeline_state_fill(const struct vk_device *device, } #undef IS_DYNAMIC +#undef IS_NEEDED void vk_graphics_pipeline_state_merge(struct vk_graphics_pipeline_state *dst, @@ -1086,3 +1208,271 @@ vk_graphics_pipeline_state_merge(struct vk_graphics_pipeline_state *dst, #undef MERGE } + +const struct vk_dynamic_graphics_state vk_default_dynamic_graphics_state = { + .rs = { + .line = { + .width = 1.0f, + }, + }, + .fsr = { + .fragment_size = {1u, 1u}, + .combiner_ops = { + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR, + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR, + }, + }, + .ds = { + .depth = { + .bounds_test = { + .min = 0.0f, + .max = 1.0f, + }, + }, + .stencil = { + .front = { + .compare_mask = -1, + .write_mask = -1, + }, + .back = { + .compare_mask = -1, + .write_mask = -1, + }, + }, + }, + .cb = { + .color_write_enables = 0xffffffffu, + }, +}; + +void +vk_dynamic_graphics_state_init(struct vk_dynamic_graphics_state *dyn) +{ + *dyn = vk_default_dynamic_graphics_state; +} + +void +vk_dynamic_graphics_state_clear(struct vk_dynamic_graphics_state *dyn) +{ + struct vk_vertex_input_state *vi = dyn->vi; + struct vk_sample_locations_state *sl = dyn->ms.sample_locations; + + *dyn = vk_default_dynamic_graphics_state; + + if (vi != NULL) { + memset(vi, 0, sizeof(*vi)); + dyn->vi = vi; + } + + if (sl != NULL) { + memset(sl, 0, sizeof(*sl)); + dyn->ms.sample_locations = sl; + } +} + +void +vk_dynamic_graphics_state_fill(struct vk_dynamic_graphics_state *dyn, + const struct vk_graphics_pipeline_state *p) +{ + /* This funciton (and the individual vk_dynamic_graphics_state_init_* + * functions it calls) are a bit sloppy. Instead of checking every single + * bit, we just copy everything and set the bits the right way at the end + * based on what groups we actually had. + */ + enum mesa_vk_graphics_state_groups groups = 0; + + BITSET_DECLARE(needed, MESA_VK_DYNAMIC_GRAPHICS_STATE_ENUM_MAX); + BITSET_COPY(needed, p->dynamic); + BITSET_NOT(needed); + + /* We only want to copy these if the driver has filled out the relevant + * pointer in the dynamic state struct. If not, they don't support them + * as dynamic state and we should leave them alone. + */ + if (dyn->vi == NULL) + BITSET_CLEAR(needed, MESA_VK_DYNAMIC_VI); + if (dyn->ms.sample_locations == NULL) + BITSET_CLEAR(needed, MESA_VK_DYNAMIC_MS_SAMPLE_LOCATIONS); + +#define INIT_DYNAMIC_STATE(STATE, type, s) \ + if (p->s != NULL) { \ + vk_dynamic_graphics_state_init_##s(dyn, needed, p->s); \ + groups |= STATE; \ + } + + FOREACH_STATE_GROUP(INIT_DYNAMIC_STATE); + +#undef INIT_DYNAMIC_STATE + + /* Mask off all but the groups we actually found */ + get_dynamic_state_groups(dyn->set, groups); + BITSET_AND(dyn->set, dyn->set, needed); +} + +#define SET_DYN_VALUE(dst, STATE, state, value) do { \ + if (!BITSET_TEST((dst)->set, MESA_VK_DYNAMIC_##STATE) || \ + (dst)->state != (value)) { \ + (dst)->state = (value); \ + assert((dst)->state == (value)); \ + BITSET_SET(dst->set, MESA_VK_DYNAMIC_##STATE); \ + BITSET_SET(dst->dirty, MESA_VK_DYNAMIC_##STATE); \ + } \ +} while(0) + +#define SET_DYN_BOOL(dst, STATE, state, value) \ + SET_DYN_VALUE(dst, STATE, state, (bool)value); + +#define SET_DYN_ARRAY(dst, STATE, state, start, count, src) do { \ + assert(start + count <= ARRAY_SIZE((dst)->state)); \ + STATIC_ASSERT(sizeof(*(dst)->state) == sizeof(*(src))); \ + const size_t __state_size = sizeof(*(dst)->state) * (count); \ + if (!BITSET_TEST((dst)->set, MESA_VK_DYNAMIC_##STATE) || \ + memcmp((dst)->state + start, src, __state_size)) { \ + memcpy((dst)->state + start, src, __state_size); \ + BITSET_SET(dst->set, MESA_VK_DYNAMIC_##STATE); \ + BITSET_SET(dst->dirty, MESA_VK_DYNAMIC_##STATE); \ + } \ +} while(0) + +void +vk_dynamic_graphics_state_copy(struct vk_dynamic_graphics_state *dst, + const struct vk_dynamic_graphics_state *src) +{ +#define IS_SET_IN_SRC(STATE) \ + BITSET_TEST(src->set, MESA_VK_DYNAMIC_##STATE) + +#define COPY_MEMBER(STATE, state) \ + SET_DYN_VALUE(dst, STATE, state, src->state) + +#define COPY_ARRAY(STATE, state, count) \ + SET_DYN_ARRAY(dst, STATE, state, 0, count, src->state) + +#define COPY_IF_SET(STATE, state) \ + if (IS_SET_IN_SRC(STATE)) SET_DYN_VALUE(dst, STATE, state, src->state) + + assert((dst->vi != NULL) == (src->vi != NULL)); + if (dst->vi != NULL && IS_SET_IN_SRC(VI)) { + COPY_MEMBER(VI, vi->bindings_valid); + u_foreach_bit(b, src->vi->bindings_valid) { + COPY_MEMBER(VI, vi->bindings[b].stride); + COPY_MEMBER(VI, vi->bindings[b].input_rate); + COPY_MEMBER(VI, vi->bindings[b].divisor); + } + COPY_MEMBER(VI, vi->attributes_valid); + u_foreach_bit(a, src->vi->attributes_valid) { + COPY_MEMBER(VI, vi->attributes[a].binding); + COPY_MEMBER(VI, vi->attributes[a].format); + COPY_MEMBER(VI, vi->attributes[a].offset); + } + } + + if (IS_SET_IN_SRC(VI_BINDING_STRIDES)) { + COPY_ARRAY(VI_BINDING_STRIDES, vi_binding_strides, + MESA_VK_MAX_VERTEX_BINDINGS); + } + + COPY_IF_SET(IA_PRIMITIVE_TOPOLOGY, ia.primitive_topology); + COPY_IF_SET(IA_PRIMITIVE_RESTART_ENABLE, ia.primitive_restart_enable); + COPY_IF_SET(TS_PATCH_CONTROL_POINTS, ts.patch_control_points); + + COPY_IF_SET(VP_VIEWPORT_COUNT, vp.viewport_count); + if (IS_SET_IN_SRC(VP_VIEWPORTS)) { + assert(IS_SET_IN_SRC(VP_VIEWPORT_COUNT)); + COPY_ARRAY(VP_VIEWPORT_COUNT, vp.viewports, src->vp.viewport_count); + } + + COPY_IF_SET(VP_SCISSOR_COUNT, vp.scissor_count); + if (IS_SET_IN_SRC(VP_SCISSORS)) { + assert(IS_SET_IN_SRC(VP_SCISSOR_COUNT)); + COPY_ARRAY(VP_SCISSOR_COUNT, vp.scissors, src->vp.scissor_count); + } + + if (IS_SET_IN_SRC(DR_RECTANGLES)) { + COPY_MEMBER(DR_RECTANGLES, dr.rectangle_count); + COPY_ARRAY(DR_RECTANGLES, dr.rectangles, src->dr.rectangle_count); + } + + COPY_IF_SET(RS_RASTERIZER_DISCARD_ENABLE, rs.rasterizer_discard_enable); + COPY_IF_SET(RS_CULL_MODE, rs.cull_mode); + COPY_IF_SET(RS_FRONT_FACE, rs.front_face); + COPY_IF_SET(RS_DEPTH_BIAS_ENABLE, rs.depth_bias.enable); + COPY_IF_SET(RS_DEPTH_BIAS_FACTORS, rs.depth_bias.constant); + COPY_IF_SET(RS_DEPTH_BIAS_FACTORS, rs.depth_bias.clamp); + COPY_IF_SET(RS_DEPTH_BIAS_FACTORS, rs.depth_bias.slope); + COPY_IF_SET(RS_LINE_WIDTH, rs.line.width); + COPY_IF_SET(RS_LINE_STIPPLE, rs.line.stipple.factor); + COPY_IF_SET(RS_LINE_STIPPLE, rs.line.stipple.pattern); + + COPY_IF_SET(FSR, fsr.fragment_size.width); + COPY_IF_SET(FSR, fsr.fragment_size.height); + COPY_IF_SET(FSR, fsr.combiner_ops[0]); + COPY_IF_SET(FSR, fsr.combiner_ops[1]); + + assert((dst->ms.sample_locations == NULL) == + (src->ms.sample_locations == NULL)); + if (dst->ms.sample_locations != NULL && + IS_SET_IN_SRC(MS_SAMPLE_LOCATIONS)) { + COPY_MEMBER(MS_SAMPLE_LOCATIONS, ms.sample_locations->per_pixel); + COPY_MEMBER(MS_SAMPLE_LOCATIONS, ms.sample_locations->grid_size.width); + COPY_MEMBER(MS_SAMPLE_LOCATIONS, ms.sample_locations->grid_size.height); + const uint32_t sl_count = src->ms.sample_locations->per_pixel * + src->ms.sample_locations->grid_size.width * + src->ms.sample_locations->grid_size.height; + COPY_ARRAY(MS_SAMPLE_LOCATIONS, ms.sample_locations->locations, sl_count); + } + + COPY_IF_SET(DS_DEPTH_TEST_ENABLE, ds.depth.test_enable); + COPY_IF_SET(DS_DEPTH_WRITE_ENABLE, ds.depth.write_enable); + COPY_IF_SET(DS_DEPTH_COMPARE_OP, ds.depth.compare_op); + COPY_IF_SET(DS_DEPTH_BOUNDS_TEST_ENABLE, ds.depth.bounds_test.enable); + if (IS_SET_IN_SRC(DS_DEPTH_BOUNDS_TEST_BOUNDS)) { + COPY_MEMBER(DS_DEPTH_BOUNDS_TEST_BOUNDS, ds.depth.bounds_test.min); + COPY_MEMBER(DS_DEPTH_BOUNDS_TEST_BOUNDS, ds.depth.bounds_test.max); + } + + COPY_IF_SET(DS_STENCIL_TEST_ENABLE, ds.stencil.test_enable); + if (IS_SET_IN_SRC(DS_STENCIL_OP)) { + COPY_MEMBER(DS_STENCIL_OP, ds.stencil.front.op.fail); + COPY_MEMBER(DS_STENCIL_OP, ds.stencil.front.op.pass); + COPY_MEMBER(DS_STENCIL_OP, ds.stencil.front.op.depth_fail); + COPY_MEMBER(DS_STENCIL_OP, ds.stencil.front.op.compare); + COPY_MEMBER(DS_STENCIL_OP, ds.stencil.back.op.fail); + COPY_MEMBER(DS_STENCIL_OP, ds.stencil.back.op.pass); + COPY_MEMBER(DS_STENCIL_OP, ds.stencil.back.op.depth_fail); + COPY_MEMBER(DS_STENCIL_OP, ds.stencil.back.op.compare); + } + if (IS_SET_IN_SRC(DS_STENCIL_COMPARE_MASK)) { + COPY_MEMBER(DS_STENCIL_COMPARE_MASK, ds.stencil.front.compare_mask); + COPY_MEMBER(DS_STENCIL_COMPARE_MASK, ds.stencil.back.compare_mask); + } + if (IS_SET_IN_SRC(DS_STENCIL_WRITE_MASK)) { + COPY_MEMBER(DS_STENCIL_WRITE_MASK, ds.stencil.front.write_mask); + COPY_MEMBER(DS_STENCIL_WRITE_MASK, ds.stencil.back.write_mask); + } + if (IS_SET_IN_SRC(DS_STENCIL_REFERENCE)) { + COPY_MEMBER(DS_STENCIL_REFERENCE, ds.stencil.front.reference); + COPY_MEMBER(DS_STENCIL_REFERENCE, ds.stencil.back.reference); + } + + COPY_IF_SET(CB_LOGIC_OP, cb.logic_op); + COPY_IF_SET(CB_COLOR_WRITE_ENABLES, cb.color_write_enables); + if (IS_SET_IN_SRC(CB_BLEND_CONSTANTS)) + COPY_ARRAY(CB_BLEND_CONSTANTS, cb.blend_constants, 4); + +#undef IS_SET_IN_SRC +#undef MARK_DIRTY +#undef COPY_MEMBER +#undef COPY_ARRAY +#undef COPY_IF_SET + + for (uint32_t w = 0; w < ARRAY_SIZE(dst->dirty); w++) { + /* If it's in the source but isn't set in the destination at all, mark + * it dirty. It's possible that the default values just happen to equal + * the value from src. + */ + dst->dirty[w] |= src->set[w] & ~dst->set[w]; + + /* Everything that was in the source is now in the destination */ + dst->set[w] |= src->set[w]; + } +} diff --git a/src/vulkan/runtime/vk_graphics_state.h b/src/vulkan/runtime/vk_graphics_state.h index 0d7ef70ddba..f593052fdaa 100644 --- a/src/vulkan/runtime/vk_graphics_state.h +++ b/src/vulkan/runtime/vk_graphics_state.h @@ -474,6 +474,184 @@ struct vk_render_pass_state { VkFormat stencil_attachment_format; }; +/** Struct representing all dynamic graphics state + * + * Before invoking any core functions, the driver must properly populate + * initialize this struct: + * + * - Initialize using vk_default_dynamic_graphics_state, if desired + * - Set vi to a driver-allocated vk_vertex_input_state struct + * - Set ms.sample_locations to a driver-allocated + * vk_sample_locations_state struct + */ +struct vk_dynamic_graphics_state { + /** Vertex input state + * + * Must be provided by the driver if VK_EXT_vertex_input_dynamic_state is + * supported. + * + * MESA_VK_DYNAMIC_GRAPHICS_STATE_VI + */ + struct vk_vertex_input_state *vi; + + /** Vertex binding strides + * + * MESA_VK_DYNAMIC_GRAPHICS_STATE_VI_BINDING_STRIDES + */ + uint16_t vi_binding_strides[MESA_VK_MAX_VERTEX_BINDINGS]; + + struct vk_input_assembly_state ia; + + struct { + uint32_t patch_control_points; + } ts; + + /** Viewport state */ + struct { + /** Viewport count + * + * MESA_VK_DYNAMIC_GRAPHICS_STATE_VP_VIEWPORT_COUNT + */ + uint32_t viewport_count; + + /** Viewports + * + * MESA_VK_DYNAMIC_GRAPHICS_STATE_VP_VIEWPORTS + */ + VkViewport viewports[MESA_VK_MAX_VIEWPORTS]; + + /** Scissor count + * + * MESA_VK_DYNAMIC_GRAPHICS_STATE_VP_SCISSOR_COUNT + */ + uint32_t scissor_count; + + /** Scissor rects + * + * MESA_VK_DYNAMIC_GRAPHICS_STATE_VP_SCISSORS + */ + VkRect2D scissors[MESA_VK_MAX_SCISSORS]; + } vp; + + /** Discard rectangles + * + * MESA_VK_DYNAMIC_GRAPHICS_STATE_DR_RECTANGLES + */ + struct { + uint32_t rectangle_count; + VkRect2D rectangles[MESA_VK_MAX_DISCARD_RECTANGLES]; + } dr; + + /** Rasterization state */ + struct { + /** Rasterizer discard + * + * MESA_VK_DYNAMIC_GRAPHICS_STATE_RS_RASTERIZER_DISCARD_ENABLE + */ + bool rasterizer_discard_enable; + + /** Cull mode + * + * MESA_VK_DYNAMIC_GRAPHICS_STATE_RS_CULL_MODE + */ + VkCullModeFlags cull_mode; + + /** Front face + * + * MESA_VK_DYNAMIC_GRAPHICS_STATE_RS_FRONT_FACE + */ + VkFrontFace front_face; + + struct { + /** Depth bias enable + * + * MESA_VK_DYNAMIC_GRAPHICS_STATE_RS_DEPTH_BIAS_ENABLE + */ + bool enable; + + /** Depth bias constant factor + * + * MESA_VK_DYNAMIC_GRAPHICS_STATE_RS_DEPTH_BIAS_FACTORS + */ + float constant; + + /** Depth bias clamp + * + * MESA_VK_DYNAMIC_GRAPHICS_STATE_RS_DEPTH_BIAS_FACTORS + */ + float clamp; + + /** Depth bias slope + * + * MESA_VK_DYNAMIC_GRAPHICS_STATE_RS_DEPTH_BIAS_FACTORS + */ + float slope; + } depth_bias; + + struct { + /** Line width + * + * MESA_VK_DYNAMIC_GRAPHICS_STATE_RS_LINE_WIDTH + */ + float width; + + /** Line stipple + * + * MESA_VK_DYNAMIC_GRAPHICS_STATE_RS_LINE_STIPPLE + */ + struct { + uint32_t factor; + uint16_t pattern; + } stipple; + } line; + } rs; + + struct vk_fragment_shading_rate_state fsr; + + /** Multisample state */ + struct { + /** Sample locations + * + * Must be provided by the driver if VK_EXT_sample_locations is + * supported. + * + * MESA_VK_DYNAMIC_GRAPHICS_STATE_MS_SAMPLE_LOCATIONS + */ + struct vk_sample_locations_state *sample_locations; + } ms; + + struct vk_depth_stencil_state ds; + + /** Color blend state */ + struct { + /** Integer color logic op + * + * MESA_VK_DYNAMIC_GRAPHICS_STATE_CB_LOGIC_OP, + */ + VkLogicOp logic_op; + + /** Color write enables + * + * Bitmask of color write enables, indexed by color attachment index. + * + * MESA_VK_DYNAMIC_GRAPHICS_STATE_CB_COLOR_WRITE_ENABLES, + */ + uint32_t color_write_enables; + + /** Blend constants + * + * MESA_VK_DYNAMIC_GRAPHICS_STATE_CB_BLEND_CONSTANTS, + */ + float blend_constants[4]; + } cb; + + /** For pipelines, which bits of dynamic state are set */ + BITSET_DECLARE(set, MESA_VK_DYNAMIC_GRAPHICS_STATE_ENUM_MAX); + + /** For command buffers, which bits of dynamic state have changed */ + BITSET_DECLARE(dirty, MESA_VK_DYNAMIC_GRAPHICS_STATE_ENUM_MAX); +}; + struct vk_graphics_pipeline_all_state { struct vk_vertex_input_state vi; struct vk_input_assembly_state ia; @@ -606,6 +784,75 @@ void vk_graphics_pipeline_state_merge(struct vk_graphics_pipeline_state *dst, const struct vk_graphics_pipeline_state *src); +extern const struct vk_dynamic_graphics_state vk_default_dynamic_graphics_state; + +/** Initialize a vk_dynamic_graphics_state with defaults + * + * @param[out] dyn Dynamic graphics state to initizlie + */ +void +vk_dynamic_graphics_state_init(struct vk_dynamic_graphics_state *dyn); + +/** Clear a vk_dynamic_graphics_state to defaults + * + * @param[out] dyn Dynamic graphics state to initizlie + */ +void +vk_dynamic_graphics_state_clear(struct vk_dynamic_graphics_state *dyn); + +/** Initialize a vk_dynamic_graphics_state for a pipeline + * + * @param[out] dyn Dynamic graphics state to initizlie + * @param[in] supported Bitset of all dynamic state supported by the driver. + * @param[in] p The pipeline state from which to initialize the + * dynamic state. + */ +void +vk_dynamic_graphics_state_fill(struct vk_dynamic_graphics_state *dyn, + const struct vk_graphics_pipeline_state *p); + +/** Mark all states in the given vk_dynamic_graphics_state dirty + * + * @param[out] d Dynamic graphics state struct + */ +static inline void +vk_dynamic_graphics_state_dirty_all(struct vk_dynamic_graphics_state *d) +{ + BITSET_SET_RANGE(d->dirty, 0, MESA_VK_DYNAMIC_GRAPHICS_STATE_ENUM_MAX - 1); +} + +/** Mark all states in the given vk_dynamic_graphics_state not dirty + * + * @param[out] d Dynamic graphics state struct + */ +static inline void +vk_dynamic_graphics_state_clear_dirty(struct vk_dynamic_graphics_state *d) +{ + memset(d->dirty, 0, sizeof(d->dirty)); +} + +/** Test if any states in the given vk_dynamic_graphics_state are dirty + * + * @param[in] d Dynamic graphics state struct to test + * @returns true if any state is dirty + */ +static inline bool +vk_dynamic_graphics_state_any_dirty(const struct vk_dynamic_graphics_state *d) +{ + return BITSET_TEST_RANGE(d->dirty, + 0, MESA_VK_DYNAMIC_GRAPHICS_STATE_ENUM_MAX - 1); +} + +/** Copies all set state from src to dst + * + * Both src and dst are assumed to be properly initialized dynamic state + * structs. Anything not set in src, as indicated by src->set, is ignored and + * those bits of dst are left untouched. + */ +void +vk_dynamic_graphics_state_copy(struct vk_dynamic_graphics_state *dst, + const struct vk_dynamic_graphics_state *src); + #ifdef __cplusplus } #endif