diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index f8216d08a..66e233a45 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml @@ -74,6 +74,7 @@ + @string/renderer_accuracy_low @string/renderer_accuracy_normal @string/renderer_accuracy_high @string/renderer_accuracy_extreme @@ -83,6 +84,7 @@ 0 1 2 + 3 diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 518184aa2..f0f53f70d 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -610,6 +610,7 @@ None + Low Normal High Extreme (Slow) diff --git a/src/citron/configuration/shared_translation.cpp b/src/citron/configuration/shared_translation.cpp index 607ea1477..6d9f9cb1c 100644 --- a/src/citron/configuration/shared_translation.cpp +++ b/src/citron/configuration/shared_translation.cpp @@ -352,6 +352,7 @@ std::unique_ptr ComboboxEnumeration(QWidget* parent) { }}); translations->insert({Settings::EnumMetadata::Index(), { + PAIR(GpuAccuracy, Low, tr("Low")), PAIR(GpuAccuracy, Normal, tr("Normal")), PAIR(GpuAccuracy, High, tr("High")), PAIR(GpuAccuracy, Extreme, tr("Extreme")), diff --git a/src/citron/configuration/shared_translation.h b/src/citron/configuration/shared_translation.h index 16487dab0..be6fa948b 100644 --- a/src/citron/configuration/shared_translation.h +++ b/src/citron/configuration/shared_translation.h @@ -51,6 +51,7 @@ static const std::map use_docked_mode_texts_map }; static const std::map gpu_accuracy_texts_map = { + {Settings::GpuAccuracy::Low, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Low"))}, {Settings::GpuAccuracy::Normal, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Normal"))}, {Settings::GpuAccuracy::High, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "High"))}, {Settings::GpuAccuracy::Extreme, QStringLiteral(QT_TRANSLATE_NOOP("GMainWindow", "Extreme"))}, diff --git a/src/citron/main.cpp b/src/citron/main.cpp index 94f2c9017..4fbd021e2 100644 --- a/src/citron/main.cpp +++ b/src/citron/main.cpp @@ -3960,14 +3960,21 @@ void GMainWindow::OnToggleDockedMode() { void GMainWindow::OnToggleGpuAccuracy() { switch (Settings::values.gpu_accuracy.GetValue()) { - case Settings::GpuAccuracy::High: { + case Settings::GpuAccuracy::Low: { Settings::values.gpu_accuracy.SetValue(Settings::GpuAccuracy::Normal); break; } - case Settings::GpuAccuracy::Normal: + case Settings::GpuAccuracy::Normal: { + Settings::values.gpu_accuracy.SetValue(Settings::GpuAccuracy::High); + break; + } + case Settings::GpuAccuracy::High: { + Settings::values.gpu_accuracy.SetValue(Settings::GpuAccuracy::Low); + break; + } case Settings::GpuAccuracy::Extreme: default: { - Settings::values.gpu_accuracy.SetValue(Settings::GpuAccuracy::High); + Settings::values.gpu_accuracy.SetValue(Settings::GpuAccuracy::Normal); break; } } diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 5ee33b5c4..080e5f032 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -150,6 +150,12 @@ bool IsGPULevelHigh() { values.current_gpu_accuracy == GpuAccuracy::High; } +bool IsGPULevelNormal() { + return values.current_gpu_accuracy == GpuAccuracy::Extreme || + values.current_gpu_accuracy == GpuAccuracy::High || + values.current_gpu_accuracy == GpuAccuracy::Normal; +} + bool IsFastmemEnabled() { if (values.cpu_debug_mode) { return static_cast(values.cpuopt_fastmem); diff --git a/src/common/settings.h b/src/common/settings.h index 63b452346..543755fc5 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -393,7 +393,7 @@ struct Values { #else GpuAccuracy::High, #endif - GpuAccuracy::Normal, + GpuAccuracy::Low, GpuAccuracy::Extreme, "gpu_accuracy", Category::RendererAdvanced, @@ -661,6 +661,7 @@ extern Values values; void UpdateGPUAccuracy(); bool IsGPULevelExtreme(); bool IsGPULevelHigh(); +bool IsGPULevelNormal(); bool IsFastmemEnabled(); void SetNceEnabled(bool is_64bit); diff --git a/src/common/settings_enums.h b/src/common/settings_enums.h index a655fe07d..36dfcc9a7 100644 --- a/src/common/settings_enums.h +++ b/src/common/settings_enums.h @@ -130,7 +130,7 @@ ENUM(RendererBackend, OpenGL, Vulkan, Null); ENUM(ShaderBackend, Glsl, Glasm, SpirV); -ENUM(GpuAccuracy, Normal, High, Extreme); +ENUM(GpuAccuracy, Low, Normal, High, Extreme); ENUM(CpuBackend, Dynarmic, Nce); diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index 70991d7af..040f13b3b 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -65,6 +65,8 @@ static const char* TranslateRenderer(Settings::RendererBackend backend) { static const char* TranslateGPUAccuracyLevel(Settings::GpuAccuracy backend) { switch (backend) { + case Settings::GpuAccuracy::Low: + return "Low"; case Settings::GpuAccuracy::Normal: return "Normal"; case Settings::GpuAccuracy::High: diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp index dae02b12f..f147ef2b0 100644 --- a/src/video_core/dma_pusher.cpp +++ b/src/video_core/dma_pusher.cpp @@ -98,7 +98,8 @@ bool DmaPusher::Step() { &command_headers); ProcessCommands(headers); }; - if (Settings::IsGPULevelHigh()) { + if (Settings::IsGPULevelNormal()) { + // Normal/High/Extreme: Use safe reads for most operations if (dma_state.method >= MacroRegistersStart) { unsafe_process(); return true; @@ -106,6 +107,10 @@ bool DmaPusher::Step() { safe_process(); return true; } + // Low accuracy: Use unsafe reads for maximum performance everywhere + unsafe_process(); + return true; + // Note: The code below is unreachable for Low, but kept for reference // Even in normal accuracy, use safe reads for KeplerCompute inline methods if (subchannel_type[dma_state.subchannel] == Engines::EngineTypes::KeplerCompute && dma_state.method == ComputeInline) { diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 0d47b032c..9a459e3f6 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -221,7 +221,8 @@ void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool } void Maxwell3D::RefreshParametersImpl() { - if (!Settings::IsGPULevelHigh()) { + if (!Settings::IsGPULevelNormal()) { + // Skip parameter refresh for Low accuracy - ultimate performance return; } size_t current_index = 0; diff --git a/src/video_core/fence_manager.h b/src/video_core/fence_manager.h index 2135f1f2d..49555092f 100644 --- a/src/video_core/fence_manager.h +++ b/src/video_core/fence_manager.h @@ -72,7 +72,7 @@ public: } void SignalFence(std::function&& func) { - bool delay_fence = Settings::IsGPULevelHigh(); + bool delay_fence = Settings::IsGPULevelNormal(); if constexpr (!can_async_check) { TryReleasePendingFences(); } diff --git a/src/video_core/query_cache/query_cache.h b/src/video_core/query_cache/query_cache.h index 08b779055..2a1c92c47 100644 --- a/src/video_core/query_cache/query_cache.h +++ b/src/video_core/query_cache/query_cache.h @@ -257,7 +257,7 @@ void QueryCacheBase::CounterReport(GPUVAddr addr, QueryType counter_type }; u8* pointer = impl->device_memory.template GetPointer(cpu_addr); u8* pointer_timestamp = impl->device_memory.template GetPointer(cpu_addr + 8); - bool is_synced = !Settings::IsGPULevelHigh() && is_fence; + bool is_synced = !Settings::IsGPULevelNormal() && is_fence; std::function operation([this, is_synced, streamer, query_base = query, query_location, pointer, pointer_timestamp] { if (True(query_base->flags & QueryFlagBits::IsInvalidated)) { @@ -287,7 +287,8 @@ void QueryCacheBase::CounterReport(GPUVAddr addr, QueryType counter_type if (is_fence) { impl->rasterizer.SignalFence(std::move(operation)); } else { - if (!Settings::IsGPULevelHigh() && counter_type == QueryType::Payload) { + if (!Settings::IsGPULevelNormal() && counter_type == QueryType::Payload) { + // Low accuracy: Immediately write payload for ultimate performance if (has_timestamp) { u64 timestamp = impl->gpu.GetTicks(); u64 value = static_cast(payload); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 45cc31fd7..723d1b29b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -545,7 +545,8 @@ bool RasterizerOpenGL::MustFlushRegion(DAddr addr, u64 size, VideoCommon::CacheT return true; } } - if (!Settings::IsGPULevelHigh()) { + if (!Settings::IsGPULevelNormal()) { + // Skip texture cache checks for Low accuracy - ultimate performance return false; } if (True(which & VideoCommon::CacheType::TextureCache)) { @@ -740,7 +741,8 @@ bool RasterizerOpenGL::AccelerateConditionalRendering() { // Reimplement Host conditional rendering. return false; } - // Medium / Low Hack: stub any checks on queries written into the buffer cache. + // Normal / Low Hack: stub any checks on queries written into the buffer cache. + // Low accuracy: Always stub for maximum performance const GPUVAddr condition_address{maxwell3d->regs.render_enable.Address()}; Maxwell::ReportSemaphore::Compare cmp; if (gpu_memory->IsMemoryDirty(condition_address, sizeof(cmp), diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp index 715ee028e..9d5ec7a08 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp @@ -153,7 +153,7 @@ public: ReserveHostQuery(); scheduler.Record([query_pool = current_query_pool, query_index = current_bank_slot](vk::CommandBuffer cmdbuf) { - const bool use_precise = Settings::IsGPULevelHigh(); + const bool use_precise = Settings::IsGPULevelNormal(); cmdbuf.BeginQuery(query_pool, static_cast(query_index), use_precise ? VK_QUERY_CONTROL_PRECISE_BIT : 0); }); @@ -1415,8 +1415,9 @@ bool QueryCacheRuntime::HostConditionalRenderingCompareValues(VideoCommon::Looku return false; } - const bool is_gpu_high = Settings::IsGPULevelHigh(); + const bool is_gpu_high = Settings::IsGPULevelNormal(); if (!is_gpu_high && impl->device.GetDriverID() == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) { + // Low accuracy: stub conditional rendering on Intel for performance return true; } diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 91071f8fe..fdc102f51 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -565,7 +565,8 @@ bool RasterizerVulkan::MustFlushRegion(DAddr addr, u64 size, VideoCommon::CacheT return true; } } - if (!Settings::IsGPULevelHigh()) { + if (!Settings::IsGPULevelNormal()) { + // Skip texture cache checks for Low accuracy - ultimate performance return false; } if (True(which & VideoCommon::CacheType::TextureCache)) { diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 146923db4..461cdb809 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -260,11 +260,14 @@ void Scheduler::AllocateNewContext() { if (query_cache) { #if ANDROID if (Settings::IsGPULevelHigh()) { - // This is problematic on Android, disable on GPU Normal. + // This is problematic on Android, disable on GPU Normal and Low. query_cache->NotifySegment(true); } #else - query_cache->NotifySegment(true); + if (Settings::IsGPULevelNormal()) { + // Skip query cache operations for Low accuracy + query_cache->NotifySegment(true); + } #endif } } @@ -278,13 +281,16 @@ void Scheduler::InvalidateState() { void Scheduler::EndPendingOperations() { #if ANDROID if (Settings::IsGPULevelHigh()) { - // This is problematic on Android, disable on GPU Normal. + // This is problematic on Android, disable on GPU Normal and Low. // query_cache->DisableStreams(); } #else // query_cache->DisableStreams(); #endif - query_cache->NotifySegment(false); + if (Settings::IsGPULevelNormal()) { + // Skip query cache operations for Low accuracy + query_cache->NotifySegment(false); + } EndRenderPass(); }