From 9d98d507b0692c456fa006c8fda00d79cc45b471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dar=C3=ADo?= Date: Fri, 31 Jan 2025 16:43:23 -0300 Subject: [PATCH] Add low-end defaults for low-end devices. (#252) * Add low-end defaults for low-end devices. Uses either the reported type by the API or the VRAM. * Update video.cpp * Check for UMA flag on D3D12 to detect integrated GPUs. * Display device type and UMA in inspector. * Dynamic depth bias on F1. --------- Co-authored-by: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com> --- UnleashedRecomp/gpu/rhi/plume_d3d12.cpp | 9 +++ .../gpu/rhi/plume_render_interface_types.h | 12 ++++ UnleashedRecomp/gpu/rhi/plume_vulkan.cpp | 16 +++++ UnleashedRecomp/gpu/video.cpp | 59 ++++++++++++++++++- 4 files changed, 95 insertions(+), 1 deletion(-) diff --git a/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp b/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp index 515d4331..32aac2a8 100644 --- a/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp +++ b/UnleashedRecomp/gpu/rhi/plume_d3d12.cpp @@ -3324,6 +3324,14 @@ namespace plume { dynamicDepthBiasOption = d3d12Options16.DynamicDepthBiasSupported; } + // Check if the architecture has UMA. + bool uma = false; + D3D12_FEATURE_DATA_ARCHITECTURE1 architecture1 = {}; + res = deviceOption->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE1, &architecture1, sizeof(architecture1)); + if (SUCCEEDED(res)) { + uma = architecture1.UMA; + } + // Pick this adapter and device if it has better feature support than the current one. bool preferOverNothing = (adapter == nullptr) || (d3d == nullptr); bool preferVideoMemory = adapterDesc.DedicatedVideoMemory > description.dedicatedVideoMemory; @@ -3346,6 +3354,7 @@ namespace plume { capabilities.sampleLocations = samplePositionsOption; capabilities.triangleFan = triangleFanSupportOption; capabilities.dynamicDepthBias = dynamicDepthBiasOption; + capabilities.uma = uma; description.name = Utf16ToUtf8(adapterDesc.Description); description.dedicatedVideoMemory = adapterDesc.DedicatedVideoMemory; diff --git a/UnleashedRecomp/gpu/rhi/plume_render_interface_types.h b/UnleashedRecomp/gpu/rhi/plume_render_interface_types.h index 89974ced..7352e863 100644 --- a/UnleashedRecomp/gpu/rhi/plume_render_interface_types.h +++ b/UnleashedRecomp/gpu/rhi/plume_render_interface_types.h @@ -475,6 +475,14 @@ namespace plume { typedef uint32_t RenderSampleCounts; + enum class RenderDeviceType { + UNKNOWN, + INTEGRATED, + DISCRETE, + VIRTUAL, + CPU + }; + // Global functions. constexpr uint32_t RenderFormatSize(RenderFormat format) { @@ -1754,6 +1762,7 @@ namespace plume { struct RenderDeviceDescription { std::string name = "Unknown"; + RenderDeviceType type = RenderDeviceType::UNKNOWN; uint32_t driverVersion = 0; uint64_t dedicatedVideoMemory = 0; }; @@ -1780,6 +1789,9 @@ namespace plume { // Draw. bool triangleFan = false; bool dynamicDepthBias = false; + + // UMA. + bool uma = false; }; struct RenderInterfaceCapabilities { diff --git a/UnleashedRecomp/gpu/rhi/plume_vulkan.cpp b/UnleashedRecomp/gpu/rhi/plume_vulkan.cpp index 8d7c2ca7..192c7ed5 100644 --- a/UnleashedRecomp/gpu/rhi/plume_vulkan.cpp +++ b/UnleashedRecomp/gpu/rhi/plume_vulkan.cpp @@ -705,6 +705,21 @@ namespace plume { } } + static RenderDeviceType toDeviceType(VkPhysicalDeviceType type) { + switch (type) { + case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: + return RenderDeviceType::INTEGRATED; + case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: + return RenderDeviceType::DISCRETE; + case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: + return RenderDeviceType::VIRTUAL; + case VK_PHYSICAL_DEVICE_TYPE_CPU: + return RenderDeviceType::CPU; + default: + return RenderDeviceType::UNKNOWN; + } + } + static void setObjectName(VkDevice device, VkDebugReportObjectTypeEXT objectType, uint64_t object, const std::string &name) { # ifdef VULKAN_OBJECT_NAMES_ENABLED VkDebugMarkerObjectNameInfoEXT nameInfo = {}; @@ -3496,6 +3511,7 @@ namespace plume { if (preferOption) { physicalDevice = physicalDevices[i]; description.name = std::string(deviceProperties.deviceName); + description.type = toDeviceType(deviceProperties.deviceType); description.driverVersion = deviceProperties.driverVersion; currentDeviceTypeScore = deviceTypeScore; } diff --git a/UnleashedRecomp/gpu/video.cpp b/UnleashedRecomp/gpu/video.cpp index 3c640a61..282d75cd 100644 --- a/UnleashedRecomp/gpu/video.cpp +++ b/UnleashedRecomp/gpu/video.cpp @@ -1480,6 +1480,31 @@ static void BeginCommandList() commandList->setGraphicsDescriptorSet(g_samplerDescriptorSet.get(), 3); } +template +static void ApplyLowEndDefault(ConfigDef &configDef, T newDefault, bool &changed) +{ + if (configDef.IsDefaultValue() && !configDef.IsLoadedFromConfig) + { + configDef = newDefault; + changed = true; + } +} + +static void ApplyLowEndDefaults() +{ + bool changed = false; + + ApplyLowEndDefault(Config::AntiAliasing, EAntiAliasing::MSAA2x, changed); + ApplyLowEndDefault(Config::ShadowResolution, EShadowResolution::Original, changed); + ApplyLowEndDefault(Config::TransparencyAntiAliasing, false, changed); + ApplyLowEndDefault(Config::GITextureFiltering, EGITextureFiltering::Bilinear, changed); + + if (changed) + { + Config::Save(); + } +} + bool Video::CreateHostDevice(const char *sdlVideoDriver) { for (uint32_t i = 0; i < 16; i++) @@ -1527,9 +1552,21 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver) return false; } + g_capabilities = g_device->getCapabilities(); + LoadEmbeddedResources(); - g_capabilities = g_device->getCapabilities(); + constexpr uint64_t LowEndMemoryLimit = 2048ULL * 1024ULL * 1024ULL; + RenderDeviceDescription deviceDescription = g_device->getDescription(); + bool lowEndType = deviceDescription.type != RenderDeviceType::UNKNOWN && deviceDescription.type != RenderDeviceType::DISCRETE; + bool lowEndMemory = deviceDescription.dedicatedVideoMemory < LowEndMemoryLimit; + bool lowEndUMA = deviceDescription.type == RenderDeviceType::UNKNOWN && g_capabilities.uma; + if (lowEndType || lowEndMemory || lowEndUMA) + { + // Switch to low end defaults if a non-discrete GPU was detected or a low amount of VRAM was detected. + // Checking for UMA on D3D12 seems to be a reliable way to detect integrated GPUs. + ApplyLowEndDefaults(); + } g_queue = g_device->createCommandQueue(RenderCommandListType::DIRECT); @@ -2032,6 +2069,23 @@ static Profiler g_renderDirectorProfiler; static bool g_profilerVisible; static bool g_profilerWasToggled; +static const char *DeviceTypeName(RenderDeviceType type) +{ + switch (type) + { + case RenderDeviceType::INTEGRATED: + return "Integrated"; + case RenderDeviceType::DISCRETE: + return "Discrete"; + case RenderDeviceType::VIRTUAL: + return "Virtual"; + case RenderDeviceType::CPU: + return "CPU"; + default: + return "Unknown"; + } +} + static void DrawProfiler() { bool toggleProfiler = SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_F1] != 0; @@ -2095,11 +2149,14 @@ static void DrawProfiler() ImGui::Text("Present Wait: %s", g_capabilities.presentWait ? "Supported" : "Unsupported"); ImGui::Text("Triangle Fan: %s", g_capabilities.triangleFan ? "Supported" : "Unsupported"); + ImGui::Text("Dynamic Depth Bias: %s", g_capabilities.dynamicDepthBias ? "Supported" : "Unsupported"); ImGui::NewLine(); ImGui::Text("API: %s", g_vulkan ? "Vulkan" : "D3D12"); ImGui::Text("Device: %s", g_device->getDescription().name.c_str()); + ImGui::Text("Device Type: %s", DeviceTypeName(g_device->getDescription().type)); ImGui::Text("VRAM: %.2f MiB", (double)(g_device->getDescription().dedicatedVideoMemory) / (1024.0 * 1024.0)); + ImGui::Text("UMA: %s", g_capabilities.uma ? "Supported" : "Unsupported"); const char* sdlVideoDriver = SDL_GetCurrentVideoDriver(); if (sdlVideoDriver != nullptr)