NVIDIA Driver Workaround.

This commit is contained in:
Dario 2024-11-04 23:00:57 -03:00
parent 646bb813a5
commit 6de3939913
7 changed files with 95 additions and 42 deletions

View File

@ -18,7 +18,6 @@ namespace RT64 {
j["resolution"] = cfg.resolution;
j["displayBuffering"] = cfg.displayBuffering;
j["antialiasing"] = cfg.antialiasing;
j["hardwareResolve"] = cfg.hardwareResolve;
j["resolutionMultiplier"] = cfg.resolutionMultiplier;
j["downsampleMultiplier"] = cfg.downsampleMultiplier;
j["filtering"] = cfg.filtering;
@ -31,6 +30,7 @@ namespace RT64 {
j["refreshRate"] = cfg.refreshRate;
j["refreshRateTarget"] = cfg.refreshRateTarget;
j["internalColorFormat"] = cfg.internalColorFormat;
j["hardwareResolve"] = cfg.hardwareResolve;
j["idleWorkActive"] = cfg.idleWorkActive;
j["developerMode"] = cfg.developerMode;
}
@ -41,7 +41,6 @@ namespace RT64 {
cfg.resolution = j.value("resolution", defaultCfg.resolution);
cfg.displayBuffering = j.value("displayBuffering", defaultCfg.displayBuffering);
cfg.antialiasing = j.value("antialiasing", defaultCfg.antialiasing);
cfg.hardwareResolve = j.value("hardwareResolve", defaultCfg.hardwareResolve);
cfg.resolutionMultiplier = j.value("resolutionMultiplier", defaultCfg.resolutionMultiplier);
cfg.downsampleMultiplier = j.value("downsampleMultiplier", defaultCfg.downsampleMultiplier);
cfg.filtering = j.value("filtering", defaultCfg.filtering);
@ -54,6 +53,7 @@ namespace RT64 {
cfg.refreshRate = j.value("refreshRate", defaultCfg.refreshRate);
cfg.refreshRateTarget = j.value("refreshRateTarget", defaultCfg.refreshRateTarget);
cfg.internalColorFormat = j.value("internalColorFormat", defaultCfg.internalColorFormat);
cfg.hardwareResolve = j.value("hardwareResolve", defaultCfg.hardwareResolve);
cfg.idleWorkActive = j.value("idleWorkActive", defaultCfg.idleWorkActive);
cfg.developerMode = j.value("developerMode", defaultCfg.developerMode);
}
@ -72,7 +72,6 @@ namespace RT64 {
resolution = Resolution::WindowIntegerScale;
displayBuffering = DisplayBuffering::Double;
antialiasing = Antialiasing::None;
hardwareResolve = true;
resolutionMultiplier = 2.0f;
downsampleMultiplier = 1;
filtering = Filtering::AntiAliasedPixelScaling;
@ -85,6 +84,7 @@ namespace RT64 {
refreshRate = RefreshRate::Original;
refreshRateTarget = 60;
internalColorFormat = InternalColorFormat::Automatic;
hardwareResolve = HardwareResolve::Automatic;
idleWorkActive = true;
developerMode = false;
}
@ -100,6 +100,7 @@ namespace RT64 {
clampEnum<Upscale2D>(upscale2D);
clampEnum<RefreshRate>(refreshRate);
clampEnum<InternalColorFormat>(internalColorFormat);
clampEnum<HardwareResolve>(hardwareResolve);
resolutionMultiplier = std::clamp<double>(resolutionMultiplier, 0.0f, ResolutionMultiplierLimit);
downsampleMultiplier = std::clamp<int>(downsampleMultiplier, 1, ResolutionMultiplierLimit);
aspectTarget = std::clamp<double>(aspectTarget, 0.1f, 100.0f);

View File

@ -76,11 +76,17 @@ namespace RT64 {
OptionCount
};
enum class HardwareResolve {
Disabled,
Enabled,
Automatic,
OptionCount
};
GraphicsAPI graphicsAPI;
Resolution resolution;
DisplayBuffering displayBuffering;
Antialiasing antialiasing;
bool hardwareResolve;
double resolutionMultiplier;
int downsampleMultiplier;
Filtering filtering;
@ -93,6 +99,7 @@ namespace RT64 {
RefreshRate refreshRate;
int refreshRateTarget;
InternalColorFormat internalColorFormat;
HardwareResolve hardwareResolve;
bool idleWorkActive;
bool developerMode;
@ -153,6 +160,12 @@ namespace RT64 {
{ UserConfiguration::InternalColorFormat::Automatic, "Automatic" }
});
NLOHMANN_JSON_SERIALIZE_ENUM(UserConfiguration::HardwareResolve, {
{ UserConfiguration::HardwareResolve::Disabled, "Disabled" },
{ UserConfiguration::HardwareResolve::Enabled, "Enabled" },
{ UserConfiguration::HardwareResolve::Automatic, "Automatic" }
});
struct ConfigurationJSON {
static bool read(UserConfiguration &cfg, std::istream &stream);
static bool write(const UserConfiguration &cfg, std::ostream &stream);

View File

@ -3232,6 +3232,13 @@ namespace RT64 {
capabilities.sampleLocations = samplePositionsOption;
description.name = win32::Utf16ToUtf8(adapterDesc.Description);
description.dedicatedVideoMemory = adapterDesc.DedicatedVideoMemory;
description.vendor = RenderDeviceVendor(adapterDesc.VendorId);
LARGE_INTEGER adapterVersion = {};
res = adapter->CheckInterfaceSupport(__uuidof(IDXGIDevice), &adapterVersion);
if (SUCCEEDED(res)) {
description.driverVersion = adapterVersion.QuadPart;
}
if (preferUserChoice) {
break;

View File

@ -156,29 +156,63 @@ namespace RT64 {
return SetupResult::GraphicsDeviceNotFound;
}
// Detect if the application should use hardware resolve or not.
bool usesHardwareResolve = (userConfig.hardwareResolve != UserConfiguration::HardwareResolve::Disabled);
// Driver workarounds.
//
// Wireframe artifacts have been reported when using a high-precision color format on RDNA3 GPUs in D3D12. The workaround is to switch to Vulkan if this is the case.
bool isRDNA3 = device->getDescription().name.find("AMD Radeon RX 7") != std::string::npos;
bool useHDRinD3D12 = (userConfig.graphicsAPI == UserConfiguration::GraphicsAPI::D3D12) && (userConfig.internalColorFormat == UserConfiguration::InternalColorFormat::Automatic) && device->getCapabilities().preferHDR;
if (isRDNA3 && useHDRinD3D12) {
device.reset();
renderInterface.reset();
renderInterface = CreateVulkanInterface();
if (renderInterface == nullptr) {
fprintf(stderr, "Unable to initialize graphics API.\n");
return SetupResult::GraphicsAPINotFound;
const RenderDeviceVendor deviceVendor = device->getDescription().vendor;
const uint64_t driverVersion = device->getDescription().driverVersion;
if (deviceVendor == RenderDeviceVendor::NVIDIA) {
if (createdGraphicsAPI == UserConfiguration::GraphicsAPI::D3D12) {
if (usesHardwareResolve) {
// MSAA Resolve in D3D12 is broken since 565.90. During Resolve operations, the contents from unrelated graphics commands in a queue can leak to other commands
// being run in a different queue even if the resources aren't shared at all. The workaround is to disable hardware resolve and use rasterization instead.
const uint64_t BrokenNVIDIADriverD3D12 = 0x00200000000f19be; // 565.90
const uint64_t FixedNVIDIADriverD3D12 = UINT64_MAX; // No driver is known to fix the issue at the moment.
if ((driverVersion >= BrokenNVIDIADriverD3D12) && (driverVersion < FixedNVIDIADriverD3D12) && (userConfig.hardwareResolve == UserConfiguration::HardwareResolve::Automatic)) {
usesHardwareResolve = false;
}
}
}
}
else if (deviceVendor == RenderDeviceVendor::AMD) {
// Wireframe artifacts have been reported when using a high-precision color format on RDNA3 GPUs in D3D12. The workaround is to switch to Vulkan if this is the case.
bool isRDNA3 = device->getDescription().name.find("AMD Radeon RX 7") != std::string::npos;
bool useHDRinD3D12 = (userConfig.graphicsAPI == UserConfiguration::GraphicsAPI::D3D12) && (userConfig.internalColorFormat == UserConfiguration::InternalColorFormat::Automatic) && device->getCapabilities().preferHDR;
if (isRDNA3 && useHDRinD3D12) {
device.reset();
renderInterface.reset();
renderInterface = CreateVulkanInterface();
if (renderInterface == nullptr) {
fprintf(stderr, "Unable to initialize graphics API.\n");
return SetupResult::GraphicsAPINotFound;
}
createdGraphicsAPI = UserConfiguration::GraphicsAPI::Vulkan;
createdGraphicsAPI = UserConfiguration::GraphicsAPI::Vulkan;
device = renderInterface->createDevice();
if (device == nullptr) {
fprintf(stderr, "Unable to find compatible graphics device.\n");
return SetupResult::GraphicsDeviceNotFound;
device = renderInterface->createDevice();
if (device == nullptr) {
fprintf(stderr, "Unable to find compatible graphics device.\n");
return SetupResult::GraphicsDeviceNotFound;
}
}
}
// Detect if the application should use HDR framebuffers or not.
bool usesHDR;
switch (userConfig.internalColorFormat) {
case UserConfiguration::InternalColorFormat::High:
usesHDR = true;
break;
case UserConfiguration::InternalColorFormat::Automatic:
usesHDR = device->getCapabilities().preferHDR;
break;
case UserConfiguration::InternalColorFormat::Standard:
default:
usesHDR = false;
break;
}
// Call the init hook if one was attached.
RenderHookInit *initHook = GetRenderHookInit();
if (initHook != nullptr) {
@ -201,21 +235,6 @@ namespace RT64 {
// Create the swap chain with the buffer count specified from the configuration.
const uint32_t bufferCount = (userConfig.displayBuffering == UserConfiguration::DisplayBuffering::Triple) ? 3 : 2;
swapChain = presentGraphicsWorker->commandQueue->createSwapChain(appWindow->windowHandle, bufferCount, RenderFormat::B8G8R8A8_UNORM);
// Detect if the application should use HDR framebuffers or not.
bool usesHDR;
switch (userConfig.internalColorFormat) {
case UserConfiguration::InternalColorFormat::High:
usesHDR = true;
break;
case UserConfiguration::InternalColorFormat::Automatic:
usesHDR = device->getCapabilities().preferHDR;
break;
case UserConfiguration::InternalColorFormat::Standard:
default:
usesHDR = false;
break;
}
// Before configuring multisampling, make sure the device actually supports it for the formats we'll use. If it doesn't, turn off antialiasing in the configuration.
const RenderSampleCounts colorSampleCounts = device->getSampleCountsSupported(RenderTarget::colorBufferFormat(usesHDR));
@ -227,7 +246,7 @@ namespace RT64 {
// Create the shader library.
const RenderMultisampling multisampling = RasterShader::generateMultisamplingPattern(userConfig.msaaSampleCount(), device->getCapabilities().sampleLocations);
shaderLibrary = std::make_unique<ShaderLibrary>(usesHDR, userConfig.hardwareResolve);
shaderLibrary = std::make_unique<ShaderLibrary>(usesHDR, usesHardwareResolve);
shaderLibrary->setupCommonShaders(renderInterface.get(), device.get());
shaderLibrary->setupMultisamplingShaders(renderInterface.get(), device.get(), multisampling);

View File

@ -5,6 +5,7 @@
#include "rt64_state.h"
#include <cassert>
#include <cinttypes>
#include "im3d/im3d.h"
#include "im3d/im3d_math.h"
@ -2080,14 +2081,14 @@ namespace RT64 {
ImGui::Text("You must restart the application for this change to be applied.");
}
genConfigChanged = ImGui::Checkbox("Three-Point Filtering", &userConfig.threePointFiltering) || genConfigChanged;
genConfigChanged = ImGui::Checkbox("High Performance State", &userConfig.idleWorkActive) || genConfigChanged;
if (ImGui::Checkbox("Hardware Resolve", &userConfig.hardwareResolve)) {
if (ImGui::Combo("Hardware Resolve", reinterpret_cast<int *>(&userConfig.hardwareResolve), "Disabled\0Enabled\0Automatic\0")) {
// Update shader library to automatically control all logic around hardware resolve.
ext.shaderLibrary->usesHardwareResolve = userConfig.hardwareResolve;
ext.shaderLibrary->usesHardwareResolve = (userConfig.hardwareResolve != UserConfiguration::HardwareResolve::Disabled);
genConfigChanged = true;
}
genConfigChanged = ImGui::Checkbox("Three-Point Filtering", &userConfig.threePointFiltering) || genConfigChanged;
genConfigChanged = ImGui::Checkbox("High Performance State", &userConfig.idleWorkActive) || genConfigChanged;
// Emulator configuration.
ImGui::NewLine();
@ -2430,12 +2431,15 @@ namespace RT64 {
ImGui::NewLine();
const RenderDeviceDescription &description = ext.device->getDescription();
const RenderDeviceCapabilities &capabilities = ext.device->getCapabilities();
ImGui::Text("Display Refresh Rate (OS): %d\n", ext.appWindow->getRefreshRate());
if (capabilities.displayTiming) {
ImGui::Text("Display Refresh Rate (RHI): %d\n", ext.swapChain->getRefreshRate());
}
ImGui::Text("Vendor ID: 0x%08x", uint32_t(description.vendor));
ImGui::Text("Driver Version: 0x%016" PRIx64, description.driverVersion);
ImGui::Text("Raytracing: %d", capabilities.raytracing);
ImGui::Text("Raytracing State Update: %d", capabilities.raytracingStateUpdate);
ImGui::Text("Sample Locations: %d", capabilities.sampleLocations);

View File

@ -63,6 +63,13 @@ namespace RT64 {
// Enums.
enum class RenderDeviceVendor {
UNKNOWN = 0x0,
AMD = 0x1002,
NVIDIA = 0x10DE,
INTEL = 0x8086
};
enum class RenderFormat {
UNKNOWN,
R32G32B32A32_TYPELESS,
@ -1692,7 +1699,8 @@ namespace RT64 {
struct RenderDeviceDescription {
std::string name = "Unknown";
uint32_t driverVersion = 0;
RenderDeviceVendor vendor = RenderDeviceVendor::UNKNOWN;
uint64_t driverVersion = 0;
uint64_t dedicatedVideoMemory = 0;
};

View File

@ -3389,6 +3389,7 @@ namespace RT64 {
physicalDevice = physicalDevices[i];
description.name = std::string(deviceProperties.deviceName);
description.driverVersion = deviceProperties.driverVersion;
description.vendor = RenderDeviceVendor(deviceProperties.vendorID);
currentDeviceTypeScore = deviceTypeScore;
}
}