2022-06-27 15:03:02 +01:00
|
|
|
#include "vk_graphics_state.h"
|
|
|
|
|
2022-07-13 16:02:30 +01:00
|
|
|
#include "vk_alloc.h"
|
2022-07-01 04:35:44 +01:00
|
|
|
#include "vk_command_buffer.h"
|
|
|
|
#include "vk_common_entrypoints.h"
|
2022-07-13 16:02:30 +01:00
|
|
|
#include "vk_device.h"
|
|
|
|
#include "vk_log.h"
|
|
|
|
#include "vk_render_pass.h"
|
|
|
|
#include "vk_standard_sample_locations.h"
|
|
|
|
#include "vk_util.h"
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
enum mesa_vk_graphics_state_groups {
|
|
|
|
MESA_VK_GRAPHICS_STATE_VERTEX_INPUT_BIT = (1 << 0),
|
|
|
|
MESA_VK_GRAPHICS_STATE_INPUT_ASSEMBLY_BIT = (1 << 1),
|
|
|
|
MESA_VK_GRAPHICS_STATE_TESSELLATION_BIT = (1 << 2),
|
|
|
|
MESA_VK_GRAPHICS_STATE_VIEWPORT_BIT = (1 << 3),
|
|
|
|
MESA_VK_GRAPHICS_STATE_DISCARD_RECTANGLES_BIT = (1 << 4),
|
|
|
|
MESA_VK_GRAPHICS_STATE_RASTERIZATION_BIT = (1 << 5),
|
|
|
|
MESA_VK_GRAPHICS_STATE_FRAGMENT_SHADING_RATE_BIT = (1 << 6),
|
|
|
|
MESA_VK_GRAPHICS_STATE_MULTISAMPLE_BIT = (1 << 7),
|
|
|
|
MESA_VK_GRAPHICS_STATE_DEPTH_STENCIL_BIT = (1 << 8),
|
|
|
|
MESA_VK_GRAPHICS_STATE_COLOR_BLEND_BIT = (1 << 9),
|
|
|
|
MESA_VK_GRAPHICS_STATE_RENDER_PASS_BIT = (1 << 10),
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
clear_all_dynamic_state(BITSET_WORD *dynamic)
|
|
|
|
{
|
|
|
|
/* Clear the whole array so there are no undefined bits at the top */
|
|
|
|
memset(dynamic, 0, sizeof(*dynamic) *
|
|
|
|
BITSET_WORDS(MESA_VK_DYNAMIC_GRAPHICS_STATE_ENUM_MAX));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
get_dynamic_state_groups(BITSET_WORD *dynamic,
|
|
|
|
enum mesa_vk_graphics_state_groups groups)
|
|
|
|
{
|
|
|
|
clear_all_dynamic_state(dynamic);
|
|
|
|
|
|
|
|
if (groups & MESA_VK_GRAPHICS_STATE_VERTEX_INPUT_BIT) {
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_VI);
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_VI_BINDING_STRIDES);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (groups & MESA_VK_GRAPHICS_STATE_INPUT_ASSEMBLY_BIT) {
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_IA_PRIMITIVE_TOPOLOGY);
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_IA_PRIMITIVE_RESTART_ENABLE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (groups & MESA_VK_GRAPHICS_STATE_TESSELLATION_BIT)
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_TS_PATCH_CONTROL_POINTS);
|
|
|
|
|
|
|
|
if (groups & MESA_VK_GRAPHICS_STATE_VIEWPORT_BIT) {
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_VP_VIEWPORT_COUNT);
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_VP_VIEWPORTS);
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_VP_SCISSOR_COUNT);
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_VP_SCISSORS);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (groups & MESA_VK_GRAPHICS_STATE_DISCARD_RECTANGLES_BIT)
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_DR_RECTANGLES);
|
|
|
|
|
|
|
|
if (groups & MESA_VK_GRAPHICS_STATE_RASTERIZATION_BIT) {
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_RS_RASTERIZER_DISCARD_ENABLE);
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_RS_CULL_MODE);
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_RS_FRONT_FACE);
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_RS_DEPTH_BIAS_ENABLE);
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_RS_DEPTH_BIAS_FACTORS);
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_RS_LINE_WIDTH);
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_RS_LINE_STIPPLE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (groups & MESA_VK_GRAPHICS_STATE_FRAGMENT_SHADING_RATE_BIT)
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_FSR);
|
|
|
|
|
|
|
|
if (groups & MESA_VK_GRAPHICS_STATE_MULTISAMPLE_BIT)
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_MS_SAMPLE_LOCATIONS);
|
|
|
|
|
|
|
|
if (groups & MESA_VK_GRAPHICS_STATE_DEPTH_STENCIL_BIT) {
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_DS_DEPTH_TEST_ENABLE);
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_DS_DEPTH_WRITE_ENABLE);
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_DS_DEPTH_COMPARE_OP);
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_DS_DEPTH_BOUNDS_TEST_ENABLE);
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_DS_DEPTH_BOUNDS_TEST_BOUNDS);
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_DS_STENCIL_TEST_ENABLE);
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_DS_STENCIL_OP);
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_DS_STENCIL_COMPARE_MASK);
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_DS_STENCIL_WRITE_MASK);
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_DS_STENCIL_REFERENCE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (groups & MESA_VK_GRAPHICS_STATE_COLOR_BLEND_BIT) {
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_CB_LOGIC_OP);
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_CB_COLOR_WRITE_ENABLES);
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_CB_BLEND_CONSTANTS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
validate_dynamic_state_groups(const BITSET_WORD *dynamic,
|
|
|
|
enum mesa_vk_graphics_state_groups groups)
|
|
|
|
{
|
|
|
|
#ifndef NDEBUG
|
|
|
|
BITSET_DECLARE(all_dynamic, MESA_VK_DYNAMIC_GRAPHICS_STATE_ENUM_MAX);
|
|
|
|
get_dynamic_state_groups(all_dynamic, groups);
|
|
|
|
|
|
|
|
for (uint32_t w = 0; w < ARRAY_SIZE(all_dynamic); w++)
|
|
|
|
assert(!(dynamic[w] & ~all_dynamic[w]));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2022-06-27 15:03:02 +01:00
|
|
|
void
|
|
|
|
vk_get_dynamic_graphics_states(BITSET_WORD *dynamic,
|
|
|
|
const VkPipelineDynamicStateCreateInfo *info)
|
|
|
|
{
|
2022-07-13 16:02:30 +01:00
|
|
|
clear_all_dynamic_state(dynamic);
|
|
|
|
|
2022-06-27 15:03:02 +01:00
|
|
|
/* From the Vulkan 1.3.218 spec:
|
|
|
|
*
|
|
|
|
* "pDynamicState is a pointer to a VkPipelineDynamicStateCreateInfo
|
|
|
|
* structure defining which properties of the pipeline state object are
|
|
|
|
* dynamic and can be changed independently of the pipeline state. This
|
|
|
|
* can be NULL, which means no state in the pipeline is considered
|
|
|
|
* dynamic."
|
|
|
|
*/
|
|
|
|
if (info == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
#define CASE(VK, MESA) \
|
|
|
|
case VK_DYNAMIC_STATE_##VK: \
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_##MESA); \
|
|
|
|
break;
|
|
|
|
|
|
|
|
#define CASE2(VK, MESA1, MESA2) \
|
|
|
|
case VK_DYNAMIC_STATE_##VK: \
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_##MESA1); \
|
|
|
|
BITSET_SET(dynamic, MESA_VK_DYNAMIC_##MESA2); \
|
|
|
|
break;
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < info->dynamicStateCount; i++) {
|
|
|
|
switch (info->pDynamicStates[i]) {
|
|
|
|
CASE2(VERTEX_INPUT_EXT, VI, VI_BINDING_STRIDES)
|
|
|
|
CASE( VERTEX_INPUT_BINDING_STRIDE, VI_BINDING_STRIDES)
|
|
|
|
CASE( VIEWPORT, VP_VIEWPORTS)
|
|
|
|
CASE( SCISSOR, VP_SCISSORS)
|
|
|
|
CASE( LINE_WIDTH, RS_LINE_WIDTH)
|
|
|
|
CASE( DEPTH_BIAS, RS_DEPTH_BIAS_FACTORS)
|
|
|
|
CASE( BLEND_CONSTANTS, CB_BLEND_CONSTANTS)
|
|
|
|
CASE( DEPTH_BOUNDS, DS_DEPTH_BOUNDS_TEST_BOUNDS)
|
|
|
|
CASE( STENCIL_COMPARE_MASK, DS_STENCIL_COMPARE_MASK)
|
|
|
|
CASE( STENCIL_WRITE_MASK, DS_STENCIL_WRITE_MASK)
|
|
|
|
CASE( STENCIL_REFERENCE, DS_STENCIL_REFERENCE)
|
|
|
|
CASE( CULL_MODE, RS_CULL_MODE)
|
|
|
|
CASE( FRONT_FACE, RS_FRONT_FACE)
|
|
|
|
CASE( PRIMITIVE_TOPOLOGY, IA_PRIMITIVE_TOPOLOGY)
|
|
|
|
CASE2(VIEWPORT_WITH_COUNT, VP_VIEWPORT_COUNT, VP_VIEWPORTS)
|
|
|
|
CASE2(SCISSOR_WITH_COUNT, VP_SCISSOR_COUNT, VP_SCISSORS)
|
|
|
|
CASE( DEPTH_TEST_ENABLE, DS_DEPTH_TEST_ENABLE)
|
|
|
|
CASE( DEPTH_WRITE_ENABLE, DS_DEPTH_WRITE_ENABLE)
|
|
|
|
CASE( DEPTH_COMPARE_OP, DS_DEPTH_COMPARE_OP)
|
|
|
|
CASE( DEPTH_BOUNDS_TEST_ENABLE, DS_DEPTH_BOUNDS_TEST_ENABLE)
|
|
|
|
CASE( STENCIL_TEST_ENABLE, DS_STENCIL_TEST_ENABLE)
|
|
|
|
CASE( STENCIL_OP, DS_STENCIL_OP)
|
|
|
|
CASE( RASTERIZER_DISCARD_ENABLE, RS_RASTERIZER_DISCARD_ENABLE)
|
|
|
|
CASE( DEPTH_BIAS_ENABLE, RS_DEPTH_BIAS_ENABLE)
|
|
|
|
CASE( PRIMITIVE_RESTART_ENABLE, IA_PRIMITIVE_RESTART_ENABLE)
|
|
|
|
CASE( DISCARD_RECTANGLE_EXT, DR_RECTANGLES)
|
|
|
|
CASE( SAMPLE_LOCATIONS_EXT, MS_SAMPLE_LOCATIONS)
|
|
|
|
CASE( FRAGMENT_SHADING_RATE_KHR, FSR)
|
|
|
|
CASE( LINE_STIPPLE_EXT, RS_LINE_STIPPLE)
|
|
|
|
CASE( PATCH_CONTROL_POINTS_EXT, TS_PATCH_CONTROL_POINTS)
|
|
|
|
CASE( LOGIC_OP_EXT, CB_LOGIC_OP)
|
|
|
|
CASE( COLOR_WRITE_ENABLE_EXT, CB_COLOR_WRITE_ENABLES)
|
|
|
|
default:
|
|
|
|
unreachable("Unsupported dynamic graphics state");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-07-13 16:02:30 +01:00
|
|
|
|
|
|
|
#define IS_DYNAMIC(STATE) \
|
|
|
|
BITSET_TEST(dynamic, MESA_VK_DYNAMIC_##STATE)
|
|
|
|
|
2022-06-30 00:26:05 +01:00
|
|
|
#define IS_NEEDED(STATE) \
|
|
|
|
BITSET_TEST(needed, MESA_VK_DYNAMIC_##STATE)
|
|
|
|
|
2022-07-13 16:02:30 +01:00
|
|
|
static void
|
|
|
|
vk_vertex_input_state_init(struct vk_vertex_input_state *vi,
|
|
|
|
const BITSET_WORD *dynamic,
|
|
|
|
const VkPipelineVertexInputStateCreateInfo *vi_info)
|
|
|
|
{
|
|
|
|
assert(!IS_DYNAMIC(VI));
|
|
|
|
|
|
|
|
memset(vi, 0, sizeof(*vi));
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < vi_info->vertexBindingDescriptionCount; i++) {
|
|
|
|
const VkVertexInputBindingDescription *desc =
|
|
|
|
&vi_info->pVertexBindingDescriptions[i];
|
|
|
|
|
|
|
|
assert(desc->binding < MESA_VK_MAX_VERTEX_BINDINGS);
|
|
|
|
assert(desc->stride <= MESA_VK_MAX_VERTEX_BINDING_STRIDE);
|
|
|
|
assert(desc->inputRate <= 1);
|
|
|
|
|
|
|
|
const uint32_t b = desc->binding;
|
|
|
|
vi->bindings_valid |= BITFIELD_BIT(b);
|
|
|
|
vi->bindings[b].stride = desc->stride;
|
|
|
|
vi->bindings[b].input_rate = desc->inputRate;
|
|
|
|
vi->bindings[b].divisor = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < vi_info->vertexAttributeDescriptionCount; i++) {
|
|
|
|
const VkVertexInputAttributeDescription *desc =
|
|
|
|
&vi_info->pVertexAttributeDescriptions[i];
|
|
|
|
|
|
|
|
assert(desc->location < MESA_VK_MAX_VERTEX_ATTRIBUTES);
|
|
|
|
assert(desc->binding < MESA_VK_MAX_VERTEX_BINDINGS);
|
|
|
|
assert(vi->bindings_valid & BITFIELD_BIT(desc->binding));
|
|
|
|
|
|
|
|
const uint32_t a = desc->location;
|
|
|
|
vi->attributes_valid |= BITFIELD_BIT(a);
|
|
|
|
vi->attributes[a].binding = desc->binding;
|
|
|
|
vi->attributes[a].format = desc->format;
|
|
|
|
vi->attributes[a].offset = desc->offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
const VkPipelineVertexInputDivisorStateCreateInfoEXT *vi_div_state =
|
|
|
|
vk_find_struct_const(vi_info->pNext,
|
|
|
|
PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT);
|
|
|
|
if (vi_div_state) {
|
|
|
|
for (uint32_t i = 0; i < vi_div_state->vertexBindingDivisorCount; i++) {
|
|
|
|
const VkVertexInputBindingDivisorDescriptionEXT *desc =
|
|
|
|
&vi_div_state->pVertexBindingDivisors[i];
|
|
|
|
|
|
|
|
assert(desc->binding < MESA_VK_MAX_VERTEX_BINDINGS);
|
|
|
|
assert(vi->bindings_valid & BITFIELD_BIT(desc->binding));
|
|
|
|
|
|
|
|
const uint32_t b = desc->binding;
|
|
|
|
vi->bindings[b].divisor = desc->divisor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-30 00:26:05 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-13 16:02:30 +01:00
|
|
|
static void
|
|
|
|
vk_input_assembly_state_init(struct vk_input_assembly_state *ia,
|
|
|
|
const BITSET_WORD *dynamic,
|
|
|
|
const VkPipelineInputAssemblyStateCreateInfo *ia_info)
|
|
|
|
{
|
|
|
|
if (IS_DYNAMIC(IA_PRIMITIVE_TOPOLOGY)) {
|
|
|
|
ia->primitive_topology = -1;
|
|
|
|
} else {
|
|
|
|
assert(ia_info->topology <= UINT8_MAX);
|
|
|
|
ia->primitive_topology = ia_info->topology;
|
|
|
|
}
|
|
|
|
|
|
|
|
ia->primitive_restart_enable = ia_info->primitiveRestartEnable;
|
|
|
|
}
|
|
|
|
|
2022-06-30 00:26:05 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-07-13 16:02:30 +01:00
|
|
|
static void
|
|
|
|
vk_tessellation_state_init(struct vk_tessellation_state *ts,
|
|
|
|
const BITSET_WORD *dynamic,
|
|
|
|
const VkPipelineTessellationStateCreateInfo *ts_info)
|
|
|
|
{
|
|
|
|
if (IS_DYNAMIC(TS_PATCH_CONTROL_POINTS)) {
|
|
|
|
ts->patch_control_points = 0;
|
|
|
|
} else {
|
|
|
|
assert(ts_info->patchControlPoints <= UINT8_MAX);
|
|
|
|
ts->patch_control_points = ts_info->patchControlPoints;
|
|
|
|
}
|
|
|
|
|
|
|
|
const VkPipelineTessellationDomainOriginStateCreateInfo *ts_do_info =
|
|
|
|
vk_find_struct_const(ts_info->pNext,
|
|
|
|
PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO);
|
|
|
|
if (ts_do_info != NULL) {
|
|
|
|
assert(ts_do_info->domainOrigin <= UINT8_MAX);
|
|
|
|
ts->domain_origin = ts_do_info->domainOrigin;
|
|
|
|
} else {
|
|
|
|
ts->domain_origin = VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-30 00:26:05 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-07-13 16:02:30 +01:00
|
|
|
static void
|
|
|
|
vk_viewport_state_init(struct vk_viewport_state *vp,
|
|
|
|
const BITSET_WORD *dynamic,
|
|
|
|
const VkPipelineViewportStateCreateInfo *vp_info)
|
|
|
|
{
|
|
|
|
memset(vp, 0, sizeof(*vp));
|
|
|
|
|
|
|
|
if (!IS_DYNAMIC(VP_VIEWPORT_COUNT)) {
|
|
|
|
assert(vp_info->viewportCount <= MESA_VK_MAX_VIEWPORTS);
|
|
|
|
vp->viewport_count = vp_info->viewportCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IS_DYNAMIC(VP_VIEWPORTS)) {
|
|
|
|
assert(!IS_DYNAMIC(VP_VIEWPORT_COUNT));
|
|
|
|
typed_memcpy(vp->viewports, vp_info->pViewports,
|
|
|
|
vp_info->viewportCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IS_DYNAMIC(VP_SCISSOR_COUNT)) {
|
|
|
|
assert(vp_info->scissorCount <= MESA_VK_MAX_SCISSORS);
|
|
|
|
vp->scissor_count = vp_info->scissorCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IS_DYNAMIC(VP_SCISSORS)) {
|
|
|
|
assert(!IS_DYNAMIC(VP_SCISSOR_COUNT));
|
|
|
|
typed_memcpy(vp->scissors, vp_info->pScissors,
|
|
|
|
vp_info->scissorCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
const VkPipelineViewportDepthClipControlCreateInfoEXT *vp_dcc_info =
|
|
|
|
vk_find_struct_const(vp_info->pNext,
|
|
|
|
PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT);
|
|
|
|
if (vp_dcc_info != NULL)
|
|
|
|
vp->negative_one_to_one = vp_dcc_info->negativeOneToOne;
|
|
|
|
}
|
|
|
|
|
2022-06-30 00:26:05 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2022-07-13 16:02:30 +01:00
|
|
|
static void
|
|
|
|
vk_discard_rectangles_state_init(struct vk_discard_rectangles_state *dr,
|
|
|
|
const BITSET_WORD *dynamic,
|
|
|
|
const VkPipelineDiscardRectangleStateCreateInfoEXT *dr_info)
|
|
|
|
{
|
|
|
|
memset(dr, 0, sizeof(*dr));
|
|
|
|
|
|
|
|
if (dr_info == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
dr->mode = dr_info->discardRectangleMode;
|
|
|
|
|
|
|
|
if (!IS_DYNAMIC(DR_RECTANGLES)) {
|
|
|
|
assert(dr_info->discardRectangleCount <= MESA_VK_MAX_DISCARD_RECTANGLES);
|
|
|
|
dr->rectangle_count = dr_info->discardRectangleCount;
|
|
|
|
typed_memcpy(dr->rectangles, dr_info->pDiscardRectangles,
|
|
|
|
dr_info->discardRectangleCount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-30 00:26:05 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2022-07-13 16:02:30 +01:00
|
|
|
static void
|
|
|
|
vk_rasterization_state_init(struct vk_rasterization_state *rs,
|
|
|
|
const BITSET_WORD *dynamic,
|
|
|
|
const VkPipelineRasterizationStateCreateInfo *rs_info)
|
|
|
|
{
|
|
|
|
*rs = (struct vk_rasterization_state) {
|
|
|
|
.rasterizer_discard_enable = false,
|
|
|
|
.conservative_mode = VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT,
|
|
|
|
.rasterization_order_amd = VK_RASTERIZATION_ORDER_STRICT_AMD,
|
|
|
|
.provoking_vertex = VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT,
|
|
|
|
.line.mode = VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (!IS_DYNAMIC(RS_RASTERIZER_DISCARD_ENABLE))
|
|
|
|
rs->rasterizer_discard_enable = rs_info->rasterizerDiscardEnable;
|
|
|
|
|
|
|
|
/* From the Vulkan 1.3.218 spec:
|
|
|
|
*
|
|
|
|
* "If VkPipelineRasterizationDepthClipStateCreateInfoEXT is present in
|
|
|
|
* the graphics pipeline state then depth clipping is disabled if
|
|
|
|
* VkPipelineRasterizationDepthClipStateCreateInfoEXT::depthClipEnable
|
|
|
|
* is VK_FALSE. Otherwise, if
|
|
|
|
* VkPipelineRasterizationDepthClipStateCreateInfoEXT is not present,
|
|
|
|
* depth clipping is disabled when
|
|
|
|
* VkPipelineRasterizationStateCreateInfo::depthClampEnable is VK_TRUE.
|
|
|
|
*/
|
|
|
|
rs->depth_clamp_enable = rs_info->depthClampEnable;
|
|
|
|
rs->depth_clip_enable = !rs_info->depthClampEnable;
|
|
|
|
|
|
|
|
rs->polygon_mode = rs_info->polygonMode;
|
|
|
|
|
|
|
|
rs->cull_mode = rs_info->cullMode;
|
|
|
|
rs->front_face = rs_info->frontFace;
|
|
|
|
rs->depth_bias.enable = rs_info->depthBiasEnable;
|
|
|
|
if ((rs_info->depthBiasEnable || IS_DYNAMIC(RS_DEPTH_BIAS_ENABLE)) &&
|
|
|
|
!IS_DYNAMIC(RS_DEPTH_BIAS_FACTORS)) {
|
|
|
|
rs->depth_bias.constant = rs_info->depthBiasConstantFactor;
|
|
|
|
rs->depth_bias.clamp = rs_info->depthBiasClamp;
|
|
|
|
rs->depth_bias.slope = rs_info->depthBiasSlopeFactor;
|
|
|
|
}
|
|
|
|
rs->line.width = rs_info->lineWidth;
|
|
|
|
|
|
|
|
vk_foreach_struct_const(ext, rs_info->pNext) {
|
|
|
|
switch (ext->sType) {
|
|
|
|
case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT: {
|
|
|
|
const VkPipelineRasterizationConservativeStateCreateInfoEXT *rcs_info =
|
|
|
|
(const VkPipelineRasterizationConservativeStateCreateInfoEXT *)ext;
|
|
|
|
rs->conservative_mode = rcs_info->conservativeRasterizationMode;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT: {
|
|
|
|
const VkPipelineRasterizationDepthClipStateCreateInfoEXT *rdc_info =
|
|
|
|
(const VkPipelineRasterizationDepthClipStateCreateInfoEXT *)ext;
|
|
|
|
rs->depth_clip_enable = rdc_info->depthClipEnable;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT: {
|
|
|
|
const VkPipelineRasterizationLineStateCreateInfoEXT *rl_info =
|
|
|
|
(const VkPipelineRasterizationLineStateCreateInfoEXT *)ext;
|
|
|
|
rs->line.mode = rl_info->lineRasterizationMode;
|
|
|
|
rs->line.stipple.enable = rl_info->stippledLineEnable;
|
|
|
|
if (rs->line.stipple.enable && !IS_DYNAMIC(RS_LINE_STIPPLE)) {
|
|
|
|
rs->line.stipple.factor = rl_info->lineStippleFactor;
|
|
|
|
rs->line.stipple.pattern = rl_info->lineStipplePattern;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT: {
|
|
|
|
const VkPipelineRasterizationProvokingVertexStateCreateInfoEXT *rpv_info =
|
|
|
|
(const VkPipelineRasterizationProvokingVertexStateCreateInfoEXT *)ext;
|
|
|
|
rs->provoking_vertex = rpv_info->provokingVertexMode;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD: {
|
|
|
|
const VkPipelineRasterizationStateRasterizationOrderAMD *rro_info =
|
|
|
|
(const VkPipelineRasterizationStateRasterizationOrderAMD *)ext;
|
|
|
|
rs->rasterization_order_amd = rro_info->rasterizationOrder;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT: {
|
|
|
|
const VkPipelineRasterizationStateStreamCreateInfoEXT *rss_info =
|
|
|
|
(const VkPipelineRasterizationStateStreamCreateInfoEXT *)ext;
|
|
|
|
rs->rasterization_stream = rss_info->rasterizationStream;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-30 00:26:05 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-07-13 16:02:30 +01:00
|
|
|
static void
|
|
|
|
vk_fragment_shading_rate_state_init(
|
|
|
|
struct vk_fragment_shading_rate_state *fsr,
|
|
|
|
const BITSET_WORD *dynamic,
|
|
|
|
const VkPipelineFragmentShadingRateStateCreateInfoKHR *fsr_info)
|
|
|
|
{
|
|
|
|
if (fsr_info != NULL) {
|
|
|
|
fsr->fragment_size = fsr_info->fragmentSize;
|
|
|
|
fsr->combiner_ops[0] = fsr_info->combinerOps[0];
|
|
|
|
fsr->combiner_ops[1] = fsr_info->combinerOps[1];
|
|
|
|
} else {
|
|
|
|
fsr->fragment_size = (VkExtent2D) { 1, 1 };
|
|
|
|
fsr->combiner_ops[0] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR;
|
|
|
|
fsr->combiner_ops[1] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-30 00:26:05 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-07-13 16:02:30 +01:00
|
|
|
static void
|
|
|
|
vk_sample_locations_state_init(struct vk_sample_locations_state *sl,
|
|
|
|
const VkSampleLocationsInfoEXT *sl_info)
|
|
|
|
{
|
|
|
|
sl->per_pixel = sl_info->sampleLocationsPerPixel;
|
|
|
|
sl->grid_size = sl_info->sampleLocationGridSize;
|
|
|
|
|
|
|
|
/* From the Vulkan 1.3.218 spec:
|
|
|
|
*
|
|
|
|
* VUID-VkSampleLocationsInfoEXT-sampleLocationsCount-01527
|
|
|
|
*
|
|
|
|
* "sampleLocationsCount must equal sampleLocationsPerPixel *
|
|
|
|
* sampleLocationGridSize.width * sampleLocationGridSize.height"
|
|
|
|
*/
|
|
|
|
assert(sl_info->sampleLocationsCount ==
|
|
|
|
sl_info->sampleLocationsPerPixel *
|
|
|
|
sl_info->sampleLocationGridSize.width *
|
|
|
|
sl_info->sampleLocationGridSize.height);
|
|
|
|
|
|
|
|
assert(sl_info->sampleLocationsCount <= MESA_VK_MAX_SAMPLE_LOCATIONS);
|
|
|
|
typed_memcpy(sl->locations, sl_info->pSampleLocations,
|
|
|
|
sl_info->sampleLocationsCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
vk_multisample_state_init(struct vk_multisample_state *ms,
|
|
|
|
const BITSET_WORD *dynamic,
|
|
|
|
const VkPipelineMultisampleStateCreateInfo *ms_info)
|
|
|
|
{
|
|
|
|
ms->rasterization_samples = ms_info->rasterizationSamples;
|
|
|
|
ms->sample_shading_enable = ms_info->sampleShadingEnable;
|
|
|
|
ms->min_sample_shading = ms_info->minSampleShading;
|
|
|
|
|
|
|
|
/* From the Vulkan 1.3.218 spec:
|
|
|
|
*
|
|
|
|
* "If pSampleMask is NULL, it is treated as if the mask has all bits
|
|
|
|
* set to 1."
|
|
|
|
*/
|
|
|
|
ms->sample_mask = ms_info->pSampleMask ? *ms_info->pSampleMask : ~0;
|
|
|
|
|
|
|
|
ms->alpha_to_coverage_enable = ms_info->alphaToCoverageEnable;
|
|
|
|
ms->alpha_to_one_enable = ms_info->alphaToOneEnable;
|
|
|
|
|
|
|
|
/* These get filled in by vk_multisample_sample_locations_state_init() */
|
|
|
|
ms->sample_locations_enable = false;
|
|
|
|
ms->sample_locations = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
needs_sample_locations_state(
|
|
|
|
const BITSET_WORD *dynamic,
|
|
|
|
const VkPipelineSampleLocationsStateCreateInfoEXT *sl_info)
|
|
|
|
{
|
|
|
|
return !IS_DYNAMIC(MS_SAMPLE_LOCATIONS) &&
|
|
|
|
sl_info != NULL && sl_info->sampleLocationsEnable;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
vk_multisample_sample_locations_state_init(
|
|
|
|
struct vk_multisample_state *ms,
|
|
|
|
struct vk_sample_locations_state *sl,
|
|
|
|
const BITSET_WORD *dynamic,
|
|
|
|
const VkPipelineMultisampleStateCreateInfo *ms_info,
|
|
|
|
const VkPipelineSampleLocationsStateCreateInfoEXT *sl_info)
|
|
|
|
{
|
|
|
|
ms->sample_locations_enable =
|
|
|
|
sl_info != NULL && sl_info->sampleLocationsEnable;
|
|
|
|
|
|
|
|
assert(ms->sample_locations == NULL);
|
|
|
|
if (!IS_DYNAMIC(MS_SAMPLE_LOCATIONS)) {
|
|
|
|
if (ms->sample_locations_enable) {
|
|
|
|
vk_sample_locations_state_init(sl, &sl_info->sampleLocationsInfo);
|
|
|
|
ms->sample_locations = sl;
|
|
|
|
} else {
|
|
|
|
/* Otherwise, pre-populate with the standard sample locations. If
|
|
|
|
* the driver doesn't support standard sample locations, it probably
|
|
|
|
* doesn't support custom locations either and can completely ignore
|
|
|
|
* this state.
|
|
|
|
*/
|
|
|
|
ms->sample_locations =
|
|
|
|
vk_standard_sample_locations_state(ms_info->rasterizationSamples);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-30 00:26:05 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-07-13 16:02:30 +01:00
|
|
|
static void
|
|
|
|
vk_stencil_test_face_state_init(struct vk_stencil_test_face_state *face,
|
|
|
|
const VkStencilOpState *info)
|
|
|
|
{
|
|
|
|
face->op.fail = info->failOp;
|
|
|
|
face->op.pass = info->passOp;
|
|
|
|
face->op.depth_fail = info->depthFailOp;
|
|
|
|
face->op.compare = info->compareOp;
|
|
|
|
face->compare_mask = info->compareMask;
|
|
|
|
face->write_mask = info->writeMask;
|
|
|
|
face->reference = info->reference;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
vk_depth_stencil_state_init(struct vk_depth_stencil_state *ds,
|
|
|
|
const BITSET_WORD *dynamic,
|
|
|
|
const VkPipelineDepthStencilStateCreateInfo *ds_info)
|
|
|
|
{
|
|
|
|
memset(ds, 0, sizeof(*ds));
|
|
|
|
|
|
|
|
ds->depth.test_enable = ds_info->depthTestEnable;
|
|
|
|
ds->depth.write_enable = ds_info->depthWriteEnable;
|
|
|
|
ds->depth.compare_op = ds_info->depthCompareOp;
|
|
|
|
ds->depth.bounds_test.enable = ds_info->depthBoundsTestEnable;
|
|
|
|
ds->depth.bounds_test.min = ds_info->minDepthBounds;
|
|
|
|
ds->depth.bounds_test.max = ds_info->maxDepthBounds;
|
|
|
|
|
|
|
|
ds->stencil.test_enable = ds_info->stencilTestEnable;
|
2022-07-07 18:09:16 +01:00
|
|
|
ds->stencil.write_enable = true;
|
2022-07-13 16:02:30 +01:00
|
|
|
vk_stencil_test_face_state_init(&ds->stencil.front, &ds_info->front);
|
|
|
|
vk_stencil_test_face_state_init(&ds->stencil.back, &ds_info->back);
|
|
|
|
}
|
|
|
|
|
2022-06-30 00:26:05 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-07-07 18:09:16 +01:00
|
|
|
static bool
|
|
|
|
optimize_stencil_face(struct vk_stencil_test_face_state *face,
|
|
|
|
VkCompareOp depthCompareOp)
|
|
|
|
{
|
|
|
|
/* If compareOp is ALWAYS then the stencil test will never fail and failOp
|
|
|
|
* will never happen. Set failOp to KEEP in this case.
|
|
|
|
*/
|
|
|
|
if (face->op.compare == VK_COMPARE_OP_ALWAYS)
|
|
|
|
face->op.fail = VK_STENCIL_OP_KEEP;
|
|
|
|
|
|
|
|
/* If compareOp is NEVER or depthCompareOp is NEVER then one of the depth
|
|
|
|
* or stencil tests will fail and passOp will never happen.
|
|
|
|
*/
|
|
|
|
if (face->op.compare == VK_COMPARE_OP_NEVER ||
|
|
|
|
depthCompareOp == VK_COMPARE_OP_NEVER)
|
|
|
|
face->op.pass = VK_STENCIL_OP_KEEP;
|
|
|
|
|
|
|
|
/* If compareOp is NEVER or depthCompareOp is ALWAYS then either the
|
|
|
|
* stencil test will fail or the depth test will pass. In either case,
|
|
|
|
* depthFailOp will never happen.
|
|
|
|
*/
|
|
|
|
if (face->op.compare == VK_COMPARE_OP_NEVER ||
|
|
|
|
depthCompareOp == VK_COMPARE_OP_ALWAYS)
|
|
|
|
face->op.depth_fail = VK_STENCIL_OP_KEEP;
|
|
|
|
|
|
|
|
return face->op.fail != VK_STENCIL_OP_KEEP ||
|
|
|
|
face->op.depth_fail != VK_STENCIL_OP_KEEP ||
|
|
|
|
face->op.pass != VK_STENCIL_OP_KEEP;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
vk_optimize_depth_stencil_state(struct vk_depth_stencil_state *ds,
|
|
|
|
VkImageAspectFlags ds_aspects)
|
|
|
|
{
|
|
|
|
/* stencil.write_enable is a dummy right now that should always be true */
|
|
|
|
assert(ds->stencil.write_enable);
|
|
|
|
|
|
|
|
/* If the depth test is disabled, we won't be writing anything. Make sure we
|
|
|
|
* treat the test as always passing later on as well.
|
|
|
|
*
|
|
|
|
* Also, the Vulkan spec requires that if either depth or stencil is not
|
|
|
|
* present, the pipeline is to act as if the test silently passes. In that
|
|
|
|
* case we won't write either.
|
|
|
|
*/
|
|
|
|
if (!ds->depth.test_enable || !(ds_aspects & VK_IMAGE_ASPECT_DEPTH_BIT)) {
|
|
|
|
ds->depth.write_enable = false;
|
|
|
|
ds->depth.compare_op = VK_COMPARE_OP_ALWAYS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(ds_aspects & VK_IMAGE_ASPECT_STENCIL_BIT)) {
|
|
|
|
ds->stencil.write_enable = false;
|
|
|
|
ds->stencil.front.op.compare = VK_COMPARE_OP_ALWAYS;
|
|
|
|
ds->stencil.back.op.compare = VK_COMPARE_OP_ALWAYS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the stencil test is enabled and always fails, then we will never get
|
|
|
|
* to the depth test so we can just disable the depth test entirely.
|
|
|
|
*/
|
|
|
|
if (ds->stencil.test_enable &&
|
|
|
|
ds->stencil.front.op.compare == VK_COMPARE_OP_NEVER &&
|
|
|
|
ds->stencil.back.op.compare == VK_COMPARE_OP_NEVER) {
|
|
|
|
ds->depth.test_enable = false;
|
|
|
|
ds->depth.write_enable = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If depthCompareOp is EQUAL then the value we would be writing to the
|
|
|
|
* depth buffer is the same as the value that's already there so there's no
|
|
|
|
* point in writing it.
|
|
|
|
*/
|
|
|
|
if (ds->depth.compare_op == VK_COMPARE_OP_EQUAL)
|
|
|
|
ds->depth.write_enable = false;
|
|
|
|
|
|
|
|
/* If the stencil ops are such that we don't actually ever modify the
|
|
|
|
* stencil buffer, we should disable writes.
|
|
|
|
*/
|
|
|
|
if (!optimize_stencil_face(&ds->stencil.front, ds->depth.compare_op) &&
|
|
|
|
!optimize_stencil_face(&ds->stencil.back, ds->depth.compare_op))
|
|
|
|
ds->stencil.write_enable = false;
|
|
|
|
|
|
|
|
/* If the depth test always passes and we never write out depth, that's the
|
|
|
|
* same as if the depth test is disabled entirely.
|
|
|
|
*/
|
|
|
|
if (ds->depth.compare_op == VK_COMPARE_OP_ALWAYS && !ds->depth.write_enable)
|
|
|
|
ds->depth.test_enable = false;
|
|
|
|
|
|
|
|
/* If the stencil test always passes and we never write out stencil, that's
|
|
|
|
* the same as if the stencil test is disabled entirely.
|
|
|
|
*/
|
|
|
|
if (ds->stencil.front.op.compare == VK_COMPARE_OP_ALWAYS &&
|
|
|
|
ds->stencil.back.op.compare == VK_COMPARE_OP_ALWAYS &&
|
|
|
|
!ds->stencil.write_enable)
|
|
|
|
ds->stencil.test_enable = false;
|
|
|
|
}
|
|
|
|
|
2022-07-13 16:02:30 +01:00
|
|
|
static void
|
|
|
|
vk_color_blend_state_init(struct vk_color_blend_state *cb,
|
|
|
|
const BITSET_WORD *dynamic,
|
|
|
|
const VkPipelineColorBlendStateCreateInfo *cb_info)
|
|
|
|
{
|
|
|
|
memset(cb, 0, sizeof(*cb));
|
|
|
|
|
|
|
|
cb->logic_op_enable = cb_info->logicOpEnable;
|
|
|
|
cb->logic_op = cb_info->logicOp;
|
|
|
|
|
|
|
|
assert(cb_info->attachmentCount <= MESA_VK_MAX_COLOR_ATTACHMENTS);
|
|
|
|
cb->attachment_count = cb_info->attachmentCount;
|
|
|
|
for (uint32_t a = 0; a < cb_info->attachmentCount; a++) {
|
|
|
|
const VkPipelineColorBlendAttachmentState *att =
|
|
|
|
&cb_info->pAttachments[a];
|
|
|
|
|
|
|
|
cb->attachments[a] = (struct vk_color_blend_attachment_state) {
|
|
|
|
.blend_enable = att->blendEnable,
|
|
|
|
.src_color_blend_factor = att->srcColorBlendFactor,
|
|
|
|
.dst_color_blend_factor = att->dstColorBlendFactor,
|
|
|
|
.src_alpha_blend_factor = att->srcAlphaBlendFactor,
|
|
|
|
.dst_alpha_blend_factor = att->dstAlphaBlendFactor,
|
|
|
|
.write_mask = att->colorWriteMask,
|
|
|
|
.color_blend_op = att->colorBlendOp,
|
|
|
|
.alpha_blend_op = att->alphaBlendOp,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < 4; i++)
|
|
|
|
cb->blend_constants[i] = cb_info->blendConstants[i];
|
|
|
|
|
|
|
|
const VkPipelineColorWriteCreateInfoEXT *cw_info =
|
|
|
|
vk_find_struct_const(cb_info->pNext, PIPELINE_COLOR_WRITE_CREATE_INFO_EXT);
|
|
|
|
if (cw_info != NULL) {
|
|
|
|
assert(cb_info->attachmentCount == cw_info->attachmentCount);
|
|
|
|
for (uint32_t a = 0; a < cw_info->attachmentCount; a++) {
|
|
|
|
if (cw_info->pColorWriteEnables[a])
|
|
|
|
cb->color_write_enables |= BITFIELD_BIT(a);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
cb->color_write_enables = BITFIELD_MASK(cb_info->attachmentCount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-30 00:26:05 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2022-07-13 16:02:30 +01:00
|
|
|
static bool
|
|
|
|
vk_render_pass_state_is_complete(const struct vk_render_pass_state *rp)
|
|
|
|
{
|
|
|
|
return rp->attachment_aspects != VK_IMAGE_ASPECT_METADATA_BIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
vk_render_pass_state_init(struct vk_render_pass_state *rp,
|
|
|
|
const struct vk_render_pass_state *old_rp,
|
|
|
|
const VkGraphicsPipelineCreateInfo *info,
|
|
|
|
const struct vk_subpass_info *sp_info,
|
|
|
|
VkGraphicsPipelineLibraryFlagsEXT lib)
|
|
|
|
{
|
|
|
|
/* If we already have render pass state and it has attachment info, then
|
|
|
|
* it's complete and we don't need a new one.
|
|
|
|
*/
|
|
|
|
if (old_rp != NULL && vk_render_pass_state_is_complete(old_rp)) {
|
|
|
|
*rp = *old_rp;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
*rp = (struct vk_render_pass_state) {
|
|
|
|
.depth_attachment_format = VK_FORMAT_UNDEFINED,
|
|
|
|
.stencil_attachment_format = VK_FORMAT_UNDEFINED,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (info->renderPass != VK_NULL_HANDLE && sp_info != NULL) {
|
|
|
|
rp->render_pass = info->renderPass;
|
|
|
|
rp->subpass = info->subpass;
|
|
|
|
rp->attachment_aspects = sp_info->attachment_aspects;
|
|
|
|
rp->view_mask = sp_info->view_mask;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const VkPipelineRenderingCreateInfo *r_info =
|
|
|
|
vk_get_pipeline_rendering_create_info(info);
|
|
|
|
|
|
|
|
if (r_info == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
rp->view_mask = r_info->viewMask;
|
|
|
|
|
|
|
|
/* From the Vulkan 1.3.218 spec description of pre-rasterization state:
|
|
|
|
*
|
|
|
|
* "Fragment shader state is defined by:
|
|
|
|
* ...
|
|
|
|
* * VkRenderPass and subpass parameter
|
|
|
|
* * The viewMask parameter of VkPipelineRenderingCreateInfo (formats
|
|
|
|
* are ignored)"
|
|
|
|
*
|
|
|
|
* The description of fragment shader state contains identical text.
|
|
|
|
*
|
|
|
|
* If we have a render pass then we have full information. Even if we're
|
|
|
|
* dynamic-rendering-only, the presence of a render pass means the
|
|
|
|
* rendering info came from a vk_render_pass and is therefore complete.
|
|
|
|
* Otherwise, all we can grab is the view mask and we have to leave the
|
|
|
|
* rest for later.
|
|
|
|
*/
|
|
|
|
if (info->renderPass == VK_NULL_HANDLE &&
|
|
|
|
!(lib & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT)) {
|
|
|
|
rp->attachment_aspects = VK_IMAGE_ASPECT_METADATA_BIT;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(r_info->colorAttachmentCount <= MESA_VK_MAX_COLOR_ATTACHMENTS);
|
|
|
|
rp->color_attachment_count = r_info->colorAttachmentCount;
|
|
|
|
for (uint32_t i = 0; i < r_info->colorAttachmentCount; i++) {
|
|
|
|
rp->color_attachment_formats[i] = r_info->pColorAttachmentFormats[i];
|
|
|
|
if (r_info->pColorAttachmentFormats[i] != VK_FORMAT_UNDEFINED)
|
|
|
|
rp->attachment_aspects |= VK_IMAGE_ASPECT_COLOR_BIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
rp->depth_attachment_format = r_info->depthAttachmentFormat;
|
|
|
|
if (r_info->depthAttachmentFormat != VK_FORMAT_UNDEFINED)
|
|
|
|
rp->attachment_aspects |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
|
|
|
|
|
|
|
rp->stencil_attachment_format = r_info->stencilAttachmentFormat;
|
|
|
|
if (r_info->stencilAttachmentFormat != VK_FORMAT_UNDEFINED)
|
|
|
|
rp->attachment_aspects |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
|
|
|
|
|
|
|
const VkRenderingSelfDependencyInfoMESA *rsd_info =
|
|
|
|
vk_find_struct_const(r_info->pNext, RENDERING_SELF_DEPENDENCY_INFO_MESA);
|
|
|
|
if (rsd_info != NULL) {
|
|
|
|
STATIC_ASSERT(sizeof(rp->color_self_dependencies) * 8 >=
|
|
|
|
MESA_VK_MAX_COLOR_ATTACHMENTS);
|
|
|
|
rp->color_self_dependencies = rsd_info->colorSelfDependencies;
|
|
|
|
rp->depth_self_dependency = rsd_info->depthSelfDependency;
|
|
|
|
rp->stencil_self_dependency = rsd_info->stencilSelfDependency;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-30 00:26:05 +01:00
|
|
|
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)
|
|
|
|
{ }
|
|
|
|
|
2022-07-13 16:02:30 +01:00
|
|
|
#define FOREACH_STATE_GROUP(f) \
|
|
|
|
f(MESA_VK_GRAPHICS_STATE_VERTEX_INPUT_BIT, \
|
|
|
|
vk_vertex_input_state, vi); \
|
|
|
|
f(MESA_VK_GRAPHICS_STATE_INPUT_ASSEMBLY_BIT, \
|
|
|
|
vk_input_assembly_state, ia); \
|
|
|
|
f(MESA_VK_GRAPHICS_STATE_TESSELLATION_BIT, \
|
|
|
|
vk_tessellation_state, ts); \
|
|
|
|
f(MESA_VK_GRAPHICS_STATE_VIEWPORT_BIT, \
|
|
|
|
vk_viewport_state, vp); \
|
|
|
|
f(MESA_VK_GRAPHICS_STATE_DISCARD_RECTANGLES_BIT, \
|
|
|
|
vk_discard_rectangles_state, dr); \
|
|
|
|
f(MESA_VK_GRAPHICS_STATE_RASTERIZATION_BIT, \
|
|
|
|
vk_rasterization_state, rs); \
|
|
|
|
f(MESA_VK_GRAPHICS_STATE_FRAGMENT_SHADING_RATE_BIT, \
|
|
|
|
vk_fragment_shading_rate_state, fsr); \
|
|
|
|
f(MESA_VK_GRAPHICS_STATE_MULTISAMPLE_BIT, \
|
|
|
|
vk_multisample_state, ms); \
|
|
|
|
f(MESA_VK_GRAPHICS_STATE_DEPTH_STENCIL_BIT, \
|
|
|
|
vk_depth_stencil_state, ds); \
|
|
|
|
f(MESA_VK_GRAPHICS_STATE_COLOR_BLEND_BIT, \
|
|
|
|
vk_color_blend_state, cb); \
|
|
|
|
f(MESA_VK_GRAPHICS_STATE_RENDER_PASS_BIT, \
|
|
|
|
vk_render_pass_state, rp);
|
|
|
|
|
|
|
|
static void
|
|
|
|
vk_graphics_pipeline_state_validate(const struct vk_graphics_pipeline_state *state)
|
|
|
|
{
|
|
|
|
#ifndef NDEBUG
|
|
|
|
/* For now, we just validate dynamic state */
|
|
|
|
enum mesa_vk_graphics_state_groups has = 0;
|
|
|
|
|
|
|
|
#define FILL_HAS(STATE, type, s) \
|
|
|
|
if (state->s != NULL) has |= STATE
|
|
|
|
|
|
|
|
FOREACH_STATE_GROUP(FILL_HAS)
|
|
|
|
|
|
|
|
#undef FILL_HAS
|
|
|
|
|
|
|
|
validate_dynamic_state_groups(state->dynamic, has);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
may_have_rasterization(const struct vk_graphics_pipeline_state *state,
|
|
|
|
const BITSET_WORD *dynamic,
|
|
|
|
const VkGraphicsPipelineCreateInfo *info)
|
|
|
|
{
|
|
|
|
if (state->rs) {
|
|
|
|
/* We default rasterizer_discard_enable to false when dynamic */
|
|
|
|
return !state->rs->rasterizer_discard_enable;
|
|
|
|
} else {
|
|
|
|
return IS_DYNAMIC(RS_RASTERIZER_DISCARD_ENABLE) ||
|
|
|
|
!info->pRasterizationState->rasterizerDiscardEnable;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VkResult
|
|
|
|
vk_graphics_pipeline_state_fill(const struct vk_device *device,
|
|
|
|
struct vk_graphics_pipeline_state *state,
|
|
|
|
const VkGraphicsPipelineCreateInfo *info,
|
|
|
|
const struct vk_subpass_info *sp_info,
|
|
|
|
struct vk_graphics_pipeline_all_state *all,
|
|
|
|
const VkAllocationCallbacks *alloc,
|
|
|
|
VkSystemAllocationScope scope,
|
|
|
|
void **alloc_ptr_out)
|
|
|
|
{
|
|
|
|
vk_graphics_pipeline_state_validate(state);
|
|
|
|
|
|
|
|
BITSET_DECLARE(dynamic, MESA_VK_DYNAMIC_GRAPHICS_STATE_ENUM_MAX);
|
|
|
|
vk_get_dynamic_graphics_states(dynamic, info->pDynamicState);
|
|
|
|
|
|
|
|
VkShaderStageFlags stages = 0;
|
|
|
|
for (uint32_t i = 0; i < info->stageCount; i++)
|
|
|
|
stages |= info->pStages[i].stage;
|
|
|
|
|
|
|
|
/* In case we return early */
|
|
|
|
if (alloc_ptr_out != NULL)
|
|
|
|
*alloc_ptr_out = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* First, figure out which library-level shader/state groups we need
|
|
|
|
*/
|
|
|
|
|
|
|
|
VkGraphicsPipelineLibraryFlagsEXT lib;
|
|
|
|
if (info->flags & VK_PIPELINE_CREATE_LIBRARY_BIT_KHR) {
|
|
|
|
const VkGraphicsPipelineLibraryCreateInfoEXT *gfx_lib_info =
|
|
|
|
vk_find_struct_const(info->pNext, GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT);
|
|
|
|
|
|
|
|
/* If we're building a pipeline library, trust the client.
|
|
|
|
*
|
|
|
|
* From the Vulkan 1.3.218 spec:
|
|
|
|
*
|
|
|
|
* VUID-VkGraphicsPipelineLibraryCreateInfoEXT-flags-requiredbitmask
|
|
|
|
*
|
|
|
|
* "flags must not be 0"
|
|
|
|
*/
|
|
|
|
assert(gfx_lib_info->flags != 0);
|
|
|
|
lib = gfx_lib_info->flags;
|
|
|
|
} else {
|
|
|
|
/* We're building a complete pipeline. From the Vulkan 1.3.218 spec:
|
|
|
|
*
|
|
|
|
* "A complete graphics pipeline always includes pre-rasterization
|
|
|
|
* shader state, with other subsets included depending on that state.
|
|
|
|
* If the pre-rasterization shader state includes a vertex shader,
|
|
|
|
* then vertex input state is included in a complete graphics
|
|
|
|
* pipeline. If the value of
|
|
|
|
* VkPipelineRasterizationStateCreateInfo::rasterizerDiscardEnable in
|
|
|
|
* the pre-rasterization shader state is VK_FALSE or the
|
|
|
|
* VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE dynamic state is
|
|
|
|
* enabled fragment shader state and fragment output interface state
|
|
|
|
* is included in a complete graphics pipeline."
|
|
|
|
*/
|
|
|
|
lib = VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT;
|
|
|
|
|
|
|
|
if (stages & VK_SHADER_STAGE_VERTEX_BIT)
|
|
|
|
lib |= VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT;
|
|
|
|
|
|
|
|
if (may_have_rasterization(state, dynamic, info)) {
|
|
|
|
lib |= VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT;
|
|
|
|
lib |= VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Next, turn those into individual states. Among other things, this
|
|
|
|
* de-duplicates things like FSR and multisample state which appear in
|
|
|
|
* multiple library groups.
|
|
|
|
*/
|
|
|
|
|
|
|
|
enum mesa_vk_graphics_state_groups needs = 0;
|
|
|
|
if (lib & VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT) {
|
|
|
|
needs |= MESA_VK_GRAPHICS_STATE_VERTEX_INPUT_BIT;
|
|
|
|
needs |= MESA_VK_GRAPHICS_STATE_INPUT_ASSEMBLY_BIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Other stuff potentially depends on this so gather it early */
|
|
|
|
struct vk_render_pass_state rp;
|
|
|
|
if (lib & (VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT |
|
|
|
|
VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT |
|
|
|
|
VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT)) {
|
|
|
|
vk_render_pass_state_init(&rp, state->rp, info, sp_info, lib);
|
|
|
|
|
|
|
|
needs |= MESA_VK_GRAPHICS_STATE_RENDER_PASS_BIT;
|
|
|
|
|
|
|
|
/* If the old state was incomplete but the new one isn't, set state->rp
|
|
|
|
* to NULL so it gets replaced with the new version.
|
|
|
|
*/
|
|
|
|
if (state->rp != NULL &&
|
|
|
|
!vk_render_pass_state_is_complete(state->rp) &&
|
|
|
|
vk_render_pass_state_is_complete(&rp))
|
|
|
|
state->rp = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lib & VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT) {
|
|
|
|
/* From the Vulkan 1.3.218 spec:
|
|
|
|
*
|
|
|
|
* VUID-VkGraphicsPipelineCreateInfo-stage-02096
|
|
|
|
*
|
|
|
|
* "If the pipeline is being created with pre-rasterization shader
|
|
|
|
* state the stage member of one element of pStages must be either
|
|
|
|
* VK_SHADER_STAGE_VERTEX_BIT or VK_SHADER_STAGE_MESH_BIT_NV"
|
|
|
|
*/
|
|
|
|
assert(stages & (VK_SHADER_STAGE_VERTEX_BIT |
|
|
|
|
VK_SHADER_STAGE_MESH_BIT_NV));
|
|
|
|
|
|
|
|
if (stages & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT |
|
|
|
|
VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT))
|
|
|
|
needs |= MESA_VK_GRAPHICS_STATE_TESSELLATION_BIT;
|
|
|
|
|
|
|
|
if (may_have_rasterization(state, dynamic, info))
|
|
|
|
needs |= MESA_VK_GRAPHICS_STATE_VIEWPORT_BIT;
|
|
|
|
|
|
|
|
needs |= MESA_VK_GRAPHICS_STATE_DISCARD_RECTANGLES_BIT;
|
|
|
|
needs |= MESA_VK_GRAPHICS_STATE_RASTERIZATION_BIT;
|
|
|
|
needs |= MESA_VK_GRAPHICS_STATE_FRAGMENT_SHADING_RATE_BIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lib & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT) {
|
|
|
|
needs |= MESA_VK_GRAPHICS_STATE_FRAGMENT_SHADING_RATE_BIT;
|
|
|
|
needs |= MESA_VK_GRAPHICS_STATE_MULTISAMPLE_BIT;
|
|
|
|
|
|
|
|
/* From the Vulkan 1.3.218 spec:
|
|
|
|
*
|
|
|
|
* VUID-VkGraphicsPipelineCreateInfo-renderPass-06043
|
|
|
|
*
|
|
|
|
* "If renderPass is not VK_NULL_HANDLE, the pipeline is being
|
|
|
|
* created with fragment shader state, and subpass uses a
|
|
|
|
* depth/stencil attachment, pDepthStencilState must be a valid
|
|
|
|
* pointer to a valid VkPipelineDepthStencilStateCreateInfo
|
|
|
|
* structure"
|
|
|
|
*
|
|
|
|
* VUID-VkGraphicsPipelineCreateInfo-renderPass-06053
|
|
|
|
*
|
|
|
|
* "If renderPass is VK_NULL_HANDLE, the pipeline is being created
|
|
|
|
* with fragment shader state and fragment output interface state,
|
|
|
|
* and either of VkPipelineRenderingCreateInfo::depthAttachmentFormat
|
|
|
|
* or VkPipelineRenderingCreateInfo::stencilAttachmentFormat are not
|
|
|
|
* VK_FORMAT_UNDEFINED, pDepthStencilState must be a valid pointer to
|
|
|
|
* a valid VkPipelineDepthStencilStateCreateInfo structure"
|
|
|
|
*
|
|
|
|
* VUID-VkGraphicsPipelineCreateInfo-renderPass-06590
|
|
|
|
*
|
|
|
|
* "If renderPass is VK_NULL_HANDLE and the pipeline is being created
|
|
|
|
* with fragment shader state but not fragment output interface
|
|
|
|
* state, pDepthStencilState must be a valid pointer to a valid
|
|
|
|
* VkPipelineDepthStencilStateCreateInfo structure"
|
|
|
|
*
|
|
|
|
* In the first case, we'll have a real set of aspects in rp. In the
|
|
|
|
* second case, where we have both fragment shader and fragment output
|
|
|
|
* state, we will also have a valid set of aspects. In the third case
|
|
|
|
* where we only have fragment shader state and no render pass, the
|
|
|
|
* vk_render_pass_state will be incomplete.
|
|
|
|
*/
|
|
|
|
if ((rp.attachment_aspects & (VK_IMAGE_ASPECT_DEPTH_BIT |
|
|
|
|
VK_IMAGE_ASPECT_STENCIL_BIT)) ||
|
|
|
|
!vk_render_pass_state_is_complete(&rp))
|
|
|
|
needs |= MESA_VK_GRAPHICS_STATE_DEPTH_STENCIL_BIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lib & VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT) {
|
|
|
|
if (rp.attachment_aspects & (VK_IMAGE_ASPECT_DEPTH_BIT |
|
|
|
|
VK_IMAGE_ASPECT_STENCIL_BIT))
|
|
|
|
needs |= MESA_VK_GRAPHICS_STATE_DEPTH_STENCIL_BIT;
|
|
|
|
|
|
|
|
if (rp.attachment_aspects & (VK_IMAGE_ASPECT_COLOR_BIT))
|
|
|
|
needs |= MESA_VK_GRAPHICS_STATE_COLOR_BLEND_BIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Next, Filter off any states we already have.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define FILTER_NEEDS(STATE, type, s) \
|
|
|
|
if (state->s != NULL) needs &= ~STATE
|
|
|
|
|
|
|
|
FOREACH_STATE_GROUP(FILTER_NEEDS)
|
|
|
|
|
|
|
|
#undef FILTER_NEEDS
|
|
|
|
|
|
|
|
/* Filter dynamic state down to just what we're adding */
|
|
|
|
BITSET_DECLARE(dynamic_filter, MESA_VK_DYNAMIC_GRAPHICS_STATE_ENUM_MAX);
|
|
|
|
get_dynamic_state_groups(dynamic_filter, needs);
|
|
|
|
BITSET_AND(dynamic, dynamic, dynamic_filter);
|
|
|
|
|
|
|
|
/* And add it in */
|
|
|
|
BITSET_OR(state->dynamic, state->dynamic, dynamic);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If vertex state or fragment shading rate state are fully dynamic, we
|
|
|
|
* don't need to even allocate them. Do this after we've filtered
|
|
|
|
* dynamic state because we want to keep the MESA_VK_DYNAMIC_VI and
|
|
|
|
* MESA_VK_DYNAMIC_FSR bits in the dynamic state but don't want the
|
|
|
|
* actual state.
|
|
|
|
*/
|
|
|
|
if (BITSET_TEST(dynamic, MESA_VK_DYNAMIC_VI))
|
|
|
|
needs &= ~MESA_VK_GRAPHICS_STATE_VERTEX_INPUT_BIT;
|
|
|
|
if (BITSET_TEST(dynamic, MESA_VK_DYNAMIC_FSR))
|
|
|
|
needs &= ~MESA_VK_GRAPHICS_STATE_FRAGMENT_SHADING_RATE_BIT;
|
|
|
|
|
|
|
|
/* If we don't need to set up any new states, bail early */
|
|
|
|
if (needs == 0)
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now, ensure that we have space for each of the states we're going to
|
|
|
|
* fill. If all != NULL, we'll pull from that. Otherwise, we need to
|
|
|
|
* allocate memory.
|
|
|
|
*/
|
|
|
|
|
|
|
|
VK_MULTIALLOC(ma);
|
|
|
|
|
|
|
|
#define ENSURE_STATE_IF_NEEDED(STATE, type, s) \
|
|
|
|
struct type *new_##s = NULL; \
|
|
|
|
if (needs & STATE) { \
|
|
|
|
if (all == NULL) { \
|
|
|
|
vk_multialloc_add(&ma, &new_##s, struct type, 1); \
|
|
|
|
} else { \
|
|
|
|
new_##s = &all->s; \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
FOREACH_STATE_GROUP(ENSURE_STATE_IF_NEEDED)
|
|
|
|
|
|
|
|
#undef ENSURE_STATE_IF_NEEDED
|
|
|
|
|
|
|
|
/* Sample locations are a bit special. We don't want to waste the memory
|
|
|
|
* for 64 floats if we don't need to. Also, we set up standard sample
|
|
|
|
* locations if no user-provided sample locations are available.
|
|
|
|
*/
|
|
|
|
const VkPipelineSampleLocationsStateCreateInfoEXT *sl_info = NULL;
|
|
|
|
struct vk_sample_locations_state *new_sl = NULL;
|
|
|
|
if (needs & MESA_VK_GRAPHICS_STATE_MULTISAMPLE_BIT) {
|
|
|
|
sl_info = vk_find_struct_const(info->pMultisampleState->pNext,
|
|
|
|
PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT);
|
|
|
|
if (needs_sample_locations_state(dynamic, sl_info)) {
|
|
|
|
if (all == NULL) {
|
|
|
|
vk_multialloc_add(&ma, &new_sl, struct vk_sample_locations_state, 1);
|
|
|
|
} else {
|
|
|
|
new_sl = &all->ms_sample_locations;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate memory, if needed
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (ma.size > 0) {
|
|
|
|
assert(all == NULL);
|
|
|
|
*alloc_ptr_out = vk_multialloc_alloc2(&ma, &device->alloc, alloc, scope);
|
|
|
|
if (*alloc_ptr_out == NULL)
|
|
|
|
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create aliases for various input infos so we can use or FOREACH macro
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define INFO_ALIAS(_State, s) \
|
|
|
|
const VkPipeline##_State##StateCreateInfo *s##_info = info->p##_State##State
|
|
|
|
|
|
|
|
INFO_ALIAS(VertexInput, vi);
|
|
|
|
INFO_ALIAS(InputAssembly, ia);
|
|
|
|
INFO_ALIAS(Tessellation, ts);
|
|
|
|
INFO_ALIAS(Viewport, vp);
|
|
|
|
INFO_ALIAS(Rasterization, rs);
|
|
|
|
INFO_ALIAS(Multisample, ms);
|
|
|
|
INFO_ALIAS(DepthStencil, ds);
|
|
|
|
INFO_ALIAS(ColorBlend, cb);
|
|
|
|
|
|
|
|
#undef INFO_ALIAS
|
|
|
|
|
|
|
|
const VkPipelineDiscardRectangleStateCreateInfoEXT *dr_info =
|
|
|
|
vk_find_struct_const(info->pNext, PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT);
|
|
|
|
|
|
|
|
const VkPipelineFragmentShadingRateStateCreateInfoKHR *fsr_info =
|
|
|
|
vk_find_struct_const(info->pNext, PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Finally, fill out all the states
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define INIT_STATE_IF_NEEDED(STATE, type, s) \
|
|
|
|
if (needs & STATE) { \
|
|
|
|
type##_init(new_##s, dynamic, s##_info); \
|
|
|
|
state->s = new_##s; \
|
|
|
|
}
|
|
|
|
|
|
|
|
/* render pass state is special and we just copy it */
|
|
|
|
#define vk_render_pass_state_init(s, d, i) *s = rp
|
|
|
|
|
|
|
|
FOREACH_STATE_GROUP(INIT_STATE_IF_NEEDED)
|
|
|
|
|
|
|
|
#undef vk_render_pass_state_init
|
|
|
|
#undef INIT_STATE_IF_NEEDED
|
|
|
|
|
|
|
|
if (needs & MESA_VK_GRAPHICS_STATE_MULTISAMPLE_BIT) {
|
|
|
|
vk_multisample_sample_locations_state_init(new_ms, new_sl, dynamic,
|
|
|
|
ms_info, sl_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef IS_DYNAMIC
|
2022-06-30 00:26:05 +01:00
|
|
|
#undef IS_NEEDED
|
2022-07-13 16:02:30 +01:00
|
|
|
|
|
|
|
void
|
|
|
|
vk_graphics_pipeline_state_merge(struct vk_graphics_pipeline_state *dst,
|
|
|
|
const struct vk_graphics_pipeline_state *src)
|
|
|
|
{
|
|
|
|
vk_graphics_pipeline_state_validate(dst);
|
|
|
|
vk_graphics_pipeline_state_validate(src);
|
|
|
|
|
|
|
|
BITSET_OR(dst->dynamic, dst->dynamic, src->dynamic);
|
|
|
|
|
|
|
|
/* Render pass state needs special care because a render pass state may be
|
|
|
|
* incomplete (view mask only). See vk_render_pass_state_init().
|
|
|
|
*/
|
|
|
|
if (dst->rp != NULL && src->rp != NULL &&
|
|
|
|
!vk_render_pass_state_is_complete(dst->rp) &&
|
|
|
|
vk_render_pass_state_is_complete(src->rp))
|
|
|
|
dst->rp = src->rp;
|
|
|
|
|
|
|
|
#define MERGE(STATE, type, state) \
|
|
|
|
if (dst->state == NULL && src->state != NULL) dst->state = src->state;
|
|
|
|
|
|
|
|
FOREACH_STATE_GROUP(MERGE)
|
|
|
|
|
|
|
|
#undef MERGE
|
|
|
|
}
|
2022-06-30 00:26:05 +01:00
|
|
|
|
|
|
|
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 = {
|
2022-07-07 18:09:16 +01:00
|
|
|
.write_enable = true,
|
2022-06-30 00:26:05 +01:00
|
|
|
.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];
|
|
|
|
}
|
|
|
|
}
|
2022-07-01 04:35:44 +01:00
|
|
|
|
|
|
|
void
|
|
|
|
vk_cmd_set_dynamic_graphics_state(struct vk_command_buffer *cmd,
|
|
|
|
const struct vk_dynamic_graphics_state *state)
|
|
|
|
{
|
|
|
|
vk_dynamic_graphics_state_copy(&cmd->dynamic_graphics_state, state);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetVertexInputEXT(VkCommandBuffer commandBuffer,
|
|
|
|
uint32_t vertexBindingDescriptionCount,
|
|
|
|
const VkVertexInputBindingDescription2EXT* pVertexBindingDescriptions,
|
|
|
|
uint32_t vertexAttributeDescriptionCount,
|
|
|
|
const VkVertexInputAttributeDescription2EXT* pVertexAttributeDescriptions)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
uint32_t bindings_valid = 0;
|
|
|
|
for (uint32_t i = 0; i < vertexBindingDescriptionCount; i++) {
|
|
|
|
const VkVertexInputBindingDescription2EXT *desc =
|
|
|
|
&pVertexBindingDescriptions[i];
|
|
|
|
|
|
|
|
assert(desc->binding < MESA_VK_MAX_VERTEX_BINDINGS);
|
|
|
|
assert(desc->stride <= MESA_VK_MAX_VERTEX_BINDING_STRIDE);
|
|
|
|
assert(desc->inputRate <= UINT8_MAX);
|
|
|
|
|
|
|
|
const uint32_t b = desc->binding;
|
|
|
|
bindings_valid |= BITFIELD_BIT(b);
|
|
|
|
SET_DYN_VALUE(dyn, VI, vi->bindings[b].stride, desc->stride);
|
|
|
|
SET_DYN_VALUE(dyn, VI, vi->bindings[b].input_rate, desc->inputRate);
|
|
|
|
SET_DYN_VALUE(dyn, VI, vi->bindings[b].divisor, desc->divisor);
|
|
|
|
|
|
|
|
/* Also set bindings_strides in case a driver is keying off that */
|
|
|
|
SET_DYN_VALUE(dyn, VI_BINDING_STRIDES,
|
|
|
|
vi_binding_strides[b], desc->stride);
|
|
|
|
}
|
|
|
|
SET_DYN_VALUE(dyn, VI, vi->bindings_valid, bindings_valid);
|
|
|
|
|
|
|
|
uint32_t attributes_valid = 0;
|
|
|
|
for (uint32_t i = 0; i < vertexAttributeDescriptionCount; i++) {
|
|
|
|
const VkVertexInputAttributeDescription2EXT *desc =
|
|
|
|
&pVertexAttributeDescriptions[i];
|
|
|
|
|
|
|
|
assert(desc->location < MESA_VK_MAX_VERTEX_ATTRIBUTES);
|
|
|
|
assert(desc->binding < MESA_VK_MAX_VERTEX_BINDINGS);
|
|
|
|
assert(bindings_valid & BITFIELD_BIT(desc->binding));
|
|
|
|
|
|
|
|
const uint32_t a = desc->location;
|
|
|
|
attributes_valid |= BITFIELD_BIT(a);
|
|
|
|
SET_DYN_VALUE(dyn, VI, vi->attributes[a].binding, desc->binding);
|
|
|
|
SET_DYN_VALUE(dyn, VI, vi->attributes[a].format, desc->format);
|
|
|
|
SET_DYN_VALUE(dyn, VI, vi->attributes[a].offset, desc->offset);
|
|
|
|
}
|
|
|
|
SET_DYN_VALUE(dyn, VI, vi->attributes_valid, attributes_valid);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
vk_cmd_set_vertex_binding_strides(struct vk_command_buffer *cmd,
|
|
|
|
uint32_t first_binding,
|
|
|
|
uint32_t binding_count,
|
|
|
|
const VkDeviceSize *strides)
|
|
|
|
{
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < binding_count; i++) {
|
|
|
|
SET_DYN_VALUE(dyn, VI_BINDING_STRIDES,
|
|
|
|
vi_binding_strides[first_binding + i], strides[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetPrimitiveTopology(VkCommandBuffer commandBuffer,
|
|
|
|
VkPrimitiveTopology primitiveTopology)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_VALUE(dyn, IA_PRIMITIVE_TOPOLOGY,
|
|
|
|
ia.primitive_topology, primitiveTopology);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetPrimitiveRestartEnable(VkCommandBuffer commandBuffer,
|
|
|
|
VkBool32 primitiveRestartEnable)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_BOOL(dyn, IA_PRIMITIVE_RESTART_ENABLE,
|
|
|
|
ia.primitive_restart_enable, primitiveRestartEnable);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetPatchControlPointsEXT(VkCommandBuffer commandBuffer,
|
|
|
|
uint32_t patchControlPoints)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_VALUE(dyn, TS_PATCH_CONTROL_POINTS,
|
|
|
|
ts.patch_control_points, patchControlPoints);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetViewport(VkCommandBuffer commandBuffer,
|
|
|
|
uint32_t firstViewport,
|
|
|
|
uint32_t viewportCount,
|
|
|
|
const VkViewport *pViewports)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_ARRAY(dyn, VP_VIEWPORTS, vp.viewports,
|
|
|
|
firstViewport, viewportCount, pViewports);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetViewportWithCount(VkCommandBuffer commandBuffer,
|
|
|
|
uint32_t viewportCount,
|
|
|
|
const VkViewport *pViewports)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_VALUE(dyn, VP_VIEWPORT_COUNT, vp.viewport_count, viewportCount);
|
|
|
|
SET_DYN_ARRAY(dyn, VP_VIEWPORTS, vp.viewports, 0, viewportCount, pViewports);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetScissor(VkCommandBuffer commandBuffer,
|
|
|
|
uint32_t firstScissor,
|
|
|
|
uint32_t scissorCount,
|
|
|
|
const VkRect2D *pScissors)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_ARRAY(dyn, VP_SCISSORS, vp.scissors,
|
|
|
|
firstScissor, scissorCount, pScissors);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetScissorWithCount(VkCommandBuffer commandBuffer,
|
|
|
|
uint32_t scissorCount,
|
|
|
|
const VkRect2D *pScissors)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_VALUE(dyn, VP_SCISSOR_COUNT, vp.scissor_count, scissorCount);
|
|
|
|
SET_DYN_ARRAY(dyn, VP_SCISSORS, vp.scissors, 0, scissorCount, pScissors);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetDiscardRectangleEXT(VkCommandBuffer commandBuffer,
|
|
|
|
uint32_t firstDiscardRectangle,
|
|
|
|
uint32_t discardRectangleCount,
|
|
|
|
const VkRect2D *pDiscardRectangles)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_VALUE(dyn, DR_RECTANGLES, dr.rectangle_count, discardRectangleCount);
|
|
|
|
SET_DYN_ARRAY(dyn, DR_RECTANGLES, dr.rectangles, firstDiscardRectangle,
|
|
|
|
discardRectangleCount, pDiscardRectangles);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetRasterizerDiscardEnableEXT(VkCommandBuffer commandBuffer,
|
|
|
|
VkBool32 rasterizerDiscardEnable)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_BOOL(dyn, RS_RASTERIZER_DISCARD_ENABLE,
|
|
|
|
rs.rasterizer_discard_enable, rasterizerDiscardEnable);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetCullMode(VkCommandBuffer commandBuffer,
|
|
|
|
VkCullModeFlags cullMode)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_VALUE(dyn, RS_CULL_MODE, rs.cull_mode, cullMode);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetFrontFace(VkCommandBuffer commandBuffer,
|
|
|
|
VkFrontFace frontFace)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_VALUE(dyn, RS_FRONT_FACE, rs.front_face, frontFace);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetDepthBiasEnable(VkCommandBuffer commandBuffer,
|
|
|
|
VkBool32 depthBiasEnable)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_BOOL(dyn, RS_DEPTH_BIAS_ENABLE,
|
|
|
|
rs.depth_bias.enable, depthBiasEnable);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetDepthBias(VkCommandBuffer commandBuffer,
|
|
|
|
float depthBiasConstantFactor,
|
|
|
|
float depthBiasClamp,
|
|
|
|
float depthBiasSlopeFactor)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_VALUE(dyn, RS_DEPTH_BIAS_FACTORS,
|
|
|
|
rs.depth_bias.constant, depthBiasConstantFactor);
|
|
|
|
SET_DYN_VALUE(dyn, RS_DEPTH_BIAS_FACTORS,
|
|
|
|
rs.depth_bias.clamp, depthBiasClamp);
|
|
|
|
SET_DYN_VALUE(dyn, RS_DEPTH_BIAS_FACTORS,
|
|
|
|
rs.depth_bias.slope, depthBiasSlopeFactor);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetLineWidth(VkCommandBuffer commandBuffer,
|
|
|
|
float lineWidth)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_VALUE(dyn, RS_LINE_WIDTH, rs.line.width, lineWidth);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetLineStippleEXT(VkCommandBuffer commandBuffer,
|
|
|
|
uint32_t lineStippleFactor,
|
|
|
|
uint16_t lineStipplePattern)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_VALUE(dyn, RS_LINE_STIPPLE,
|
|
|
|
rs.line.stipple.factor, lineStippleFactor);
|
|
|
|
SET_DYN_VALUE(dyn, RS_LINE_STIPPLE,
|
|
|
|
rs.line.stipple.pattern, lineStipplePattern);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetFragmentShadingRateKHR(VkCommandBuffer commandBuffer,
|
|
|
|
const VkExtent2D *pFragmentSize,
|
|
|
|
const VkFragmentShadingRateCombinerOpKHR combinerOps[2])
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_VALUE(dyn, FSR, fsr.fragment_size.width, pFragmentSize->width);
|
|
|
|
SET_DYN_VALUE(dyn, FSR, fsr.fragment_size.height, pFragmentSize->height);
|
|
|
|
SET_DYN_VALUE(dyn, FSR, fsr.combiner_ops[0], combinerOps[0]);
|
|
|
|
SET_DYN_VALUE(dyn, FSR, fsr.combiner_ops[1], combinerOps[1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetSampleLocationsEXT(VkCommandBuffer commandBuffer,
|
|
|
|
const VkSampleLocationsInfoEXT *pSampleLocationsInfo)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_VALUE(dyn, MS_SAMPLE_LOCATIONS,
|
|
|
|
ms.sample_locations->per_pixel,
|
|
|
|
pSampleLocationsInfo->sampleLocationsPerPixel);
|
|
|
|
SET_DYN_VALUE(dyn, MS_SAMPLE_LOCATIONS,
|
|
|
|
ms.sample_locations->grid_size.width,
|
|
|
|
pSampleLocationsInfo->sampleLocationGridSize.width);
|
|
|
|
SET_DYN_VALUE(dyn, MS_SAMPLE_LOCATIONS,
|
|
|
|
ms.sample_locations->grid_size.height,
|
|
|
|
pSampleLocationsInfo->sampleLocationGridSize.height);
|
|
|
|
|
|
|
|
assert(pSampleLocationsInfo->sampleLocationsCount ==
|
|
|
|
pSampleLocationsInfo->sampleLocationsPerPixel *
|
|
|
|
pSampleLocationsInfo->sampleLocationGridSize.width *
|
|
|
|
pSampleLocationsInfo->sampleLocationGridSize.height);
|
|
|
|
|
|
|
|
assert(pSampleLocationsInfo->sampleLocationsCount <=
|
|
|
|
MESA_VK_MAX_SAMPLE_LOCATIONS);
|
|
|
|
|
|
|
|
SET_DYN_ARRAY(dyn, MS_SAMPLE_LOCATIONS,
|
|
|
|
ms.sample_locations->locations,
|
|
|
|
0, pSampleLocationsInfo->sampleLocationsCount,
|
|
|
|
pSampleLocationsInfo->pSampleLocations);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetDepthTestEnable(VkCommandBuffer commandBuffer,
|
|
|
|
VkBool32 depthTestEnable)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_BOOL(dyn, DS_DEPTH_TEST_ENABLE,
|
|
|
|
ds.depth.test_enable, depthTestEnable);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetDepthWriteEnable(VkCommandBuffer commandBuffer,
|
|
|
|
VkBool32 depthWriteEnable)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_BOOL(dyn, DS_DEPTH_WRITE_ENABLE,
|
|
|
|
ds.depth.write_enable, depthWriteEnable);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetDepthCompareOp(VkCommandBuffer commandBuffer,
|
|
|
|
VkCompareOp depthCompareOp)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_VALUE(dyn, DS_DEPTH_COMPARE_OP, ds.depth.compare_op,
|
|
|
|
depthCompareOp);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetDepthBoundsTestEnable(VkCommandBuffer commandBuffer,
|
|
|
|
VkBool32 depthBoundsTestEnable)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_BOOL(dyn, DS_DEPTH_BOUNDS_TEST_ENABLE,
|
|
|
|
ds.depth.bounds_test.enable, depthBoundsTestEnable);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetDepthBounds(VkCommandBuffer commandBuffer,
|
|
|
|
float minDepthBounds,
|
|
|
|
float maxDepthBounds)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_VALUE(dyn, DS_DEPTH_BOUNDS_TEST_BOUNDS,
|
|
|
|
ds.depth.bounds_test.min, minDepthBounds);
|
|
|
|
SET_DYN_VALUE(dyn, DS_DEPTH_BOUNDS_TEST_BOUNDS,
|
|
|
|
ds.depth.bounds_test.max, maxDepthBounds);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetStencilTestEnable(VkCommandBuffer commandBuffer,
|
|
|
|
VkBool32 stencilTestEnable)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_BOOL(dyn, DS_STENCIL_TEST_ENABLE,
|
|
|
|
ds.stencil.test_enable, stencilTestEnable);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetStencilOp(VkCommandBuffer commandBuffer,
|
|
|
|
VkStencilFaceFlags faceMask,
|
|
|
|
VkStencilOp failOp,
|
|
|
|
VkStencilOp passOp,
|
|
|
|
VkStencilOp depthFailOp,
|
|
|
|
VkCompareOp compareOp)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
if (faceMask & VK_STENCIL_FACE_FRONT_BIT) {
|
|
|
|
SET_DYN_VALUE(dyn, DS_STENCIL_OP, ds.stencil.front.op.fail, failOp);
|
|
|
|
SET_DYN_VALUE(dyn, DS_STENCIL_OP, ds.stencil.front.op.pass, passOp);
|
|
|
|
SET_DYN_VALUE(dyn, DS_STENCIL_OP, ds.stencil.front.op.depth_fail, depthFailOp);
|
|
|
|
SET_DYN_VALUE(dyn, DS_STENCIL_OP, ds.stencil.front.op.compare, compareOp);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (faceMask & VK_STENCIL_FACE_BACK_BIT) {
|
|
|
|
SET_DYN_VALUE(dyn, DS_STENCIL_OP, ds.stencil.back.op.fail, failOp);
|
|
|
|
SET_DYN_VALUE(dyn, DS_STENCIL_OP, ds.stencil.back.op.pass, passOp);
|
|
|
|
SET_DYN_VALUE(dyn, DS_STENCIL_OP, ds.stencil.back.op.depth_fail, depthFailOp);
|
|
|
|
SET_DYN_VALUE(dyn, DS_STENCIL_OP, ds.stencil.back.op.compare, compareOp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetStencilCompareMask(VkCommandBuffer commandBuffer,
|
|
|
|
VkStencilFaceFlags faceMask,
|
|
|
|
uint32_t compareMask)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
/* We assume 8-bit stencil always */
|
|
|
|
STATIC_ASSERT(sizeof(dyn->ds.stencil.front.write_mask) == 1);
|
|
|
|
|
|
|
|
if (faceMask & VK_STENCIL_FACE_FRONT_BIT) {
|
|
|
|
SET_DYN_VALUE(dyn, DS_STENCIL_COMPARE_MASK,
|
|
|
|
ds.stencil.front.compare_mask, (uint8_t)compareMask);
|
|
|
|
}
|
|
|
|
if (faceMask & VK_STENCIL_FACE_BACK_BIT) {
|
|
|
|
SET_DYN_VALUE(dyn, DS_STENCIL_COMPARE_MASK,
|
|
|
|
ds.stencil.back.compare_mask, (uint8_t)compareMask);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetStencilWriteMask(VkCommandBuffer commandBuffer,
|
|
|
|
VkStencilFaceFlags faceMask,
|
|
|
|
uint32_t writeMask)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
/* We assume 8-bit stencil always */
|
|
|
|
STATIC_ASSERT(sizeof(dyn->ds.stencil.front.write_mask) == 1);
|
|
|
|
|
|
|
|
if (faceMask & VK_STENCIL_FACE_FRONT_BIT) {
|
|
|
|
SET_DYN_VALUE(dyn, DS_STENCIL_WRITE_MASK,
|
|
|
|
ds.stencil.front.write_mask, (uint8_t)writeMask);
|
|
|
|
}
|
|
|
|
if (faceMask & VK_STENCIL_FACE_BACK_BIT) {
|
|
|
|
SET_DYN_VALUE(dyn, DS_STENCIL_WRITE_MASK,
|
|
|
|
ds.stencil.back.write_mask, (uint8_t)writeMask);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetStencilReference(VkCommandBuffer commandBuffer,
|
|
|
|
VkStencilFaceFlags faceMask,
|
|
|
|
uint32_t reference)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
/* We assume 8-bit stencil always */
|
|
|
|
STATIC_ASSERT(sizeof(dyn->ds.stencil.front.write_mask) == 1);
|
|
|
|
|
|
|
|
if (faceMask & VK_STENCIL_FACE_FRONT_BIT) {
|
|
|
|
SET_DYN_VALUE(dyn, DS_STENCIL_REFERENCE,
|
|
|
|
ds.stencil.front.reference, (uint8_t)reference);
|
|
|
|
}
|
|
|
|
if (faceMask & VK_STENCIL_FACE_BACK_BIT) {
|
|
|
|
SET_DYN_VALUE(dyn, DS_STENCIL_REFERENCE,
|
|
|
|
ds.stencil.back.reference, (uint8_t)reference);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetLogicOpEXT(VkCommandBuffer commandBuffer,
|
|
|
|
VkLogicOp logicOp)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_VALUE(dyn, CB_LOGIC_OP, cb.logic_op, logicOp);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetColorWriteEnableEXT(VkCommandBuffer commandBuffer,
|
|
|
|
uint32_t attachmentCount,
|
|
|
|
const VkBool32 *pColorWriteEnables)
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
assert(attachmentCount <= MESA_VK_MAX_COLOR_ATTACHMENTS);
|
|
|
|
|
|
|
|
uint8_t color_write_enables = 0;
|
|
|
|
for (uint32_t a = 0; a < attachmentCount; a++) {
|
|
|
|
if (pColorWriteEnables[a])
|
|
|
|
color_write_enables |= BITFIELD_BIT(a);
|
|
|
|
}
|
|
|
|
|
|
|
|
SET_DYN_VALUE(dyn, CB_COLOR_WRITE_ENABLES,
|
|
|
|
cb.color_write_enables, color_write_enables);
|
|
|
|
}
|
|
|
|
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
|
|
vk_common_CmdSetBlendConstants(VkCommandBuffer commandBuffer,
|
|
|
|
const float blendConstants[4])
|
|
|
|
{
|
|
|
|
VK_FROM_HANDLE(vk_command_buffer, cmd, commandBuffer);
|
|
|
|
struct vk_dynamic_graphics_state *dyn = &cmd->dynamic_graphics_state;
|
|
|
|
|
|
|
|
SET_DYN_ARRAY(dyn, CB_BLEND_CONSTANTS, cb.blend_constants,
|
|
|
|
0, 4, blendConstants);
|
|
|
|
}
|