summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ameerj2020-08-02 13:05:41 -0400
committerGravatar ameerj2020-08-16 12:02:22 -0400
commit31a76410e8fa09462d960c10148c075125dc385a (patch)
treea5e45c1f609cdf7d4537d1215699e741a469ba17 /src
parentVk Async Worker directly emplace in cache (diff)
downloadyuzu-31a76410e8fa09462d960c10148c075125dc385a.tar.gz
yuzu-31a76410e8fa09462d960c10148c075125dc385a.tar.xz
yuzu-31a76410e8fa09462d960c10148c075125dc385a.zip
Address feedback, add shader compile notifier, update setting text
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_vulkan/vk_device.h5
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp9
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.h30
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp23
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.h58
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp19
-rw-r--r--src/video_core/shader/async_shaders.cpp110
-rw-r--r--src/video_core/shader/async_shaders.h23
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.ui2
9 files changed, 117 insertions, 162 deletions
diff --git a/src/video_core/renderer_vulkan/vk_device.h b/src/video_core/renderer_vulkan/vk_device.h
index 30cd3e189..26a233db1 100644
--- a/src/video_core/renderer_vulkan/vk_device.h
+++ b/src/video_core/renderer_vulkan/vk_device.h
@@ -202,6 +202,7 @@ public:
202 return reported_extensions; 202 return reported_extensions;
203 } 203 }
204 204
205 /// Returns true if the setting for async shader compilation is enabled.
205 bool UseAsynchronousShaders() const { 206 bool UseAsynchronousShaders() const {
206 return use_asynchronous_shaders; 207 return use_asynchronous_shaders;
207 } 208 }
@@ -255,7 +256,9 @@ private:
255 bool ext_custom_border_color{}; ///< Support for VK_EXT_custom_border_color. 256 bool ext_custom_border_color{}; ///< Support for VK_EXT_custom_border_color.
256 bool ext_extended_dynamic_state{}; ///< Support for VK_EXT_extended_dynamic_state. 257 bool ext_extended_dynamic_state{}; ///< Support for VK_EXT_extended_dynamic_state.
257 bool nv_device_diagnostics_config{}; ///< Support for VK_NV_device_diagnostics_config. 258 bool nv_device_diagnostics_config{}; ///< Support for VK_NV_device_diagnostics_config.
258 bool use_asynchronous_shaders{}; 259
260 // Asynchronous Graphics Pipeline setting
261 bool use_asynchronous_shaders{}; ///< Setting to use asynchronous shaders/graphics pipeline
259 262
260 // Telemetry parameters 263 // Telemetry parameters
261 std::string vendor_name; ///< Device's driver name. 264 std::string vendor_name; ///< Device's driver name.
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index 7d51b9836..5dc4cd5af 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -78,14 +78,15 @@ VKGraphicsPipeline::VKGraphicsPipeline(const VKDevice& device, VKScheduler& sche
78 const GraphicsPipelineCacheKey& key, 78 const GraphicsPipelineCacheKey& key,
79 vk::Span<VkDescriptorSetLayoutBinding> bindings, 79 vk::Span<VkDescriptorSetLayoutBinding> bindings,
80 const SPIRVProgram& program) 80 const SPIRVProgram& program)
81 : device{device}, scheduler{scheduler}, fixed_state{key.fixed_state}, hash{key.Hash()}, 81 : device{device}, scheduler{scheduler}, hash{key.Hash()}, cache_key{key},
82 descriptor_set_layout{CreateDescriptorSetLayout(bindings)}, 82 descriptor_set_layout{CreateDescriptorSetLayout(bindings)},
83 descriptor_allocator{descriptor_pool, *descriptor_set_layout}, 83 descriptor_allocator{descriptor_pool, *descriptor_set_layout},
84 update_descriptor_queue{update_descriptor_queue}, layout{CreatePipelineLayout()}, 84 update_descriptor_queue{update_descriptor_queue}, layout{CreatePipelineLayout()},
85 descriptor_template{CreateDescriptorUpdateTemplate(program)}, modules{CreateShaderModules( 85 descriptor_template{CreateDescriptorUpdateTemplate(program)}, modules{CreateShaderModules(
86 program)}, 86 program)},
87 renderpass{renderpass_cache.GetRenderPass(key.renderpass_params)}, 87 renderpass{renderpass_cache.GetRenderPass(key.renderpass_params)}, pipeline{CreatePipeline(
88 pipeline{CreatePipeline(key.renderpass_params, program)}, m_key{key} {} 88 key.renderpass_params,
89 program)} {}
89 90
90VKGraphicsPipeline::~VKGraphicsPipeline() = default; 91VKGraphicsPipeline::~VKGraphicsPipeline() = default;
91 92
@@ -180,7 +181,7 @@ std::vector<vk::ShaderModule> VKGraphicsPipeline::CreateShaderModules(
180 181
181vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpass_params, 182vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpass_params,
182 const SPIRVProgram& program) const { 183 const SPIRVProgram& program) const {
183 const auto& state = fixed_state; 184 const auto& state = cache_key.fixed_state;
184 const auto& viewport_swizzles = state.viewport_swizzles; 185 const auto& viewport_swizzles = state.viewport_swizzles;
185 186
186 FixedPipelineState::DynamicState dynamic; 187 FixedPipelineState::DynamicState dynamic;
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
index d50bd347c..9d462db0a 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
@@ -19,7 +19,27 @@ namespace Vulkan {
19 19
20using Maxwell = Tegra::Engines::Maxwell3D::Regs; 20using Maxwell = Tegra::Engines::Maxwell3D::Regs;
21 21
22struct GraphicsPipelineCacheKey; 22struct GraphicsPipelineCacheKey {
23 RenderPassParams renderpass_params;
24 u32 padding;
25 std::array<GPUVAddr, Maxwell::MaxShaderProgram> shaders;
26 FixedPipelineState fixed_state;
27
28 std::size_t Hash() const noexcept;
29
30 bool operator==(const GraphicsPipelineCacheKey& rhs) const noexcept;
31
32 bool operator!=(const GraphicsPipelineCacheKey& rhs) const noexcept {
33 return !operator==(rhs);
34 }
35
36 std::size_t Size() const noexcept {
37 return sizeof(renderpass_params) + sizeof(padding) + sizeof(shaders) + fixed_state.Size();
38 }
39};
40static_assert(std::has_unique_object_representations_v<GraphicsPipelineCacheKey>);
41static_assert(std::is_trivially_copyable_v<GraphicsPipelineCacheKey>);
42static_assert(std::is_trivially_constructible_v<GraphicsPipelineCacheKey>);
23 43
24class VKDescriptorPool; 44class VKDescriptorPool;
25class VKDevice; 45class VKDevice;
@@ -54,8 +74,8 @@ public:
54 return renderpass; 74 return renderpass;
55 } 75 }
56 76
57 const GraphicsPipelineCacheKey& GetCacheKey() const { 77 GraphicsPipelineCacheKey GetCacheKey() const {
58 return m_key; 78 return cache_key;
59 } 79 }
60 80
61private: 81private:
@@ -74,8 +94,8 @@ private:
74 94
75 const VKDevice& device; 95 const VKDevice& device;
76 VKScheduler& scheduler; 96 VKScheduler& scheduler;
77 const FixedPipelineState fixed_state;
78 const u64 hash; 97 const u64 hash;
98 GraphicsPipelineCacheKey cache_key;
79 99
80 vk::DescriptorSetLayout descriptor_set_layout; 100 vk::DescriptorSetLayout descriptor_set_layout;
81 DescriptorAllocator descriptor_allocator; 101 DescriptorAllocator descriptor_allocator;
@@ -86,8 +106,6 @@ private:
86 106
87 VkRenderPass renderpass; 107 VkRenderPass renderpass;
88 vk::Pipeline pipeline; 108 vk::Pipeline pipeline;
89
90 const GraphicsPipelineCacheKey& m_key;
91}; 109};
92 110
93} // namespace Vulkan 111} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 1a8b2c62b..20ffbeb38 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -28,6 +28,7 @@
28#include "video_core/shader/compiler_settings.h" 28#include "video_core/shader/compiler_settings.h"
29#include "video_core/shader/memory_util.h" 29#include "video_core/shader/memory_util.h"
30#include "video_core/shader_cache.h" 30#include "video_core/shader_cache.h"
31#include "video_core/shader_notify.h"
31 32
32namespace Vulkan { 33namespace Vulkan {
33 34
@@ -214,27 +215,31 @@ VKGraphicsPipeline* VKPipelineCache::GetGraphicsPipeline(
214 } 215 }
215 last_graphics_key = key; 216 last_graphics_key = key;
216 217
217 if (device.UseAsynchronousShaders()) { 218 if (device.UseAsynchronousShaders() && async_shaders.IsShaderAsync(system.GPU())) {
218 std::unique_lock lock{pipeline_cache}; 219 std::unique_lock lock{pipeline_cache};
219 const auto [pair, is_cache_miss] = graphics_cache.try_emplace(key); 220 const auto [pair, is_cache_miss] = graphics_cache.try_emplace(key);
220 if (is_cache_miss) { 221 if (is_cache_miss) {
222 system.GPU().ShaderNotify().MarkSharderBuilding();
221 LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash()); 223 LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash());
222 const auto [program, bindings] = DecompileShaders(key.fixed_state); 224 const auto [program, bindings] = DecompileShaders(key.fixed_state);
223 async_shaders.QueueVulkanShader(this, bindings, program, key.renderpass_params, 225 async_shaders.QueueVulkanShader(this, device, scheduler, descriptor_pool,
224 key.padding, key.shaders, key.fixed_state); 226 update_descriptor_queue, renderpass_cache, bindings,
227 program, key);
225 } 228 }
226 last_graphics_pipeline = graphics_cache.at(key).get(); 229 last_graphics_pipeline = pair->second.get();
227 return last_graphics_pipeline; 230 return last_graphics_pipeline;
228 } 231 }
229 232
230 const auto [pair, is_cache_miss] = graphics_cache.try_emplace(key); 233 const auto [pair, is_cache_miss] = graphics_cache.try_emplace(key);
231 auto& entry = pair->second; 234 auto& entry = pair->second;
232 if (is_cache_miss) { 235 if (is_cache_miss) {
236 system.GPU().ShaderNotify().MarkSharderBuilding();
233 LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash()); 237 LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash());
234 const auto [program, bindings] = DecompileShaders(key.fixed_state); 238 const auto [program, bindings] = DecompileShaders(key.fixed_state);
235 entry = std::make_unique<VKGraphicsPipeline>(device, scheduler, descriptor_pool, 239 entry = std::make_unique<VKGraphicsPipeline>(device, scheduler, descriptor_pool,
236 update_descriptor_queue, renderpass_cache, key, 240 update_descriptor_queue, renderpass_cache, key,
237 bindings, program); 241 bindings, program);
242 system.GPU().ShaderNotify().MarkShaderComplete();
238 } 243 }
239 last_graphics_pipeline = entry.get(); 244 last_graphics_pipeline = entry.get();
240 return last_graphics_pipeline; 245 return last_graphics_pipeline;
@@ -294,14 +299,8 @@ VKComputePipeline& VKPipelineCache::GetComputePipeline(const ComputePipelineCach
294 299
295void VKPipelineCache::EmplacePipeline(std::unique_ptr<VKGraphicsPipeline> pipeline) { 300void VKPipelineCache::EmplacePipeline(std::unique_ptr<VKGraphicsPipeline> pipeline) {
296 std::unique_lock lock{pipeline_cache}; 301 std::unique_lock lock{pipeline_cache};
297 const auto [pair, is_cache_miss] = graphics_cache.try_emplace(pipeline->GetCacheKey()); 302 graphics_cache.at(pipeline->GetCacheKey()) = std::move(pipeline);
298 auto& entry = pair->second; 303 system.GPU().ShaderNotify().MarkShaderComplete();
299 if (entry) {
300 LOG_INFO(Render_Vulkan, "Pipeline already here 0x{:016X}", pipeline->GetCacheKey().Hash());
301 duplicates.push_back(std::move(pipeline));
302 } else {
303 entry = std::move(pipeline);
304 }
305} 304}
306 305
307void VKPipelineCache::OnShaderRemoval(Shader* shader) { 306void VKPipelineCache::OnShaderRemoval(Shader* shader) {
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
index 777ef2038..c04829e77 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
@@ -44,28 +44,6 @@ class VKUpdateDescriptorQueue;
44 44
45using Maxwell = Tegra::Engines::Maxwell3D::Regs; 45using Maxwell = Tegra::Engines::Maxwell3D::Regs;
46 46
47struct GraphicsPipelineCacheKey {
48 RenderPassParams renderpass_params;
49 u32 padding;
50 std::array<GPUVAddr, Maxwell::MaxShaderProgram> shaders;
51 FixedPipelineState fixed_state;
52
53 std::size_t Hash() const noexcept;
54
55 bool operator==(const GraphicsPipelineCacheKey& rhs) const noexcept;
56
57 bool operator!=(const GraphicsPipelineCacheKey& rhs) const noexcept {
58 return !operator==(rhs);
59 }
60
61 std::size_t Size() const noexcept {
62 return sizeof(renderpass_params) + sizeof(padding) + sizeof(shaders) + fixed_state.Size();
63 }
64};
65static_assert(std::has_unique_object_representations_v<GraphicsPipelineCacheKey>);
66static_assert(std::is_trivially_copyable_v<GraphicsPipelineCacheKey>);
67static_assert(std::is_trivially_constructible_v<GraphicsPipelineCacheKey>);
68
69struct ComputePipelineCacheKey { 47struct ComputePipelineCacheKey {
70 GPUVAddr shader; 48 GPUVAddr shader;
71 u32 shared_memory_size; 49 u32 shared_memory_size;
@@ -158,41 +136,6 @@ public:
158 136
159 VKComputePipeline& GetComputePipeline(const ComputePipelineCacheKey& key); 137 VKComputePipeline& GetComputePipeline(const ComputePipelineCacheKey& key);
160 138
161 const VKDevice& GetDevice() const {
162 return device;
163 }
164
165 VKScheduler& GetScheduler() {
166 return scheduler;
167 }
168 const VKScheduler& GetScheduler() const {
169 return scheduler;
170 }
171
172 VKDescriptorPool& GetDescriptorPool() {
173 return descriptor_pool;
174 }
175
176 const VKDescriptorPool& GetDescriptorPool() const {
177 return descriptor_pool;
178 }
179
180 VKUpdateDescriptorQueue& GetUpdateDescriptorQueue() {
181 return update_descriptor_queue;
182 }
183
184 const VKUpdateDescriptorQueue& GetUpdateDescriptorQueue() const {
185 return update_descriptor_queue;
186 }
187
188 VKRenderPassCache& GetRenderpassCache() {
189 return renderpass_cache;
190 }
191
192 const VKRenderPassCache& GetRenderpassCache() const {
193 return renderpass_cache;
194 }
195
196 void EmplacePipeline(std::unique_ptr<VKGraphicsPipeline> pipeline); 139 void EmplacePipeline(std::unique_ptr<VKGraphicsPipeline> pipeline);
197 140
198protected: 141protected:
@@ -216,7 +159,6 @@ private:
216 159
217 GraphicsPipelineCacheKey last_graphics_key; 160 GraphicsPipelineCacheKey last_graphics_key;
218 VKGraphicsPipeline* last_graphics_pipeline = nullptr; 161 VKGraphicsPipeline* last_graphics_pipeline = nullptr;
219 std::vector<std::unique_ptr<VKGraphicsPipeline>> duplicates;
220 162
221 std::mutex pipeline_cache; 163 std::mutex pipeline_cache;
222 std::unordered_map<GraphicsPipelineCacheKey, std::unique_ptr<VKGraphicsPipeline>> 164 std::unordered_map<GraphicsPipelineCacheKey, std::unique_ptr<VKGraphicsPipeline>>
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index fc1b51a96..720802ad5 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -14,6 +14,7 @@
14#include "common/assert.h" 14#include "common/assert.h"
15#include "common/logging/log.h" 15#include "common/logging/log.h"
16#include "common/microprofile.h" 16#include "common/microprofile.h"
17#include "common/scope_exit.h"
17#include "core/core.h" 18#include "core/core.h"
18#include "core/settings.h" 19#include "core/settings.h"
19#include "video_core/engines/kepler_compute.h" 20#include "video_core/engines/kepler_compute.h"
@@ -408,15 +409,10 @@ RasterizerVulkan::RasterizerVulkan(Core::System& system, Core::Frontend::EmuWind
408 409
409 // Max worker threads we should allow 410 // Max worker threads we should allow
410 constexpr u32 MAX_THREADS = 4; 411 constexpr u32 MAX_THREADS = 4;
411 // Amount of threads we should reserve for other parts of yuzu 412 // Deduce how many threads we can use
412 constexpr u32 RESERVED_THREADS = 6; 413 const auto threads_used = std::thread::hardware_concurrency() / 4;
413 // Get the amount of threads we can use(this can return zero)
414 const auto cpu_thread_count =
415 std::max(RESERVED_THREADS, std::thread::hardware_concurrency());
416 // Deduce how many "extra" threads we have to use.
417 const auto max_threads_unused = cpu_thread_count - RESERVED_THREADS;
418 // Always allow at least 1 thread regardless of our settings 414 // Always allow at least 1 thread regardless of our settings
419 const auto max_worker_count = std::max(1u, max_threads_unused); 415 const auto max_worker_count = std::max(1U, threads_used);
420 // Don't use more than MAX_THREADS 416 // Don't use more than MAX_THREADS
421 const auto worker_count = std::min(max_worker_count, MAX_THREADS); 417 const auto worker_count = std::min(max_worker_count, MAX_THREADS);
422 async_shaders.AllocateWorkers(worker_count); 418 async_shaders.AllocateWorkers(worker_count);
@@ -432,6 +428,8 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
432 428
433 query_cache.UpdateCounters(); 429 query_cache.UpdateCounters();
434 430
431 SCOPE_EXIT({ system.GPU().TickWork(); });
432
435 const auto& gpu = system.GPU().Maxwell3D(); 433 const auto& gpu = system.GPU().Maxwell3D();
436 GraphicsPipelineCacheKey key; 434 GraphicsPipelineCacheKey key;
437 key.fixed_state.Fill(gpu.regs, device.IsExtExtendedDynamicStateSupported()); 435 key.fixed_state.Fill(gpu.regs, device.IsExtExtendedDynamicStateSupported());
@@ -458,10 +456,9 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
458 key.renderpass_params = GetRenderPassParams(texceptions); 456 key.renderpass_params = GetRenderPassParams(texceptions);
459 key.padding = 0; 457 key.padding = 0;
460 458
461 auto pipeline = pipeline_cache.GetGraphicsPipeline(key, async_shaders); 459 auto* pipeline = pipeline_cache.GetGraphicsPipeline(key, async_shaders);
462 if (pipeline == nullptr || pipeline->GetHandle() == VK_NULL_HANDLE) { 460 if (pipeline == nullptr || pipeline->GetHandle() == VK_NULL_HANDLE) {
463 // Async graphics pipeline was not ready. 461 // Async graphics pipeline was not ready.
464 system.GPU().TickWork();
465 return; 462 return;
466 } 463 }
467 464
@@ -488,8 +485,6 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
488 }); 485 });
489 486
490 EndTransformFeedback(); 487 EndTransformFeedback();
491
492 system.GPU().TickWork();
493} 488}
494 489
495void RasterizerVulkan::Clear() { 490void RasterizerVulkan::Clear() {
diff --git a/src/video_core/shader/async_shaders.cpp b/src/video_core/shader/async_shaders.cpp
index 54a81460b..ea813d506 100644
--- a/src/video_core/shader/async_shaders.cpp
+++ b/src/video_core/shader/async_shaders.cpp
@@ -2,7 +2,6 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <chrono>
6#include <condition_variable> 5#include <condition_variable>
7#include <mutex> 6#include <mutex>
8#include <thread> 7#include <thread>
@@ -111,38 +110,44 @@ void AsyncShaders::QueueOpenGLShader(const OpenGL::Device& device,
111 VideoCommon::Shader::CompilerSettings compiler_settings, 110 VideoCommon::Shader::CompilerSettings compiler_settings,
112 const VideoCommon::Shader::Registry& registry, 111 const VideoCommon::Shader::Registry& registry,
113 VAddr cpu_addr) { 112 VAddr cpu_addr) {
114 auto params = std::make_unique<WorkerParams>(); 113 WorkerParams params{
115 params->backend = device.UseAssemblyShaders() ? Backend::GLASM : Backend::OpenGL; 114 .backend = device.UseAssemblyShaders() ? Backend::GLASM : Backend::OpenGL,
116 params->device = &device; 115 .device = &device,
117 params->shader_type = shader_type; 116 .shader_type = shader_type,
118 params->uid = uid; 117 .uid = uid,
119 params->code = std::move(code); 118 .code = std::move(code),
120 params->code_b = std::move(code_b); 119 .code_b = std::move(code_b),
121 params->main_offset = main_offset; 120 .main_offset = main_offset,
122 params->compiler_settings = compiler_settings; 121 .compiler_settings = compiler_settings,
123 params->registry = &registry; 122 .registry = &registry,
124 params->cpu_address = cpu_addr; 123 .cpu_address = cpu_addr,
124 };
125 std::unique_lock lock(queue_mutex); 125 std::unique_lock lock(queue_mutex);
126 pending_queue.push(std::move(params)); 126 pending_queue.push(std::move(params));
127 cv.notify_one(); 127 cv.notify_one();
128} 128}
129 129
130void AsyncShaders::QueueVulkanShader( 130void AsyncShaders::QueueVulkanShader(Vulkan::VKPipelineCache* pp_cache,
131 Vulkan::VKPipelineCache* pp_cache, std::vector<VkDescriptorSetLayoutBinding> bindings, 131 const Vulkan::VKDevice& device, Vulkan::VKScheduler& scheduler,
132 Vulkan::SPIRVProgram program, Vulkan::RenderPassParams renderpass_params, u32 padding, 132 Vulkan::VKDescriptorPool& descriptor_pool,
133 std::array<GPUVAddr, Vulkan::Maxwell::MaxShaderProgram> shaders, 133 Vulkan::VKUpdateDescriptorQueue& update_descriptor_queue,
134 Vulkan::FixedPipelineState fixed_state) { 134 Vulkan::VKRenderPassCache& renderpass_cache,
135 135 std::vector<VkDescriptorSetLayoutBinding> bindings,
136 auto params = std::make_unique<WorkerParams>(); 136 Vulkan::SPIRVProgram program,
137 137 Vulkan::GraphicsPipelineCacheKey key) {
138 params->backend = Backend::Vulkan; 138
139 params->pp_cache = pp_cache; 139 WorkerParams params{
140 params->bindings = bindings; 140 .backend = Backend::Vulkan,
141 params->program = program; 141 .pp_cache = pp_cache,
142 params->renderpass_params = renderpass_params; 142 .vk_device = &device,
143 params->padding = padding; 143 .scheduler = &scheduler,
144 params->shaders = shaders; 144 .descriptor_pool = &descriptor_pool,
145 params->fixed_state = fixed_state; 145 .update_descriptor_queue = &update_descriptor_queue,
146 .renderpass_cache = &renderpass_cache,
147 .bindings = bindings,
148 .program = program,
149 .key = key,
150 };
146 151
147 std::unique_lock lock(queue_mutex); 152 std::unique_lock lock(queue_mutex);
148 pending_queue.push(std::move(params)); 153 pending_queue.push(std::move(params));
@@ -150,7 +155,6 @@ void AsyncShaders::QueueVulkanShader(
150} 155}
151 156
152void AsyncShaders::ShaderCompilerThread(Core::Frontend::GraphicsContext* context) { 157void AsyncShaders::ShaderCompilerThread(Core::Frontend::GraphicsContext* context) {
153 using namespace std::chrono_literals;
154 while (!is_thread_exiting.load(std::memory_order_relaxed)) { 158 while (!is_thread_exiting.load(std::memory_order_relaxed)) {
155 std::unique_lock lock{queue_mutex}; 159 std::unique_lock lock{queue_mutex};
156 cv.wait(lock, [this] { return HasWorkQueued() || is_thread_exiting; }); 160 cv.wait(lock, [this] { return HasWorkQueued() || is_thread_exiting; });
@@ -168,53 +172,43 @@ void AsyncShaders::ShaderCompilerThread(Core::Frontend::GraphicsContext* context
168 } 172 }
169 173
170 // Pull work from queue 174 // Pull work from queue
171 auto work = std::move(pending_queue.front()); 175 WorkerParams work = std::move(pending_queue.front());
172 pending_queue.pop(); 176 pending_queue.pop();
173 lock.unlock(); 177 lock.unlock();
174 178
175 if (work->backend == Backend::OpenGL || work->backend == Backend::GLASM) { 179 if (work.backend == Backend::OpenGL || work.backend == Backend::GLASM) {
176 VideoCommon::Shader::Registry registry = *work->registry; 180 VideoCommon::Shader::Registry registry = *work.registry;
177 const ShaderIR ir(work->code, work->main_offset, work->compiler_settings, registry); 181 const ShaderIR ir(work.code, work.main_offset, work.compiler_settings, registry);
178 const auto scope = context->Acquire(); 182 const auto scope = context->Acquire();
179 auto program = 183 auto program =
180 OpenGL::BuildShader(*work->device, work->shader_type, work->uid, ir, registry); 184 OpenGL::BuildShader(*work.device, work.shader_type, work.uid, ir, registry);
181 Result result{}; 185 Result result{};
182 result.backend = work->backend; 186 result.backend = work.backend;
183 result.cpu_address = work->cpu_address; 187 result.cpu_address = work.cpu_address;
184 result.uid = work->uid; 188 result.uid = work.uid;
185 result.code = std::move(work->code); 189 result.code = std::move(work.code);
186 result.code_b = std::move(work->code_b); 190 result.code_b = std::move(work.code_b);
187 result.shader_type = work->shader_type; 191 result.shader_type = work.shader_type;
188 192
189 if (work->backend == Backend::OpenGL) { 193 if (work.backend == Backend::OpenGL) {
190 result.program.opengl = std::move(program->source_program); 194 result.program.opengl = std::move(program->source_program);
191 } else if (work->backend == Backend::GLASM) { 195 } else if (work.backend == Backend::GLASM) {
192 result.program.glasm = std::move(program->assembly_program); 196 result.program.glasm = std::move(program->assembly_program);
193 } 197 }
194 work.reset();
195 198
196 { 199 {
197 std::unique_lock complete_lock(completed_mutex); 200 std::unique_lock complete_lock(completed_mutex);
198 finished_work.push_back(std::move(result)); 201 finished_work.push_back(std::move(result));
199 } 202 }
200 } else if (work->backend == Backend::Vulkan) { 203 } else if (work.backend == Backend::Vulkan) {
201 Vulkan::GraphicsPipelineCacheKey params_key{
202 .renderpass_params = work->renderpass_params,
203 .padding = work->padding,
204 .shaders = work->shaders,
205 .fixed_state = work->fixed_state,
206 };
207 204
208 auto pipeline = std::make_unique<Vulkan::VKGraphicsPipeline>( 205 auto pipeline = std::make_unique<Vulkan::VKGraphicsPipeline>(
209 work->pp_cache->GetDevice(), work->pp_cache->GetScheduler(), 206 *work.vk_device, *work.scheduler, *work.descriptor_pool,
210 work->pp_cache->GetDescriptorPool(), work->pp_cache->GetUpdateDescriptorQueue(), 207 *work.update_descriptor_queue, *work.renderpass_cache, work.key, work.bindings,
211 work->pp_cache->GetRenderpassCache(), params_key, work->bindings, work->program); 208 work.program);
212 209
213 work->pp_cache->EmplacePipeline(std::move(pipeline)); 210 work.pp_cache->EmplacePipeline(std::move(pipeline));
214 work.reset();
215 } 211 }
216 // Give a chance for another thread to get work.
217 std::this_thread::yield();
218 } 212 }
219} 213}
220 214
diff --git a/src/video_core/shader/async_shaders.h b/src/video_core/shader/async_shaders.h
index d4eeb8fb6..7c10bd63f 100644
--- a/src/video_core/shader/async_shaders.h
+++ b/src/video_core/shader/async_shaders.h
@@ -86,12 +86,13 @@ public:
86 VideoCommon::Shader::CompilerSettings compiler_settings, 86 VideoCommon::Shader::CompilerSettings compiler_settings,
87 const VideoCommon::Shader::Registry& registry, VAddr cpu_addr); 87 const VideoCommon::Shader::Registry& registry, VAddr cpu_addr);
88 88
89 void QueueVulkanShader(Vulkan::VKPipelineCache* pp_cache, 89 void QueueVulkanShader(Vulkan::VKPipelineCache* pp_cache, const Vulkan::VKDevice& device,
90 Vulkan::VKScheduler& scheduler,
91 Vulkan::VKDescriptorPool& descriptor_pool,
92 Vulkan::VKUpdateDescriptorQueue& update_descriptor_queue,
93 Vulkan::VKRenderPassCache& renderpass_cache,
90 std::vector<VkDescriptorSetLayoutBinding> bindings, 94 std::vector<VkDescriptorSetLayoutBinding> bindings,
91 Vulkan::SPIRVProgram program, Vulkan::RenderPassParams renderpass_params, 95 Vulkan::SPIRVProgram program, Vulkan::GraphicsPipelineCacheKey key);
92 u32 padding,
93 std::array<GPUVAddr, Vulkan::Maxwell::MaxShaderProgram> shaders,
94 Vulkan::FixedPipelineState fixed_state);
95 96
96private: 97private:
97 void ShaderCompilerThread(Core::Frontend::GraphicsContext* context); 98 void ShaderCompilerThread(Core::Frontend::GraphicsContext* context);
@@ -114,12 +115,14 @@ private:
114 115
115 // For Vulkan 116 // For Vulkan
116 Vulkan::VKPipelineCache* pp_cache; 117 Vulkan::VKPipelineCache* pp_cache;
118 const Vulkan::VKDevice* vk_device;
119 Vulkan::VKScheduler* scheduler;
120 Vulkan::VKDescriptorPool* descriptor_pool;
121 Vulkan::VKUpdateDescriptorQueue* update_descriptor_queue;
122 Vulkan::VKRenderPassCache* renderpass_cache;
117 std::vector<VkDescriptorSetLayoutBinding> bindings; 123 std::vector<VkDescriptorSetLayoutBinding> bindings;
118 Vulkan::SPIRVProgram program; 124 Vulkan::SPIRVProgram program;
119 Vulkan::RenderPassParams renderpass_params; 125 Vulkan::GraphicsPipelineCacheKey key;
120 u32 padding;
121 std::array<GPUVAddr, Vulkan::Maxwell::MaxShaderProgram> shaders;
122 Vulkan::FixedPipelineState fixed_state;
123 }; 126 };
124 127
125 std::condition_variable cv; 128 std::condition_variable cv;
@@ -128,7 +131,7 @@ private:
128 std::atomic<bool> is_thread_exiting{}; 131 std::atomic<bool> is_thread_exiting{};
129 std::vector<std::unique_ptr<Core::Frontend::GraphicsContext>> context_list; 132 std::vector<std::unique_ptr<Core::Frontend::GraphicsContext>> context_list;
130 std::vector<std::thread> worker_threads; 133 std::vector<std::thread> worker_threads;
131 std::queue<std::unique_ptr<WorkerParams>> pending_queue; 134 std::queue<WorkerParams> pending_queue;
132 std::vector<AsyncShaders::Result> finished_work; 135 std::vector<AsyncShaders::Result> finished_work;
133 Core::Frontend::EmuWindow& emu_window; 136 Core::Frontend::EmuWindow& emu_window;
134}; 137};
diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui
index a793c803d..846a30586 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.ui
+++ b/src/yuzu/configuration/configure_graphics_advanced.ui
@@ -92,7 +92,7 @@
92 <string>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</string> 92 <string>Enables asynchronous shader compilation, which may reduce shader stutter. This feature is experimental.</string>
93 </property> 93 </property>
94 <property name="text"> 94 <property name="text">
95 <string>Use asynchronous shader building (experimental, OpenGL or Assembly shaders only)</string> 95 <string>Use asynchronous shader building (experimental)</string>
96 </property> 96 </property>
97 </widget> 97 </widget>
98 </item> 98 </item>