From f2931c756690d57716610ea19446cb2619d967ea Mon Sep 17 00:00:00 2001 From: Zephyron Date: Thu, 13 Mar 2025 16:30:23 +1000 Subject: [PATCH] vulkan: Implement AMD driver workaround for logic operations - Added conditional check for AMD graphics drivers - Automatically disable logic operations when float vertex attributes are present to work around driver quirks - Maintain original logic op state to preserve emulator behavior - Prepare dynamic state management infrastructure for future OpenGL implementation changes OpenGL implementation will follow in subsequent commits. Signed-off-by: Zephyron --- .../renderer_vulkan/vk_rasterizer.cpp | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 8ba50a834..cd0b255a0 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -1,4 +1,5 @@ // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include @@ -928,6 +929,8 @@ bool AccelerateDMA::BufferToImage(const Tegra::DMA::ImageCopy& copy_info, void RasterizerVulkan::UpdateDynamicStates() { auto& regs = maxwell3d->regs; + + // Always update base dynamic states. UpdateViewportsState(regs); UpdateScissorsState(regs); UpdateDepthBias(regs); @@ -935,7 +938,9 @@ void RasterizerVulkan::UpdateDynamicStates() { UpdateDepthBounds(regs); UpdateStencilFaces(regs); UpdateLineWidth(regs); + if (device.IsExtExtendedDynamicStateSupported()) { + // Update extended dynamic states. UpdateCullMode(regs); UpdateDepthCompareOp(regs); UpdateFrontFace(regs); @@ -946,16 +951,44 @@ void RasterizerVulkan::UpdateDynamicStates() { UpdateDepthTestEnable(regs); UpdateDepthWriteEnable(regs); UpdateStencilTestEnable(regs); + if (device.IsExtExtendedDynamicState2Supported()) { UpdatePrimitiveRestartEnable(regs); UpdateRasterizerDiscardEnable(regs); UpdateDepthBiasEnable(regs); } + if (device.IsExtExtendedDynamicState3EnablesSupported()) { - UpdateLogicOpEnable(regs); + // Store the original logic_op.enable state. + const auto oldLogicOpEnable = regs.logic_op.enable; + + // Determine if the current driver is an AMD driver. + bool isAmdDriver = (device.GetDriverID() == VK_DRIVER_ID_AMD_OPEN_SOURCE || + device.GetDriverID() == VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR || + device.GetDriverID() == VK_DRIVER_ID_AMD_PROPRIETARY || + device.GetDriverID() == VK_DRIVER_ID_AMD_PROPRIETARY_KHR || + device.GetDriverID() == VK_DRIVER_ID_MESA_RADV); + + if (isAmdDriver) { + // Check if any vertex attribute is of type Float. + bool hasFloat = std::any_of( + regs.vertex_attrib_format.begin(), regs.vertex_attrib_format.end(), + [](const auto& attrib) { + return attrib.type == Tegra::Engines::Maxwell3D::Regs::VertexAttribute::Type::Float; + }); + + // For AMD drivers, disable logic_op if a float attribute is present. + regs.logic_op.enable = static_cast(!hasFloat); + UpdateLogicOpEnable(regs); + // Restore the original value. + regs.logic_op.enable = oldLogicOpEnable; + } else { + UpdateLogicOpEnable(regs); + } UpdateDepthClampEnable(regs); } } + if (device.IsExtExtendedDynamicState2ExtrasSupported()) { UpdateLogicOp(regs); } @@ -963,6 +996,7 @@ void RasterizerVulkan::UpdateDynamicStates() { UpdateBlending(regs); } } + if (device.IsExtVertexInputDynamicStateSupported()) { UpdateVertexInput(regs); }