summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2021-06-06 00:11:36 -0300
committerGravatar ameerj2021-07-22 21:51:35 -0400
commitcffd4716c5ebf9b93505b5bfa96d9b407f349336 (patch)
treee94c3daa5420fc066695b1082b0f0af60c5cb555
parentvk_pipeline_cache: Add asynchronous shaders (diff)
downloadyuzu-cffd4716c5ebf9b93505b5bfa96d9b407f349336.tar.gz
yuzu-cffd4716c5ebf9b93505b5bfa96d9b407f349336.tar.xz
yuzu-cffd4716c5ebf9b93505b5bfa96d9b407f349336.zip
vk_pipeline_cache,shader_notify: Add shader notifications
Diffstat (limited to '')
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.cpp12
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.h7
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp30
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.h22
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp50
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.h9
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp2
-rw-r--r--src/video_core/shader_notify.cpp51
-rw-r--r--src/video_core/shader_notify.h28
-rw-r--r--src/yuzu/main.cpp12
10 files changed, 127 insertions, 96 deletions
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
index ca59042ff..cc855a62e 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
@@ -14,6 +14,7 @@
14#include "video_core/renderer_vulkan/vk_pipeline_cache.h" 14#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
15#include "video_core/renderer_vulkan/vk_scheduler.h" 15#include "video_core/renderer_vulkan/vk_scheduler.h"
16#include "video_core/renderer_vulkan/vk_update_descriptor.h" 16#include "video_core/renderer_vulkan/vk_update_descriptor.h"
17#include "video_core/shader_notify.h"
17#include "video_core/vulkan_common/vulkan_device.h" 18#include "video_core/vulkan_common/vulkan_device.h"
18#include "video_core/vulkan_common/vulkan_wrapper.h" 19#include "video_core/vulkan_common/vulkan_wrapper.h"
19 20
@@ -24,14 +25,18 @@ using Tegra::Texture::TexturePair;
24 25
25ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descriptor_pool, 26ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descriptor_pool,
26 VKUpdateDescriptorQueue& update_descriptor_queue_, 27 VKUpdateDescriptorQueue& update_descriptor_queue_,
27 Common::ThreadWorker* thread_worker, const Shader::Info& info_, 28 Common::ThreadWorker* thread_worker,
29 VideoCore::ShaderNotify* shader_notify, const Shader::Info& info_,
28 vk::ShaderModule spv_module_) 30 vk::ShaderModule spv_module_)
29 : device{device_}, update_descriptor_queue{update_descriptor_queue_}, info{info_}, 31 : device{device_}, update_descriptor_queue{update_descriptor_queue_}, info{info_},
30 spv_module(std::move(spv_module_)) { 32 spv_module(std::move(spv_module_)) {
33 if (shader_notify) {
34 shader_notify->MarkShaderBuilding();
35 }
31 std::copy_n(info.constant_buffer_used_sizes.begin(), uniform_buffer_sizes.size(), 36 std::copy_n(info.constant_buffer_used_sizes.begin(), uniform_buffer_sizes.size(),
32 uniform_buffer_sizes.begin()); 37 uniform_buffer_sizes.begin());
33 38
34 auto func{[this, &descriptor_pool] { 39 auto func{[this, &descriptor_pool, shader_notify] {
35 DescriptorLayoutBuilder builder{device.GetLogical()}; 40 DescriptorLayoutBuilder builder{device.GetLogical()};
36 builder.Add(info, VK_SHADER_STAGE_COMPUTE_BIT); 41 builder.Add(info, VK_SHADER_STAGE_COMPUTE_BIT);
37 42
@@ -66,6 +71,9 @@ ComputePipeline::ComputePipeline(const Device& device_, DescriptorPool& descript
66 std::lock_guard lock{build_mutex}; 71 std::lock_guard lock{build_mutex};
67 is_built = true; 72 is_built = true;
68 build_condvar.notify_one(); 73 build_condvar.notify_one();
74 if (shader_notify) {
75 shader_notify->MarkShaderComplete();
76 }
69 }}; 77 }};
70 if (thread_worker) { 78 if (thread_worker) {
71 thread_worker->QueueWork(std::move(func)); 79 thread_worker->QueueWork(std::move(func));
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.h b/src/video_core/renderer_vulkan/vk_compute_pipeline.h
index a6043866d..52fec04d3 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.h
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.h
@@ -18,6 +18,10 @@
18#include "video_core/renderer_vulkan/vk_update_descriptor.h" 18#include "video_core/renderer_vulkan/vk_update_descriptor.h"
19#include "video_core/vulkan_common/vulkan_wrapper.h" 19#include "video_core/vulkan_common/vulkan_wrapper.h"
20 20
21namespace VideoCore {
22class ShaderNotify;
23}
24
21namespace Vulkan { 25namespace Vulkan {
22 26
23class Device; 27class Device;
@@ -27,7 +31,8 @@ class ComputePipeline {
27public: 31public:
28 explicit ComputePipeline(const Device& device, DescriptorPool& descriptor_pool, 32 explicit ComputePipeline(const Device& device, DescriptorPool& descriptor_pool,
29 VKUpdateDescriptorQueue& update_descriptor_queue, 33 VKUpdateDescriptorQueue& update_descriptor_queue,
30 Common::ThreadWorker* thread_worker, const Shader::Info& info, 34 Common::ThreadWorker* thread_worker,
35 VideoCore::ShaderNotify* shader_notify, const Shader::Info& info,
31 vk::ShaderModule spv_module); 36 vk::ShaderModule spv_module);
32 37
33 ComputePipeline& operator=(ComputePipeline&&) noexcept = delete; 38 ComputePipeline& operator=(ComputePipeline&&) noexcept = delete;
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index 627ca0158..5c916c869 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -17,6 +17,7 @@
17#include "video_core/renderer_vulkan/vk_scheduler.h" 17#include "video_core/renderer_vulkan/vk_scheduler.h"
18#include "video_core/renderer_vulkan/vk_texture_cache.h" 18#include "video_core/renderer_vulkan/vk_texture_cache.h"
19#include "video_core/renderer_vulkan/vk_update_descriptor.h" 19#include "video_core/renderer_vulkan/vk_update_descriptor.h"
20#include "video_core/shader_notify.h"
20#include "video_core/vulkan_common/vulkan_device.h" 21#include "video_core/vulkan_common/vulkan_device.h"
21 22
22#if defined(_MSC_VER) && defined(NDEBUG) 23#if defined(_MSC_VER) && defined(NDEBUG)
@@ -203,30 +204,30 @@ ConfigureFuncPtr ConfigureFunc(const std::array<vk::ShaderModule, NUM_STAGES>& m
203} 204}
204} // Anonymous namespace 205} // Anonymous namespace
205 206
206GraphicsPipeline::GraphicsPipeline(Tegra::Engines::Maxwell3D& maxwell3d_, 207GraphicsPipeline::GraphicsPipeline(
207 Tegra::MemoryManager& gpu_memory_, VKScheduler& scheduler_, 208 Tegra::Engines::Maxwell3D& maxwell3d_, Tegra::MemoryManager& gpu_memory_,
208 BufferCache& buffer_cache_, TextureCache& texture_cache_, 209 VKScheduler& scheduler_, BufferCache& buffer_cache_, TextureCache& texture_cache_,
209 const Device& device_, DescriptorPool& descriptor_pool, 210 VideoCore::ShaderNotify* shader_notify, const Device& device_, DescriptorPool& descriptor_pool,
210 VKUpdateDescriptorQueue& update_descriptor_queue_, 211 VKUpdateDescriptorQueue& update_descriptor_queue_, Common::ThreadWorker* worker_thread,
211 Common::ThreadWorker* worker_thread, 212 RenderPassCache& render_pass_cache, const GraphicsPipelineCacheKey& key_,
212 RenderPassCache& render_pass_cache, 213 std::array<vk::ShaderModule, NUM_STAGES> stages,
213 const GraphicsPipelineCacheKey& key_, 214 const std::array<const Shader::Info*, NUM_STAGES>& infos)
214 std::array<vk::ShaderModule, NUM_STAGES> stages,
215 const std::array<const Shader::Info*, NUM_STAGES>& infos)
216 : key{key_}, maxwell3d{maxwell3d_}, gpu_memory{gpu_memory_}, device{device_}, 215 : key{key_}, maxwell3d{maxwell3d_}, gpu_memory{gpu_memory_}, device{device_},
217 texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, scheduler{scheduler_}, 216 texture_cache{texture_cache_}, buffer_cache{buffer_cache_}, scheduler{scheduler_},
218 update_descriptor_queue{update_descriptor_queue_}, spv_modules{std::move(stages)} { 217 update_descriptor_queue{update_descriptor_queue_}, spv_modules{std::move(stages)} {
219 std::ranges::transform(infos, stage_infos.begin(), 218 if (shader_notify) {
220 [](const Shader::Info* info) { return info ? *info : Shader::Info{}; }); 219 shader_notify->MarkShaderBuilding();
220 }
221 for (size_t stage = 0; stage < NUM_STAGES; ++stage) { 221 for (size_t stage = 0; stage < NUM_STAGES; ++stage) {
222 const Shader::Info* const info{infos[stage]}; 222 const Shader::Info* const info{infos[stage]};
223 if (!info) { 223 if (!info) {
224 continue; 224 continue;
225 } 225 }
226 stage_infos[stage] = *info;
226 enabled_uniform_buffer_masks[stage] = info->constant_buffer_mask; 227 enabled_uniform_buffer_masks[stage] = info->constant_buffer_mask;
227 std::ranges::copy(info->constant_buffer_used_sizes, uniform_buffer_sizes[stage].begin()); 228 std::ranges::copy(info->constant_buffer_used_sizes, uniform_buffer_sizes[stage].begin());
228 } 229 }
229 auto func{[this, &render_pass_cache, &descriptor_pool] { 230 auto func{[this, shader_notify, &render_pass_cache, &descriptor_pool] {
230 DescriptorLayoutBuilder builder{MakeBuilder(device, stage_infos)}; 231 DescriptorLayoutBuilder builder{MakeBuilder(device, stage_infos)};
231 descriptor_set_layout = builder.CreateDescriptorSetLayout(); 232 descriptor_set_layout = builder.CreateDescriptorSetLayout();
232 descriptor_allocator = descriptor_pool.Allocator(*descriptor_set_layout, stage_infos); 233 descriptor_allocator = descriptor_pool.Allocator(*descriptor_set_layout, stage_infos);
@@ -242,6 +243,9 @@ GraphicsPipeline::GraphicsPipeline(Tegra::Engines::Maxwell3D& maxwell3d_,
242 std::lock_guard lock{build_mutex}; 243 std::lock_guard lock{build_mutex};
243 is_built = true; 244 is_built = true;
244 build_condvar.notify_one(); 245 build_condvar.notify_one();
246 if (shader_notify) {
247 shader_notify->MarkShaderComplete();
248 }
245 }}; 249 }};
246 if (worker_thread) { 250 if (worker_thread) {
247 worker_thread->QueueWork(std::move(func)); 251 worker_thread->QueueWork(std::move(func));
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
index 3f8895927..40d1edabd 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
@@ -20,6 +20,10 @@
20#include "video_core/renderer_vulkan/vk_texture_cache.h" 20#include "video_core/renderer_vulkan/vk_texture_cache.h"
21#include "video_core/vulkan_common/vulkan_wrapper.h" 21#include "video_core/vulkan_common/vulkan_wrapper.h"
22 22
23namespace VideoCore {
24class ShaderNotify;
25}
26
23namespace Vulkan { 27namespace Vulkan {
24 28
25struct GraphicsPipelineCacheKey { 29struct GraphicsPipelineCacheKey {
@@ -64,16 +68,14 @@ class GraphicsPipeline {
64 static constexpr size_t NUM_STAGES = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage; 68 static constexpr size_t NUM_STAGES = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage;
65 69
66public: 70public:
67 explicit GraphicsPipeline(Tegra::Engines::Maxwell3D& maxwell3d, 71 explicit GraphicsPipeline(
68 Tegra::MemoryManager& gpu_memory, VKScheduler& scheduler, 72 Tegra::Engines::Maxwell3D& maxwell3d, Tegra::MemoryManager& gpu_memory,
69 BufferCache& buffer_cache, TextureCache& texture_cache, 73 VKScheduler& scheduler, BufferCache& buffer_cache, TextureCache& texture_cache,
70 const Device& device, DescriptorPool& descriptor_pool, 74 VideoCore::ShaderNotify* shader_notify, const Device& device,
71 VKUpdateDescriptorQueue& update_descriptor_queue, 75 DescriptorPool& descriptor_pool, VKUpdateDescriptorQueue& update_descriptor_queue,
72 Common::ThreadWorker* worker_thread, 76 Common::ThreadWorker* worker_thread, RenderPassCache& render_pass_cache,
73 RenderPassCache& render_pass_cache, 77 const GraphicsPipelineCacheKey& key, std::array<vk::ShaderModule, NUM_STAGES> stages,
74 const GraphicsPipelineCacheKey& key, 78 const std::array<const Shader::Info*, NUM_STAGES>& infos);
75 std::array<vk::ShaderModule, NUM_STAGES> stages,
76 const std::array<const Shader::Info*, NUM_STAGES>& infos);
77 79
78 GraphicsPipeline& operator=(GraphicsPipeline&&) noexcept = delete; 80 GraphicsPipeline& operator=(GraphicsPipeline&&) noexcept = delete;
79 GraphicsPipeline(GraphicsPipeline&&) noexcept = delete; 81 GraphicsPipeline(GraphicsPipeline&&) noexcept = delete;
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 741ed1a98..e61d76490 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -235,11 +235,11 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, Tegra::Engines::Maxw
235 VKScheduler& scheduler_, DescriptorPool& descriptor_pool_, 235 VKScheduler& scheduler_, DescriptorPool& descriptor_pool_,
236 VKUpdateDescriptorQueue& update_descriptor_queue_, 236 VKUpdateDescriptorQueue& update_descriptor_queue_,
237 RenderPassCache& render_pass_cache_, BufferCache& buffer_cache_, 237 RenderPassCache& render_pass_cache_, BufferCache& buffer_cache_,
238 TextureCache& texture_cache_) 238 TextureCache& texture_cache_, VideoCore::ShaderNotify& shader_notify_)
239 : VideoCommon::ShaderCache{rasterizer_, gpu_memory_, maxwell3d_, kepler_compute_}, 239 : VideoCommon::ShaderCache{rasterizer_, gpu_memory_, maxwell3d_, kepler_compute_},
240 device{device_}, scheduler{scheduler_}, descriptor_pool{descriptor_pool_}, 240 device{device_}, scheduler{scheduler_}, descriptor_pool{descriptor_pool_},
241 update_descriptor_queue{update_descriptor_queue_}, render_pass_cache{render_pass_cache_}, 241 update_descriptor_queue{update_descriptor_queue_}, render_pass_cache{render_pass_cache_},
242 buffer_cache{buffer_cache_}, texture_cache{texture_cache_}, 242 buffer_cache{buffer_cache_}, texture_cache{texture_cache_}, shader_notify{shader_notify_},
243 use_asynchronous_shaders{Settings::values.use_asynchronous_shaders.GetValue()}, 243 use_asynchronous_shaders{Settings::values.use_asynchronous_shaders.GetValue()},
244 workers(std::max(std::thread::hardware_concurrency(), 2U) - 1, "yuzu:PipelineBuilder"), 244 workers(std::max(std::thread::hardware_concurrency(), 2U) - 1, "yuzu:PipelineBuilder"),
245 serialization_thread(1, "yuzu:PipelineSerialization") { 245 serialization_thread(1, "yuzu:PipelineSerialization") {
@@ -307,19 +307,7 @@ GraphicsPipeline* PipelineCache::CurrentGraphicsPipeline() {
307 return BuiltPipeline(current_pipeline); 307 return BuiltPipeline(current_pipeline);
308 } 308 }
309 } 309 }
310 const auto [pair, is_new]{graphics_cache.try_emplace(graphics_key)}; 310 return CurrentGraphicsPipelineSlowPath();
311 auto& pipeline{pair->second};
312 if (is_new) {
313 pipeline = CreateGraphicsPipeline();
314 }
315 if (!pipeline) {
316 return nullptr;
317 }
318 if (current_pipeline) {
319 current_pipeline->AddTransition(pipeline.get());
320 }
321 current_pipeline = pipeline.get();
322 return BuiltPipeline(current_pipeline);
323} 311}
324 312
325ComputePipeline* PipelineCache::CurrentComputePipeline() { 313ComputePipeline* PipelineCache::CurrentComputePipeline() {
@@ -416,6 +404,22 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading
416 workers.WaitForRequests(); 404 workers.WaitForRequests();
417} 405}
418 406
407GraphicsPipeline* PipelineCache::CurrentGraphicsPipelineSlowPath() {
408 const auto [pair, is_new]{graphics_cache.try_emplace(graphics_key)};
409 auto& pipeline{pair->second};
410 if (is_new) {
411 pipeline = CreateGraphicsPipeline();
412 }
413 if (!pipeline) {
414 return nullptr;
415 }
416 if (current_pipeline) {
417 current_pipeline->AddTransition(pipeline.get());
418 }
419 current_pipeline = pipeline.get();
420 return BuiltPipeline(current_pipeline);
421}
422
419GraphicsPipeline* PipelineCache::BuiltPipeline(GraphicsPipeline* pipeline) const noexcept { 423GraphicsPipeline* PipelineCache::BuiltPipeline(GraphicsPipeline* pipeline) const noexcept {
420 if (pipeline->IsBuilt()) { 424 if (pipeline->IsBuilt()) {
421 return pipeline; 425 return pipeline;
@@ -484,14 +488,16 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
484 device.SaveShader(code); 488 device.SaveShader(code);
485 modules[stage_index] = BuildShader(device, code); 489 modules[stage_index] = BuildShader(device, code);
486 if (device.HasDebuggingToolAttached()) { 490 if (device.HasDebuggingToolAttached()) {
487 const std::string name{fmt::format("{:016x}", key.unique_hashes[index])}; 491 const std::string name{fmt::format("Shader {:016x}", key.unique_hashes[index])};
488 modules[stage_index].SetObjectNameEXT(name.c_str()); 492 modules[stage_index].SetObjectNameEXT(name.c_str());
489 } 493 }
490 } 494 }
491 Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; 495 Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr};
492 return std::make_unique<GraphicsPipeline>( 496 VideoCore::ShaderNotify* const notify{build_in_parallel ? &shader_notify : nullptr};
493 maxwell3d, gpu_memory, scheduler, buffer_cache, texture_cache, device, descriptor_pool, 497 return std::make_unique<GraphicsPipeline>(maxwell3d, gpu_memory, scheduler, buffer_cache,
494 update_descriptor_queue, thread_worker, render_pass_cache, key, std::move(modules), infos); 498 texture_cache, notify, device, descriptor_pool,
499 update_descriptor_queue, thread_worker,
500 render_pass_cache, key, std::move(modules), infos);
495 501
496} catch (const Shader::Exception& exception) { 502} catch (const Shader::Exception& exception) {
497 LOG_ERROR(Render_Vulkan, "{}", exception.what()); 503 LOG_ERROR(Render_Vulkan, "{}", exception.what());
@@ -550,12 +556,14 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
550 device.SaveShader(code); 556 device.SaveShader(code);
551 vk::ShaderModule spv_module{BuildShader(device, code)}; 557 vk::ShaderModule spv_module{BuildShader(device, code)};
552 if (device.HasDebuggingToolAttached()) { 558 if (device.HasDebuggingToolAttached()) {
553 const auto name{fmt::format("{:016x}", key.unique_hash)}; 559 const auto name{fmt::format("Shader {:016x}", key.unique_hash)};
554 spv_module.SetObjectNameEXT(name.c_str()); 560 spv_module.SetObjectNameEXT(name.c_str());
555 } 561 }
556 Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr}; 562 Common::ThreadWorker* const thread_worker{build_in_parallel ? &workers : nullptr};
563 VideoCore::ShaderNotify* const notify{build_in_parallel ? &shader_notify : nullptr};
557 return std::make_unique<ComputePipeline>(device, descriptor_pool, update_descriptor_queue, 564 return std::make_unique<ComputePipeline>(device, descriptor_pool, update_descriptor_queue,
558 thread_worker, program.info, std::move(spv_module)); 565 thread_worker, notify, program.info,
566 std::move(spv_module));
559 567
560} catch (const Shader::Exception& exception) { 568} catch (const Shader::Exception& exception) {
561 LOG_ERROR(Render_Vulkan, "{}", exception.what()); 569 LOG_ERROR(Render_Vulkan, "{}", exception.what());
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
index 869c63baf..167a2ee2e 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
@@ -38,6 +38,10 @@ namespace Shader::IR {
38struct Program; 38struct Program;
39} 39}
40 40
41namespace VideoCore {
42class ShaderNotify;
43}
44
41namespace Vulkan { 45namespace Vulkan {
42 46
43using Maxwell = Tegra::Engines::Maxwell3D::Regs; 47using Maxwell = Tegra::Engines::Maxwell3D::Regs;
@@ -104,7 +108,7 @@ public:
104 VKScheduler& scheduler, DescriptorPool& descriptor_pool, 108 VKScheduler& scheduler, DescriptorPool& descriptor_pool,
105 VKUpdateDescriptorQueue& update_descriptor_queue, 109 VKUpdateDescriptorQueue& update_descriptor_queue,
106 RenderPassCache& render_pass_cache, BufferCache& buffer_cache, 110 RenderPassCache& render_pass_cache, BufferCache& buffer_cache,
107 TextureCache& texture_cache); 111 TextureCache& texture_cache, VideoCore::ShaderNotify& shader_notify_);
108 ~PipelineCache(); 112 ~PipelineCache();
109 113
110 [[nodiscard]] GraphicsPipeline* CurrentGraphicsPipeline(); 114 [[nodiscard]] GraphicsPipeline* CurrentGraphicsPipeline();
@@ -115,6 +119,8 @@ public:
115 const VideoCore::DiskResourceLoadCallback& callback); 119 const VideoCore::DiskResourceLoadCallback& callback);
116 120
117private: 121private:
122 [[nodiscard]] GraphicsPipeline* CurrentGraphicsPipelineSlowPath();
123
118 [[nodiscard]] GraphicsPipeline* BuiltPipeline(GraphicsPipeline* pipeline) const noexcept; 124 [[nodiscard]] GraphicsPipeline* BuiltPipeline(GraphicsPipeline* pipeline) const noexcept;
119 125
120 std::unique_ptr<GraphicsPipeline> CreateGraphicsPipeline(); 126 std::unique_ptr<GraphicsPipeline> CreateGraphicsPipeline();
@@ -138,6 +144,7 @@ private:
138 RenderPassCache& render_pass_cache; 144 RenderPassCache& render_pass_cache;
139 BufferCache& buffer_cache; 145 BufferCache& buffer_cache;
140 TextureCache& texture_cache; 146 TextureCache& texture_cache;
147 VideoCore::ShaderNotify& shader_notify;
141 148
142 GraphicsPipelineCacheKey graphics_key{}; 149 GraphicsPipelineCacheKey graphics_key{};
143 GraphicsPipeline* current_pipeline{}; 150 GraphicsPipeline* current_pipeline{};
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index e72f8426b..d284b3653 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -140,7 +140,7 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
140 buffer_cache(*this, maxwell3d, kepler_compute, gpu_memory, cpu_memory_, buffer_cache_runtime), 140 buffer_cache(*this, maxwell3d, kepler_compute, gpu_memory, cpu_memory_, buffer_cache_runtime),
141 pipeline_cache(*this, maxwell3d, kepler_compute, gpu_memory, device, scheduler, 141 pipeline_cache(*this, maxwell3d, kepler_compute, gpu_memory, device, scheduler,
142 descriptor_pool, update_descriptor_queue, render_pass_cache, buffer_cache, 142 descriptor_pool, update_descriptor_queue, render_pass_cache, buffer_cache,
143 texture_cache), 143 texture_cache, gpu.ShaderNotify()),
144 query_cache{*this, maxwell3d, gpu_memory, device, scheduler}, accelerate_dma{ buffer_cache }, 144 query_cache{*this, maxwell3d, gpu_memory, device, scheduler}, accelerate_dma{ buffer_cache },
145 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler), 145 fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler),
146 wfi_event(device.GetLogical().CreateEvent()) { 146 wfi_event(device.GetLogical().CreateEvent()) {
diff --git a/src/video_core/shader_notify.cpp b/src/video_core/shader_notify.cpp
index 693e47158..dc6995b46 100644
--- a/src/video_core/shader_notify.cpp
+++ b/src/video_core/shader_notify.cpp
@@ -2,42 +2,35 @@
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 <mutex> 5#include <atomic>
6#include <chrono>
7#include <optional>
8
6#include "video_core/shader_notify.h" 9#include "video_core/shader_notify.h"
7 10
8using namespace std::chrono_literals; 11using namespace std::chrono_literals;
9 12
10namespace VideoCore { 13namespace VideoCore {
11namespace {
12constexpr auto UPDATE_TICK = 32ms;
13}
14
15ShaderNotify::ShaderNotify() = default;
16ShaderNotify::~ShaderNotify() = default;
17 14
18std::size_t ShaderNotify::GetShadersBuilding() { 15const auto TIME_TO_STOP_REPORTING = 2s;
19 const auto now = std::chrono::high_resolution_clock::now(); 16
20 const auto diff = now - last_update; 17int ShaderNotify::ShadersBuilding() noexcept {
21 if (diff > UPDATE_TICK) { 18 const int now_complete = num_complete.load(std::memory_order::relaxed);
22 std::shared_lock lock(mutex); 19 const int now_building = num_building.load(std::memory_order::relaxed);
23 last_updated_count = accurate_count; 20 if (now_complete == now_building) {
21 const auto now = std::chrono::high_resolution_clock::now();
22 if (completed && num_complete == num_when_completed) {
23 if (now - complete_time > TIME_TO_STOP_REPORTING) {
24 report_base = now_complete;
25 completed = false;
26 }
27 } else {
28 completed = true;
29 num_when_completed = num_complete;
30 complete_time = now;
31 }
24 } 32 }
25 return last_updated_count; 33 return now_building - report_base;
26}
27
28std::size_t ShaderNotify::GetShadersBuildingAccurate() {
29 std::shared_lock lock{mutex};
30 return accurate_count;
31}
32
33void ShaderNotify::MarkShaderComplete() {
34 std::unique_lock lock{mutex};
35 accurate_count--;
36}
37
38void ShaderNotify::MarkSharderBuilding() {
39 std::unique_lock lock{mutex};
40 accurate_count++;
41} 34}
42 35
43} // namespace VideoCore 36} // namespace VideoCore
diff --git a/src/video_core/shader_notify.h b/src/video_core/shader_notify.h
index a9c92d179..ad363bfb5 100644
--- a/src/video_core/shader_notify.h
+++ b/src/video_core/shader_notify.h
@@ -4,26 +4,30 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <atomic>
7#include <chrono> 8#include <chrono>
8#include <shared_mutex> 9#include <optional>
9#include "common/common_types.h"
10 10
11namespace VideoCore { 11namespace VideoCore {
12class ShaderNotify { 12class ShaderNotify {
13public: 13public:
14 ShaderNotify(); 14 [[nodiscard]] int ShadersBuilding() noexcept;
15 ~ShaderNotify();
16 15
17 std::size_t GetShadersBuilding(); 16 void MarkShaderComplete() noexcept {
18 std::size_t GetShadersBuildingAccurate(); 17 ++num_complete;
18 }
19 19
20 void MarkShaderComplete(); 20 void MarkShaderBuilding() noexcept {
21 void MarkSharderBuilding(); 21 ++num_building;
22 }
22 23
23private: 24private:
24 std::size_t last_updated_count{}; 25 std::atomic_int num_building{};
25 std::size_t accurate_count{}; 26 std::atomic_int num_complete{};
26 std::shared_mutex mutex; 27 int report_base{};
27 std::chrono::high_resolution_clock::time_point last_update{}; 28
29 bool completed{};
30 int num_when_completed{};
31 std::chrono::high_resolution_clock::time_point complete_time;
28}; 32};
29} // namespace VideoCore 33} // namespace VideoCore
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 03a909d17..7e0b1adc4 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -2900,13 +2900,13 @@ void GMainWindow::UpdateStatusBar() {
2900 return; 2900 return;
2901 } 2901 }
2902 2902
2903 auto results = Core::System::GetInstance().GetAndResetPerfStats(); 2903 auto& system = Core::System::GetInstance();
2904 auto& shader_notify = Core::System::GetInstance().GPU().ShaderNotify(); 2904 auto results = system.GetAndResetPerfStats();
2905 const auto shaders_building = shader_notify.GetShadersBuilding(); 2905 auto& shader_notify = system.GPU().ShaderNotify();
2906 const int shaders_building = shader_notify.ShadersBuilding();
2906 2907
2907 if (shaders_building != 0) { 2908 if (shaders_building > 0) {
2908 shader_building_label->setText( 2909 shader_building_label->setText(tr("Building: %n shader(s)", "", shaders_building));
2909 tr("Building: %n shader(s)", "", static_cast<int>(shaders_building)));
2910 shader_building_label->setVisible(true); 2910 shader_building_label->setVisible(true);
2911 } else { 2911 } else {
2912 shader_building_label->setVisible(false); 2912 shader_building_label->setVisible(false);