summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ameerj2020-07-30 15:41:11 -0400
committerGravatar ameerj2020-08-16 12:02:22 -0400
commit4539073ce1d8fd6df03263e826d3805b4909e055 (patch)
treed0ed30c327c5b6da9c6d6c8ba256803167f00de2 /src
parentVk Async pipeline compilation (diff)
downloadyuzu-4539073ce1d8fd6df03263e826d3805b4909e055.tar.gz
yuzu-4539073ce1d8fd6df03263e826d3805b4909e055.tar.xz
yuzu-4539073ce1d8fd6df03263e826d3805b4909e055.zip
Address feedback. Bruteforce delete duplicates
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.h2
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp16
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.h19
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp18
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.h2
-rw-r--r--src/video_core/shader/async_shaders.cpp135
-rw-r--r--src/video_core/shader/async_shaders.h4
7 files changed, 116 insertions, 80 deletions
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
index 39c73a139..d50bd347c 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h
@@ -54,7 +54,7 @@ public:
54 return renderpass; 54 return renderpass;
55 } 55 }
56 56
57 const GraphicsPipelineCacheKey& GetCacheKey() { 57 const GraphicsPipelineCacheKey& GetCacheKey() const {
58 return m_key; 58 return m_key;
59 } 59 }
60 60
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 45d4dcb8c..a7ce621ca 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -205,20 +205,20 @@ std::array<Shader*, Maxwell::MaxShaderProgram> VKPipelineCache::GetShaders() {
205 return last_shaders = shaders; 205 return last_shaders = shaders;
206} 206}
207 207
208VKGraphicsPipeline& VKPipelineCache::GetGraphicsPipeline( 208VKGraphicsPipeline* VKPipelineCache::GetGraphicsPipeline(
209 const GraphicsPipelineCacheKey& key, VideoCommon::Shader::AsyncShaders& async_shaders) { 209 const GraphicsPipelineCacheKey& key, VideoCommon::Shader::AsyncShaders& async_shaders) {
210 MICROPROFILE_SCOPE(Vulkan_PipelineCache); 210 MICROPROFILE_SCOPE(Vulkan_PipelineCache);
211 211
212 if (last_graphics_pipeline && last_graphics_key == key) { 212 if (last_graphics_pipeline && last_graphics_key == key) {
213 return *last_graphics_pipeline; 213 return last_graphics_pipeline;
214 } 214 }
215 last_graphics_key = key; 215 last_graphics_key = key;
216 216
217 if (device.UseAsynchronousShaders()) { 217 if (device.UseAsynchronousShaders()) {
218 auto work = async_shaders.GetCompletedWork(); 218 auto work = async_shaders.GetCompletedWork();
219 for (std::size_t i = 0; i < work.size(); ++i) { 219 for (auto& w : work) {
220 auto& entry = graphics_cache.at(work[i].pipeline->GetCacheKey()); 220 auto& entry = graphics_cache.at(w.pipeline->GetCacheKey());
221 entry = std::move(work[i].pipeline); 221 entry = std::move(w.pipeline);
222 } 222 }
223 const auto [pair, is_cache_miss] = graphics_cache.try_emplace(key); 223 const auto [pair, is_cache_miss] = graphics_cache.try_emplace(key);
224 if (is_cache_miss) { 224 if (is_cache_miss) {
@@ -227,7 +227,8 @@ VKGraphicsPipeline& VKPipelineCache::GetGraphicsPipeline(
227 async_shaders.QueueVulkanShader(this, bindings, program, key.renderpass_params, 227 async_shaders.QueueVulkanShader(this, bindings, program, key.renderpass_params,
228 key.padding, key.shaders, key.fixed_state); 228 key.padding, key.shaders, key.fixed_state);
229 } 229 }
230 return *(last_graphics_pipeline = graphics_cache.at(key).get()); 230 last_graphics_pipeline = graphics_cache.at(key).get();
231 return last_graphics_pipeline;
231 } 232 }
232 233
233 const auto [pair, is_cache_miss] = graphics_cache.try_emplace(key); 234 const auto [pair, is_cache_miss] = graphics_cache.try_emplace(key);
@@ -239,7 +240,8 @@ VKGraphicsPipeline& VKPipelineCache::GetGraphicsPipeline(
239 update_descriptor_queue, renderpass_cache, key, 240 update_descriptor_queue, renderpass_cache, key,
240 bindings, program); 241 bindings, program);
241 } 242 }
242 return *(last_graphics_pipeline = entry.get()); 243 last_graphics_pipeline = entry.get();
244 return last_graphics_pipeline;
243} 245}
244 246
245VKComputePipeline& VKPipelineCache::GetComputePipeline(const ComputePipelineCacheKey& key) { 247VKComputePipeline& VKPipelineCache::GetComputePipeline(const ComputePipelineCacheKey& key) {
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
index c70da6da4..404f2b3f7 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h
@@ -153,31 +153,46 @@ public:
153 153
154 std::array<Shader*, Maxwell::MaxShaderProgram> GetShaders(); 154 std::array<Shader*, Maxwell::MaxShaderProgram> GetShaders();
155 155
156 VKGraphicsPipeline& GetGraphicsPipeline(const GraphicsPipelineCacheKey& key, 156 VKGraphicsPipeline* GetGraphicsPipeline(const GraphicsPipelineCacheKey& key,
157 VideoCommon::Shader::AsyncShaders& async_shaders); 157 VideoCommon::Shader::AsyncShaders& async_shaders);
158 158
159 VKComputePipeline& GetComputePipeline(const ComputePipelineCacheKey& key); 159 VKComputePipeline& GetComputePipeline(const ComputePipelineCacheKey& key);
160 160
161 const VKDevice& GetDevice() { 161 const VKDevice& GetDevice() const {
162 return device; 162 return device;
163 } 163 }
164 164
165 VKScheduler& GetScheduler() { 165 VKScheduler& GetScheduler() {
166 return scheduler; 166 return scheduler;
167 } 167 }
168 const VKScheduler& GetScheduler() const {
169 return scheduler;
170 }
168 171
169 VKDescriptorPool& GetDescriptorPool() { 172 VKDescriptorPool& GetDescriptorPool() {
170 return descriptor_pool; 173 return descriptor_pool;
171 } 174 }
172 175
176 const VKDescriptorPool& GetDescriptorPool() const {
177 return descriptor_pool;
178 }
179
173 VKUpdateDescriptorQueue& GetUpdateDescriptorQueue() { 180 VKUpdateDescriptorQueue& GetUpdateDescriptorQueue() {
174 return update_descriptor_queue; 181 return update_descriptor_queue;
175 } 182 }
176 183
184 const VKUpdateDescriptorQueue& GetUpdateDescriptorQueue() const {
185 return update_descriptor_queue;
186 }
187
177 VKRenderPassCache& GetRenderpassCache() { 188 VKRenderPassCache& GetRenderpassCache() {
178 return renderpass_cache; 189 return renderpass_cache;
179 } 190 }
180 191
192 const VKRenderPassCache& GetRenderpassCache() const {
193 return renderpass_cache;
194 }
195
181protected: 196protected:
182 void OnShaderRemoval(Shader* shader) final; 197 void OnShaderRemoval(Shader* shader) final;
183 198
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 6310e898c..fc1b51a96 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -404,10 +404,12 @@ RasterizerVulkan::RasterizerVulkan(Core::System& system, Core::Frontend::EmuWind
404 wfi_event{device.GetLogical().CreateNewEvent()}, async_shaders{renderer} { 404 wfi_event{device.GetLogical().CreateNewEvent()}, async_shaders{renderer} {
405 scheduler.SetQueryCache(query_cache); 405 scheduler.SetQueryCache(query_cache);
406 if (device.UseAsynchronousShaders()) { 406 if (device.UseAsynchronousShaders()) {
407 // The following is subject to move into the allocate workers method, to be api agnostic
408
407 // Max worker threads we should allow 409 // Max worker threads we should allow
408 constexpr auto MAX_THREADS = 2u; 410 constexpr u32 MAX_THREADS = 4;
409 // Amount of threads we should reserve for other parts of yuzu 411 // Amount of threads we should reserve for other parts of yuzu
410 constexpr auto RESERVED_THREADS = 6u; 412 constexpr u32 RESERVED_THREADS = 6;
411 // Get the amount of threads we can use(this can return zero) 413 // Get the amount of threads we can use(this can return zero)
412 const auto cpu_thread_count = 414 const auto cpu_thread_count =
413 std::max(RESERVED_THREADS, std::thread::hardware_concurrency()); 415 std::max(RESERVED_THREADS, std::thread::hardware_concurrency());
@@ -456,16 +458,16 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
456 key.renderpass_params = GetRenderPassParams(texceptions); 458 key.renderpass_params = GetRenderPassParams(texceptions);
457 key.padding = 0; 459 key.padding = 0;
458 460
459 auto& pipeline = pipeline_cache.GetGraphicsPipeline(key, async_shaders); 461 auto pipeline = pipeline_cache.GetGraphicsPipeline(key, async_shaders);
460 if (&pipeline == nullptr || pipeline.GetHandle() == VK_NULL_HANDLE) { 462 if (pipeline == nullptr || pipeline->GetHandle() == VK_NULL_HANDLE) {
461 // Async graphics pipeline was not ready. 463 // Async graphics pipeline was not ready.
462 system.GPU().TickWork(); 464 system.GPU().TickWork();
463 return; 465 return;
464 } 466 }
465 467
466 scheduler.BindGraphicsPipeline(pipeline.GetHandle()); 468 scheduler.BindGraphicsPipeline(pipeline->GetHandle());
467 469
468 const auto renderpass = pipeline.GetRenderPass(); 470 const auto renderpass = pipeline->GetRenderPass();
469 const auto [framebuffer, render_area] = ConfigureFramebuffers(renderpass); 471 const auto [framebuffer, render_area] = ConfigureFramebuffers(renderpass);
470 scheduler.RequestRenderpass(renderpass, framebuffer, render_area); 472 scheduler.RequestRenderpass(renderpass, framebuffer, render_area);
471 473
@@ -475,8 +477,8 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
475 477
476 BeginTransformFeedback(); 478 BeginTransformFeedback();
477 479
478 const auto pipeline_layout = pipeline.GetLayout(); 480 const auto pipeline_layout = pipeline->GetLayout();
479 const auto descriptor_set = pipeline.CommitDescriptorSet(); 481 const auto descriptor_set = pipeline->CommitDescriptorSet();
480 scheduler.Record([pipeline_layout, descriptor_set, draw_params](vk::CommandBuffer cmdbuf) { 482 scheduler.Record([pipeline_layout, descriptor_set, draw_params](vk::CommandBuffer cmdbuf) {
481 if (descriptor_set) { 483 if (descriptor_set) {
482 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 484 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout,
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h
index 27604b9a3..f640ba649 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.h
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.h
@@ -287,7 +287,6 @@ private:
287 VKMemoryManager& memory_manager; 287 VKMemoryManager& memory_manager;
288 StateTracker& state_tracker; 288 StateTracker& state_tracker;
289 VKScheduler& scheduler; 289 VKScheduler& scheduler;
290 VideoCommon::Shader::AsyncShaders async_shaders;
291 290
292 VKStagingBufferPool staging_pool; 291 VKStagingBufferPool staging_pool;
293 VKDescriptorPool descriptor_pool; 292 VKDescriptorPool descriptor_pool;
@@ -307,6 +306,7 @@ private:
307 vk::Buffer default_buffer; 306 vk::Buffer default_buffer;
308 VKMemoryCommit default_buffer_commit; 307 VKMemoryCommit default_buffer_commit;
309 vk::Event wfi_event; 308 vk::Event wfi_event;
309 VideoCommon::Shader::AsyncShaders async_shaders;
310 310
311 std::array<View, Maxwell::NumRenderTargets> color_attachments; 311 std::array<View, Maxwell::NumRenderTargets> color_attachments;
312 View zeta_attachment; 312 View zeta_attachment;
diff --git a/src/video_core/shader/async_shaders.cpp b/src/video_core/shader/async_shaders.cpp
index 335a0d05b..c536b025b 100644
--- a/src/video_core/shader/async_shaders.cpp
+++ b/src/video_core/shader/async_shaders.cpp
@@ -111,20 +111,19 @@ void AsyncShaders::QueueOpenGLShader(const OpenGL::Device& device,
111 VideoCommon::Shader::CompilerSettings compiler_settings, 111 VideoCommon::Shader::CompilerSettings compiler_settings,
112 const VideoCommon::Shader::Registry& registry, 112 const VideoCommon::Shader::Registry& registry,
113 VAddr cpu_addr) { 113 VAddr cpu_addr) {
114 WorkerParams params{device.UseAssemblyShaders() ? AsyncShaders::Backend::GLASM 114 auto p = std::make_unique<WorkerParams>();
115 : AsyncShaders::Backend::OpenGL, 115 p->backend = device.UseAssemblyShaders() ? Backend::GLASM : Backend::OpenGL;
116 &device, 116 p->device = &device;
117 shader_type, 117 p->shader_type = shader_type;
118 uid, 118 p->uid = uid;
119 std::move(code), 119 p->code = std::move(code);
120 std::move(code_b), 120 p->code_b = std::move(code_b);
121 main_offset, 121 p->main_offset = main_offset;
122 compiler_settings, 122 p->compiler_settings = compiler_settings;
123 &registry, 123 p->registry = &registry;
124 cpu_addr}; 124 p->cpu_address = cpu_addr;
125
126 std::unique_lock lock(queue_mutex); 125 std::unique_lock lock(queue_mutex);
127 pending_queue.push_back(std::move(params)); 126 pending_queue.push(std::move(p));
128 cv.notify_one(); 127 cv.notify_one();
129} 128}
130 129
@@ -134,19 +133,19 @@ void AsyncShaders::QueueVulkanShader(
134 std::array<GPUVAddr, Vulkan::Maxwell::MaxShaderProgram> shaders, 133 std::array<GPUVAddr, Vulkan::Maxwell::MaxShaderProgram> shaders,
135 Vulkan::FixedPipelineState fixed_state) { 134 Vulkan::FixedPipelineState fixed_state) {
136 135
137 WorkerParams params{ 136 auto p = std::make_unique<WorkerParams>();
138 .backend = AsyncShaders::Backend::Vulkan, 137
139 .pp_cache = pp_cache, 138 p->backend = Backend::Vulkan;
140 .bindings = bindings, 139 p->pp_cache = pp_cache;
141 .program = program, 140 p->bindings = bindings;
142 .renderpass_params = renderpass_params, 141 p->program = program;
143 .padding = padding, 142 p->renderpass_params = renderpass_params;
144 .shaders = shaders, 143 p->padding = padding;
145 .fixed_state = fixed_state, 144 p->shaders = shaders;
146 }; 145 p->fixed_state = fixed_state;
147 146
148 std::unique_lock lock(queue_mutex); 147 std::unique_lock lock(queue_mutex);
149 pending_queue.push_back(std::move(params)); 148 pending_queue.push(std::move(p));
150 cv.notify_one(); 149 cv.notify_one();
151} 150}
152 151
@@ -168,64 +167,82 @@ void AsyncShaders::ShaderCompilerThread(Core::Frontend::GraphicsContext* context
168 if (pending_queue.empty()) { 167 if (pending_queue.empty()) {
169 continue; 168 continue;
170 } 169 }
171 // Pull work from queue
172 WorkerParams work = std::move(pending_queue.front());
173 pending_queue.pop_front();
174 170
171 // Pull work from queue
172 auto work = std::move(pending_queue.front());
173 pending_queue.pop();
175 lock.unlock(); 174 lock.unlock();
176 175
177 if (work.backend == AsyncShaders::Backend::OpenGL || 176 if (work->backend == Backend::OpenGL || work->backend == Backend::GLASM) {
178 work.backend == AsyncShaders::Backend::GLASM) { 177 VideoCommon::Shader::Registry registry = *work->registry;
179 VideoCommon::Shader::Registry registry = *work.registry; 178 const ShaderIR ir(work->code, work->main_offset, work->compiler_settings, registry);
180 const ShaderIR ir(work.code, work.main_offset, work.compiler_settings, registry);
181 const auto scope = context->Acquire(); 179 const auto scope = context->Acquire();
182 auto program = 180 auto program =
183 OpenGL::BuildShader(*work.device, work.shader_type, work.uid, ir, registry); 181 OpenGL::BuildShader(*work->device, work->shader_type, work->uid, ir, registry);
184 Result result{}; 182 Result result{};
185 result.backend = work.backend; 183 result.backend = work->backend;
186 result.cpu_address = work.cpu_address; 184 result.cpu_address = work->cpu_address;
187 result.uid = work.uid; 185 result.uid = work->uid;
188 result.code = std::move(work.code); 186 result.code = std::move(work->code);
189 result.code_b = std::move(work.code_b); 187 result.code_b = std::move(work->code_b);
190 result.shader_type = work.shader_type; 188 result.shader_type = work->shader_type;
191 189 // LOG_CRITICAL(Render_Vulkan, "Shader hast been Compiled \t0x{:016X} id {}",
192 if (work.backend == AsyncShaders::Backend::OpenGL) { 190 // result.uid, id);
191
192 if (work->backend == Backend::OpenGL) {
193 result.program.opengl = std::move(program->source_program); 193 result.program.opengl = std::move(program->source_program);
194 } else if (work.backend == AsyncShaders::Backend::GLASM) { 194 } else if (work->backend == Backend::GLASM) {
195 result.program.glasm = std::move(program->assembly_program); 195 result.program.glasm = std::move(program->assembly_program);
196 } 196 }
197 work.reset();
197 198
198 { 199 {
199 std::unique_lock complete_lock(completed_mutex); 200 std::unique_lock complete_lock(completed_mutex);
200 finished_work.push_back(std::move(result)); 201 finished_work.push_back(std::move(result));
201 } 202 }
202 203 } else if (work->backend == Backend::Vulkan) {
203 } else if (work.backend == AsyncShaders::Backend::Vulkan) {
204 Vulkan::GraphicsPipelineCacheKey params_key{ 204 Vulkan::GraphicsPipelineCacheKey params_key{
205 work.renderpass_params, 205 .renderpass_params = work->renderpass_params,
206 work.padding, 206 .padding = work->padding,
207 work.shaders, 207 .shaders = work->shaders,
208 work.fixed_state, 208 .fixed_state = work->fixed_state,
209 }; 209 };
210
210 { 211 {
211 std::unique_lock complete_lock(completed_mutex); 212 std::unique_lock find_lock{completed_mutex};
213 for (size_t i = 0; i < finished_work.size(); ++i) {
214 // This loop deletes duplicate pipelines in finished_work
215 // in favor of the pipeline about to be created
216
217 if (finished_work[i].pipeline &&
218 finished_work[i].pipeline->GetCacheKey().Hash() == params_key.Hash()) {
219 LOG_CRITICAL(Render_Vulkan,
220 "Pipeliene was already here \t0x{:016X} matches 0x{:016X} ",
221 params_key.Hash(),
222 finished_work[i].pipeline->GetCacheKey().Hash());
223 finished_work.erase(finished_work.begin() + i);
224 }
225 }
226 find_lock.unlock();
227 }
228
229 auto pipeline = std::make_unique<Vulkan::VKGraphicsPipeline>(
230 work->pp_cache->GetDevice(), work->pp_cache->GetScheduler(),
231 work->pp_cache->GetDescriptorPool(), work->pp_cache->GetUpdateDescriptorQueue(),
232 work->pp_cache->GetRenderpassCache(), params_key, work->bindings, work->program);
212 233
213 // Duplicate creation of pipelines leads to instability and crashing, caused by a 234 {
214 // race condition but band-aid solution is locking the making of the pipeline 235 std::unique_lock complete_lock(completed_mutex);
215 // results in only one pipeline created at a time.
216 Result result{ 236 Result result{
217 .backend = work.backend, 237 .backend = Backend::Vulkan,
218 .pipeline = std::make_unique<Vulkan::VKGraphicsPipeline>( 238 .pipeline = std::move(pipeline),
219 work.pp_cache->GetDevice(), work.pp_cache->GetScheduler(),
220 work.pp_cache->GetDescriptorPool(),
221 work.pp_cache->GetUpdateDescriptorQueue(),
222 work.pp_cache->GetRenderpassCache(), params_key, work.bindings,
223 work.program),
224 }; 239 };
225
226 finished_work.push_back(std::move(result)); 240 finished_work.push_back(std::move(result));
241 complete_lock.unlock();
227 } 242 }
228 } 243 }
244 // Give a chance for another thread to get work. Lessens duplicates
245 std::this_thread::yield();
229 } 246 }
230} 247}
231 248
diff --git a/src/video_core/shader/async_shaders.h b/src/video_core/shader/async_shaders.h
index 702026ce2..d4eeb8fb6 100644
--- a/src/video_core/shader/async_shaders.h
+++ b/src/video_core/shader/async_shaders.h
@@ -100,7 +100,7 @@ private:
100 bool HasWorkQueued(); 100 bool HasWorkQueued();
101 101
102 struct WorkerParams { 102 struct WorkerParams {
103 AsyncShaders::Backend backend; 103 Backend backend;
104 // For OGL 104 // For OGL
105 const OpenGL::Device* device; 105 const OpenGL::Device* device;
106 Tegra::Engines::ShaderType shader_type; 106 Tegra::Engines::ShaderType shader_type;
@@ -128,7 +128,7 @@ private:
128 std::atomic<bool> is_thread_exiting{}; 128 std::atomic<bool> is_thread_exiting{};
129 std::vector<std::unique_ptr<Core::Frontend::GraphicsContext>> context_list; 129 std::vector<std::unique_ptr<Core::Frontend::GraphicsContext>> context_list;
130 std::vector<std::thread> worker_threads; 130 std::vector<std::thread> worker_threads;
131 std::deque<WorkerParams> pending_queue; 131 std::queue<std::unique_ptr<WorkerParams>> pending_queue;
132 std::vector<AsyncShaders::Result> finished_work; 132 std::vector<AsyncShaders::Result> finished_work;
133 Core::Frontend::EmuWindow& emu_window; 133 Core::Frontend::EmuWindow& emu_window;
134}; 134};