From 281838fde1e51f26ccd0d462f19beb2a0886904c Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Fri, 18 Nov 2022 20:48:39 +0000 Subject: [PATCH] Apply GPU readback hack to both buffers and textures And rename as appropriate. --- .../main/cpp/skyline/common/android_settings.h | 2 +- app/src/main/cpp/skyline/common/settings.h | 4 +++- app/src/main/cpp/skyline/gpu/buffer.cpp | 17 ++++++++++++++++- app/src/main/cpp/skyline/gpu/buffer.h | 5 +++++ .../main/cpp/skyline/gpu/texture/texture.cpp | 2 +- .../java/emu/skyline/utils/NativeSettings.kt | 4 +++- .../emu/skyline/utils/PreferenceSettings.kt | 4 +++- app/src/main/res/values/strings.xml | 8 +++++--- app/src/main/res/xml/preferences.xml | 12 ++++++++---- 9 files changed, 45 insertions(+), 13 deletions(-) diff --git a/app/src/main/cpp/skyline/common/android_settings.h b/app/src/main/cpp/skyline/common/android_settings.h index 9d8b3ec6..c6d026f4 100644 --- a/app/src/main/cpp/skyline/common/android_settings.h +++ b/app/src/main/cpp/skyline/common/android_settings.h @@ -40,7 +40,7 @@ namespace skyline { gpuDriver = ktSettings.GetString("gpuDriver"); gpuDriverLibraryName = ktSettings.GetString("gpuDriverLibraryName"); executorSlotCount = ktSettings.GetInt("executorSlotCount"); - enableTextureReadbackHack = ktSettings.GetBool("enableTextureReadbackHack"); + enableFastGpuReadbackHack = ktSettings.GetBool("enableFastGpuReadbackHack"); isAudioOutputDisabled = ktSettings.GetBool("isAudioOutputDisabled"); validationLayer = ktSettings.GetBool("validationLayer"); }; diff --git a/app/src/main/cpp/skyline/common/settings.h b/app/src/main/cpp/skyline/common/settings.h index baa17bc6..4c8ee61b 100644 --- a/app/src/main/cpp/skyline/common/settings.h +++ b/app/src/main/cpp/skyline/common/settings.h @@ -72,7 +72,9 @@ namespace skyline { Setting gpuDriver; //!< The label of the GPU driver to use Setting gpuDriverLibraryName; //!< The name of the GPU driver library to use Setting executorSlotCount; //!< Number of GPU executor slots that can be used concurrently - Setting enableTextureReadbackHack; //!< If the CPU texture readback skipping hack should be used + + // Hacks + Setting enableFastGpuReadbackHack; //!< If the CPU texture readback skipping hack should be used // Audio Setting isAudioOutputDisabled; //!< Disables audio output diff --git a/app/src/main/cpp/skyline/gpu/buffer.cpp b/app/src/main/cpp/skyline/gpu/buffer.cpp index 54fb63dd..0fe94cbc 100644 --- a/app/src/main/cpp/skyline/gpu/buffer.cpp +++ b/app/src/main/cpp/skyline/gpu/buffer.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "buffer.h" namespace skyline::gpu { @@ -38,8 +39,14 @@ namespace skyline::gpu { // If this mutex would cause other callbacks to be blocked then we should block on this mutex in advance std::shared_ptr waitCycle{}; do { - if (waitCycle) + if (waitCycle) { + i64 startNs{buffer->accumulatedGuestWaitCounter > FastReadbackHackWaitCountThreshold ? util::GetTimeNs() : 0}; waitCycle->Wait(); + if (startNs) + buffer->accumulatedGuestWaitTime += std::chrono::nanoseconds(util::GetTimeNs() - startNs); + + buffer->accumulatedGuestWaitCounter++; + } std::scoped_lock lock{*buffer}; if (waitCycle && buffer->cycle == waitCycle) { @@ -89,6 +96,14 @@ namespace skyline::gpu { return true; } + if (buffer->accumulatedGuestWaitTime > FastReadbackHackWaitTimeThreshold && *buffer->gpu.state.settings->enableFastGpuReadbackHack) { + // As opposed to skipping readback as we do for textures, with buffers we can still perform the readback but just without syncinc the GPU + // While the read data may be invalid it's still better than nothing and works in most cases + memcpy(buffer->mirror.data(), buffer->backing.data(), buffer->mirror.size()); + buffer->dirtyState = DirtyState::Clean; + return true; + } + std::unique_lock lock{*buffer, std::try_to_lock}; if (!lock) return false; diff --git a/app/src/main/cpp/skyline/gpu/buffer.h b/app/src/main/cpp/skyline/gpu/buffer.h index 6bb15b51..1b286748 100644 --- a/app/src/main/cpp/skyline/gpu/buffer.h +++ b/app/src/main/cpp/skyline/gpu/buffer.h @@ -90,6 +90,11 @@ namespace skyline::gpu { static constexpr size_t FrequentlyLockedThreshold{2}; //!< Threshold for the number of times a buffer can be locked (not from context locks, only normal) before it should be considered frequently locked size_t accumulatedCpuLockCounter{}; //!< Number of times buffer has been locked through non-ContextLocks + static constexpr size_t FastReadbackHackWaitCountThreshold{8}; //!< Threshold for the number of times a buffer can be waited on before it should be considered for the readback hack + static constexpr std::chrono::nanoseconds FastReadbackHackWaitTimeThreshold{constant::NsInSecond / 2}; //!< Threshold for the amount of time buffer texture can be waited on before it should be considered for the readback hack, `SkipReadbackHackWaitCountThreshold` needs to be hit before this + size_t accumulatedGuestWaitCounter{}; //!< Total number of times the buffer has been waited on + std::chrono::nanoseconds accumulatedGuestWaitTime{}; //!< Amount of time the buffer has been waited on for since the `FastReadbackHackWaitTimeThreshold`th wait on it by the guest + /** * @brief Resets all megabuffer tracking state */ diff --git a/app/src/main/cpp/skyline/gpu/texture/texture.cpp b/app/src/main/cpp/skyline/gpu/texture/texture.cpp index 4dba914b..6e50ac13 100644 --- a/app/src/main/cpp/skyline/gpu/texture/texture.cpp +++ b/app/src/main/cpp/skyline/gpu/texture/texture.cpp @@ -225,7 +225,7 @@ namespace skyline::gpu { return true; // If the texture is already CPU dirty or we can transition it to being CPU dirty then we don't need to do anything } - if (texture->accumulatedGuestWaitTime > SkipReadbackHackWaitTimeThreshold && *texture->gpu.state.settings->enableTextureReadbackHack) { + if (texture->accumulatedGuestWaitTime > SkipReadbackHackWaitTimeThreshold && *texture->gpu.state.settings->enableFastGpuReadbackHack) { texture->dirtyState = DirtyState::Clean; return true; } diff --git a/app/src/main/java/emu/skyline/utils/NativeSettings.kt b/app/src/main/java/emu/skyline/utils/NativeSettings.kt index b4a976af..5f2c825c 100644 --- a/app/src/main/java/emu/skyline/utils/NativeSettings.kt +++ b/app/src/main/java/emu/skyline/utils/NativeSettings.kt @@ -26,7 +26,9 @@ class NativeSettings(context : Context, pref : PreferenceSettings) { var gpuDriver : String = if (pref.gpuDriver == PreferenceSettings.SYSTEM_GPU_DRIVER) "" else pref.gpuDriver var gpuDriverLibraryName : String = if (pref.gpuDriver == PreferenceSettings.SYSTEM_GPU_DRIVER) "" else GpuDriverHelper.getLibraryName(context, pref.gpuDriver) var executorSlotCount : Int = pref.executorSlotCount - var enableTextureReadbackHack : Boolean = pref.enableTextureReadbackHack + + // Hacks + var enableFastGpuReadbackHack : Boolean = pref.enableFastGpuReadbackHack // Audio var isAudioOutputDisabled : Boolean = pref.isAudioOutputDisabled diff --git a/app/src/main/java/emu/skyline/utils/PreferenceSettings.kt b/app/src/main/java/emu/skyline/utils/PreferenceSettings.kt index ca0dcd8b..29378f22 100644 --- a/app/src/main/java/emu/skyline/utils/PreferenceSettings.kt +++ b/app/src/main/java/emu/skyline/utils/PreferenceSettings.kt @@ -39,7 +39,9 @@ class PreferenceSettings @Inject constructor(@ApplicationContext private val con // GPU var gpuDriver by sharedPreferences(context, SYSTEM_GPU_DRIVER) var executorSlotCount by sharedPreferences(context, 6) - var enableTextureReadbackHack by sharedPreferences(context, false) + + // Hacks + var enableFastGpuReadbackHack by sharedPreferences(context, false) // Audio var isAudioOutputDisabled by sharedPreferences(context, false) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 98064f56..441f8fc0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -75,9 +75,11 @@ Allow UI elements to be drawn in the cutout area Executor Slot Count Maximum number of simultaneous GPU executions (Higher may sometimes perform better but will use more RAM) - Enable Texture Readback Hack - Texture readback hack is enabled (Will break some games but others will have higher performance) - Texture readback hack is disabled (Ensures highest accuracy) + + Hacks + Enable fast GPU readback + Fast GPU readback is enabled (Will break some games but others will have higher performance) + Fast GPU readback is disabled (Ensures highest accuracy) Audio Disable Audio Output diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 4b22dd42..84eb983d 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -135,12 +135,16 @@ app:key="executor_slot_count" app:title="@string/executor_slot_count" app:showSeekBarValue="true" /> + + + android:summaryOff="@string/enable_fast_gpu_readback_enabled" + android:summaryOn="@string/enable_fast_gpu_readback_disabled" + app:key="enable_fast_gpu_readback_hack" + app:title="@string/enable_fast_gpu_readback" />