renderer_vulkan: Resore color write dynamic state (#3453)

This commit is contained in:
TheTurtle
2025-08-25 00:30:59 +03:00
committed by GitHub
parent 6d98a5ab60
commit c90781d3e2
9 changed files with 61 additions and 6 deletions

View File

@@ -127,6 +127,14 @@ union CompMapping {
}; };
} }
[[nodiscard]] u32 ApplyMask(u32 mask) const {
u32 swizzled_mask{};
for (u32 i = 0; i < 4; ++i) {
swizzled_mask |= ((mask >> i) & 1) << Map(i);
}
return swizzled_mask;
}
[[nodiscard]] CompMapping Inverse() const { [[nodiscard]] CompMapping Inverse() const {
CompMapping result{}; CompMapping result{};
InverseSingle(result.r, CompSwizzle::Red); InverseSingle(result.r, CompSwizzle::Red);

View File

@@ -168,6 +168,9 @@ GraphicsPipeline::GraphicsPipeline(
dynamic_states.push_back(vk::DynamicState::eDepthBoundsTestEnable); dynamic_states.push_back(vk::DynamicState::eDepthBoundsTestEnable);
dynamic_states.push_back(vk::DynamicState::eDepthBounds); dynamic_states.push_back(vk::DynamicState::eDepthBounds);
} }
if (instance.IsDynamicColorWriteMaskSupported()) {
dynamic_states.push_back(vk::DynamicState::eColorWriteMaskEXT);
}
if (instance.IsVertexInputDynamicState()) { if (instance.IsVertexInputDynamicState()) {
dynamic_states.push_back(vk::DynamicState::eVertexInputEXT); dynamic_states.push_back(vk::DynamicState::eVertexInputEXT);
} else if (!vertex_bindings.empty()) { } else if (!vertex_bindings.empty()) {
@@ -288,7 +291,11 @@ GraphicsPipeline::GraphicsPipeline(
.alphaBlendOp = control.separate_alpha_blend .alphaBlendOp = control.separate_alpha_blend
? LiverpoolToVK::BlendOp(control.alpha_func) ? LiverpoolToVK::BlendOp(control.alpha_func)
: color_blend, : color_blend,
.colorWriteMask = vk::ColorComponentFlags{key.write_masks[i]}, .colorWriteMask =
instance.IsDynamicColorWriteMaskSupported()
? vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG |
vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA
: key.write_masks[i],
}; };
// On GCN GPU there is an additional mask which allows to control color components exported // On GCN GPU there is an additional mask which allows to control color components exported

View File

@@ -38,7 +38,7 @@ struct GraphicsPipelineKey {
u32 num_color_attachments; u32 num_color_attachments;
std::array<Shader::PsColorBuffer, Liverpool::NumColorBuffers> color_buffers; std::array<Shader::PsColorBuffer, Liverpool::NumColorBuffers> color_buffers;
std::array<Liverpool::BlendControl, Liverpool::NumColorBuffers> blend_controls; std::array<Liverpool::BlendControl, Liverpool::NumColorBuffers> blend_controls;
std::array<u32, Liverpool::NumColorBuffers> write_masks; std::array<vk::ColorComponentFlags, Liverpool::NumColorBuffers> write_masks;
Liverpool::ColorBufferMask cb_shader_mask; Liverpool::ColorBufferMask cb_shader_mask;
Liverpool::ColorControl::LogicOp logic_op; Liverpool::ColorControl::LogicOp logic_op;
u32 num_samples; u32 num_samples;
@@ -80,6 +80,10 @@ public:
return fetch_shader; return fetch_shader;
} }
auto GetWriteMasks() const {
return key.write_masks;
}
u32 GetMrtMask() const { u32 GetMrtMask() const {
return key.mrt_mask; return key.mrt_mask;
} }

View File

@@ -255,6 +255,13 @@ bool Instance::CreateDevice() {
// Optional // Optional
maintenance_8 = add_extension(VK_KHR_MAINTENANCE_8_EXTENSION_NAME); maintenance_8 = add_extension(VK_KHR_MAINTENANCE_8_EXTENSION_NAME);
depth_range_unrestricted = add_extension(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME); depth_range_unrestricted = add_extension(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME);
dynamic_state_3 = add_extension(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
if (dynamic_state_3) {
dynamic_state_3_features =
feature_chain.get<vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT>();
LOG_INFO(Render_Vulkan, "- extendedDynamicState3ColorWriteMask: {}",
dynamic_state_3_features.extendedDynamicState3ColorWriteMask);
}
robustness2 = add_extension(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME); robustness2 = add_extension(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME);
if (robustness2) { if (robustness2) {
robustness2_features = feature_chain.get<vk::PhysicalDeviceRobustness2FeaturesEXT>(); robustness2_features = feature_chain.get<vk::PhysicalDeviceRobustness2FeaturesEXT>();
@@ -419,6 +426,10 @@ bool Instance::CreateDevice() {
.customBorderColors = true, .customBorderColors = true,
.customBorderColorWithoutFormat = true, .customBorderColorWithoutFormat = true,
}, },
vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT{
.extendedDynamicState3ColorWriteMask =
dynamic_state_3_features.extendedDynamicState3ColorWriteMask,
},
vk::PhysicalDeviceDepthClipControlFeaturesEXT{ vk::PhysicalDeviceDepthClipControlFeaturesEXT{
.depthClipControl = true, .depthClipControl = true,
}, },
@@ -494,6 +505,9 @@ bool Instance::CreateDevice() {
if (!custom_border_color) { if (!custom_border_color) {
device_chain.unlink<vk::PhysicalDeviceCustomBorderColorFeaturesEXT>(); device_chain.unlink<vk::PhysicalDeviceCustomBorderColorFeaturesEXT>();
} }
if (!dynamic_state_3) {
device_chain.unlink<vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT>();
}
if (!depth_clip_control) { if (!depth_clip_control) {
device_chain.unlink<vk::PhysicalDeviceDepthClipControlFeaturesEXT>(); device_chain.unlink<vk::PhysicalDeviceDepthClipControlFeaturesEXT>();
} }

View File

@@ -139,6 +139,12 @@ public:
return depth_range_unrestricted; return depth_range_unrestricted;
} }
/// Returns true when the extendedDynamicState3ColorWriteMask feature o
/// VK_EXT_extended_dynamic_state3 is supported.
bool IsDynamicColorWriteMaskSupported() const {
return dynamic_state_3 && dynamic_state_3_features.extendedDynamicState3ColorWriteMask;
}
/// Returns true when VK_EXT_vertex_input_dynamic_state is supported. /// Returns true when VK_EXT_vertex_input_dynamic_state is supported.
bool IsVertexInputDynamicState() const { bool IsVertexInputDynamicState() const {
return vertex_input_dynamic_state; return vertex_input_dynamic_state;
@@ -433,6 +439,7 @@ private:
vk::PhysicalDeviceFeatures features; vk::PhysicalDeviceFeatures features;
vk::PhysicalDeviceVulkan12Features vk12_features; vk::PhysicalDeviceVulkan12Features vk12_features;
vk::PhysicalDevicePortabilitySubsetFeaturesKHR portability_features; vk::PhysicalDevicePortabilitySubsetFeaturesKHR portability_features;
vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT dynamic_state_3_features;
vk::PhysicalDeviceRobustness2FeaturesEXT robustness2_features; vk::PhysicalDeviceRobustness2FeaturesEXT robustness2_features;
vk::PhysicalDeviceShaderAtomicFloat2FeaturesEXT shader_atomic_float2_features; vk::PhysicalDeviceShaderAtomicFloat2FeaturesEXT shader_atomic_float2_features;
vk::PhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR vk::PhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR
@@ -453,6 +460,7 @@ private:
bool amd_shader_explicit_vertex_parameter{}; bool amd_shader_explicit_vertex_parameter{};
bool depth_clip_control{}; bool depth_clip_control{};
bool depth_clip_enable{}; bool depth_clip_enable{};
bool dynamic_state_3{};
bool depth_range_unrestricted{}; bool depth_range_unrestricted{};
bool vertex_input_dynamic_state{}; bool vertex_input_dynamic_state{};
bool robustness2{}; bool robustness2{};

View File

@@ -345,10 +345,8 @@ bool PipelineCache::RefreshGraphicsKey() {
!col_buf.info.blend_bypass); !col_buf.info.blend_bypass);
// Apply swizzle to target mask // Apply swizzle to target mask
const auto& swizzle = key.color_buffers[cb].swizzle; key.write_masks[cb] =
for (u32 i = 0; i < 4; ++i) { vk::ColorComponentFlags{key.color_buffers[cb].swizzle.ApplyMask(target_mask)};
key.write_masks[cb] |= ((target_mask >> i) & 1) << swizzle.Map(i);
}
} }
// Compile and bind shader stages // Compile and bind shader stages

View File

@@ -1097,6 +1097,7 @@ void Rasterizer::UpdateDynamicState(const GraphicsPipeline& pipeline) const {
auto& dynamic_state = scheduler.GetDynamicState(); auto& dynamic_state = scheduler.GetDynamicState();
dynamic_state.SetBlendConstants(liverpool->regs.blend_constants); dynamic_state.SetBlendConstants(liverpool->regs.blend_constants);
dynamic_state.SetColorWriteMasks(pipeline.GetWriteMasks());
// Commit new dynamic state to the command buffer. // Commit new dynamic state to the command buffer.
dynamic_state.Commit(instance, scheduler.CommandBuffer()); dynamic_state.Commit(instance, scheduler.CommandBuffer());

View File

@@ -323,6 +323,12 @@ void DynamicState::Commit(const Instance& instance, const vk::CommandBuffer& cmd
dirty_state.blend_constants = false; dirty_state.blend_constants = false;
cmdbuf.setBlendConstants(blend_constants.data()); cmdbuf.setBlendConstants(blend_constants.data());
} }
if (dirty_state.color_write_masks) {
dirty_state.color_write_masks = false;
if (instance.IsDynamicColorWriteMaskSupported()) {
cmdbuf.setColorWriteMaskEXT(0, color_write_masks);
}
}
if (dirty_state.line_width) { if (dirty_state.line_width) {
dirty_state.line_width = false; dirty_state.line_width = false;
cmdbuf.setLineWidth(line_width); cmdbuf.setLineWidth(line_width);

View File

@@ -108,6 +108,7 @@ struct DynamicState {
bool front_face : 1; bool front_face : 1;
bool blend_constants : 1; bool blend_constants : 1;
bool color_write_masks : 1;
bool line_width : 1; bool line_width : 1;
} dirty_state{}; } dirty_state{};
@@ -143,6 +144,7 @@ struct DynamicState {
vk::FrontFace front_face{}; vk::FrontFace front_face{};
std::array<float, 4> blend_constants{}; std::array<float, 4> blend_constants{};
ColorWriteMasks color_write_masks{};
float line_width{}; float line_width{};
/// Commits the dynamic state to the provided command buffer. /// Commits the dynamic state to the provided command buffer.
@@ -306,6 +308,13 @@ struct DynamicState {
} }
} }
void SetColorWriteMasks(const ColorWriteMasks& color_write_masks_) {
if (!std::ranges::equal(color_write_masks, color_write_masks_)) {
color_write_masks = color_write_masks_;
dirty_state.color_write_masks = true;
}
}
void SetLineWidth(const float width) { void SetLineWidth(const float width) {
if (line_width != width) { if (line_width != width) {
line_width = width; line_width = width;