summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/CMakeLists.txt68
-rw-r--r--src/common/logging/filter.cpp4
-rw-r--r--src/common/logging/types.h4
-rw-r--r--src/common/scm_rev.cpp.in2
-rw-r--r--src/common/settings.cpp8
-rw-r--r--src/common/settings.h34
-rw-r--r--src/common/thread_worker.cpp58
-rw-r--r--src/common/thread_worker.h103
-rw-r--r--src/common/unique_function.h62
-rw-r--r--src/common/uuid.h5
10 files changed, 197 insertions, 151 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index a6fa9a85d..57922b51c 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -1,8 +1,3 @@
1# Add a custom command to generate a new shader_cache_version hash when any of the following files change
2# NOTE: This is an approximation of what files affect shader generation, its possible something else
3# could affect the result, but much more unlikely than the following files. Keeping a list of files
4# like this allows for much better caching since it doesn't force the user to recompile binary shaders every update
5set(VIDEO_CORE "${CMAKE_SOURCE_DIR}/src/video_core")
6if (DEFINED ENV{AZURECIREPO}) 1if (DEFINED ENV{AZURECIREPO})
7 set(BUILD_REPOSITORY $ENV{AZURECIREPO}) 2 set(BUILD_REPOSITORY $ENV{AZURECIREPO})
8endif() 3endif()
@@ -30,64 +25,7 @@ add_custom_command(OUTPUT scm_rev.cpp
30 -DGIT_EXECUTABLE=${GIT_EXECUTABLE} 25 -DGIT_EXECUTABLE=${GIT_EXECUTABLE}
31 -P ${CMAKE_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake 26 -P ${CMAKE_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake
32 DEPENDS 27 DEPENDS
33 # WARNING! It was too much work to try and make a common location for this list, 28 # Check that the scm_rev files haven't changed
34 # so if you need to change it, please update CMakeModules/GenerateSCMRev.cmake as well
35 "${VIDEO_CORE}/renderer_opengl/gl_arb_decompiler.cpp"
36 "${VIDEO_CORE}/renderer_opengl/gl_arb_decompiler.h"
37 "${VIDEO_CORE}/renderer_opengl/gl_shader_cache.cpp"
38 "${VIDEO_CORE}/renderer_opengl/gl_shader_cache.h"
39 "${VIDEO_CORE}/renderer_opengl/gl_shader_decompiler.cpp"
40 "${VIDEO_CORE}/renderer_opengl/gl_shader_decompiler.h"
41 "${VIDEO_CORE}/renderer_opengl/gl_shader_disk_cache.cpp"
42 "${VIDEO_CORE}/renderer_opengl/gl_shader_disk_cache.h"
43 "${VIDEO_CORE}/shader/decode/arithmetic.cpp"
44 "${VIDEO_CORE}/shader/decode/arithmetic_half.cpp"
45 "${VIDEO_CORE}/shader/decode/arithmetic_half_immediate.cpp"
46 "${VIDEO_CORE}/shader/decode/arithmetic_immediate.cpp"
47 "${VIDEO_CORE}/shader/decode/arithmetic_integer.cpp"
48 "${VIDEO_CORE}/shader/decode/arithmetic_integer_immediate.cpp"
49 "${VIDEO_CORE}/shader/decode/bfe.cpp"
50 "${VIDEO_CORE}/shader/decode/bfi.cpp"
51 "${VIDEO_CORE}/shader/decode/conversion.cpp"
52 "${VIDEO_CORE}/shader/decode/ffma.cpp"
53 "${VIDEO_CORE}/shader/decode/float_set.cpp"
54 "${VIDEO_CORE}/shader/decode/float_set_predicate.cpp"
55 "${VIDEO_CORE}/shader/decode/half_set.cpp"
56 "${VIDEO_CORE}/shader/decode/half_set_predicate.cpp"
57 "${VIDEO_CORE}/shader/decode/hfma2.cpp"
58 "${VIDEO_CORE}/shader/decode/image.cpp"
59 "${VIDEO_CORE}/shader/decode/integer_set.cpp"
60 "${VIDEO_CORE}/shader/decode/integer_set_predicate.cpp"
61 "${VIDEO_CORE}/shader/decode/memory.cpp"
62 "${VIDEO_CORE}/shader/decode/texture.cpp"
63 "${VIDEO_CORE}/shader/decode/other.cpp"
64 "${VIDEO_CORE}/shader/decode/predicate_set_predicate.cpp"
65 "${VIDEO_CORE}/shader/decode/predicate_set_register.cpp"
66 "${VIDEO_CORE}/shader/decode/register_set_predicate.cpp"
67 "${VIDEO_CORE}/shader/decode/shift.cpp"
68 "${VIDEO_CORE}/shader/decode/video.cpp"
69 "${VIDEO_CORE}/shader/decode/warp.cpp"
70 "${VIDEO_CORE}/shader/decode/xmad.cpp"
71 "${VIDEO_CORE}/shader/ast.cpp"
72 "${VIDEO_CORE}/shader/ast.h"
73 "${VIDEO_CORE}/shader/compiler_settings.cpp"
74 "${VIDEO_CORE}/shader/compiler_settings.h"
75 "${VIDEO_CORE}/shader/control_flow.cpp"
76 "${VIDEO_CORE}/shader/control_flow.h"
77 "${VIDEO_CORE}/shader/decode.cpp"
78 "${VIDEO_CORE}/shader/expr.cpp"
79 "${VIDEO_CORE}/shader/expr.h"
80 "${VIDEO_CORE}/shader/node.h"
81 "${VIDEO_CORE}/shader/node_helper.cpp"
82 "${VIDEO_CORE}/shader/node_helper.h"
83 "${VIDEO_CORE}/shader/registry.cpp"
84 "${VIDEO_CORE}/shader/registry.h"
85 "${VIDEO_CORE}/shader/shader_ir.cpp"
86 "${VIDEO_CORE}/shader/shader_ir.h"
87 "${VIDEO_CORE}/shader/track.cpp"
88 "${VIDEO_CORE}/shader/transform_feedback.cpp"
89 "${VIDEO_CORE}/shader/transform_feedback.h"
90 # and also check that the scm_rev files haven't changed
91 "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in" 29 "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in"
92 "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.h" 30 "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.h"
93 # technically we should regenerate if the git version changed, but its not worth the effort imo 31 # technically we should regenerate if the git version changed, but its not worth the effort imo
@@ -180,7 +118,6 @@ add_library(common STATIC
180 thread.cpp 118 thread.cpp
181 thread.h 119 thread.h
182 thread_queue_list.h 120 thread_queue_list.h
183 thread_worker.cpp
184 thread_worker.h 121 thread_worker.h
185 threadsafe_queue.h 122 threadsafe_queue.h
186 time_zone.cpp 123 time_zone.cpp
@@ -188,6 +125,7 @@ add_library(common STATIC
188 tiny_mt.h 125 tiny_mt.h
189 tree.h 126 tree.h
190 uint128.h 127 uint128.h
128 unique_function.h
191 uuid.cpp 129 uuid.cpp
192 uuid.h 130 uuid.h
193 vector_math.h 131 vector_math.h
@@ -231,7 +169,7 @@ endif()
231 169
232create_target_directory_groups(common) 170create_target_directory_groups(common)
233 171
234target_link_libraries(common PUBLIC ${Boost_LIBRARIES} fmt::fmt microprofile) 172target_link_libraries(common PUBLIC ${Boost_LIBRARIES} fmt::fmt microprofile Threads::Threads)
235target_link_libraries(common PRIVATE lz4::lz4 xbyak) 173target_link_libraries(common PRIVATE lz4::lz4 xbyak)
236if (MSVC) 174if (MSVC)
237 target_link_libraries(common PRIVATE zstd::zstd) 175 target_link_libraries(common PRIVATE zstd::zstd)
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp
index 4f2cc29e1..f055f0e11 100644
--- a/src/common/logging/filter.cpp
+++ b/src/common/logging/filter.cpp
@@ -144,6 +144,10 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
144 SUB(Render, Software) \ 144 SUB(Render, Software) \
145 SUB(Render, OpenGL) \ 145 SUB(Render, OpenGL) \
146 SUB(Render, Vulkan) \ 146 SUB(Render, Vulkan) \
147 CLS(Shader) \
148 SUB(Shader, SPIRV) \
149 SUB(Shader, GLASM) \
150 SUB(Shader, GLSL) \
147 CLS(Audio) \ 151 CLS(Audio) \
148 SUB(Audio, DSP) \ 152 SUB(Audio, DSP) \
149 SUB(Audio, Sink) \ 153 SUB(Audio, Sink) \
diff --git a/src/common/logging/types.h b/src/common/logging/types.h
index 88b0e9c01..7ad0334fc 100644
--- a/src/common/logging/types.h
+++ b/src/common/logging/types.h
@@ -114,6 +114,10 @@ enum class Class : u8 {
114 Render_Software, ///< Software renderer backend 114 Render_Software, ///< Software renderer backend
115 Render_OpenGL, ///< OpenGL backend 115 Render_OpenGL, ///< OpenGL backend
116 Render_Vulkan, ///< Vulkan backend 116 Render_Vulkan, ///< Vulkan backend
117 Shader, ///< Shader recompiler
118 Shader_SPIRV, ///< Shader SPIR-V code generation
119 Shader_GLASM, ///< Shader GLASM code generation
120 Shader_GLSL, ///< Shader GLSL code generation
117 Audio, ///< Audio emulation 121 Audio, ///< Audio emulation
118 Audio_DSP, ///< The HLE implementation of the DSP 122 Audio_DSP, ///< The HLE implementation of the DSP
119 Audio_Sink, ///< Emulator audio output backend 123 Audio_Sink, ///< Emulator audio output backend
diff --git a/src/common/scm_rev.cpp.in b/src/common/scm_rev.cpp.in
index 5f126f324..cc88994c6 100644
--- a/src/common/scm_rev.cpp.in
+++ b/src/common/scm_rev.cpp.in
@@ -14,7 +14,6 @@
14#define BUILD_ID "@BUILD_ID@" 14#define BUILD_ID "@BUILD_ID@"
15#define TITLE_BAR_FORMAT_IDLE "@TITLE_BAR_FORMAT_IDLE@" 15#define TITLE_BAR_FORMAT_IDLE "@TITLE_BAR_FORMAT_IDLE@"
16#define TITLE_BAR_FORMAT_RUNNING "@TITLE_BAR_FORMAT_RUNNING@" 16#define TITLE_BAR_FORMAT_RUNNING "@TITLE_BAR_FORMAT_RUNNING@"
17#define SHADER_CACHE_VERSION "@SHADER_CACHE_VERSION@"
18 17
19namespace Common { 18namespace Common {
20 19
@@ -28,7 +27,6 @@ const char g_build_version[] = BUILD_VERSION;
28const char g_build_id[] = BUILD_ID; 27const char g_build_id[] = BUILD_ID;
29const char g_title_bar_format_idle[] = TITLE_BAR_FORMAT_IDLE; 28const char g_title_bar_format_idle[] = TITLE_BAR_FORMAT_IDLE;
30const char g_title_bar_format_running[] = TITLE_BAR_FORMAT_RUNNING; 29const char g_title_bar_format_running[] = TITLE_BAR_FORMAT_RUNNING;
31const char g_shader_cache_version[] = SHADER_CACHE_VERSION;
32 30
33} // namespace 31} // namespace
34 32
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 0061e29cc..66268ea0f 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -57,7 +57,7 @@ void LogSettings() {
57 log_setting("Renderer_UseNvdecEmulation", values.use_nvdec_emulation.GetValue()); 57 log_setting("Renderer_UseNvdecEmulation", values.use_nvdec_emulation.GetValue());
58 log_setting("Renderer_AccelerateASTC", values.accelerate_astc.GetValue()); 58 log_setting("Renderer_AccelerateASTC", values.accelerate_astc.GetValue());
59 log_setting("Renderer_UseVsync", values.use_vsync.GetValue()); 59 log_setting("Renderer_UseVsync", values.use_vsync.GetValue());
60 log_setting("Renderer_UseAssemblyShaders", values.use_assembly_shaders.GetValue()); 60 log_setting("Renderer_ShaderBackend", values.shader_backend.GetValue());
61 log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue()); 61 log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue());
62 log_setting("Renderer_UseGarbageCollection", values.use_caches_gc.GetValue()); 62 log_setting("Renderer_UseGarbageCollection", values.use_caches_gc.GetValue());
63 log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue()); 63 log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue());
@@ -93,7 +93,7 @@ bool IsGPULevelHigh() {
93} 93}
94 94
95bool IsFastmemEnabled() { 95bool IsFastmemEnabled() {
96 if (values.cpu_accuracy.GetValue() == CPUAccuracy::DebugMode) { 96 if (values.cpu_debug_mode) {
97 return static_cast<bool>(values.cpuopt_fastmem); 97 return static_cast<bool>(values.cpuopt_fastmem);
98 } 98 }
99 return true; 99 return true;
@@ -103,7 +103,7 @@ float Volume() {
103 if (values.audio_muted) { 103 if (values.audio_muted) {
104 return 0.0f; 104 return 0.0f;
105 } 105 }
106 return values.volume.GetValue(); 106 return values.volume.GetValue() / 100.0f;
107} 107}
108 108
109void RestoreGlobalState(bool is_powered_on) { 109void RestoreGlobalState(bool is_powered_on) {
@@ -140,7 +140,7 @@ void RestoreGlobalState(bool is_powered_on) {
140 values.use_nvdec_emulation.SetGlobal(true); 140 values.use_nvdec_emulation.SetGlobal(true);
141 values.accelerate_astc.SetGlobal(true); 141 values.accelerate_astc.SetGlobal(true);
142 values.use_vsync.SetGlobal(true); 142 values.use_vsync.SetGlobal(true);
143 values.use_assembly_shaders.SetGlobal(true); 143 values.shader_backend.SetGlobal(true);
144 values.use_asynchronous_shaders.SetGlobal(true); 144 values.use_asynchronous_shaders.SetGlobal(true);
145 values.use_fast_gpu_time.SetGlobal(true); 145 values.use_fast_gpu_time.SetGlobal(true);
146 values.use_caches_gc.SetGlobal(true); 146 values.use_caches_gc.SetGlobal(true);
diff --git a/src/common/settings.h b/src/common/settings.h
index bf83186f5..32dfb1d9f 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -24,6 +24,12 @@ enum class RendererBackend : u32 {
24 Vulkan = 1, 24 Vulkan = 1,
25}; 25};
26 26
27enum class ShaderBackend : u32 {
28 GLSL = 0,
29 GLASM = 1,
30 SPIRV = 2,
31};
32
27enum class GPUAccuracy : u32 { 33enum class GPUAccuracy : u32 {
28 Normal = 0, 34 Normal = 0,
29 High = 1, 35 High = 1,
@@ -31,9 +37,9 @@ enum class GPUAccuracy : u32 {
31}; 37};
32 38
33enum class CPUAccuracy : u32 { 39enum class CPUAccuracy : u32 {
34 Accurate = 0, 40 Auto = 0,
35 Unsafe = 1, 41 Accurate = 1,
36 DebugMode = 2, 42 Unsafe = 2,
37}; 43};
38 44
39/** The BasicSetting class is a simple resource manager. It defines a label and default value 45/** The BasicSetting class is a simple resource manager. It defines a label and default value
@@ -278,13 +284,16 @@ struct Values {
278 BasicSetting<std::string> sink_id{"auto", "output_engine"}; 284 BasicSetting<std::string> sink_id{"auto", "output_engine"};
279 BasicSetting<bool> audio_muted{false, "audio_muted"}; 285 BasicSetting<bool> audio_muted{false, "audio_muted"};
280 Setting<bool> enable_audio_stretching{true, "enable_audio_stretching"}; 286 Setting<bool> enable_audio_stretching{true, "enable_audio_stretching"};
281 Setting<float> volume{1.0f, "volume"}; 287 Setting<u8> volume{100, "volume"};
282 288
283 // Core 289 // Core
284 Setting<bool> use_multi_core{true, "use_multi_core"}; 290 Setting<bool> use_multi_core{true, "use_multi_core"};
285 291
286 // Cpu 292 // Cpu
287 Setting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Accurate, "cpu_accuracy"}; 293 Setting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Auto, "cpu_accuracy"};
294 // TODO: remove cpu_accuracy_first_time, migration setting added 8 July 2021
295 BasicSetting<bool> cpu_accuracy_first_time{true, "cpu_accuracy_first_time"};
296 BasicSetting<bool> cpu_debug_mode{false, "cpu_debug_mode"};
288 297
289 BasicSetting<bool> cpuopt_page_tables{true, "cpuopt_page_tables"}; 298 BasicSetting<bool> cpuopt_page_tables{true, "cpuopt_page_tables"};
290 BasicSetting<bool> cpuopt_block_linking{true, "cpuopt_block_linking"}; 299 BasicSetting<bool> cpuopt_block_linking{true, "cpuopt_block_linking"};
@@ -305,6 +314,9 @@ struct Values {
305 // Renderer 314 // Renderer
306 Setting<RendererBackend> renderer_backend{RendererBackend::OpenGL, "backend"}; 315 Setting<RendererBackend> renderer_backend{RendererBackend::OpenGL, "backend"};
307 BasicSetting<bool> renderer_debug{false, "debug"}; 316 BasicSetting<bool> renderer_debug{false, "debug"};
317 BasicSetting<bool> enable_nsight_aftermath{false, "nsight_aftermath"};
318 BasicSetting<bool> disable_shader_loop_safety_checks{false,
319 "disable_shader_loop_safety_checks"};
308 Setting<int> vulkan_device{0, "vulkan_device"}; 320 Setting<int> vulkan_device{0, "vulkan_device"};
309 321
310 Setting<u16> resolution_factor{1, "resolution_factor"}; 322 Setting<u16> resolution_factor{1, "resolution_factor"};
@@ -327,15 +339,15 @@ struct Values {
327 Setting<bool> use_nvdec_emulation{true, "use_nvdec_emulation"}; 339 Setting<bool> use_nvdec_emulation{true, "use_nvdec_emulation"};
328 Setting<bool> accelerate_astc{true, "accelerate_astc"}; 340 Setting<bool> accelerate_astc{true, "accelerate_astc"};
329 Setting<bool> use_vsync{true, "use_vsync"}; 341 Setting<bool> use_vsync{true, "use_vsync"};
330 Setting<bool> disable_fps_limit{false, "disable_fps_limit"}; 342 BasicSetting<bool> disable_fps_limit{false, "disable_fps_limit"};
331 Setting<bool> use_assembly_shaders{false, "use_assembly_shaders"}; 343 Setting<ShaderBackend> shader_backend{ShaderBackend::GLASM, "shader_backend"};
332 Setting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"}; 344 Setting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"};
333 Setting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"}; 345 Setting<bool> use_fast_gpu_time{true, "use_fast_gpu_time"};
334 Setting<bool> use_caches_gc{false, "use_caches_gc"}; 346 Setting<bool> use_caches_gc{false, "use_caches_gc"};
335 347
336 Setting<float> bg_red{0.0f, "bg_red"}; 348 Setting<u8> bg_red{0, "bg_red"};
337 Setting<float> bg_green{0.0f, "bg_green"}; 349 Setting<u8> bg_green{0, "bg_green"};
338 Setting<float> bg_blue{0.0f, "bg_blue"}; 350 Setting<u8> bg_blue{0, "bg_blue"};
339 351
340 // System 352 // System
341 Setting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"}; 353 Setting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"};
@@ -365,7 +377,7 @@ struct Values {
365 "udp_input_servers"}; 377 "udp_input_servers"};
366 378
367 BasicSetting<bool> mouse_panning{false, "mouse_panning"}; 379 BasicSetting<bool> mouse_panning{false, "mouse_panning"};
368 BasicSetting<float> mouse_panning_sensitivity{1.0f, "mouse_panning_sensitivity"}; 380 BasicSetting<u8> mouse_panning_sensitivity{10, "mouse_panning_sensitivity"};
369 BasicSetting<bool> mouse_enabled{false, "mouse_enabled"}; 381 BasicSetting<bool> mouse_enabled{false, "mouse_enabled"};
370 std::string mouse_device; 382 std::string mouse_device;
371 MouseButtonsRaw mouse_buttons; 383 MouseButtonsRaw mouse_buttons;
diff --git a/src/common/thread_worker.cpp b/src/common/thread_worker.cpp
deleted file mode 100644
index 8f9bf447a..000000000
--- a/src/common/thread_worker.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/thread.h"
6#include "common/thread_worker.h"
7
8namespace Common {
9
10ThreadWorker::ThreadWorker(std::size_t num_workers, const std::string& name) {
11 for (std::size_t i = 0; i < num_workers; ++i)
12 threads.emplace_back([this, thread_name{std::string{name}}] {
13 Common::SetCurrentThreadName(thread_name.c_str());
14
15 // Wait for first request
16 {
17 std::unique_lock lock{queue_mutex};
18 condition.wait(lock, [this] { return stop || !requests.empty(); });
19 }
20
21 while (true) {
22 std::function<void()> task;
23
24 {
25 std::unique_lock lock{queue_mutex};
26 condition.wait(lock, [this] { return stop || !requests.empty(); });
27 if (stop || requests.empty()) {
28 return;
29 }
30 task = std::move(requests.front());
31 requests.pop();
32 }
33
34 task();
35 }
36 });
37}
38
39ThreadWorker::~ThreadWorker() {
40 {
41 std::unique_lock lock{queue_mutex};
42 stop = true;
43 }
44 condition.notify_all();
45 for (std::thread& thread : threads) {
46 thread.join();
47 }
48}
49
50void ThreadWorker::QueueWork(std::function<void()>&& work) {
51 {
52 std::unique_lock lock{queue_mutex};
53 requests.emplace(work);
54 }
55 condition.notify_one();
56}
57
58} // namespace Common
diff --git a/src/common/thread_worker.h b/src/common/thread_worker.h
index f1859971f..cd0017726 100644
--- a/src/common/thread_worker.h
+++ b/src/common/thread_worker.h
@@ -5,26 +5,113 @@
5#pragma once 5#pragma once
6 6
7#include <atomic> 7#include <atomic>
8#include <condition_variable>
8#include <functional> 9#include <functional>
9#include <mutex> 10#include <mutex>
11#include <stop_token>
10#include <string> 12#include <string>
13#include <thread>
14#include <type_traits>
11#include <vector> 15#include <vector>
12#include <queue> 16#include <queue>
13 17
18#include "common/thread.h"
19#include "common/unique_function.h"
20
14namespace Common { 21namespace Common {
15 22
16class ThreadWorker final { 23template <class StateType = void>
24class StatefulThreadWorker {
25 static constexpr bool with_state = !std::is_same_v<StateType, void>;
26
27 struct DummyCallable {
28 int operator()() const noexcept {
29 return 0;
30 }
31 };
32
33 using Task =
34 std::conditional_t<with_state, UniqueFunction<void, StateType*>, UniqueFunction<void>>;
35 using StateMaker = std::conditional_t<with_state, std::function<StateType()>, DummyCallable>;
36
17public: 37public:
18 explicit ThreadWorker(std::size_t num_workers, const std::string& name); 38 explicit StatefulThreadWorker(size_t num_workers, std::string name, StateMaker func = {})
19 ~ThreadWorker(); 39 : workers_queued{num_workers}, thread_name{std::move(name)} {
20 void QueueWork(std::function<void()>&& work); 40 const auto lambda = [this, func](std::stop_token stop_token) {
41 Common::SetCurrentThreadName(thread_name.c_str());
42 {
43 [[maybe_unused]] std::conditional_t<with_state, StateType, int> state{func()};
44 while (!stop_token.stop_requested()) {
45 Task task;
46 {
47 std::unique_lock lock{queue_mutex};
48 if (requests.empty()) {
49 wait_condition.notify_all();
50 }
51 condition.wait(lock, stop_token, [this] { return !requests.empty(); });
52 if (stop_token.stop_requested()) {
53 break;
54 }
55 task = std::move(requests.front());
56 requests.pop();
57 }
58 if constexpr (with_state) {
59 task(&state);
60 } else {
61 task();
62 }
63 ++work_done;
64 }
65 }
66 ++workers_stopped;
67 wait_condition.notify_all();
68 };
69 threads.reserve(num_workers);
70 for (size_t i = 0; i < num_workers; ++i) {
71 threads.emplace_back(lambda);
72 }
73 }
74
75 StatefulThreadWorker& operator=(const StatefulThreadWorker&) = delete;
76 StatefulThreadWorker(const StatefulThreadWorker&) = delete;
77
78 StatefulThreadWorker& operator=(StatefulThreadWorker&&) = delete;
79 StatefulThreadWorker(StatefulThreadWorker&&) = delete;
80
81 void QueueWork(Task work) {
82 {
83 std::unique_lock lock{queue_mutex};
84 requests.emplace(std::move(work));
85 ++work_scheduled;
86 }
87 condition.notify_one();
88 }
89
90 void WaitForRequests(std::stop_token stop_token = {}) {
91 std::stop_callback callback(stop_token, [this] {
92 for (auto& thread : threads) {
93 thread.request_stop();
94 }
95 });
96 std::unique_lock lock{queue_mutex};
97 wait_condition.wait(lock, [this] {
98 return workers_stopped >= workers_queued || work_done >= work_scheduled;
99 });
100 }
21 101
22private: 102private:
23 std::vector<std::thread> threads; 103 std::queue<Task> requests;
24 std::queue<std::function<void()>> requests;
25 std::mutex queue_mutex; 104 std::mutex queue_mutex;
26 std::condition_variable condition; 105 std::condition_variable_any condition;
27 std::atomic_bool stop{}; 106 std::condition_variable wait_condition;
107 std::atomic<size_t> work_scheduled{};
108 std::atomic<size_t> work_done{};
109 std::atomic<size_t> workers_stopped{};
110 std::atomic<size_t> workers_queued{};
111 std::string thread_name;
112 std::vector<std::jthread> threads;
28}; 113};
29 114
115using ThreadWorker = StatefulThreadWorker<>;
116
30} // namespace Common 117} // namespace Common
diff --git a/src/common/unique_function.h b/src/common/unique_function.h
new file mode 100644
index 000000000..ca0559071
--- /dev/null
+++ b/src/common/unique_function.h
@@ -0,0 +1,62 @@
1// Copyright 2021 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <utility>
9
10namespace Common {
11
12/// General purpose function wrapper similar to std::function.
13/// Unlike std::function, the captured values don't have to be copyable.
14/// This class can be moved but not copied.
15template <typename ResultType, typename... Args>
16class UniqueFunction {
17 class CallableBase {
18 public:
19 virtual ~CallableBase() = default;
20 virtual ResultType operator()(Args&&...) = 0;
21 };
22
23 template <typename Functor>
24 class Callable final : public CallableBase {
25 public:
26 Callable(Functor&& functor_) : functor{std::move(functor_)} {}
27 ~Callable() override = default;
28
29 ResultType operator()(Args&&... args) override {
30 return functor(std::forward<Args>(args)...);
31 }
32
33 private:
34 Functor functor;
35 };
36
37public:
38 UniqueFunction() = default;
39
40 template <typename Functor>
41 UniqueFunction(Functor&& functor)
42 : callable{std::make_unique<Callable<Functor>>(std::move(functor))} {}
43
44 UniqueFunction& operator=(UniqueFunction&& rhs) noexcept = default;
45 UniqueFunction(UniqueFunction&& rhs) noexcept = default;
46
47 UniqueFunction& operator=(const UniqueFunction&) = delete;
48 UniqueFunction(const UniqueFunction&) = delete;
49
50 ResultType operator()(Args&&... args) const {
51 return (*callable)(std::forward<Args>(args)...);
52 }
53
54 explicit operator bool() const noexcept {
55 return static_cast<bool>(callable);
56 }
57
58private:
59 std::unique_ptr<CallableBase> callable;
60};
61
62} // namespace Common
diff --git a/src/common/uuid.h b/src/common/uuid.h
index 2e7a18405..0ffa37e7c 100644
--- a/src/common/uuid.h
+++ b/src/common/uuid.h
@@ -20,12 +20,11 @@ struct UUID {
20 constexpr explicit UUID(const u64 lo, const u64 hi) : uuid{{lo, hi}} {} 20 constexpr explicit UUID(const u64 lo, const u64 hi) : uuid{{lo, hi}} {}
21 21
22 [[nodiscard]] constexpr explicit operator bool() const { 22 [[nodiscard]] constexpr explicit operator bool() const {
23 return uuid[0] != INVALID_UUID[0] && uuid[1] != INVALID_UUID[1]; 23 return uuid != INVALID_UUID;
24 } 24 }
25 25
26 [[nodiscard]] constexpr bool operator==(const UUID& rhs) const { 26 [[nodiscard]] constexpr bool operator==(const UUID& rhs) const {
27 // TODO(DarkLordZach): Replace with uuid == rhs.uuid with C++20 27 return uuid == rhs.uuid;
28 return uuid[0] == rhs.uuid[0] && uuid[1] == rhs.uuid[1];
29 } 28 }
30 29
31 [[nodiscard]] constexpr bool operator!=(const UUID& rhs) const { 30 [[nodiscard]] constexpr bool operator!=(const UUID& rhs) const {