blob: 820dfac12cead53622040378b39165558d3eb484 [file] [log] [blame]
/*
* Copyright © 2022 Collabora, Ltd
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef VK_GRAPHICS_STATE_H
#define VK_GRAPHICS_STATE_H
#include "vulkan/vulkan_core.h"
#include "vk_limits.h"
#include "util/bitset.h"
#include "util/enum_operators.h"
#ifdef __cplusplus
extern "C" {
#endif
struct vk_command_buffer;
struct vk_device;
/** Enumeration of all Vulkan dynamic graphics states
*
* Enumerants are named with both the abbreviation of the state group to which
* the state belongs as well as the name of the state itself. These are
* intended to pretty closely match the VkDynamicState enum but may not match
* perfectly all the time.
*/
enum mesa_vk_dynamic_graphics_state {
MESA_VK_DYNAMIC_VI,
MESA_VK_DYNAMIC_VI_BINDINGS_VALID,
MESA_VK_DYNAMIC_VI_BINDING_STRIDES,
MESA_VK_DYNAMIC_IA_PRIMITIVE_TOPOLOGY,
MESA_VK_DYNAMIC_IA_PRIMITIVE_RESTART_ENABLE,
MESA_VK_DYNAMIC_TS_PATCH_CONTROL_POINTS,
MESA_VK_DYNAMIC_TS_DOMAIN_ORIGIN,
MESA_VK_DYNAMIC_VP_VIEWPORT_COUNT,
MESA_VK_DYNAMIC_VP_VIEWPORTS,
MESA_VK_DYNAMIC_VP_SCISSOR_COUNT,
MESA_VK_DYNAMIC_VP_SCISSORS,
MESA_VK_DYNAMIC_VP_DEPTH_CLIP_NEGATIVE_ONE_TO_ONE,
MESA_VK_DYNAMIC_VP_DEPTH_CLAMP_RANGE,
MESA_VK_DYNAMIC_DR_RECTANGLES,
MESA_VK_DYNAMIC_DR_MODE,
MESA_VK_DYNAMIC_DR_ENABLE,
MESA_VK_DYNAMIC_RS_RASTERIZER_DISCARD_ENABLE,
MESA_VK_DYNAMIC_RS_DEPTH_CLAMP_ENABLE,
MESA_VK_DYNAMIC_RS_DEPTH_CLIP_ENABLE,
MESA_VK_DYNAMIC_RS_POLYGON_MODE,
MESA_VK_DYNAMIC_RS_CULL_MODE,
MESA_VK_DYNAMIC_RS_FRONT_FACE,
MESA_VK_DYNAMIC_RS_CONSERVATIVE_MODE,
MESA_VK_DYNAMIC_RS_EXTRA_PRIMITIVE_OVERESTIMATION_SIZE,
MESA_VK_DYNAMIC_RS_RASTERIZATION_ORDER_AMD,
MESA_VK_DYNAMIC_RS_PROVOKING_VERTEX,
MESA_VK_DYNAMIC_RS_RASTERIZATION_STREAM,
MESA_VK_DYNAMIC_RS_DEPTH_BIAS_ENABLE,
MESA_VK_DYNAMIC_RS_DEPTH_BIAS_FACTORS,
MESA_VK_DYNAMIC_RS_LINE_WIDTH,
MESA_VK_DYNAMIC_RS_LINE_MODE,
MESA_VK_DYNAMIC_RS_LINE_STIPPLE_ENABLE,
MESA_VK_DYNAMIC_RS_LINE_STIPPLE,
MESA_VK_DYNAMIC_FSR,
MESA_VK_DYNAMIC_MS_RASTERIZATION_SAMPLES,
MESA_VK_DYNAMIC_MS_SAMPLE_MASK,
MESA_VK_DYNAMIC_MS_ALPHA_TO_COVERAGE_ENABLE,
MESA_VK_DYNAMIC_MS_ALPHA_TO_ONE_ENABLE,
MESA_VK_DYNAMIC_MS_SAMPLE_LOCATIONS_ENABLE,
MESA_VK_DYNAMIC_MS_SAMPLE_LOCATIONS,
MESA_VK_DYNAMIC_DS_DEPTH_TEST_ENABLE,
MESA_VK_DYNAMIC_DS_DEPTH_WRITE_ENABLE,
MESA_VK_DYNAMIC_DS_DEPTH_COMPARE_OP,
MESA_VK_DYNAMIC_DS_DEPTH_BOUNDS_TEST_ENABLE,
MESA_VK_DYNAMIC_DS_DEPTH_BOUNDS_TEST_BOUNDS,
MESA_VK_DYNAMIC_DS_STENCIL_TEST_ENABLE,
MESA_VK_DYNAMIC_DS_STENCIL_OP,
MESA_VK_DYNAMIC_DS_STENCIL_COMPARE_MASK,
MESA_VK_DYNAMIC_DS_STENCIL_WRITE_MASK,
MESA_VK_DYNAMIC_DS_STENCIL_REFERENCE,
MESA_VK_DYNAMIC_CB_LOGIC_OP_ENABLE,
MESA_VK_DYNAMIC_CB_LOGIC_OP,
MESA_VK_DYNAMIC_CB_ATTACHMENT_COUNT,
MESA_VK_DYNAMIC_CB_COLOR_WRITE_ENABLES,
MESA_VK_DYNAMIC_CB_BLEND_ENABLES,
MESA_VK_DYNAMIC_CB_BLEND_EQUATIONS,
MESA_VK_DYNAMIC_CB_WRITE_MASKS,
MESA_VK_DYNAMIC_CB_BLEND_CONSTANTS,
MESA_VK_DYNAMIC_RP_ATTACHMENTS,
MESA_VK_DYNAMIC_ATTACHMENT_FEEDBACK_LOOP_ENABLE,
MESA_VK_DYNAMIC_COLOR_ATTACHMENT_MAP,
MESA_VK_DYNAMIC_INPUT_ATTACHMENT_MAP,
/* Must be left at the end */
MESA_VK_DYNAMIC_GRAPHICS_STATE_ENUM_MAX,
};
#define MESA_VK_ATTACHMENT_UNUSED (0xff)
/* This means that input attachments without an index map to this attachment.
* It is only used for depth and stencil attachments.
*/
#define MESA_VK_ATTACHMENT_NO_INDEX (0xfe)
/** Populate a bitset with dynamic states
*
* This function maps a VkPipelineDynamicStateCreateInfo to a bitset indexed
* by mesa_vk_dynamic_graphics_state enumerants.
*
* :param dynamic: |out| Bitset to populate
* :param info: |in| VkPipelineDynamicStateCreateInfo or NULL
*/
void
vk_get_dynamic_graphics_states(BITSET_WORD *dynamic,
const VkPipelineDynamicStateCreateInfo *info);
/***/
struct vk_vertex_binding_state {
/** VkVertexInputBindingDescription::stride */
uint16_t stride;
/** VkVertexInputBindingDescription::inputRate */
uint16_t input_rate;
/** VkVertexInputBindingDivisorDescriptionKHR::divisor or 1 */
uint32_t divisor;
};
/***/
struct vk_vertex_attribute_state {
/** VkVertexInputAttributeDescription::binding */
uint32_t binding;
/** VkVertexInputAttributeDescription::format */
VkFormat format;
/** VkVertexInputAttributeDescription::offset */
uint32_t offset;
};
/***/
struct vk_vertex_input_state {
/** Bitset of which bindings are valid, indexed by binding */
uint32_t bindings_valid;
struct vk_vertex_binding_state bindings[MESA_VK_MAX_VERTEX_BINDINGS];
/** Bitset of which attributes are valid, indexed by location */
uint32_t attributes_valid;
struct vk_vertex_attribute_state attributes[MESA_VK_MAX_VERTEX_ATTRIBUTES];
};
/***/
struct vk_input_assembly_state {
/** VkPipelineInputAssemblyStateCreateInfo::topology
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_IA_PRIMITIVE_TOPOLOGY
*/
uint8_t primitive_topology;
/** VkPipelineInputAssemblyStateCreateInfo::primitiveRestartEnable
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_IA_PRIMITIVE_RESTART_ENABLE
*/
bool primitive_restart_enable;
};
/***/
struct vk_tessellation_state {
/** VkPipelineTessellationStateCreateInfo::patchControlPoints
*
* MESA_VK_DYNAMIC_TS_PATCH_CONTROL_POINTS
*/
uint8_t patch_control_points;
/** VkPipelineTessellationDomainOriginStateCreateInfo::domainOrigin
*
* MESA_VK_DYNAMIC_TS_DOMAIN_ORIGIN
*/
uint8_t domain_origin;
};
/***/
struct vk_viewport_state {
/** VkPipelineViewportDepthClipControlCreateInfoEXT::negativeOneToOne
*/
bool depth_clip_negative_one_to_one;
/** VkPipelineViewportDepthClampControlCreateInfoEXT::depthClampMode
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_VP_DEPTH_CLAMP_RANGE
*/
VkDepthClampModeEXT depth_clamp_mode;
/** VkPipelineViewportDepthClampControlCreateInfoEXT::pDepthClampRange
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_VP_DEPTH_CLAMP_RANGE
*/
VkDepthClampRangeEXT depth_clamp_range;
/** VkPipelineViewportStateCreateInfo::viewportCount
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_VP_VIEWPORT_COUNT
*/
uint8_t viewport_count;
/** VkPipelineViewportStateCreateInfo::scissorCount
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_VP_SCISSOR_COUNT
*/
uint8_t scissor_count;
/** VkPipelineViewportStateCreateInfo::pViewports
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_VP_VIEWPORTS
*/
VkViewport viewports[MESA_VK_MAX_VIEWPORTS];
/** VkPipelineViewportStateCreateInfo::pScissors
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_VP_SCISSORS
*/
VkRect2D scissors[MESA_VK_MAX_SCISSORS];
};
/***/
struct vk_discard_rectangles_state {
/** VkPipelineDiscardRectangleStateCreateInfoEXT::discardRectangleMode */
VkDiscardRectangleModeEXT mode;
/** VkPipelineDiscardRectangleStateCreateInfoEXT::discardRectangleCount */
uint32_t rectangle_count;
/** VkPipelineDiscardRectangleStateCreateInfoEXT::pDiscardRectangles */
VkRect2D rectangles[MESA_VK_MAX_DISCARD_RECTANGLES];
};
enum ENUM_PACKED vk_mesa_depth_clip_enable {
/** Depth clipping should be disabled */
VK_MESA_DEPTH_CLIP_ENABLE_FALSE = 0,
/** Depth clipping should be enabled */
VK_MESA_DEPTH_CLIP_ENABLE_TRUE = 1,
/** Depth clipping should be enabled iff depth clamping is disabled */
VK_MESA_DEPTH_CLIP_ENABLE_NOT_CLAMP,
};
/***/
struct vk_rasterization_state {
/** VkPipelineRasterizationStateCreateInfo::rasterizerDiscardEnable
*
* This will be false if rasterizer discard is dynamic
*
* MESA_VK_DYNAMIC_RS_RASTERIZER_DISCARD_ENABLE
*/
bool rasterizer_discard_enable;
/** VkPipelineRasterizationStateCreateInfo::depthClampEnable
*
* MESA_VK_DYNAMIC_RS_DEPTH_CLAMP_ENABLE
*/
bool depth_clamp_enable;
/** VkPipelineRasterizationDepthClipStateCreateInfoEXT::depthClipEnable
*
* MESA_VK_DYNAMIC_RS_DEPTH_CLIP_ENABLE
*/
enum vk_mesa_depth_clip_enable depth_clip_enable;
/** VkPipelineRasterizationStateCreateInfo::polygonMode
*
* MESA_VK_DYNAMIC_RS_POLYGON_MODE_ENABLEDEPTH_CLIP_ENABLE
*/
VkPolygonMode polygon_mode;
/** VkPipelineRasterizationStateCreateInfo::cullMode
*
* MESA_VK_DYNAMIC_RS_CULL_MODE
*/
VkCullModeFlags cull_mode;
/** VkPipelineRasterizationStateCreateInfo::frontFace
*
* MESA_VK_DYNAMIC_RS_FRONT_FACE
*/
VkFrontFace front_face;
/** VkPipelineRasterizationConservativeStateCreateInfoEXT::conservativeRasterizationMode
*
* MESA_VK_DYNAMIC_RS_CONSERVATIVE_MODE
*/
VkConservativeRasterizationModeEXT conservative_mode;
/** VkPipelineRasterizationConservativeStateCreateInfoEXT::extraPrimitiveOverestimationSize
*
* MESA_VK_DYNAMIC_RS_EXTRA_PRIMITIVE_OVERESTIMATION_SIZE
*/
float extra_primitive_overestimation_size;
/** VkPipelineRasterizationStateRasterizationOrderAMD::rasterizationOrder */
VkRasterizationOrderAMD rasterization_order_amd;
/** VkPipelineRasterizationProvokingVertexStateCreateInfoEXT::provokingVertexMode
*
* MESA_VK_DYNAMIC_RS_PROVOKING_VERTEX
*/
VkProvokingVertexModeEXT provoking_vertex;
/** VkPipelineRasterizationStateStreamCreateInfoEXT::rasterizationStream
*
* MESA_VK_DYNAMIC_RS_RASTERIZATION_STREAM
*/
uint32_t rasterization_stream;
struct {
/** VkPipelineRasterizationStateCreateInfo::depthBiasEnable
*
* MESA_VK_DYNAMIC_RS_DEPTH_BIAS_ENABLE
*/
bool enable;
/** VkPipelineRasterizationStateCreateInfo::depthBiasConstantFactor
*
* MESA_VK_DYNAMIC_RS_DEPTH_BIAS_FACTORS
*/
float constant_factor;
/** VkPipelineRasterizationStateCreateInfo::depthBiasClamp
*
* MESA_VK_DYNAMIC_RS_DEPTH_BIAS_FACTORS
*/
float clamp;
/** VkPipelineRasterizationStateCreateInfo::depthBiasSlopeFactor
*
* MESA_VK_DYNAMIC_RS_DEPTH_BIAS_FACTORS
*/
float slope_factor;
/** VkDepthBiasRepresentationInfoEXT::depthBiasRepresentation
*
* MESA_VK_DYNAMIC_RS_DEPTH_BIAS_FACTORS
*/
VkDepthBiasRepresentationEXT representation;
/** VkDepthBiasRepresentationInfoEXT::depthBiasExact
*
* MESA_VK_DYNAMIC_RS_DEPTH_BIAS_FACTORS
*/
bool exact;
} depth_bias;
struct {
/** VkPipelineRasterizationStateCreateInfo::lineWidth
*
* MESA_VK_DYNAMIC_RS_LINE_WIDTH
*/
float width;
/** VkPipelineRasterizationLineStateCreateInfoKHR::lineRasterizationMode
*
* Will be set to VK_LINE_RASTERIZATION_MODE_DEFAULT_KHR if
* VkPipelineRasterizationLineStateCreateInfoKHR is not provided.
*
* MESA_VK_DYNAMIC_RS_LINE_MODE
*/
VkLineRasterizationModeKHR mode;
struct {
/** VkPipelineRasterizationLineStateCreateInfoKHR::stippledLineEnable
*
* MESA_VK_DYNAMIC_RS_LINE_STIPPLE_ENABLE
*/
bool enable;
/** VkPipelineRasterizationLineStateCreateInfoKHR::lineStippleFactor
*
* MESA_VK_DYNAMIC_RS_LINE_STIPPLE
*/
uint32_t factor;
/** VkPipelineRasterizationLineStateCreateInfoKHR::lineStipplePattern
*
* MESA_VK_DYNAMIC_RS_LINE_STIPPLE
*/
uint16_t pattern;
} stipple;
} line;
};
static inline bool
vk_rasterization_state_depth_clip_enable(const struct vk_rasterization_state *rs)
{
switch (rs->depth_clip_enable) {
case VK_MESA_DEPTH_CLIP_ENABLE_FALSE: return false;
case VK_MESA_DEPTH_CLIP_ENABLE_TRUE: return true;
case VK_MESA_DEPTH_CLIP_ENABLE_NOT_CLAMP: return !rs->depth_clamp_enable;
}
unreachable("Invalid depth clip enable");
}
/***/
struct vk_fragment_shading_rate_state {
/** VkPipelineFragmentShadingRateStateCreateInfoKHR::fragmentSize
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_FSR
*/
VkExtent2D fragment_size;
/** VkPipelineFragmentShadingRateStateCreateInfoKHR::combinerOps
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_FSR
*/
VkFragmentShadingRateCombinerOpKHR combiner_ops[2];
};
static inline bool
vk_fragment_shading_rate_is_disabled(const struct vk_fragment_shading_rate_state *fsr)
{
return fsr->fragment_size.width == 1 &&
fsr->fragment_size.height == 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;
}
/***/
struct vk_sample_locations_state {
/** VkSampleLocationsInfoEXT::sampleLocationsPerPixel */
VkSampleCountFlagBits per_pixel;
/** VkSampleLocationsInfoEXT::sampleLocationGridSize */
VkExtent2D grid_size;
/** VkSampleLocationsInfoEXT::sampleLocations */
VkSampleLocationEXT locations[MESA_VK_MAX_SAMPLE_LOCATIONS];
};
/***/
struct vk_multisample_state {
/** VkPipelineMultisampleStateCreateInfo::rasterizationSamples */
VkSampleCountFlagBits rasterization_samples;
/** VkPipelineMultisampleStateCreateInfo::sampleShadingEnable */
bool sample_shading_enable;
/** VkPipelineMultisampleStateCreateInfo::minSampleShading */
float min_sample_shading;
/** VkPipelineMultisampleStateCreateInfo::pSampleMask */
uint16_t sample_mask;
/** VkPipelineMultisampleStateCreateInfo::alphaToCoverageEnable */
bool alpha_to_coverage_enable;
/** VkPipelineMultisampleStateCreateInfo::alphaToOneEnable */
bool alpha_to_one_enable;
/** VkPipelineSampleLocationsStateCreateInfoEXT::sampleLocationsEnable
*
* This will be true if sample locations enable dynamic.
*/
bool sample_locations_enable;
/** VkPipelineSampleLocationsStateCreateInfoEXT::sampleLocationsInfo
*
* May be NULL for dynamic sample locations.
*/
const struct vk_sample_locations_state *sample_locations;
};
/** Represents the stencil test state for a face */
struct vk_stencil_test_face_state {
/*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_DS_STENCIL_OP
*/
struct {
/** VkStencilOpState::failOp */
uint8_t fail;
/** VkStencilOpState::passOp */
uint8_t pass;
/** VkStencilOpState::depthFailOp */
uint8_t depth_fail;
/** VkStencilOpState::compareOp */
uint8_t compare;
} op;
/** VkStencilOpState::compareMask
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_DS_STENCIL_COMPARE_MASK
*/
uint8_t compare_mask;
/** VkStencilOpState::writeMask
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_DS_STENCIL_WRITE_MASK
*/
uint8_t write_mask;
/** VkStencilOpState::reference
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_DS_STENCIL_REFERENCE
*/
uint8_t reference;
};
/***/
struct vk_depth_stencil_state {
struct {
/** VkPipelineDepthStencilStateCreateInfo::depthTestEnable
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_DS_DEPTH_TEST_ENABLE
*/
bool test_enable;
/** VkPipelineDepthStencilStateCreateInfo::depthWriteEnable
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_DS_DEPTH_WRITE_ENABLE
*/
bool write_enable;
/** VkPipelineDepthStencilStateCreateInfo::depthCompareOp
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_DS_DEPTH_COMPARE_OP
*/
VkCompareOp compare_op;
struct {
/** VkPipelineDepthStencilStateCreateInfo::depthBoundsTestEnable
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_DS_DEPTH_BOUNDS_TEST_ENABLE
*/
bool enable;
/** VkPipelineDepthStencilStateCreateInfo::min/maxDepthBounds
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_DS_DEPTH_BOUNDS_TEST_BOUNDS
*/
float min, max;
} bounds_test;
} depth;
struct {
/** VkPipelineDepthStencilStateCreateInfo::stencilTestEnable
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_DS_STENCIL_TEST_ENABLE
*/
bool test_enable;
/** Whether or not stencil is should be written
*
* This does not map directly to any particular Vulkan API state and is
* initialized to true. If independent stencil disable ever becomes a
* thing, it will use this state. vk_optimize_depth_stencil_state() may
* set this to false if it can prove that the stencil test will never
* alter the stencil value.
*/
bool write_enable;
/** VkPipelineDepthStencilStateCreateInfo::front */
struct vk_stencil_test_face_state front;
/** VkPipelineDepthStencilStateCreateInfo::back */
struct vk_stencil_test_face_state back;
} stencil;
};
/** Optimize a depth/stencil state
*
* The way depth and stencil testing is specified, there are many case where,
* regardless of depth/stencil writes being enabled, nothing actually gets
* written due to some other bit of state being set. In the presence of
* discards, it's fairly easy to get into cases where early depth/stencil
* testing is disabled on some hardware, leading to a fairly big performance
* hit. This function attempts to optimize the depth stencil state and
* disable writes and sometimes even testing whenever possible.
*
* :param ds: |inout| The depth stencil state to optimize
* :param ds_aspects: |in| Which image aspects are present in the
* render pass.
* :param consider_write_mask: |in| If true, the write mask will be taken
* into account when optimizing. If
* false, it will be ignored.
*/
void vk_optimize_depth_stencil_state(struct vk_depth_stencil_state *ds,
VkImageAspectFlags ds_aspects,
bool consider_write_mask);
struct vk_color_blend_attachment_state {
/** VkPipelineColorBlendAttachmentState::blendEnable
*
* This will be true if blend enables are dynamic
*
* MESA_VK_DYNAMIC_CB_BLEND_ENABLES
*/
bool blend_enable;
/** VkPipelineColorBlendAttachmentState::srcColorBlendFactor
*
* MESA_VK_DYNAMIC_CB_BLEND_EQUATIONS
*/
uint8_t src_color_blend_factor;
/** VkPipelineColorBlendAttachmentState::dstColorBlendFactor
*
* MESA_VK_DYNAMIC_CB_BLEND_EQUATIONS
*/
uint8_t dst_color_blend_factor;
/** VkPipelineColorBlendAttachmentState::srcAlphaBlendFactor
*
* MESA_VK_DYNAMIC_CB_BLEND_EQUATIONS
*/
uint8_t src_alpha_blend_factor;
/** VkPipelineColorBlendAttachmentState::dstAlphaBlendFactor
*
* MESA_VK_DYNAMIC_CB_BLEND_EQUATIONS
*/
uint8_t dst_alpha_blend_factor;
/** VkPipelineColorBlendAttachmentState::colorWriteMask
*
* MESA_VK_DYNAMIC_CB_WRITE_MASKS
*/
uint8_t write_mask;
/** VkPipelineColorBlendAttachmentState::colorBlendOp
*
* MESA_VK_DYNAMIC_CB_BLEND_EQUATIONS
*/
VkBlendOp color_blend_op;
/** VkPipelineColorBlendAttachmentState::alphaBlendOp
*
* MESA_VK_DYNAMIC_CB_BLEND_EQUATIONS
*/
VkBlendOp alpha_blend_op;
};
/***/
struct vk_color_blend_state {
/** VkPipelineColorBlendStateCreateInfo::logicOpEnable
*
* MESA_VK_DYNAMIC_CB_LOGIC_OP_ENABLE,
*/
bool logic_op_enable;
/** VkPipelineColorBlendStateCreateInfo::logicOp
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_CB_LOGIC_OP,
*/
uint8_t logic_op;
/** VkPipelineColorBlendStateCreateInfo::attachmentCount
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_CB_ATTACHMENT_COUNT,
*/
uint8_t attachment_count;
/** VkPipelineColorWriteCreateInfoEXT::pColorWriteEnables
*
* Bitmask of color write enables, indexed by color attachment index.
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_CB_COLOR_WRITE_ENABLES,
*/
uint8_t color_write_enables;
/** VkPipelineColorBlendStateCreateInfo::pAttachments */
struct vk_color_blend_attachment_state attachments[MESA_VK_MAX_COLOR_ATTACHMENTS];
/** VkPipelineColorBlendStateCreateInfo::blendConstants
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_CB_BLEND_CONSTANTS,
*/
float blend_constants[4];
};
enum vk_rp_attachment_flags {
MESA_VK_RP_ATTACHMENT_NONE = 0,
MESA_VK_RP_ATTACHMENT_COLOR_0_BIT = (1 << 0),
MESA_VK_RP_ATTACHMENT_COLOR_1_BIT = (1 << 1),
MESA_VK_RP_ATTACHMENT_COLOR_2_BIT = (1 << 2),
MESA_VK_RP_ATTACHMENT_COLOR_3_BIT = (1 << 3),
MESA_VK_RP_ATTACHMENT_COLOR_4_BIT = (1 << 4),
MESA_VK_RP_ATTACHMENT_COLOR_5_BIT = (1 << 5),
MESA_VK_RP_ATTACHMENT_COLOR_6_BIT = (1 << 6),
MESA_VK_RP_ATTACHMENT_COLOR_7_BIT = (1 << 7),
MESA_VK_RP_ATTACHMENT_ANY_COLOR_BITS = 0xff,
MESA_VK_RP_ATTACHMENT_DEPTH_BIT = (1 << 8),
MESA_VK_RP_ATTACHMENT_STENCIL_BIT = (1 << 9),
MESA_VK_RP_ATTACHMENT_INFO_INVALID = 0xffff,
};
MESA_DEFINE_CPP_ENUM_BITFIELD_OPERATORS(vk_rp_attachment_flags)
static_assert(MESA_VK_MAX_COLOR_ATTACHMENTS == 8,
"This enum must match the global runtime limit");
#define MESA_VK_RP_ATTACHMENT_COLOR_BIT(n) \
((enum vk_rp_attachment_flags)(MESA_VK_RP_ATTACHMENT_COLOR_0_BIT << (n)))
#define MESA_VK_COLOR_ATTACHMENT_COUNT_UNKNOWN 0xff
/***/
struct vk_input_attachment_location_state {
/** VkRenderingInputAttachmentIndexInfoKHR::pColorAttachmentLocations
*
* MESA_VK_DYNAMIC_INPUT_ATTACHMENT_MAP
*/
uint8_t color_map[MESA_VK_MAX_COLOR_ATTACHMENTS];
/** VkRenderingInputAttachmentIndexInfoKHR::colorAttachmentCount
*
* This must match vk_render_pass_state::color_attachment_count or be equal
* to MESA_VK_COLOR_ATTACHMENT_COUNT_UNKNOWN, in which case it can be
* assumed that there is an identity mapping and every input attachment
* with an index is a color attachment. Unlike vk_render_pass_state this
* state is available when compiling the fragment shader.
*
* MESA_VK_DYNAMIC_INPUT_ATTACHMENT_MAP
*/
uint8_t color_attachment_count;
/** VkRenderingInputAttachmentIndexInfoKHR::pDepthInputAttachmentIndex
*
* MESA_VK_DYNAMIC_INPUT_ATTACHMENT_MAP
*/
uint8_t depth_att;
/** VkRenderingInputAttachmentIndexInfoKHR::pStencilInputAttachmentIndex
*
* MESA_VK_DYNAMIC_INPUT_ATTACHMENT_MAP
*/
uint8_t stencil_att;
};
/***/
struct vk_color_attachment_location_state {
/** VkRenderingAttachmentLocationInfoKHR::pColorAttachmentLocations
*
* MESA_VK_DYNAMIC_COLOR_ATTACHMENT_MAP
*/
uint8_t color_map[MESA_VK_MAX_COLOR_ATTACHMENTS];
};
/***/
struct vk_render_pass_state {
/** Set of image aspects bound as color/depth/stencil attachments
*
* Set to MESA_VK_RP_ATTACHMENT_INFO_INVALID to indicate that attachment
* info is invalid.
*/
enum vk_rp_attachment_flags attachments;
/** VkPipelineRenderingCreateInfo::viewMask */
uint32_t view_mask;
/** VkPipelineRenderingCreateInfo::colorAttachmentCount */
uint8_t color_attachment_count;
/** VkPipelineRenderingCreateInfo::pColorAttachmentFormats */
VkFormat color_attachment_formats[MESA_VK_MAX_COLOR_ATTACHMENTS];
/** VkPipelineRenderingCreateInfo::depthAttachmentFormat */
VkFormat depth_attachment_format;
/** VkPipelineRenderingCreateInfo::stencilAttachmentFormat */
VkFormat stencil_attachment_format;
/** VkAttachmentSampleCountInfoAMD::pColorAttachmentSamples */
uint8_t color_attachment_samples[MESA_VK_MAX_COLOR_ATTACHMENTS];
/** VkAttachmentSampleCountInfoAMD::depthStencilAttachmentSamples */
uint8_t depth_stencil_attachment_samples;
};
static inline bool
vk_render_pass_state_has_attachment_info(const struct vk_render_pass_state *rp)
{
return rp->attachments != MESA_VK_RP_ATTACHMENT_INFO_INVALID;
}
static inline VkImageAspectFlags
vk_pipeline_flags_feedback_loops(VkPipelineCreateFlags2KHR flags)
{
VkImageAspectFlags feedback_loops = 0;
if (flags &
VK_PIPELINE_CREATE_2_COLOR_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT)
feedback_loops |= VK_IMAGE_ASPECT_COLOR_BIT;
if (flags &
VK_PIPELINE_CREATE_2_DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT)
feedback_loops |= VK_IMAGE_ASPECT_DEPTH_BIT;
return feedback_loops;
}
/** 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;
/* This is a copy of vi->bindings_valid, used when the vertex input state
* is precompiled in the pipeline (so that vi is NULL) but the strides are
* set dynamically.
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_VI_BINDINGS_VALID
*/
uint32_t vi_bindings_valid;
/** Vertex binding strides
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_VI_BINDING_STRIDES
*/
uint16_t vi_binding_strides[MESA_VK_MAX_VERTEX_BINDINGS];
/** Input assembly state */
struct vk_input_assembly_state ia;
/** Tessellation state */
struct vk_tessellation_state ts;
/** Viewport state */
struct vk_viewport_state vp;
/** Discard rectangles state */
struct {
/** Custom enable
*
* MESA_VK_DYNAMIC_DR_ENABLE
*/
bool enable;
/** Mode
*
* MESA_VK_DYNAMIC_DR_MODE
*/
VkDiscardRectangleModeEXT mode;
/** Rectangles
*
* MESA_VK_DYNAMIC_DR_RECTANGLES
*/
VkRect2D rectangles[MESA_VK_MAX_DISCARD_RECTANGLES];
/** Number of rectangles
*
* MESA_VK_DYNAMIC_GRAPHICS_STATE_DR_RECTANGLES
*/
uint32_t rectangle_count;
} dr;
/** Rasterization state */
struct vk_rasterization_state rs;
/* Fragment shading rate state */
struct vk_fragment_shading_rate_state fsr;
/** Multisample state */
struct {
/** Rasterization samples
*
* MESA_VK_DYNAMIC_MS_RASTERIZATION_SAMPLES
*/
VkSampleCountFlagBits rasterization_samples;
/** Sample mask
*
* MESA_VK_DYNAMIC_MS_SAMPLE_MASK
*/
uint16_t sample_mask;
/** Alpha to coverage enable
*
* MESA_VK_DYNAMIC_MS_ALPHA_TO_CONVERAGE_ENABLE
*/
bool alpha_to_coverage_enable;
/** Alpha to one enable
*
* MESA_VK_DYNAMIC_MS_ALPHA_TO_ONE_ENABLE
*/
bool alpha_to_one_enable;
/** Custom sample locations enable
*
* MESA_VK_DYNAMIC_MS_SAMPLE_LOCATIONS_ENABLE
*/
bool sample_locations_enable;
/** Sample locations
*
* Must be provided by the driver if VK_EXT_sample_locations is
* supported.
*
* MESA_VK_DYNAMIC_MS_SAMPLE_LOCATIONS
*/
struct vk_sample_locations_state *sample_locations;
} ms;
/** Depth stencil state */
struct vk_depth_stencil_state ds;
/** Color blend state */
struct vk_color_blend_state cb;
struct {
enum vk_rp_attachment_flags attachments;
} rp;
/** MESA_VK_DYNAMIC_ATTACHMENT_FEEDBACK_LOOP_ENABLE */
VkImageAspectFlags feedback_loops;
/** MESA_VK_DYNAMIC_INPUT_ATTACHMENT_MAP */
struct vk_input_attachment_location_state ial;
/** MESA_VK_DYNAMIC_COLOR_ATTACHMENT_MAP */
struct vk_color_attachment_location_state cal;
/** 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;
struct vk_tessellation_state ts;
struct vk_viewport_state vp;
struct vk_discard_rectangles_state dr;
struct vk_rasterization_state rs;
struct vk_fragment_shading_rate_state fsr;
struct vk_multisample_state ms;
struct vk_sample_locations_state ms_sample_locations;
struct vk_depth_stencil_state ds;
struct vk_color_blend_state cb;
struct vk_input_attachment_location_state ial;
struct vk_color_attachment_location_state cal;
struct vk_render_pass_state rp;
};
/***/
struct vk_graphics_pipeline_state {
/** Bitset of which states are dynamic */
BITSET_DECLARE(dynamic, MESA_VK_DYNAMIC_GRAPHICS_STATE_ENUM_MAX);
VkShaderStageFlags shader_stages;
/** Flags from VkGraphicsPipelineCreateInfo::flags that are considered part
* of a stage and need to be merged when linking libraries.
*
* For drivers which use vk_render_pass, this will also include flags
* generated based on subpass self-dependencies and fragment density map.
*/
VkPipelineCreateFlags2KHR pipeline_flags;
/* True if there are feedback loops that do not involve input attachments
* managed by the driver. This is set to true by the runtime if there
* are loops indicated by a pipeline flag (which may involve any image
* rather than only input attachments under the control of the driver) or
* there was no driver-provided render pass info struct (because input
* attachments for emulated renderpasses cannot be managed by the driver).
*/
bool feedback_loop_not_input_only;
/** Vertex input state */
const struct vk_vertex_input_state *vi;
/** Input assembly state */
const struct vk_input_assembly_state *ia;
/** Tessellation state */
const struct vk_tessellation_state *ts;
/** Viewport state */
const struct vk_viewport_state *vp;
/** Discard Rectangles state */
const struct vk_discard_rectangles_state *dr;
/** Rasterization state */
const struct vk_rasterization_state *rs;
/** Fragment shading rate state */
const struct vk_fragment_shading_rate_state *fsr;
/** Multisample state */
const struct vk_multisample_state *ms;
/** Depth stencil state */
const struct vk_depth_stencil_state *ds;
/** Color blend state */
const struct vk_color_blend_state *cb;
/** Input attachment mapping state */
const struct vk_input_attachment_location_state *ial;
/** Color attachment mapping state */
const struct vk_color_attachment_location_state *cal;
/** Render pass state */
const struct vk_render_pass_state *rp;
};
/** Populate a vk_graphics_pipeline_state from VkGraphicsPipelineCreateInfo
*
* This function crawls the provided VkGraphicsPipelineCreateInfo and uses it
* to populate the vk_graphics_pipeline_state. Upon returning from this
* function, all pointers in `state` will either be `NULL` or point to a valid
* sub-state structure. Whenever an extension struct is missing, a reasonable
* default value is provided whenever possible. Some states may be left NULL
* if the state does not exist (such as when rasterizer discard is enabled) or
* if all of the corresponding states are dynamic.
*
* This function assumes that the vk_graphics_pipeline_state is already valid
* (i.e., all pointers are NULL or point to valid states). Any states already
* present are assumed to be identical to how we would populate them from
* VkGraphicsPipelineCreateInfo.
*
* This function can operate in one of two modes with respect to how the
* memory for states is allocated. If a `vk_graphics_pipeline_all_state`
* struct is provided, any newly populated states will point to the relevant
* field in `all`. If `all == NULL`, it attempts to dynamically allocate any
* newly required states using the provided allocator and scope. The pointer
* to this new blob of memory is returned via `alloc_ptr_out` and must
* eventually be freed by the driver.
*
* :param device: |in| The Vulkan device
* :param state: |out| The graphics pipeline state to populate
* :param info: |in| The pCreateInfo from vkCreateGraphicsPipelines
* :param driver_rp: |in| Renderpass state if the driver implements render
* passes itself. This should be NULL for drivers
* that use the common render pass infrastructure
* built on top of dynamic rendering.
* :param driver_rp_flags: |in| Pipeline create flags implied by the
* renderpass or subpass if the driver implements
* render passes itself. This is only used if
* driver_rp is non-NULL.
* :param all: |in| The vk_graphics_pipeline_all_state to use to
* back any newly needed states. If NULL, newly
* needed states will be dynamically allocated
* instead.
* :param alloc: |in| Allocation callbacks for dynamically allocating
* new state memory.
* :param scope: |in| Allocation scope for dynamically allocating new
* state memory.
* :param alloc_ptr_out: |out| Will be populated with a pointer to any newly
* allocated state. The driver is responsible for
* freeing this pointer.
*/
VkResult
vk_graphics_pipeline_state_fill(const struct vk_device *device,
struct vk_graphics_pipeline_state *state,
const VkGraphicsPipelineCreateInfo *info,
const struct vk_render_pass_state *driver_rp,
VkPipelineCreateFlags2KHR driver_rp_flags,
struct vk_graphics_pipeline_all_state *all,
const VkAllocationCallbacks *alloc,
VkSystemAllocationScope scope,
void **alloc_ptr_out);
/** Populate a vk_graphics_pipeline_state from another one.
*
* This allocates space for graphics pipeline state and copies it from another
* pipeline state. It ignores state in `old_state` which is not set and does
* not allocate memory if the entire group is unused. The intended use-case is
* for drivers that may be able to precompile some state ahead of time, to
* avoid allocating memory for it in pipeline libraries. The workflow looks
* something like this:
*
* struct vk_graphics_pipeline_all_state all;
* struct vk_graphics_pipeline_state state;
* vk_graphics_pipeline_state_fill(dev, &state, ..., &all, NULL, 0, NULL);
*
* ...
*
* BITSET_DECLARE(set_state, MESA_VK_DYNAMIC_GRAPHICS_STATE_ENUM_MAX);
* vk_graphics_pipeline_get_state(&state, &set_state);
*
* ...
*
* if (BITSET_TEST(set_state, MESA_VK_DYNAMIC_FOO)) {
* emit_foo(&state.foo, ...);
* BITSET_SET(state.dynamic, MESA_VK_DYNAMIC_FOO);
* }
*
* ...
*
* if (pipeline->is_library) {
* library = pipeline_to_library(pipeline);
* vk_graphics_pipeline_state_copy(dev, &library->state, &state, ...);
* }
*
* In this case we will avoid allocating memory for `library->state.foo`.
*
* :param device: |in| The Vulkan device
* :param state: |out| The graphics pipeline state to populate
* :param old_state: |in| The graphics pipeline state to copy from
* :param alloc: |in| Allocation callbacks for dynamically allocating
* new state memory.
* :param scope: |in| Allocation scope for dynamically allocating new
* state memory.
* :param alloc_ptr_out: |out| Will be populated with a pointer to any newly
* allocated state. The driver is responsible for
* freeing this pointer.
*/
VkResult
vk_graphics_pipeline_state_copy(const struct vk_device *device,
struct vk_graphics_pipeline_state *state,
const struct vk_graphics_pipeline_state *old_state,
const VkAllocationCallbacks *alloc,
VkSystemAllocationScope scope,
void **alloc_ptr_out);
/** Merge one vk_graphics_pipeline_state into another
*
* Both the destination and source states are assumed to be valid (i.e., all
* pointers are NULL or point to valid states). Any states which exist in
* both are expected to be identical and the state already in dst is used.
* The only exception here is render pass state which may be only partially
* defined in which case the fully defined one (if any) is used.
*
* :param dst: |out| The destination state. When the function returns, this
* will be the union of the original dst and src.
* :param src: |in| The source state
*/
void
vk_graphics_pipeline_state_merge(struct vk_graphics_pipeline_state *dst,
const struct vk_graphics_pipeline_state *src);
/** Get the states which will be set for a given vk_graphics_pipeline_state
*
* Return which states should be set when the pipeline is bound.
*/
void
vk_graphics_pipeline_get_state(const struct vk_graphics_pipeline_state *state,
BITSET_WORD *set_state_out);
/** Initialize a vk_dynamic_graphics_state with defaults
*
* :param dyn: |out| Dynamic graphics state to initialize
*/
void
vk_dynamic_graphics_state_init(struct vk_dynamic_graphics_state *dyn);
/** Clear a vk_dynamic_graphics_state to defaults
*
* :param dyn: |out| Dynamic graphics state to initialize
*/
void
vk_dynamic_graphics_state_clear(struct vk_dynamic_graphics_state *dyn);
/** Initialize a vk_dynamic_graphics_state for a pipeline
*
* :param dyn: |out| Dynamic graphics state to initialize
* :param supported: |in| Bitset of all dynamic state supported by the driver.
* :param p: |in| 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 d: |out| 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 d: |out| Dynamic graphics state struct
*/
static inline void
vk_dynamic_graphics_state_clear_dirty(struct vk_dynamic_graphics_state *d)
{
BITSET_ZERO(d->dirty);
}
/** Test if any states in the given vk_dynamic_graphics_state are dirty
*
* :param d: |in| 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_IS_EMPTY(d->dirty);
}
/** 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.
*
* :param dst: |out| Copy destination
* :param src: |in| Copy source
*/
void
vk_dynamic_graphics_state_copy(struct vk_dynamic_graphics_state *dst,
const struct vk_dynamic_graphics_state *src);
/** Set all of the state in src on a command buffer
*
* Anything not set, as indicated by src->set, is ignored and those states in
* the command buffer are left untouched.
*
* :param cmd: |inout| Command buffer to update
* :param src: |in| State to set
*/
void
vk_cmd_set_dynamic_graphics_state(struct vk_command_buffer *cmd,
const struct vk_dynamic_graphics_state *src);
/** Set vertex binding strides on a command buffer
*
* This is the dynamic state part of vkCmdBindVertexBuffers2().
*
* :param cmd: |inout| Command buffer to update
* :param first_binding: |in| First binding to update
* :param binding_count: |in| Number of bindings to update
* :param strides: |in| binding_count many stride values to set
*/
void
vk_cmd_set_vertex_binding_strides(struct vk_command_buffer *cmd,
uint32_t first_binding,
uint32_t binding_count,
const VkDeviceSize *strides);
/* Set color attachment count for blending on a command buffer.
*
* This is an implicit part of starting a subpass or a secondary command
* buffer in a subpass.
*/
void
vk_cmd_set_cb_attachment_count(struct vk_command_buffer *cmd,
uint32_t attachment_count);
/* Set render pass attachments on a command buffer.
*
* This is required for VK_EXT_shader_object in order to disable attachments
* based on bound shaders.
*/
void
vk_cmd_set_rp_attachments(struct vk_command_buffer *cmd,
enum vk_rp_attachment_flags attachments);
/* This is equivalent to CmdSetRenderingAttachmentLocationsKHR() but easier to
* invoke from inside drivers.
*/
void
vk_cmd_set_rendering_attachment_locations(struct vk_command_buffer *cmd,
const VkRenderingAttachmentLocationInfoKHR *info);
const char *
vk_dynamic_graphic_state_to_str(enum mesa_vk_dynamic_graphics_state state);
/** Check whether the color attachment location map is the identity
*
* :param cal: |in| Color attachment location state
*/
static inline bool
vk_color_attachment_location_state_is_identity(
const struct vk_color_attachment_location_state *cal)
{
for (unsigned i = 0; i < ARRAY_SIZE(cal->color_map); i++) {
if (cal->color_map[i] != i)
return false;
}
return true;
}
#ifdef __cplusplus
}
#endif
#endif /* VK_GRAPHICS_STATE_H */