[video_core] Improve synchronization and refactor buffer cache timing logic (#4182)

This simplifies the GPU accuracy setting by removing the intermediate Balanced mode and setting High as the default on desktop platforms.

It introduces a dedicated setting for GPU fence behavior, allowing the synchronization policy to be configured independently of GPU accuracy.

The Vulkan buffer cache now tracks GPU recording timeline ticks and waits only when necessary, reducing unnecessary synchronization while maintaining correctness for hard-to-trace graphical bugs.

GPU buffer readback has also been refined to synchronize only the affected upload regions when needed, and default DMA behavior has been updated to align with the new GPU accuracy model.

### TL;DR

The fix for particles freezing and unfreezing in mid-air in `Super Mario Odyssey` has been improved, resulting in less of a performance hit.
This game requires the new `Enable GPU Buffer Readback` option to be enabled to fix this issue.

The vertex explosions that occurred in `Super Mario Bros. Wonder`, especially in World 4, have been completely eliminated. You can now enjoy a smooth experience without graphical glitches exploding across the screen.
This game requires the new `GPU Fence Behavior` option to be set to `Strict` to fully fix this issue.

The flickering issue inside certain Shrines in `The Legend of Zelda: Tears of the Kingdom` has also been fixed.
For now, this game requires the new `GPU Fence Behavior` option to be set to `Accurate` to fully fix this issue.

These options are intended to fix graphical bugs in games that require better synchronization behavior between CPU and GPU, so other games may be affected as well.

Co-authored-by: xbzk <xbzk@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4182
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
This commit is contained in:
MaranBr
2026-07-10 05:25:12 +02:00
committed by crueter
parent 5606edd1a6
commit a27d35463e
27 changed files with 151 additions and 104 deletions
@@ -16,7 +16,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
RENDERER_USE_SPEED_LIMIT("use_speed_limit"), RENDERER_USE_SPEED_LIMIT("use_speed_limit"),
USE_CUSTOM_CPU_TICKS("use_custom_cpu_ticks"), USE_CUSTOM_CPU_TICKS("use_custom_cpu_ticks"),
SKIP_CPU_INNER_INVALIDATION("skip_cpu_inner_invalidation"), SKIP_CPU_INNER_INVALIDATION("skip_cpu_inner_invalidation"),
ANTIFLICKER("antiflicker"),
FIX_BLOOM_EFFECTS("fix_bloom_effects"), FIX_BLOOM_EFFECTS("fix_bloom_effects"),
EMULATE_BGR565("emulate_bgr565"), EMULATE_BGR565("emulate_bgr565"),
RESCALE_HACK("rescale_hack"), RESCALE_HACK("rescale_hack"),
@@ -27,6 +27,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
RENDERER_DYNA_STATE("dyna_state"), RENDERER_DYNA_STATE("dyna_state"),
DMA_ACCURACY("dma_accuracy"), DMA_ACCURACY("dma_accuracy"),
GPU_FENCE_BEHAVIOR("gpu_fence_behavior"),
FRAME_PACING_MODE("frame_pacing_mode"), FRAME_PACING_MODE("frame_pacing_mode"),
AUDIO_OUTPUT_ENGINE("output_engine"), AUDIO_OUTPUT_ENGINE("output_engine"),
MAX_ANISOTROPY("max_anisotropy"), MAX_ANISOTROPY("max_anisotropy"),
@@ -669,6 +669,15 @@ abstract class SettingsItem(
valuesId = R.array.dmaAccuracyValues valuesId = R.array.dmaAccuracyValues
) )
) )
put(
SingleChoiceSetting(
IntSetting.GPU_FENCE_BEHAVIOR,
titleId = R.string.gpu_fence_behavior,
descriptionId = R.string.gpu_fence_behavior_description,
choicesId = R.array.gpuFenceBehaviorNames,
valuesId = R.array.gpuFenceBehaviorValues
)
)
put( put(
SwitchSetting( SwitchSetting(
BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS, BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS,
@@ -757,13 +766,6 @@ abstract class SettingsItem(
descriptionId = R.string.skip_cpu_inner_invalidation_description descriptionId = R.string.skip_cpu_inner_invalidation_description
) )
) )
put(
SwitchSetting(
BooleanSetting.ANTIFLICKER,
titleId = R.string.antiflicker,
descriptionId = R.string.antiflicker_description
)
)
put( put(
SwitchSetting( SwitchSetting(
BooleanSetting.FIX_BLOOM_EFFECTS, BooleanSetting.FIX_BLOOM_EFFECTS,
@@ -283,6 +283,7 @@ class SettingsFragmentPresenter(
add(IntSetting.RENDERER_ACCURACY.key) add(IntSetting.RENDERER_ACCURACY.key)
add(IntSetting.DMA_ACCURACY.key) add(IntSetting.DMA_ACCURACY.key)
add(IntSetting.GPU_FENCE_BEHAVIOR.key)
add(IntSetting.MAX_ANISOTROPY.key) add(IntSetting.MAX_ANISOTROPY.key)
add(IntSetting.RENDERER_VRAM_USAGE_MODE.key) add(IntSetting.RENDERER_VRAM_USAGE_MODE.key)
add(IntSetting.RENDERER_ASTC_DECODE_METHOD.key) add(IntSetting.RENDERER_ASTC_DECODE_METHOD.key)
@@ -299,7 +300,6 @@ class SettingsFragmentPresenter(
add(IntSetting.FAST_GPU_TIME.key) add(IntSetting.FAST_GPU_TIME.key)
add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key) add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key)
add(BooleanSetting.ANTIFLICKER.key)
add(BooleanSetting.FIX_BLOOM_EFFECTS.key) add(BooleanSetting.FIX_BLOOM_EFFECTS.key)
add(BooleanSetting.EMULATE_BGR565.key) add(BooleanSetting.EMULATE_BGR565.key)
add(BooleanSetting.RESCALE_HACK.key) add(BooleanSetting.RESCALE_HACK.key)
@@ -506,8 +506,6 @@
<string name="fast_gpu_time_description">يُجبر هذا الخيار معظم الألعاب على العمل بأعلى دقة عرض أصلية. استخدم 256 للحصول على أقصى أداء و512 للحصول على أعلى جودة رسومات.</string> <string name="fast_gpu_time_description">يُجبر هذا الخيار معظم الألعاب على العمل بأعلى دقة عرض أصلية. استخدم 256 للحصول على أقصى أداء و512 للحصول على أعلى جودة رسومات.</string>
<string name="skip_cpu_inner_invalidation">تخطي إبطال صلاحية وحدة المعالجة المركزية الداخلية</string> <string name="skip_cpu_inner_invalidation">تخطي إبطال صلاحية وحدة المعالجة المركزية الداخلية</string>
<string name="skip_cpu_inner_invalidation_description">يتخطى بعض عمليات إبطال ذاكرة التخزين المؤقتة من جانب وحدة المعالجة المركزية أثناء تحديثات الذاكرة، مما يقلل من استخدام وحدة المعالجة المركزية ويحسن أداءها. قد يتسبب ذلك في حدوث أعطال أو تعطل في بعض الألعاب.</string> <string name="skip_cpu_inner_invalidation_description">يتخطى بعض عمليات إبطال ذاكرة التخزين المؤقتة من جانب وحدة المعالجة المركزية أثناء تحديثات الذاكرة، مما يقلل من استخدام وحدة المعالجة المركزية ويحسن أداءها. قد يتسبب ذلك في حدوث أعطال أو تعطل في بعض الألعاب.</string>
<string name="antiflicker">مضاد الوميض</string>
<string name="antiflicker_description">يُجبر هذا الوضع وظائف وحدة معالجة الرسومات على الانتظار حتى يتم إرسال العمل إليها. استخدمه مع وضع وحدة معالجة الرسومات السريع لتجنب الوميض مع تأثير أقل على الأداء.</string>
<string name="fix_bloom_effects">إصلاح تأثيرات التوهج</string> <string name="fix_bloom_effects">إصلاح تأثيرات التوهج</string>
<string name="fix_bloom_effects_description">يقلل من ضبابية التوهج في LA/EOW (Adreno A6XX - A7XX/ Turnip)، ويزيل التوهج في Burnout. تحذير: قد يسبب تشوهات رسومية في ألعاب أخرى.</string> <string name="fix_bloom_effects_description">يقلل من ضبابية التوهج في LA/EOW (Adreno A6XX - A7XX/ Turnip)، ويزيل التوهج في Burnout. تحذير: قد يسبب تشوهات رسومية في ألعاب أخرى.</string>
<string name="emulate_bgr565">محاكاة BGR565</string> <string name="emulate_bgr565">محاكاة BGR565</string>
@@ -502,8 +502,6 @@
<string name="fast_gpu_time_description">Fuerza a la mayoría de los juegos a ejecutarse a su resolución nativa más alta. Usa 256 para un máximo rendimiento y 512 para una fidelidad gráfica óptima.</string> <string name="fast_gpu_time_description">Fuerza a la mayoría de los juegos a ejecutarse a su resolución nativa más alta. Usa 256 para un máximo rendimiento y 512 para una fidelidad gráfica óptima.</string>
<string name="skip_cpu_inner_invalidation">Omitir invalidación interna de la CPU</string> <string name="skip_cpu_inner_invalidation">Omitir invalidación interna de la CPU</string>
<string name="skip_cpu_inner_invalidation_description">Omite ciertas invalidaciones de caché de la CPU durante las actualizaciones de memoria, lo que reduce el uso de la CPU y mejora su rendimiento. Esto puede causar fallos o bloqueos en algunos juegos.</string> <string name="skip_cpu_inner_invalidation_description">Omite ciertas invalidaciones de caché de la CPU durante las actualizaciones de memoria, lo que reduce el uso de la CPU y mejora su rendimiento. Esto puede causar fallos o bloqueos en algunos juegos.</string>
<string name="antiflicker">Antiparpadeo</string>
<string name="antiflicker_description">Fuerza a las funciones de devolución de llamada de la GPU a esperar a que se envíen las tareas a la GPU.\nÚsalo con el modo de GPU rápida para evitar el parpadeo con un menor impacto en el rendimiento.</string>
<string name="fix_bloom_effects">Arreglar los efectos de resplandor</string> <string name="fix_bloom_effects">Arreglar los efectos de resplandor</string>
<string name="fix_bloom_effects_description">Reduce el efecto de resplandor en LA/EOW (Adreno A6XX - A7XX/ Turnip), elimina el resplandor en Burnout. Advertencia: puede causar artefactos gráficos en otros juegos.</string> <string name="fix_bloom_effects_description">Reduce el efecto de resplandor en LA/EOW (Adreno A6XX - A7XX/ Turnip), elimina el resplandor en Burnout. Advertencia: puede causar artefactos gráficos en otros juegos.</string>
<string name="emulate_bgr565">Emular BGR565</string> <string name="emulate_bgr565">Emular BGR565</string>
@@ -499,8 +499,6 @@
<string name="fast_gpu_time_description">Принудительно запускает большинство игр в их максимальном нативном разрешении. Используйте значение 256 для максимальной производительности и 512 для максимального качества графики.</string> <string name="fast_gpu_time_description">Принудительно запускает большинство игр в их максимальном нативном разрешении. Используйте значение 256 для максимальной производительности и 512 для максимального качества графики.</string>
<string name="skip_cpu_inner_invalidation">Пропустить внутреннюю инвалидацию ЦП</string> <string name="skip_cpu_inner_invalidation">Пропустить внутреннюю инвалидацию ЦП</string>
<string name="skip_cpu_inner_invalidation_description">Пропускает некоторые инвалидации кэша на стороне ЦП при обновлениях памяти, уменьшая нагрузку на процессор и повышая производительность. Может вызывать сбои в некоторых играх.</string> <string name="skip_cpu_inner_invalidation_description">Пропускает некоторые инвалидации кэша на стороне ЦП при обновлениях памяти, уменьшая нагрузку на процессор и повышая производительность. Может вызывать сбои в некоторых играх.</string>
<string name="antiflicker">Анти-мерцание</string>
<string name="antiflicker_description">Принудительно заставляет обратные вызовы ГПУ-фильтра ожидать выполнения отправленных задач на ГПУ. Используйте с Быстрым режимом ГПУ, что бы избежать мерцаний с меньшим влиянием на производительность.</string>
<string name="fix_bloom_effects">Исправить эффекты размытия</string> <string name="fix_bloom_effects">Исправить эффекты размытия</string>
<string name="fix_bloom_effects_description">Частично убирает размытие в LA/EOW (Adreno A6XX - A7XX/ Turnip), полностью отключает его в Burnout. Внимание: может вызывать графические артефакты в других играх.</string> <string name="fix_bloom_effects_description">Частично убирает размытие в LA/EOW (Adreno A6XX - A7XX/ Turnip), полностью отключает его в Burnout. Внимание: может вызывать графические артефакты в других играх.</string>
<string name="emulate_bgr565">Эмулировать BGR565</string> <string name="emulate_bgr565">Эмулировать BGR565</string>
@@ -502,8 +502,6 @@
<string name="fast_gpu_time_description">Примушує більшість ігор працювати на їхній максимальній нативній роздільності. Використовуйте 256 для максимальної продуктивності та 512 для найкращої якості.</string> <string name="fast_gpu_time_description">Примушує більшість ігор працювати на їхній максимальній нативній роздільності. Використовуйте 256 для максимальної продуктивності та 512 для найкращої якості.</string>
<string name="skip_cpu_inner_invalidation">Пропустити внутрішнє інвалідування CPU</string> <string name="skip_cpu_inner_invalidation">Пропустити внутрішнє інвалідування CPU</string>
<string name="skip_cpu_inner_invalidation_description">Пропускає деякі інвалідації кешу на стороні CPU під час оновлення пам\'яті, зменшуючи навантаження на процесор і покращуючи продуктивність. Може спричинити збої в деяких іграх.</string> <string name="skip_cpu_inner_invalidation_description">Пропускає деякі інвалідації кешу на стороні CPU під час оновлення пам\'яті, зменшуючи навантаження на процесор і покращуючи продуктивність. Може спричинити збої в деяких іграх.</string>
<string name="antiflicker">Антимерехтіння</string>
<string name="antiflicker_description">Змушує механізм синхронізації чекати, доки ГП завершить подані завдання. Використовуйте з режимом ГП «Швидко», щоб уникнути мерехтіння з меншими втратами продуктивності.</string>
<string name="fix_bloom_effects">Виправити ефекти світіння</string> <string name="fix_bloom_effects">Виправити ефекти світіння</string>
<string name="fix_bloom_effects_description">Зменшує розмиття світіння в LA/EOW (Adreno A6XXA7XX / Turnip), прибирає світіння в Burnout. Увага: може спричинити графічні артефакти в інших іграх.</string> <string name="fix_bloom_effects_description">Зменшує розмиття світіння в LA/EOW (Adreno A6XXA7XX / Turnip), прибирає світіння в Burnout. Увага: може спричинити графічні артефакти в інших іграх.</string>
<string name="emulate_bgr565">Емулювати BGR565</string> <string name="emulate_bgr565">Емулювати BGR565</string>
@@ -498,8 +498,6 @@
<string name="fast_gpu_time_description">强制大多数游戏以其最高原生分辨率运行。设置为 256 可获得最佳性能,设置为 512 可获得最佳画面保真度。</string> <string name="fast_gpu_time_description">强制大多数游戏以其最高原生分辨率运行。设置为 256 可获得最佳性能,设置为 512 可获得最佳画面保真度。</string>
<string name="skip_cpu_inner_invalidation">跳过CPU内部无效化</string> <string name="skip_cpu_inner_invalidation">跳过CPU内部无效化</string>
<string name="skip_cpu_inner_invalidation_description">在更新内存时跳过某些 CPU 端的缓存失效操作,从而降低 CPU 占用率并提升性能。可能会在某些游戏中引发故障点或崩溃。</string> <string name="skip_cpu_inner_invalidation_description">在更新内存时跳过某些 CPU 端的缓存失效操作,从而降低 CPU 占用率并提升性能。可能会在某些游戏中引发故障点或崩溃。</string>
<string name="antiflicker">防闪烁</string>
<string name="antiflicker_description">强制 GPU 围栏回调等待已提交的 GPU 任务。配合“快速 GPU 模式”一起使用,以牺牲少量性能为代价来避免画面闪烁现象。</string>
<string name="fix_bloom_effects">修复 Bloom 效果</string> <string name="fix_bloom_effects">修复 Bloom 效果</string>
<string name="fix_bloom_effects_description">减少《智慧的再现》和《众神的三角力量2》(Adreno A6XX - A7XX/ Turnip)中的 bloom 模糊,并移除《Burnout》中的 bloom 效果。警告:可能会导致在其他游戏中出现图形异常。</string> <string name="fix_bloom_effects_description">减少《智慧的再现》和《众神的三角力量2》(Adreno A6XX - A7XX/ Turnip)中的 bloom 模糊,并移除《Burnout》中的 bloom 效果。警告:可能会导致在其他游戏中出现图形异常。</string>
<string name="emulate_bgr565">模拟 BGR565</string> <string name="emulate_bgr565">模拟 BGR565</string>
@@ -522,6 +522,21 @@
<item>2</item> <item>2</item>
</integer-array> </integer-array>
<string-array name="gpuFenceBehaviorNames">
<item>@string/gpu_fence_behavior_default</item>
<item>@string/gpu_fence_behavior_immediate</item>
<item>@string/gpu_fence_behavior_balanced</item>
<item>@string/gpu_fence_behavior_accurate</item>
<item>@string/gpu_fence_behavior_strict</item>
</string-array>
<integer-array name="gpuFenceBehaviorValues">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
</integer-array>
<string-array name="appletEntries"> <string-array name="appletEntries">
<item>@string/applet_hle</item> <item>@string/applet_hle</item>
@@ -482,6 +482,8 @@
<string name="renderer_accuracy_description">Controls the GPU emulation mode. Most games render fine with Fast or Balanced modes, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode.</string> <string name="renderer_accuracy_description">Controls the GPU emulation mode. Most games render fine with Fast or Balanced modes, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode.</string>
<string name="dma_accuracy">DMA Accuracy</string> <string name="dma_accuracy">DMA Accuracy</string>
<string name="dma_accuracy_description">Controls the DMA precision accuracy. Safe precision can fix issues in some games, but it can also impact performance in some cases. If unsure, leave this on Default.</string> <string name="dma_accuracy_description">Controls the DMA precision accuracy. Safe precision can fix issues in some games, but it can also impact performance in some cases. If unsure, leave this on Default.</string>
<string name="gpu_fence_behavior">GPU Fence Behavior</string>
<string name="gpu_fence_behavior_description">Controls the GPU fence synchronization behavior. Immediate is the fastest option, but can introduce some issues. Balanced offers better compatibility and may fix issues in some games. Accurate further improves compatibility at the cost of some performance. Strict is the slowest option, but can fix issues that require stricter synchronization. Default follows the GPU Accuracy setting.</string>
<string name="anisotropic_filtering">Anisotropic filtering</string> <string name="anisotropic_filtering">Anisotropic filtering</string>
<string name="anisotropic_filtering_description">Improves the quality of textures when viewed at oblique angles</string> <string name="anisotropic_filtering_description">Improves the quality of textures when viewed at oblique angles</string>
<string name="vram_usage_mode">VRAM Usage Mode</string> <string name="vram_usage_mode">VRAM Usage Mode</string>
@@ -514,8 +516,6 @@
<string name="fast_gpu_time_description">Forces most games to run at their highest native resolution. Use 256 for maximal performance and 512 for maximal graphics fidelity.</string> <string name="fast_gpu_time_description">Forces most games to run at their highest native resolution. Use 256 for maximal performance and 512 for maximal graphics fidelity.</string>
<string name="skip_cpu_inner_invalidation">Skip CPU Inner Invalidation</string> <string name="skip_cpu_inner_invalidation">Skip CPU Inner Invalidation</string>
<string name="skip_cpu_inner_invalidation_description">Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and improving it\'s performance. This may cause glitches or crashes on some games.</string> <string name="skip_cpu_inner_invalidation_description">Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and improving it\'s performance. This may cause glitches or crashes on some games.</string>
<string name="antiflicker">Anti-Flicker</string>
<string name="antiflicker_description">Forces GPU fence callbacks to wait for submitted GPU work. Use with Fast GPU mode, to avoid flicker with lower performance impact.</string>
<string name="fix_bloom_effects">Fix Bloom Effects</string> <string name="fix_bloom_effects">Fix Bloom Effects</string>
<string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno A6XX - A7XX/ Turnip), removes bloom in Burnout. Warning: may cause graphical artifacts in other games.</string> <string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno A6XX - A7XX/ Turnip), removes bloom in Burnout. Warning: may cause graphical artifacts in other games.</string>
<string name="emulate_bgr565">Emulate BGR565</string> <string name="emulate_bgr565">Emulate BGR565</string>
@@ -1047,6 +1047,13 @@
<string name="dma_accuracy_unsafe">Unsafe</string> <string name="dma_accuracy_unsafe">Unsafe</string>
<string name="dma_accuracy_safe">Safe</string> <string name="dma_accuracy_safe">Safe</string>
<!-- GPU Fence Behavior -->
<string name="gpu_fence_behavior_default">Default</string>
<string name="gpu_fence_behavior_immediate">Immediate</string>
<string name="gpu_fence_behavior_balanced">Balanced</string>
<string name="gpu_fence_behavior_accurate">Accurate</string>
<string name="gpu_fence_behavior_strict">Strict</string>
<!-- ASTC Decoding Method Choices --> <!-- ASTC Decoding Method Choices -->
<string name="accelerate_astc_cpu" translatable="false">CPU</string> <string name="accelerate_astc_cpu" translatable="false">CPU</string>
<string name="accelerate_astc_gpu" translatable="false">GPU</string> <string name="accelerate_astc_gpu" translatable="false">GPU</string>
+16 -8
View File
@@ -156,14 +156,6 @@ void UpdateGPUAccuracy() {
values.current_gpu_accuracy = values.gpu_accuracy.GetValue(); values.current_gpu_accuracy = values.gpu_accuracy.GetValue();
} }
bool IsGPULevelLow() {
return values.current_gpu_accuracy == GpuAccuracy::Low;
}
bool IsGPULevelMedium() {
return values.current_gpu_accuracy == GpuAccuracy::Medium;
}
bool IsGPULevelHigh() { bool IsGPULevelHigh() {
return values.current_gpu_accuracy == GpuAccuracy::High; return values.current_gpu_accuracy == GpuAccuracy::High;
} }
@@ -176,6 +168,22 @@ bool IsDMALevelSafe() {
return values.dma_accuracy.GetValue() == DmaAccuracy::Safe; return values.dma_accuracy.GetValue() == DmaAccuracy::Safe;
} }
bool IsGPUFenceBehaviorDefault() {
return values.gpu_fence_behavior.GetValue() == GpuFenceBehavior::Default;
}
bool IsGPUFenceBehaviorBalanced() {
return values.gpu_fence_behavior.GetValue() == GpuFenceBehavior::Balanced;
}
bool IsGPUFenceBehaviorAccurate() {
return values.gpu_fence_behavior.GetValue() == GpuFenceBehavior::Accurate;
}
bool IsGPUFenceBehaviorStrict() {
return values.gpu_fence_behavior.GetValue() == GpuFenceBehavior::Strict;
}
bool IsFastmemEnabled() { bool IsFastmemEnabled() {
if (values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Debugging) if (values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Debugging)
return bool(values.cpuopt_fastmem); return bool(values.cpuopt_fastmem);
+17 -11
View File
@@ -420,7 +420,7 @@ struct Values {
#ifdef __ANDROID__ #ifdef __ANDROID__
GpuAccuracy::Low, GpuAccuracy::Low,
#else #else
GpuAccuracy::Medium, GpuAccuracy::High,
#endif #endif
"gpu_accuracy", "gpu_accuracy",
Category::RendererAdvanced, Category::RendererAdvanced,
@@ -428,7 +428,7 @@ struct Values {
true, true,
true}; true};
GpuAccuracy current_gpu_accuracy{GpuAccuracy::Medium}; GpuAccuracy current_gpu_accuracy{GpuAccuracy::High};
SwitchableSetting<DmaAccuracy, true> dma_accuracy{linkage, SwitchableSetting<DmaAccuracy, true> dma_accuracy{linkage,
DmaAccuracy::Default, DmaAccuracy::Default,
@@ -438,6 +438,16 @@ struct Values {
true, true,
true}; true};
SwitchableSetting<GpuFenceBehavior, true> gpu_fence_behavior{linkage,
GpuFenceBehavior::Default,
GpuFenceBehavior::Default,
GpuFenceBehavior::Strict,
"gpu_fence_behavior",
Category::RendererAdvanced,
Specialization::Default,
true,
true};
SwitchableSetting<VramUsageMode, true> vram_usage_mode{linkage, SwitchableSetting<VramUsageMode, true> vram_usage_mode{linkage,
VramUsageMode::Conservative, VramUsageMode::Conservative,
"vram_usage_mode", "vram_usage_mode",
@@ -545,13 +555,6 @@ struct Values {
Specialization::Default, Specialization::Default,
true, true,
true}; true};
SwitchableSetting<bool> antiflicker{linkage,
false,
"antiflicker",
Category::RendererHacks,
Specialization::Default,
true,
true};
SwitchableSetting<bool> async_presentation{linkage, SwitchableSetting<bool> async_presentation{linkage,
#ifdef __ANDROID__ #ifdef __ANDROID__
false, false,
@@ -871,13 +874,16 @@ extern Values values;
bool getDebugKnobAt(u8 i); bool getDebugKnobAt(u8 i);
void UpdateGPUAccuracy(); void UpdateGPUAccuracy();
bool IsGPULevelLow();
bool IsGPULevelMedium();
bool IsGPULevelHigh(); bool IsGPULevelHigh();
bool IsDMALevelDefault(); bool IsDMALevelDefault();
bool IsDMALevelSafe(); bool IsDMALevelSafe();
bool IsGPUFenceBehaviorDefault();
bool IsGPUFenceBehaviorBalanced();
bool IsGPUFenceBehaviorAccurate();
bool IsGPUFenceBehaviorStrict();
bool IsFastmemEnabled(); bool IsFastmemEnabled();
void SetNceEnabled(bool is_64bit); void SetNceEnabled(bool is_64bit);
bool IsNceEnabled(); bool IsNceEnabled();
+2 -1
View File
@@ -135,8 +135,9 @@ ENUM(FramePacingMode, Target_Auto, Target_30, Target_60, Target_90, Target_120);
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed); ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
ENUM(VramUsageMode, Conservative, Aggressive); ENUM(VramUsageMode, Conservative, Aggressive);
ENUM(RendererBackend, OpenGL_GLSL, Vulkan, Null, OpenGL_GLASM, OpenGL_SPIRV); ENUM(RendererBackend, OpenGL_GLSL, Vulkan, Null, OpenGL_GLASM, OpenGL_SPIRV);
ENUM(GpuAccuracy, Low, Medium, High); ENUM(GpuAccuracy, Low, High);
ENUM(DmaAccuracy, Default, Unsafe, Safe); ENUM(DmaAccuracy, Default, Unsafe, Safe);
ENUM(GpuFenceBehavior, Default, Immediate, Balanced, Accurate, Strict);
ENUM(CpuBackend, Dynarmic, Nce); ENUM(CpuBackend, Dynarmic, Nce);
ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid, Debugging); ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid, Debugging);
ENUM(CpuClock, Off, Boost, Fast) ENUM(CpuClock, Off, Boost, Fast)
+13 -9
View File
@@ -193,9 +193,6 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent) {
INSERT(Settings, skip_cpu_inner_invalidation, tr("Skip CPU Inner Invalidation"), INSERT(Settings, skip_cpu_inner_invalidation, tr("Skip CPU Inner Invalidation"),
tr("Skips certain cache invalidations during memory updates, reducing CPU usage and " tr("Skips certain cache invalidations during memory updates, reducing CPU usage and "
"improving latency. This may cause soft-crashes.")); "improving latency. This may cause soft-crashes."));
INSERT(Settings, antiflicker, tr("Anti-Flicker"),
tr("Forces GPU fence callbacks to wait for submitted GPU work.\n"
"Use with Fast GPU mode, to avoid flicker with lower performance impact."));
INSERT(Settings, vsync_mode, tr("VSync Mode:"), INSERT(Settings, vsync_mode, tr("VSync Mode:"),
tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen " tr("FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen "
"refresh rate.\nFIFO Relaxed allows tearing as it recovers from a slow down.\n" "refresh rate.\nFIFO Relaxed allows tearing as it recovers from a slow down.\n"
@@ -223,14 +220,14 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent) {
tr("Controls the quality of texture rendering at oblique angles.\nSafe to set at 16x on " tr("Controls the quality of texture rendering at oblique angles.\nSafe to set at 16x on "
"most GPUs.")); "most GPUs."));
INSERT(Settings, gpu_accuracy, tr("GPU Mode:"), INSERT(Settings, gpu_accuracy, tr("GPU Mode:"),
tr("Controls the GPU emulation mode.\nMost games render fine with Fast or Balanced " tr("Controls the GPU emulation mode.\nMost games render fine with Fast, but Accurate is still "
"modes, but Accurate is still "
"required for some.\nParticles tend to only render correctly with Accurate mode.")); "required for some.\nParticles tend to only render correctly with Accurate mode."));
INSERT(Settings, dma_accuracy, tr("DMA Accuracy:"), INSERT(Settings, dma_accuracy, tr("DMA Accuracy:"),
tr("Controls the DMA precision accuracy. Safe precision fixes issues in some games but " tr("Controls the DMA read mode.\nUnsafe is faster, while Safe is more stable and can fix issues in some games.\nDefault follows the GPU Accuracy setting."));
"may degrade performance.")); INSERT(Settings, gpu_fence_behavior, tr("GPU Fence Behavior:"),
tr("Controls the GPU fence synchronization behavior.\nImmediate is the fastest option, but can introduce some issues.\nBalanced offers better compatibility and may fix issues in some games.\nAccurate further improves compatibility at the cost of some performance.\nStrict is the slowest option, but can fix issues that require stricter synchronization.\nDefault follows the GPU Accuracy setting."));
INSERT(Settings, enable_gpu_buffer_readback, tr("Enable GPU buffer readback"), INSERT(Settings, enable_gpu_buffer_readback, tr("Enable GPU buffer readback"),
tr("Preserves GPU-modified buffer data by reading it back before uploads.\nSome games require this to render certain effects properly.\nMay cause issues if the hardware cannot handle the additional workload.")); tr("Preserves GPU-modified data by reading it back before uploading.\nSome games require this to render certain effects properly."));
INSERT(Settings, use_asynchronous_shaders, tr("Enable asynchronous shader compilation"), INSERT(Settings, use_asynchronous_shaders, tr("Enable asynchronous shader compilation"),
tr("May reduce shader stutter.")); tr("May reduce shader stutter."));
INSERT(Settings, fast_gpu_time, tr("Fast GPU Time"), INSERT(Settings, fast_gpu_time, tr("Fast GPU Time"),
@@ -430,7 +427,6 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent) {
translations->insert({Settings::EnumMetadata<Settings::GpuAccuracy>::Index(), translations->insert({Settings::EnumMetadata<Settings::GpuAccuracy>::Index(),
{ {
PAIR(GpuAccuracy, Low, tr("Fast")), PAIR(GpuAccuracy, Low, tr("Fast")),
PAIR(GpuAccuracy, Medium, tr("Balanced")),
PAIR(GpuAccuracy, High, tr("Accurate")), PAIR(GpuAccuracy, High, tr("Accurate")),
}}); }});
translations->insert({Settings::EnumMetadata<Settings::DmaAccuracy>::Index(), translations->insert({Settings::EnumMetadata<Settings::DmaAccuracy>::Index(),
@@ -439,6 +435,14 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent) {
PAIR(DmaAccuracy, Unsafe, tr("Unsafe (fast)")), PAIR(DmaAccuracy, Unsafe, tr("Unsafe (fast)")),
PAIR(DmaAccuracy, Safe, tr("Safe (stable)")), PAIR(DmaAccuracy, Safe, tr("Safe (stable)")),
}}); }});
translations->insert({Settings::EnumMetadata<Settings::GpuFenceBehavior>::Index(),
{
PAIR(GpuFenceBehavior, Default, tr("Default")),
PAIR(GpuFenceBehavior, Immediate, tr("Immediate")),
PAIR(GpuFenceBehavior, Balanced, tr("Balanced")),
PAIR(GpuFenceBehavior, Accurate, tr("Accurate")),
PAIR(GpuFenceBehavior, Strict, tr("Strict")),
}});
translations->insert( translations->insert(
{Settings::EnumMetadata<Settings::CpuAccuracy>::Index(), {Settings::EnumMetadata<Settings::CpuAccuracy>::Index(),
{ {
@@ -64,7 +64,6 @@ static const std::map<Settings::ConsoleMode, QString> use_docked_mode_texts_map
static const std::map<Settings::GpuAccuracy, QString> gpu_accuracy_texts_map = { static const std::map<Settings::GpuAccuracy, QString> gpu_accuracy_texts_map = {
{Settings::GpuAccuracy::Low, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Fast"))}, {Settings::GpuAccuracy::Low, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Fast"))},
{Settings::GpuAccuracy::Medium, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Balanced"))},
{Settings::GpuAccuracy::High, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Accurate"))}, {Settings::GpuAccuracy::High, QStringLiteral(QT_TRANSLATE_NOOP("MainWindow", "Accurate"))},
}; };
@@ -121,12 +121,21 @@ public:
return size_bytes; return size_bytes;
} }
u64 getWriteTick() const noexcept {
return write_tick;
}
void setWriteTick(u64 write_tick_) {
write_tick = write_tick_;
}
private: private:
VAddr cpu_addr = 0; VAddr cpu_addr = 0;
BufferFlagBits flags{}; BufferFlagBits flags{};
int stream_score = 0; int stream_score = 0;
size_t lru_id = SIZE_MAX; size_t lru_id = SIZE_MAX;
size_t size_bytes = 0; size_t size_bytes = 0;
u64 write_tick = 0;
}; };
} // namespace VideoCommon } // namespace VideoCommon
+30 -15
View File
@@ -1430,6 +1430,10 @@ void BufferCache<P>::UpdateComputeTextureBuffers() {
template <class P> template <class P>
void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, DAddr device_addr, u32 size) { void BufferCache<P>::MarkWrittenBuffer(BufferId buffer_id, DAddr device_addr, u32 size) {
if constexpr (!IS_OPENGL) {
Buffer& buffer = slot_buffers[buffer_id];
buffer.setWriteTick(runtime.CurrentTick());
}
memory_tracker.MarkRegionAsGpuModified(device_addr, size); memory_tracker.MarkRegionAsGpuModified(device_addr, size);
gpu_modified_ranges.Add(device_addr, size); gpu_modified_ranges.Add(device_addr, size);
uncommitted_gpu_modified_ranges.Add(device_addr, size); uncommitted_gpu_modified_ranges.Add(device_addr, size);
@@ -1442,16 +1446,32 @@ BufferId BufferCache<P>::FindBuffer(DAddr device_addr, u32 size) {
} }
const u64 page = device_addr >> CACHING_PAGEBITS; const u64 page = device_addr >> CACHING_PAGEBITS;
const BufferId buffer_id = page_table[page]; const BufferId buffer_id = page_table[page];
if (!buffer_id) { if (buffer_id) {
return CreateBuffer(device_addr, size); Buffer& buffer = slot_buffers[buffer_id];
} WaitForGpuFenceIfNeeded(buffer);
const Buffer& buffer = slot_buffers[buffer_id];
if (buffer.IsInBounds(device_addr, size)) { if (buffer.IsInBounds(device_addr, size)) {
return buffer_id; return buffer_id;
} }
}
return CreateBuffer(device_addr, size); return CreateBuffer(device_addr, size);
} }
template <class P>
void BufferCache<P>::WaitForGpuFenceIfNeeded(Buffer& buffer) {
if constexpr (!IS_OPENGL) {
const bool gpu_fence_accurate = Settings::IsGPUFenceBehaviorAccurate();
const bool gpu_fence_strict = Settings::IsGPUFenceBehaviorStrict();
if (gpu_fence_accurate || gpu_fence_strict) {
const u64 gpu_tick_delay = gpu_fence_strict ? 0 : 3;
const u64 buffer_tick = buffer.getWriteTick();
const u64 gpu_tick = runtime.KnownGpuTick();
if (buffer_tick > gpu_tick + gpu_tick_delay) {
runtime.Wait(buffer_tick);
}
}
}
}
template <class P> template <class P>
typename BufferCache<P>::OverlapResult BufferCache<P>::ResolveOverlaps(DAddr device_addr, typename BufferCache<P>::OverlapResult BufferCache<P>::ResolveOverlaps(DAddr device_addr,
u32 wanted_size) { u32 wanted_size) {
@@ -1634,17 +1654,6 @@ bool BufferCache<P>::SynchronizeBuffer(Buffer& buffer, DAddr device_addr, u32 si
if (total_size_bytes == 0) { if (total_size_bytes == 0) {
return true; return true;
} }
if (Settings::values.enable_gpu_buffer_readback.GetValue()) {
u64 min_offset = (std::numeric_limits<u64>::max)();
u64 max_offset = 0;
for (const auto& copy : upload_copies) {
min_offset = (std::min)(min_offset, copy.dst_offset);
max_offset = (std::max)(max_offset, copy.dst_offset + copy.size);
}
const DAddr sync_addr = buffer.CpuAddr() + min_offset;
const u64 sync_size = max_offset - min_offset;
DownloadBufferMemory(buffer, sync_addr, sync_size);
}
const std::span<BufferCopy> copies_span(upload_copies.data(), upload_copies.size()); const std::span<BufferCopy> copies_span(upload_copies.data(), upload_copies.size());
UploadMemory(buffer, total_size_bytes, largest_copy, copies_span); UploadMemory(buffer, total_size_bytes, largest_copy, copies_span);
any_buffer_uploaded = true; any_buffer_uploaded = true;
@@ -1679,6 +1688,9 @@ void BufferCache<P>::ImmediateUploadMemory([[maybe_unused]] Buffer& buffer,
if (immediate_buffer.empty()) { if (immediate_buffer.empty()) {
immediate_buffer = ImmediateBuffer(largest_copy); immediate_buffer = ImmediateBuffer(largest_copy);
} }
if (Settings::values.enable_gpu_buffer_readback.GetValue()) {
DownloadBufferMemory(buffer, device_addr, copy.size);
}
device_memory.ReadBlockUnsafe(device_addr, immediate_buffer.data(), copy.size); device_memory.ReadBlockUnsafe(device_addr, immediate_buffer.data(), copy.size);
upload_span = immediate_buffer.subspan(0, copy.size); upload_span = immediate_buffer.subspan(0, copy.size);
} }
@@ -1697,6 +1709,9 @@ void BufferCache<P>::MappedUploadMemory([[maybe_unused]] Buffer& buffer,
for (BufferCopy& copy : copies) { for (BufferCopy& copy : copies) {
u8* const src_pointer = staging_pointer.data() + copy.src_offset; u8* const src_pointer = staging_pointer.data() + copy.src_offset;
const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset; const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset;
if (Settings::values.enable_gpu_buffer_readback.GetValue()) {
DownloadBufferMemory(buffer, device_addr, copy.size);
}
device_memory.ReadBlockUnsafe(device_addr, src_pointer, copy.size); device_memory.ReadBlockUnsafe(device_addr, src_pointer, copy.size);
// Apply the staging offset // Apply the staging offset
copy.src_offset += upload_staging.offset; copy.src_offset += upload_staging.offset;
@@ -416,6 +416,8 @@ private:
[[nodiscard]] BufferId FindBuffer(DAddr device_addr, u32 size); [[nodiscard]] BufferId FindBuffer(DAddr device_addr, u32 size);
void WaitForGpuFenceIfNeeded(Buffer& buffer);
[[nodiscard]] OverlapResult ResolveOverlaps(DAddr device_addr, u32 wanted_size); [[nodiscard]] OverlapResult ResolveOverlaps(DAddr device_addr, u32 wanted_size);
void JoinOverlap(BufferId new_buffer_id, BufferId overlap_id, bool accumulate_stream_score); void JoinOverlap(BufferId new_buffer_id, BufferId overlap_id, bool accumulate_stream_score);
+2 -1
View File
@@ -78,7 +78,8 @@ bool DmaPusher::Step() {
} }
if (header.size > 0) { if (header.size > 0) {
if (Settings::IsDMALevelDefault() ? (Settings::IsGPULevelMedium() || Settings::IsGPULevelHigh()) : Settings::IsDMALevelSafe()) { const bool use_safe = Settings::IsDMALevelDefault() ? Settings::IsGPULevelHigh() : Settings::IsDMALevelSafe();
if (use_safe) {
Tegra::Memory::GpuGuestMemory<Tegra::CommandHeader, Tegra::Memory::GuestMemoryFlags::SafeRead>headers(memory_manager, dma_state.dma_get, header.size, &command_headers); Tegra::Memory::GpuGuestMemory<Tegra::CommandHeader, Tegra::Memory::GuestMemoryFlags::SafeRead>headers(memory_manager, dma_state.dma_get, header.size, &command_headers);
ProcessCommands(headers); ProcessCommands(headers);
} else { } else {
+3 -6
View File
@@ -72,16 +72,13 @@ public:
} }
void SignalFence(std::function<void()>&& func) { void SignalFence(std::function<void()>&& func) {
const bool delay_fence = Settings::IsGPUFenceBehaviorDefault() ? Settings::IsGPULevelHigh() : Settings::IsGPUFenceBehaviorBalanced() || Settings::IsGPUFenceBehaviorAccurate() || Settings::IsGPUFenceBehaviorStrict();
const bool should_flush = ShouldFlush();
if constexpr (!can_async_check) { if constexpr (!can_async_check) {
TryReleasePendingFences<false>(); TryReleasePendingFences<false>();
} }
const bool should_flush = ShouldFlush();
const bool antiflicker_toggled = Settings::values.antiflicker.GetValue();
const bool delay_fence = Settings::IsGPULevelHigh() ||
(Settings::IsGPULevelMedium() && should_flush) ||
antiflicker_toggled;
CommitAsyncFlushes(); CommitAsyncFlushes();
TFence new_fence = CreateFence(!should_flush && !antiflicker_toggled); TFence new_fence = CreateFence(!should_flush);
if constexpr (can_async_check) { if constexpr (can_async_check) {
guard.lock(); guard.lock();
} }
+1 -1
View File
@@ -260,7 +260,7 @@ void QueryCacheBase<Traits>::CounterReport(GPUVAddr addr, QueryType counter_type
}; };
u8* pointer = impl->device_memory.template GetPointer<u8>(cpu_addr); u8* pointer = impl->device_memory.template GetPointer<u8>(cpu_addr);
u8* pointer_timestamp = impl->device_memory.template GetPointer<u8>(cpu_addr + 8); u8* pointer_timestamp = impl->device_memory.template GetPointer<u8>(cpu_addr + 8);
bool is_synced = !Settings::IsGPULevelHigh() && is_fence; bool is_synced = (Settings::IsGPUFenceBehaviorDefault() ? !Settings::IsGPULevelHigh() : !Settings::IsGPUFenceBehaviorBalanced() && !Settings::IsGPUFenceBehaviorAccurate() && !Settings::IsGPUFenceBehaviorStrict()) && is_fence;
std::function<void()> operation([this, is_synced, streamer, query_base = query, query_location, std::function<void()> operation([this, is_synced, streamer, query_base = query, query_location,
pointer, pointer_timestamp] { pointer, pointer_timestamp] {
if (True(query_base->flags & QueryFlagBits::IsInvalidated)) { if (True(query_base->flags & QueryFlagBits::IsInvalidated)) {
@@ -396,6 +396,18 @@ void BufferCacheRuntime::TickFrame(Common::SlotVector<Buffer>& slot_buffers) noe
} }
} }
u64 BufferCacheRuntime::CurrentTick() {
return scheduler.GetMasterSemaphore().CurrentTick();
}
u64 BufferCacheRuntime::KnownGpuTick() {
return scheduler.GetMasterSemaphore().KnownGpuTick();
}
void BufferCacheRuntime::Wait(u64 buffer_tick) {
scheduler.Wait(buffer_tick);
}
void BufferCacheRuntime::Finish() { void BufferCacheRuntime::Finish() {
scheduler.Finish(); scheduler.Finish();
} }
@@ -92,6 +92,12 @@ public:
void TickFrame(Common::SlotVector<Buffer>& slot_buffers) noexcept; void TickFrame(Common::SlotVector<Buffer>& slot_buffers) noexcept;
u64 CurrentTick();
u64 KnownGpuTick();
void Wait(u64 buffer_tick);
void Finish(); void Finish();
u64 GetDeviceLocalMemory() const; u64 GetDeviceLocalMemory() const;
@@ -27,8 +27,6 @@
namespace Vulkan { namespace Vulkan {
constexpr u64 MAX_PENDING_FLUSHES = 5;
void Scheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf, void Scheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf,
vk::CommandBuffer upload_cmdbuf) { vk::CommandBuffer upload_cmdbuf) {
auto command = first; auto command = first;
@@ -49,15 +47,6 @@ Scheduler::Scheduler(const Device& device_, StateTracker& state_tracker_)
master_semaphore{std::make_unique<MasterSemaphore>(device)}, master_semaphore{std::make_unique<MasterSemaphore>(device)},
command_pool{std::make_unique<CommandPool>(*master_semaphore, device)} { command_pool{std::make_unique<CommandPool>(*master_semaphore, device)} {
/*// PRE-OPTIMIZATION: Warm up the pool to prevent mid-frame spikes
{
std::scoped_lock rl{reserve_mutex};
chunk_reserve.reserve(2048); // Prevent vector resizing
for (int i = 0; i < 1024; ++i) {
chunk_reserve.push_back(std::make_unique<CommandChunk>());
}
}*/
AcquireNewChunk(); AcquireNewChunk();
AllocateWorkerCommandBuffer(); AllocateWorkerCommandBuffer();
worker_thread = std::jthread([this](std::stop_token token) { WorkerThread(token); }); worker_thread = std::jthread([this](std::stop_token token) { WorkerThread(token); });
@@ -66,18 +55,7 @@ Scheduler::Scheduler(const Device& device_, StateTracker& state_tracker_)
Scheduler::~Scheduler() = default; Scheduler::~Scheduler() = default;
u64 Scheduler::Flush(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) { u64 Scheduler::Flush(VkSemaphore signal_semaphore, VkSemaphore wait_semaphore) {
// Prevent the CPU from getting too far ahead of the GPU by limiting pending flushes. // When flushing, we only send data to the worker thread; no waiting is necessary.
const bool should_throttle = Settings::IsGPULevelHigh();
if (should_throttle) {
const u64 current_tick = master_semaphore->CurrentTick();
const u64 gap = current_tick > last_submitted_tick ? current_tick - last_submitted_tick : 0;
const u64 step = (std::min)(MAX_PENDING_FLUSHES, gap);
const u64 new_tick = last_submitted_tick + step;
if (new_tick < current_tick) {
last_submitted_tick = new_tick;
master_semaphore->Wait(last_submitted_tick);
}
}
const u64 signal_value = SubmitExecution(signal_semaphore, wait_semaphore); const u64 signal_value = SubmitExecution(signal_semaphore, wait_semaphore);
AllocateNewContext(); AllocateNewContext();
return signal_value; return signal_value;
@@ -298,8 +298,6 @@ private:
double last_target_fps{}; double last_target_fps{};
u64 max_frame_count{}; u64 max_frame_count{};
u64 frame_counter{}; u64 frame_counter{};
u64 last_submitted_tick = 0;
}; };
} // namespace Vulkan } // namespace Vulkan
-3
View File
@@ -3585,9 +3585,6 @@ void MainWindow::OnToggleDockedMode() {
void MainWindow::OnToggleGpuAccuracy() { void MainWindow::OnToggleGpuAccuracy() {
switch (Settings::values.gpu_accuracy.GetValue()) { switch (Settings::values.gpu_accuracy.GetValue()) {
case Settings::GpuAccuracy::Low: case Settings::GpuAccuracy::Low:
Settings::values.gpu_accuracy.SetValue(Settings::GpuAccuracy::Medium);
break;
case Settings::GpuAccuracy::Medium:
Settings::values.gpu_accuracy.SetValue(Settings::GpuAccuracy::High); Settings::values.gpu_accuracy.SetValue(Settings::GpuAccuracy::High);
break; break;
case Settings::GpuAccuracy::High: case Settings::GpuAccuracy::High: