[vulkan] Fixing inconsistences within VK_EXT_extended_dynamic_state1 handling

This commit is contained in:
CamilleLaVey 2026-02-15 01:02:02 -04:00 committed by crueter
parent 191af43721
commit 348433b4dc
7 changed files with 112 additions and 21 deletions

View File

@ -50,6 +50,38 @@ void RefreshXfbState(VideoCommon::TransformFeedbackState& state, const Maxwell&
});
state.varyings = regs.stream_out_layout;
}
Maxwell::PrimitiveTopology NormalizeDynamicTopologyClass(Maxwell::PrimitiveTopology topology) {
switch (topology) {
case Maxwell::PrimitiveTopology::Points:
return Maxwell::PrimitiveTopology::Points;
case Maxwell::PrimitiveTopology::Lines:
case Maxwell::PrimitiveTopology::LineStrip:
return Maxwell::PrimitiveTopology::Lines;
case Maxwell::PrimitiveTopology::Triangles:
case Maxwell::PrimitiveTopology::TriangleStrip:
case Maxwell::PrimitiveTopology::TriangleFan:
case Maxwell::PrimitiveTopology::Quads:
case Maxwell::PrimitiveTopology::QuadStrip:
case Maxwell::PrimitiveTopology::Polygon:
case Maxwell::PrimitiveTopology::LineLoop:
return Maxwell::PrimitiveTopology::Triangles;
case Maxwell::PrimitiveTopology::LinesAdjacency:
case Maxwell::PrimitiveTopology::LineStripAdjacency:
return Maxwell::PrimitiveTopology::LinesAdjacency;
case Maxwell::PrimitiveTopology::TrianglesAdjacency:
case Maxwell::PrimitiveTopology::TriangleStripAdjacency:
return Maxwell::PrimitiveTopology::TrianglesAdjacency;
case Maxwell::PrimitiveTopology::Patches:
return Maxwell::PrimitiveTopology::Patches;
}
return topology;
}
} // Anonymous namespace
void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFeatures& features) {
@ -71,7 +103,9 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe
tessellation_clockwise.Assign(regs.tessellation.params.output_primitives.Value() ==
Maxwell::Tessellation::OutputPrimitives::Triangles_CW);
patch_control_points_minus_one.Assign(regs.patch_vertices - 1);
topology.Assign(topology_);
const bool can_normalize_topology =
features.has_extended_dynamic_state && features.has_extended_dynamic_state_2;
topology.Assign(can_normalize_topology ? NormalizeDynamicTopologyClass(topology_) : topology_);
msaa_mode.Assign(regs.anti_alias_samples_mode);
raw2 = 0;

View File

@ -831,7 +831,6 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
.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,
@ -839,8 +838,11 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
};
if (key.state.extended_dynamic_state) {
static constexpr std::array extended{
VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT,
VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT,
VK_DYNAMIC_STATE_CULL_MODE_EXT,
VK_DYNAMIC_STATE_FRONT_FACE_EXT,
VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT,
VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT,
VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT,
VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT,
@ -851,6 +853,9 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
dynamic_states.insert(dynamic_states.end(), extended.begin(), extended.end());
dynamic_states.push_back(VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT);
} else {
dynamic_states.push_back(VK_DYNAMIC_STATE_VIEWPORT);
dynamic_states.push_back(VK_DYNAMIC_STATE_SCISSOR);
}
// EDS2 - Core (3 states)

View File

@ -1032,6 +1032,7 @@ void RasterizerVulkan::UpdateDynamicStates() {
UpdateCullMode(regs);
UpdateDepthCompareOp(regs);
UpdateFrontFace(regs);
UpdatePrimitiveTopology(regs);
UpdateStencilOp(regs);
if (state_tracker.TouchStateEnable()) {
UpdateDepthBoundsTestEnable(regs);
@ -1106,8 +1107,14 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg
.minDepth = 0.0f,
.maxDepth = 1.0f,
};
scheduler.Record([viewport](vk::CommandBuffer cmdbuf) {
cmdbuf.SetViewport(0, viewport);
const bool use_viewport_with_count = device.IsExtExtendedDynamicStateSupported();
scheduler.Record([viewport, use_viewport_with_count](vk::CommandBuffer cmdbuf) {
if (use_viewport_with_count) {
std::array viewports{viewport};
cmdbuf.SetViewportWithCountEXT(viewports);
} else {
cmdbuf.SetViewport(0, viewport);
}
});
return;
}
@ -1123,10 +1130,15 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg
GetViewportState(device, regs, 12, scale), GetViewportState(device, regs, 13, scale),
GetViewportState(device, regs, 14, scale), GetViewportState(device, regs, 15, scale),
};
scheduler.Record([this, viewport_list](vk::CommandBuffer cmdbuf) {
const bool use_viewport_with_count = device.IsExtExtendedDynamicStateSupported();
scheduler.Record([this, viewport_list, use_viewport_with_count](vk::CommandBuffer cmdbuf) {
const u32 num_viewports = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
const vk::Span<VkViewport> viewports(viewport_list.data(), num_viewports);
cmdbuf.SetViewport(0, viewports);
if (use_viewport_with_count) {
cmdbuf.SetViewportWithCountEXT(viewports);
} else {
cmdbuf.SetViewport(0, viewports);
}
});
}
@ -1147,8 +1159,14 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs
scissor.offset.y = static_cast<int32_t>(y);
scissor.extent.width = width;
scissor.extent.height = height;
scheduler.Record([scissor](vk::CommandBuffer cmdbuf) {
cmdbuf.SetScissor(0, scissor);
const bool use_scissor_with_count = device.IsExtExtendedDynamicStateSupported();
scheduler.Record([scissor, use_scissor_with_count](vk::CommandBuffer cmdbuf) {
if (use_scissor_with_count) {
std::array scissors{scissor};
cmdbuf.SetScissorWithCountEXT(scissors);
} else {
cmdbuf.SetScissor(0, scissor);
}
});
return;
}
@ -1176,10 +1194,15 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs
GetScissorState(regs, 14, up_scale, down_shift),
GetScissorState(regs, 15, up_scale, down_shift),
};
scheduler.Record([this, scissor_list](vk::CommandBuffer cmdbuf) {
const bool use_scissor_with_count = device.IsExtExtendedDynamicStateSupported();
scheduler.Record([this, scissor_list, use_scissor_with_count](vk::CommandBuffer cmdbuf) {
const u32 num_scissors = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
const vk::Span<VkRect2D> scissors(scissor_list.data(), num_scissors);
cmdbuf.SetScissor(0, scissors);
if (use_scissor_with_count) {
cmdbuf.SetScissorWithCountEXT(scissors);
} else {
cmdbuf.SetScissor(0, scissors);
}
});
}
@ -1451,6 +1474,17 @@ void RasterizerVulkan::UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& reg
});
}
void RasterizerVulkan::UpdatePrimitiveTopology([[maybe_unused]] Tegra::Engines::Maxwell3D::Regs& regs) {
const auto topology = maxwell3d->draw_manager->GetDrawState().topology;
if (!state_tracker.ChangePrimitiveTopology(topology)) {
return;
}
const auto vk_topology = MaxwellToVK::PrimitiveTopology(device, topology);
scheduler.Record([vk_topology](vk::CommandBuffer cmdbuf) {
cmdbuf.SetPrimitiveTopologyEXT(vk_topology);
});
}
void RasterizerVulkan::UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs) {
if (!state_tracker.TouchFrontFace()) {
return;

View File

@ -174,6 +174,7 @@ private:
void UpdateDepthTestEnable(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdatePrimitiveTopology(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdatePrimitiveRestartEnable(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateRasterizerDiscardEnable(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateDepthBiasEnable(Tegra::Engines::Maxwell3D::Regs& regs);

View File

@ -1150,8 +1150,6 @@ bool Device::GetSuitability(bool requires_swapchain) {
if (u32(Settings::values.dyna_state.GetValue()) == 0) {
LOG_INFO(Render_Vulkan, "Extended Dynamic State disabled by user setting, clearing all EDS features");
features.custom_border_color.customBorderColors = false;
features.custom_border_color.customBorderColorWithoutFormat = false;
features.extended_dynamic_state.extendedDynamicState = false;
features.extended_dynamic_state2.extendedDynamicState2 = false;
}
@ -1187,7 +1185,7 @@ void Device::RemoveUnsuitableExtensions() {
RemoveExtensionFeatureIfUnsuitable(extensions.depth_clip_control, features.depth_clip_control,
VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME);
/* */ // VK_EXT_extended_dynamic_state
// VK_EXT_extended_dynamic_state
extensions.extended_dynamic_state = features.extended_dynamic_state.extendedDynamicState;
RemoveExtensionFeatureIfUnsuitable(extensions.extended_dynamic_state,
features.extended_dynamic_state,
@ -1200,7 +1198,6 @@ void Device::RemoveUnsuitableExtensions() {
VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
// VK_EXT_robustness2
// Enable if at least one robustness2 feature is available
extensions.robustness_2 = features.robustness2.robustBufferAccess2 ||
features.robustness2.robustImageAccess2 ||
features.robustness2.nullDescriptor;
@ -1209,7 +1206,6 @@ void Device::RemoveUnsuitableExtensions() {
VK_EXT_ROBUSTNESS_2_EXTENSION_NAME);
// VK_EXT_image_robustness
// Enable if robustImageAccess is available
extensions.image_robustness = features.image_robustness.robustImageAccess;
RemoveExtensionFeatureIfUnsuitable(extensions.image_robustness, features.image_robustness,
VK_EXT_IMAGE_ROBUSTNESS_EXTENSION_NAME);
@ -1305,15 +1301,15 @@ void Device::RemoveUnsuitableExtensions() {
RemoveExtensionFeatureIfUnsuitable(extensions.swapchain_maintenance1, features.swapchain_maintenance1,
VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME);
// VK_KHR_maintenance1 (core in Vulkan 1.1, no features)
// VK_KHR_maintenance1
extensions.maintenance1 = loaded_extensions.contains(VK_KHR_MAINTENANCE_1_EXTENSION_NAME);
RemoveExtensionIfUnsuitable(extensions.maintenance1, VK_KHR_MAINTENANCE_1_EXTENSION_NAME);
// VK_KHR_maintenance2 (core in Vulkan 1.1, no features)
// VK_KHR_maintenance2
extensions.maintenance2 = loaded_extensions.contains(VK_KHR_MAINTENANCE_2_EXTENSION_NAME);
RemoveExtensionIfUnsuitable(extensions.maintenance2, VK_KHR_MAINTENANCE_2_EXTENSION_NAME);
// VK_KHR_maintenance3 (core in Vulkan 1.1, no features)
// VK_KHR_maintenance3
extensions.maintenance3 = loaded_extensions.contains(VK_KHR_MAINTENANCE_3_EXTENSION_NAME);
RemoveExtensionIfUnsuitable(extensions.maintenance3, VK_KHR_MAINTENANCE_3_EXTENSION_NAME);
@ -1343,15 +1339,15 @@ void Device::RemoveUnsuitableExtensions() {
RemoveExtensionFeatureIfUnsuitable(extensions.maintenance6, features.maintenance6,
VK_KHR_MAINTENANCE_6_EXTENSION_NAME);
// VK_KHR_maintenance7 (proposed for Vulkan 1.4, no features)
// VK_KHR_maintenance7
extensions.maintenance7 = loaded_extensions.contains(VK_KHR_MAINTENANCE_7_EXTENSION_NAME);
RemoveExtensionIfUnsuitable(extensions.maintenance7, VK_KHR_MAINTENANCE_7_EXTENSION_NAME);
// VK_KHR_maintenance8 (proposed for Vulkan 1.4, no features)
// VK_KHR_maintenance8
extensions.maintenance8 = loaded_extensions.contains(VK_KHR_MAINTENANCE_8_EXTENSION_NAME);
RemoveExtensionIfUnsuitable(extensions.maintenance8, VK_KHR_MAINTENANCE_8_EXTENSION_NAME);
// VK_KHR_maintenance9 (proposed for Vulkan 1.4, no features)
// VK_KHR_maintenance9
extensions.maintenance9 = loaded_extensions.contains(VK_KHR_MAINTENANCE_9_EXTENSION_NAME);
RemoveExtensionIfUnsuitable(extensions.maintenance9, VK_KHR_MAINTENANCE_9_EXTENSION_NAME);
}

View File

@ -133,10 +133,12 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
X(vkCmdSetDepthBounds);
X(vkCmdSetEvent);
X(vkCmdSetScissor);
X(vkCmdSetScissorWithCountEXT);
X(vkCmdSetStencilCompareMask);
X(vkCmdSetStencilReference);
X(vkCmdSetStencilWriteMask);
X(vkCmdSetViewport);
X(vkCmdSetViewportWithCountEXT);
X(vkCmdWaitEvents);
X(vkCmdBindVertexBuffers2EXT);
X(vkCmdSetCullModeEXT);
@ -243,6 +245,15 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
Proc(dld.vkCmdDrawIndirectCount, dld, "vkCmdDrawIndirectCountKHR", device);
Proc(dld.vkCmdDrawIndexedIndirectCount, dld, "vkCmdDrawIndexedIndirectCountKHR", device);
}
if (!dld.vkCmdSetPrimitiveTopologyEXT) {
Proc(dld.vkCmdSetPrimitiveTopologyEXT, dld, "vkCmdSetPrimitiveTopology", device);
}
if (!dld.vkCmdSetViewportWithCountEXT) {
Proc(dld.vkCmdSetViewportWithCountEXT, dld, "vkCmdSetViewportWithCount", device);
}
if (!dld.vkCmdSetScissorWithCountEXT) {
Proc(dld.vkCmdSetScissorWithCountEXT, dld, "vkCmdSetScissorWithCount", device);
}
#undef X
}

View File

@ -248,12 +248,14 @@ struct DeviceDispatch : InstanceDispatch {
PFN_vkCmdSetLineWidth vkCmdSetLineWidth{};
PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT{};
PFN_vkCmdSetScissor vkCmdSetScissor{};
PFN_vkCmdSetScissorWithCountEXT vkCmdSetScissorWithCountEXT{};
PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask{};
PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT{};
PFN_vkCmdSetStencilReference vkCmdSetStencilReference{};
PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT{};
PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask{};
PFN_vkCmdSetViewport vkCmdSetViewport{};
PFN_vkCmdSetViewportWithCountEXT vkCmdSetViewportWithCountEXT{};
PFN_vkCmdWaitEvents vkCmdWaitEvents{};
PFN_vkCreateBuffer vkCreateBuffer{};
PFN_vkCreateBufferView vkCreateBufferView{};
@ -1361,6 +1363,14 @@ public:
dld->vkCmdSetScissor(handle, first, scissors.size(), scissors.data());
}
void SetViewportWithCountEXT(Span<VkViewport> viewports) const noexcept {
dld->vkCmdSetViewportWithCountEXT(handle, viewports.size(), viewports.data());
}
void SetScissorWithCountEXT(Span<VkRect2D> scissors) const noexcept {
dld->vkCmdSetScissorWithCountEXT(handle, scissors.size(), scissors.data());
}
void SetBlendConstants(const float blend_constants[4]) const noexcept {
dld->vkCmdSetBlendConstants(handle, blend_constants);
}