[vulkan] Fixing DynamicState wrong core feature callings

This commit is contained in:
CamilleLaVey 2026-01-26 15:30:44 -04:00 committed by lizzie
parent 90b312617b
commit 6e17a47120
7 changed files with 151 additions and 28 deletions

View File

@ -5,6 +5,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <vector>
#include "video_core/renderer_vulkan/vk_texture_cache.h"
@ -761,10 +762,24 @@ void BlitImageHelper::ClearDepthStencil(const Framebuffer* dst_framebuffer, bool
const VkPipeline pipeline = FindOrEmplaceClearStencilPipeline(key);
const VkPipelineLayout layout = *clear_color_pipeline_layout;
scheduler.RequestRenderpass(dst_framebuffer);
scheduler.Record([pipeline, layout, clear_depth, dst_region](vk::CommandBuffer cmdbuf) {
scheduler.Record([pipeline, layout, clear_depth, dst_region, stencil_mask, stencil_ref,
stencil_compare_mask, dyn_stencil_compare, dyn_stencil_write,
dyn_stencil_ref, this](vk::CommandBuffer cmdbuf) {
constexpr std::array blend_constants{0.0f, 0.0f, 0.0f, 0.0f};
cmdbuf.SetBlendConstants(blend_constants.data());
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
if (dyn_stencil_compare) {
cmdbuf.SetStencilCompareMask(VK_STENCIL_FACE_FRONT_BIT | VK_STENCIL_FACE_BACK_BIT,
stencil_compare_mask);
}
if (dyn_stencil_write) {
cmdbuf.SetStencilWriteMask(VK_STENCIL_FACE_FRONT_BIT | VK_STENCIL_FACE_BACK_BIT,
stencil_mask);
}
if (dyn_stencil_ref) {
cmdbuf.SetStencilReference(VK_STENCIL_FACE_FRONT_BIT | VK_STENCIL_FACE_BACK_BIT,
stencil_ref);
}
BindBlitState(cmdbuf, dst_region);
cmdbuf.PushConstants(layout, VK_SHADER_STAGE_FRAGMENT_BIT, clear_depth);
cmdbuf.Draw(3, 1, 0, 0);
@ -1010,14 +1025,19 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
}
clear_stencil_keys.push_back(key);
const std::array stages = MakeStages(*clear_color_vert, *clear_stencil_frag);
// Allow using dynamic stencil masks if the device supports them.
const bool dyn_stencil_compare = device.SupportsDynamicStateStencilCompareMask();
const bool dyn_stencil_write = device.SupportsDynamicStateStencilWriteMask();
const bool dyn_stencil_ref = device.SupportsDynamicStateStencilReference();
const auto stencil = VkStencilOpState{
.failOp = VK_STENCIL_OP_KEEP,
.passOp = VK_STENCIL_OP_REPLACE,
.depthFailOp = VK_STENCIL_OP_KEEP,
.compareOp = VK_COMPARE_OP_ALWAYS,
.compareMask = key.stencil_compare_mask,
.writeMask = key.stencil_mask,
.reference = key.stencil_ref,
.compareMask = dyn_stencil_compare ? 0u : key.stencil_compare_mask,
.writeMask = dyn_stencil_write ? 0u : key.stencil_mask,
.reference = dyn_stencil_ref ? 0u : key.stencil_ref,
};
const VkPipelineDepthStencilStateCreateInfo depth_stencil_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
@ -1034,6 +1054,29 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
.maxDepthBounds = 0.0f,
};
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
// Build dynamic state list for this pipeline (base + optional stencil/linewidth)
std::vector<VkDynamicState> dyn_states(DYNAMIC_STATES.begin(), DYNAMIC_STATES.end());
if (device.SupportsDynamicStateLineWidth()) {
dyn_states.push_back(VK_DYNAMIC_STATE_LINE_WIDTH);
}
if (dyn_stencil_compare) {
dyn_states.push_back(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK);
}
if (dyn_stencil_write) {
dyn_states.push_back(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK);
}
if (dyn_stencil_ref) {
dyn_states.push_back(VK_DYNAMIC_STATE_STENCIL_REFERENCE);
}
const VkPipelineDynamicStateCreateInfo dynamic_state_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.dynamicStateCount = static_cast<u32>(dyn_states.size()),
.pDynamicStates = dyn_states.data(),
};
clear_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = nullptr,
@ -1048,7 +1091,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
.pDepthStencilState = &depth_stencil_ci,
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.pDynamicState = &dynamic_state_ci,
.layout = *clear_color_pipeline_layout,
.renderPass = key.renderpass,
.subpass = 0,

View File

@ -171,6 +171,15 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe
if (!extended_dynamic_state_3_enables) {
dynamic_state.Refresh3(regs);
}
if (features.has_depth_bounds) {
depth_bounds_min = 0;
depth_bounds_max = 0;
dynamic_state.depth_bounds_enable.Assign(0);
}
if (features.has_depth_bias) {
dynamic_state.depth_bias_enable.Assign(0);
}
if (xfb_enabled) {
RefreshXfbState(xfb_state, regs);
}

View File

@ -21,6 +21,15 @@ namespace Vulkan {
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
struct DynamicFeatures {
bool has_viewport;
bool has_scissor;
bool has_depth_bias;
bool has_blend_constants;
bool has_depth_bounds;
bool has_stencil_compare_mask;
bool has_stencil_write_mask;
bool has_stencil_reference;
bool has_line_width;
bool has_extended_dynamic_state;
bool has_extended_dynamic_state_2;
bool has_extended_dynamic_state_2_logic_op;

View File

@ -815,13 +815,35 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
.pAttachments = cb_attachments.data(),
.blendConstants = {}
};
static_vector<VkDynamicState, 34> dynamic_states{
VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR,
VK_DYNAMIC_STATE_DEPTH_BIAS, VK_DYNAMIC_STATE_BLEND_CONSTANTS,
VK_DYNAMIC_STATE_DEPTH_BOUNDS, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,
VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, VK_DYNAMIC_STATE_STENCIL_REFERENCE,
VK_DYNAMIC_STATE_LINE_WIDTH,
};
static_vector<VkDynamicState, 34> dynamic_states;
if (device.SupportsDynamicStateViewport()) {
dynamic_states.push_back(VK_DYNAMIC_STATE_VIEWPORT);
}
if (device.SupportsDynamicStateScissor()) {
dynamic_states.push_back(VK_DYNAMIC_STATE_SCISSOR);
}
if (device.SupportsDynamicStateDepthBias()) {
dynamic_states.push_back(VK_DYNAMIC_STATE_DEPTH_BIAS);
}
if (device.SupportsDynamicStateBlendConstants()) {
dynamic_states.push_back(VK_DYNAMIC_STATE_BLEND_CONSTANTS);
}
if (device.SupportsDynamicStateDepthBounds()) {
dynamic_states.push_back(VK_DYNAMIC_STATE_DEPTH_BOUNDS);
}
if (device.SupportsDynamicStateStencilCompareMask()) {
dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK);
}
if (device.SupportsDynamicStateStencilWriteMask()) {
dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK);
}
if (device.SupportsDynamicStateStencilReference()) {
dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_REFERENCE);
}
if (device.SupportsDynamicStateLineWidth()) {
dynamic_states.push_back(VK_DYNAMIC_STATE_LINE_WIDTH);
}
if (key.state.extended_dynamic_state) {
static constexpr std::array extended{
VK_DYNAMIC_STATE_CULL_MODE_EXT,

View File

@ -418,12 +418,24 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
dynamic_features = {};
// User granularity enforced in vulkan_device.cpp switch statement:
// Level 0: Core Dynamic States only
// Level 1: Core + EDS1
// Level 2: Core + EDS1 + EDS2 (accumulative)
// Level 3: Core + EDS1 + EDS2 + EDS3 (accumulative)
// Here we only verify if extensions were successfully loaded by the device
dynamic_features.has_viewport =
device.SupportsDynamicStateViewport();
dynamic_features.has_scissor =
device.SupportsDynamicStateScissor();
dynamic_features.has_depth_bias =
device.SupportsDynamicStateDepthBias();
dynamic_features.has_blend_constants =
device.SupportsDynamicStateBlendConstants();
dynamic_features.has_depth_bounds =
device.SupportsDynamicStateDepthBounds();
dynamic_features.has_stencil_compare_mask =
device.SupportsDynamicStateStencilCompareMask();
dynamic_features.has_stencil_write_mask =
device.SupportsDynamicStateStencilWriteMask();
dynamic_features.has_stencil_reference =
device.SupportsDynamicStateStencilReference();
dynamic_features.has_line_width =
device.SupportsDynamicStateLineWidth();
dynamic_features.has_extended_dynamic_state =
device.IsExtExtendedDynamicStateSupported();
@ -439,7 +451,6 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
dynamic_features.has_extended_dynamic_state_3_enables =
device.IsExtExtendedDynamicState3EnablesSupported();
// VIDS: Independent toggle (not affected by dyna_state levels)
dynamic_features.has_dynamic_vertex_input =
device.IsExtVertexInputDynamicStateSupported() &&
Settings::values.vertex_input_dynamic_state.GetValue();

View File

@ -682,13 +682,6 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
const auto dyna_state = Settings::values.dyna_state.GetValue();
// Base dynamic states (VIEWPORT, SCISSOR, DEPTH_BIAS, etc.) are ALWAYS active in vk_graphics_pipeline.cpp
// This slider controls EXTENDED dynamic states with accumulative levels per Vulkan specs:
// Level 0 = Core Dynamic States only (Vulkan 1.0)
// Level 1 = Core + VK_EXT_extended_dynamic_state
// Level 2 = Core + VK_EXT_extended_dynamic_state + VK_EXT_extended_dynamic_state2
// Level 3 = Core + VK_EXT_extended_dynamic_state + VK_EXT_extended_dynamic_state2 + VK_EXT_extended_dynamic_state3
switch (dyna_state) {
case Settings::ExtendedDynamicState::Disabled:
// Level 0: Disable all extended dynamic state extensions
@ -723,8 +716,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
break;
}
// VK_EXT_vertex_input_dynamic_state is independent from EDS
// It can be enabled even without extended_dynamic_state
// VK_EXT_vertex_input_dynamic_state is independent from ExtendedDynamicState level
if (!Settings::values.vertex_input_dynamic_state.GetValue()) {
RemoveExtensionFeature(extensions.vertex_input_dynamic_state, features.vertex_input_dynamic_state, VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
}

View File

@ -704,6 +704,43 @@ public:
return dynamic_state3_alpha_to_one;
}
// Core dynamic state support checks
bool SupportsDynamicStateViewport() const {
return dld.vkCmdSetViewport != nullptr;
}
bool SupportsDynamicStateScissor() const {
return dld.vkCmdSetScissor != nullptr;
}
bool SupportsDynamicStateDepthBias() const {
return dld.vkCmdSetDepthBias != nullptr || dld.vkCmdSetDepthBias2EXT != nullptr;
}
bool SupportsDynamicStateBlendConstants() const {
return dld.vkCmdSetBlendConstants != nullptr;
}
bool SupportsDynamicStateDepthBounds() const {
return dld.vkCmdSetDepthBounds != nullptr && IsDepthBoundsSupported();
}
bool SupportsDynamicStateStencilCompareMask() const {
return dld.vkCmdSetStencilCompareMask != nullptr;
}
bool SupportsDynamicStateStencilWriteMask() const {
return dld.vkCmdSetStencilWriteMask != nullptr;
}
bool SupportsDynamicStateStencilReference() const {
return dld.vkCmdSetStencilReference != nullptr;
}
bool SupportsDynamicStateLineWidth() const {
return dld.vkCmdSetLineWidth != nullptr;
}
/// Returns true if the device supports VK_EXT_vertex_input_dynamic_state.
bool IsExtVertexInputDynamicStateSupported() const {
return extensions.vertex_input_dynamic_state;