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 <zephyron@citron-emu.org>
This commit is contained in:
Zephyron 2025-03-13 16:30:23 +10:00
parent 12c63997d2
commit f2931c7566

View file

@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm> #include <algorithm>
@ -928,6 +929,8 @@ bool AccelerateDMA::BufferToImage(const Tegra::DMA::ImageCopy& copy_info,
void RasterizerVulkan::UpdateDynamicStates() { void RasterizerVulkan::UpdateDynamicStates() {
auto& regs = maxwell3d->regs; auto& regs = maxwell3d->regs;
// Always update base dynamic states.
UpdateViewportsState(regs); UpdateViewportsState(regs);
UpdateScissorsState(regs); UpdateScissorsState(regs);
UpdateDepthBias(regs); UpdateDepthBias(regs);
@ -935,7 +938,9 @@ void RasterizerVulkan::UpdateDynamicStates() {
UpdateDepthBounds(regs); UpdateDepthBounds(regs);
UpdateStencilFaces(regs); UpdateStencilFaces(regs);
UpdateLineWidth(regs); UpdateLineWidth(regs);
if (device.IsExtExtendedDynamicStateSupported()) { if (device.IsExtExtendedDynamicStateSupported()) {
// Update extended dynamic states.
UpdateCullMode(regs); UpdateCullMode(regs);
UpdateDepthCompareOp(regs); UpdateDepthCompareOp(regs);
UpdateFrontFace(regs); UpdateFrontFace(regs);
@ -946,16 +951,44 @@ void RasterizerVulkan::UpdateDynamicStates() {
UpdateDepthTestEnable(regs); UpdateDepthTestEnable(regs);
UpdateDepthWriteEnable(regs); UpdateDepthWriteEnable(regs);
UpdateStencilTestEnable(regs); UpdateStencilTestEnable(regs);
if (device.IsExtExtendedDynamicState2Supported()) { if (device.IsExtExtendedDynamicState2Supported()) {
UpdatePrimitiveRestartEnable(regs); UpdatePrimitiveRestartEnable(regs);
UpdateRasterizerDiscardEnable(regs); UpdateRasterizerDiscardEnable(regs);
UpdateDepthBiasEnable(regs); UpdateDepthBiasEnable(regs);
} }
if (device.IsExtExtendedDynamicState3EnablesSupported()) { 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<u32>(!hasFloat);
UpdateLogicOpEnable(regs);
// Restore the original value.
regs.logic_op.enable = oldLogicOpEnable;
} else {
UpdateLogicOpEnable(regs);
}
UpdateDepthClampEnable(regs); UpdateDepthClampEnable(regs);
} }
} }
if (device.IsExtExtendedDynamicState2ExtrasSupported()) { if (device.IsExtExtendedDynamicState2ExtrasSupported()) {
UpdateLogicOp(regs); UpdateLogicOp(regs);
} }
@ -963,6 +996,7 @@ void RasterizerVulkan::UpdateDynamicStates() {
UpdateBlending(regs); UpdateBlending(regs);
} }
} }
if (device.IsExtVertexInputDynamicStateSupported()) { if (device.IsExtVertexInputDynamicStateSupported()) {
UpdateVertexInput(regs); UpdateVertexInput(regs);
} }