diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt index d1702b8140..60e2a89564 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt @@ -67,7 +67,8 @@ enum class IntSetting(override val key: String) : AbstractIntSetting { MY_PAGE_APPLET("my_page_applet_mode"), INPUT_OVERLAY_AUTO_HIDE("input_overlay_auto_hide"), OVERLAY_GRID_SIZE("overlay_grid_size"), - GPU_LOG_RING_BUFFER_SIZE("gpu_log_ring_buffer_size") + GPU_LOG_RING_BUFFER_SIZE("gpu_log_ring_buffer_size"), + ANDROID_PIPELINE_WORKERS("pipeline_worker_count") ; override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 3a5f466f07..230390749e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -582,6 +582,16 @@ abstract class SettingsItem( units = "%" ) ) + put( + SliderSetting( + IntSetting.ANDROID_PIPELINE_WORKERS, + titleId = R.string.pipeline_worker_cores, + descriptionId = R.string.pipeline_worker_cores_description, + min = 4, + max = 8, + units = "cores" + ) + ) put( SingleChoiceSetting( IntSetting.RENDERER_ANTI_ALIASING, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index 9f0e409cf4..4da218bfcc 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -295,6 +295,7 @@ class SettingsFragmentPresenter( add(BooleanSetting.EMULATE_BGR565.key) add(BooleanSetting.RESCALE_HACK.key) add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key) + add(IntSetting.ANDROID_PIPELINE_WORKERS.key) add(BooleanSetting.RENDERER_ASYNCHRONOUS_GPU_EMULATION.key) add(BooleanSetting.RENDERER_ASYNC_PRESENTATION.key) add(SettingsItem.GPU_UNSWIZZLE_COMBINED) diff --git a/src/android/app/src/main/jni/android_settings.h b/src/android/app/src/main/jni/android_settings.h index 37da651519..304ff62f07 100644 --- a/src/android/app/src/main/jni/android_settings.h +++ b/src/android/app/src/main/jni/android_settings.h @@ -147,6 +147,13 @@ namespace AndroidSettings { &show_performance_overlay}; + Settings::Setting pipeline_worker_count{linkage, 4, "pipeline_worker_count", + Settings::Category::Android, + Settings::Specialization::Default, + true, + true}; + + Settings::Setting show_input_overlay{linkage, true, "show_input_overlay", Settings::Category::Overlay}; Settings::Setting overlay_snap_to_grid{linkage, false, "overlay_snap_to_grid", diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 7cdce5339f..7372fa5e34 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -71,6 +71,8 @@ Display current power draw and remaining capacity on battery Show Shaders Building Display current number of shaders being built + Pipeline Worker Threads + Manage the amount of cores used for building Vulkan pipelines, the higher value will improve pipeline compilation performance but temperatures will increase as well. Overlay Position Choose where the overlay is displayed on the screen Top Left @@ -491,15 +493,15 @@ Force maximum clocks (Adreno only) Forces the GPU to run at the maximum possible clocks (thermal constraints will still be applied). GPU async emulation - Runs GPU emulation asynchronously to reduce CPU stalls and improve throughput. Disable this only if you run into timing-related issues. + This hack can increase performance by running GPU emulation asynchronously at the cost of graphical issues and increased crash rates by timing-related operations. Asynchronous presentation - Slightly improves performance by moving presentation to a separate CPU thread. + This hack can increase performance by moving presentation to a separate CPU thread at the cost of graphical issues. Use reactive flushing Improves rendering accuracy in some games at the cost of performance. Enable buffer history Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games. Optimized Vertex Buffers - Enables optimized vertex buffer binding for improved performance. Requires Mesa 26.0+ Turnip drivers/ QCOM drivers. Will crash on older Turnip drivers. + Enables optimized vertex buffer binding for improved performance. Requires Mesa 26.0+ Turnip drivers/ QCOM drivers. Will crash on older Turnip drivers (25.3 and below). Hacks @@ -531,10 +533,10 @@ Extensions Extended Dynamic State - Controls the number of features that can be used in Extended Dynamic State. Higher numbers allow for more features and can increase performance, but may cause issues with some drivers and vendors. + Controls the number of features that can be used in ExtendedDynamicState (EDS). The higher value will allow to reduce the amount of pipeline compilations based on the dynamic state supported by driver. Disabled Vertex Input Dynamic State - Enables vertex input dynamic state feature for better quality and performance. + Enabling this feature allows for more flexible vertex input handling, potentially reducing pipeline compilation time in vertex/buffer. Sample Shading Allows the fragment shader to execute per sample in a multi-sampled fragment instead once per fragment. Improves graphics quality at the cost of some performance. diff --git a/src/common/settings.h b/src/common/settings.h index d9e1f09dcc..4a6b756ed3 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -389,7 +389,7 @@ struct Values { true}; SwitchableSetting use_asynchronous_gpu_emulation{ - linkage, true, "use_asynchronous_gpu_emulation", Category::Renderer}; + linkage, false, "use_asynchronous_gpu_emulation", Category::Renderer}; // *nix platforms may have issues with the borderless windowed fullscreen mode. // Default to exclusive fullscreen on these platforms for now. SwitchableSetting fullscreen_mode{linkage, @@ -542,7 +542,7 @@ struct Values { true}; SwitchableSetting async_presentation{linkage, #ifdef ANDROID - true, + false, #else false, #endif @@ -609,7 +609,7 @@ struct Values { #if defined (ANDROID) false, #else - true, + false, #endif "vertex_input_dynamic_state", Category::RendererExtensions}; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index e365425600..d3a98f1a1c 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -45,6 +45,10 @@ #include "video_core/vulkan_common/vulkan_wrapper.h" #include "video_core/gpu_logging/gpu_logging.h" +#ifdef ANDROID +#include "../../android/app/src/main/jni/android_settings.h" +#endif + namespace Vulkan { namespace { @@ -325,13 +329,13 @@ size_t GetTotalPipelineWorkers() { const size_t max_core_threads = std::max(static_cast(std::thread::hardware_concurrency()), 2ULL) - 1ULL; #ifdef ANDROID - // Leave at least one core free on Android. Previously we reserved two, but - // shipping builds benefit from one extra compilation worker. - constexpr size_t free_cores = 1ULL; - if (max_core_threads <= free_cores) { + const int configured = AndroidSettings::values.pipeline_worker_count.GetValue(); + const int clamped = std::clamp(configured, 4, 8); + const size_t desired = static_cast(clamped); + if (desired == 0) { return 1ULL; } - return max_core_threads - free_cores; + return std::min(max_core_threads, desired); #else return max_core_threads; #endif @@ -426,13 +430,12 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, driver_id == VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA, .has_broken_spirv_clamp = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS, - .has_broken_spirv_position_input = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY, + .has_broken_spirv_position_input = driver_id == false, .has_broken_unsigned_image_offsets = false, .has_broken_signed_operations = false, .has_broken_fp16_float_controls = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY, .ignore_nan_fp_comparisons = false, - .has_broken_spirv_subgroup_mask_vector_extract_dynamic = - driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY, + .has_broken_spirv_subgroup_mask_vector_extract_dynamic = false, .has_broken_robust = device.IsNvidia() && device.GetNvidiaArch() <= NvidiaArchitecture::Arch_Pascal, .min_ssbo_alignment = device.GetStorageBufferAlignment(),