summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2019-04-06 17:59:56 -0300
committerGravatar ReinUsesLisp2019-05-20 22:45:55 -0300
commitc03b8c4c192b10fad93ded9060ff1313bab93d95 (patch)
treef4c25930a6e3938c58d5e395aaca591bf05971be /src
parentMerge pull request #2455 from lioncash/config (diff)
downloadyuzu-c03b8c4c192b10fad93ded9060ff1313bab93d95.tar.gz
yuzu-c03b8c4c192b10fad93ded9060ff1313bab93d95.tar.xz
yuzu-c03b8c4c192b10fad93ded9060ff1313bab93d95.zip
gl_shader_cache: Use shared contexts to build shaders in parallel
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp8
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h3
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp116
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h14
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp6
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h3
-rw-r--r--src/yuzu/bootmanager.cpp18
7 files changed, 112 insertions, 56 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index dbd8049f5..f9b6dfeea 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -98,9 +98,11 @@ struct FramebufferCacheKey {
98 } 98 }
99}; 99};
100 100
101RasterizerOpenGL::RasterizerOpenGL(Core::System& system, ScreenInfo& info) 101RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window,
102 : res_cache{*this}, shader_cache{*this, system, device}, global_cache{*this}, system{system}, 102 ScreenInfo& info)
103 screen_info{info}, buffer_cache(*this, STREAM_BUFFER_SIZE) { 103 : res_cache{*this}, shader_cache{*this, system, emu_window, device},
104 global_cache{*this}, system{system}, screen_info{info},
105 buffer_cache(*this, STREAM_BUFFER_SIZE) {
104 OpenGLState::ApplyDefaultState(); 106 OpenGLState::ApplyDefaultState();
105 107
106 shader_program_manager = std::make_unique<GLShader::ProgramManager>(); 108 shader_program_manager = std::make_unique<GLShader::ProgramManager>();
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 71b9c5ead..d78094138 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -48,7 +48,8 @@ struct FramebufferCacheKey;
48 48
49class RasterizerOpenGL : public VideoCore::RasterizerInterface { 49class RasterizerOpenGL : public VideoCore::RasterizerInterface {
50public: 50public:
51 explicit RasterizerOpenGL(Core::System& system, ScreenInfo& info); 51 explicit RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window,
52 ScreenInfo& info);
52 ~RasterizerOpenGL() override; 53 ~RasterizerOpenGL() override;
53 54
54 void DrawArrays() override; 55 void DrawArrays() override;
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index f700dc89a..9d3f96f9c 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -2,10 +2,14 @@
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>
6#include <thread>
5#include <boost/functional/hash.hpp> 7#include <boost/functional/hash.hpp>
6#include "common/assert.h" 8#include "common/assert.h"
7#include "common/hash.h" 9#include "common/hash.h"
10#include "common/scope_exit.h"
8#include "core/core.h" 11#include "core/core.h"
12#include "core/frontend/emu_window.h"
9#include "video_core/engines/maxwell_3d.h" 13#include "video_core/engines/maxwell_3d.h"
10#include "video_core/memory_manager.h" 14#include "video_core/memory_manager.h"
11#include "video_core/renderer_opengl/gl_rasterizer.h" 15#include "video_core/renderer_opengl/gl_rasterizer.h"
@@ -344,8 +348,8 @@ ShaderDiskCacheUsage CachedShader::GetUsage(GLenum primitive_mode,
344} 348}
345 349
346ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system, 350ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system,
347 const Device& device) 351 Core::Frontend::EmuWindow& emu_window, const Device& device)
348 : RasterizerCache{rasterizer}, device{device}, disk_cache{system} {} 352 : RasterizerCache{rasterizer}, emu_window{emu_window}, device{device}, disk_cache{system} {}
349 353
350void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, 354void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading,
351 const VideoCore::DiskResourceLoadCallback& callback) { 355 const VideoCore::DiskResourceLoadCallback& callback) {
@@ -353,62 +357,106 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading,
353 if (!transferable) { 357 if (!transferable) {
354 return; 358 return;
355 } 359 }
356 const auto [raws, usages] = *transferable; 360 const auto [raws, shader_usages] = *transferable;
357 361
358 auto [decompiled, dumps] = disk_cache.LoadPrecompiled(); 362 auto [decompiled, dumps] = disk_cache.LoadPrecompiled();
359 363
360 const auto supported_formats{GetSupportedFormats()}; 364 const auto supported_formats{GetSupportedFormats()};
361 const auto unspecialized{ 365 const auto unspecialized_shaders{
362 GenerateUnspecializedShaders(stop_loading, callback, raws, decompiled)}; 366 GenerateUnspecializedShaders(stop_loading, callback, raws, decompiled)};
363 if (stop_loading) 367 if (stop_loading) {
364 return; 368 return;
369 }
365 370
366 // Track if precompiled cache was altered during loading to know if we have to serialize the 371 // Track if precompiled cache was altered during loading to know if we have to serialize the
367 // virtual precompiled cache file back to the hard drive 372 // virtual precompiled cache file back to the hard drive
368 bool precompiled_cache_altered = false; 373 bool precompiled_cache_altered = false;
369 374
370 // Build shaders 375 // Inform the frontend about shader build initialization
371 if (callback) 376 if (callback) {
372 callback(VideoCore::LoadCallbackStage::Build, 0, usages.size()); 377 callback(VideoCore::LoadCallbackStage::Build, 0, shader_usages.size());
373 for (std::size_t i = 0; i < usages.size(); ++i) { 378 }
374 if (stop_loading)
375 return;
376 379
377 const auto& usage{usages[i]}; 380 std::mutex mutex;
378 LOG_INFO(Render_OpenGL, "Building shader {:016x} ({} of {})", usage.unique_identifier, 381 std::size_t built_shaders = 0; // It doesn't have be atomic since it's used behind a mutex
379 i + 1, usages.size()); 382 std::atomic_bool compilation_failed = false;
380 383
381 const auto& unspec{unspecialized.at(usage.unique_identifier)}; 384 const auto Worker = [&](Core::Frontend::GraphicsContext* context, std::size_t begin,
382 const auto dump_it = dumps.find(usage); 385 std::size_t end) {
386 context->MakeCurrent();
387 SCOPE_EXIT({ return context->DoneCurrent(); });
383 388
384 CachedProgram shader; 389 for (std::size_t i = begin; i < end; ++i) {
385 if (dump_it != dumps.end()) { 390 if (stop_loading || compilation_failed) {
386 // If the shader is dumped, attempt to load it with 391 return;
387 shader = GeneratePrecompiledProgram(dump_it->second, supported_formats); 392 }
393 const auto& usage{shader_usages[i]};
394 LOG_INFO(Render_OpenGL, "Building shader {:016x} (index {} of {})",
395 usage.unique_identifier, i, shader_usages.size());
396
397 const auto& unspecialized{unspecialized_shaders.at(usage.unique_identifier)};
398 const auto dump{dumps.find(usage)};
399
400 CachedProgram shader;
401 if (dump != dumps.end()) {
402 // If the shader is dumped, attempt to load it with
403 shader = GeneratePrecompiledProgram(dump->second, supported_formats);
404 if (!shader) {
405 compilation_failed = true;
406 return;
407 }
408 }
388 if (!shader) { 409 if (!shader) {
389 // Invalidate the precompiled cache if a shader dumped shader was rejected 410 shader = SpecializeShader(unspecialized.code, unspecialized.entries,
390 disk_cache.InvalidatePrecompiled(); 411 unspecialized.program_type, usage.bindings,
391 precompiled_cache_altered = true; 412 usage.primitive, true);
392 dumps.clear();
393 } 413 }
414
415 std::scoped_lock lock(mutex);
416 if (callback) {
417 callback(VideoCore::LoadCallbackStage::Build, ++built_shaders,
418 shader_usages.size());
419 }
420
421 precompiled_programs.emplace(usage, std::move(shader));
394 } 422 }
395 if (!shader) { 423 };
396 shader = SpecializeShader(unspec.code, unspec.entries, unspec.program_type, 424
397 usage.bindings, usage.primitive, true); 425 const std::size_t num_workers{std::thread::hardware_concurrency() + 1};
398 } 426 const std::size_t bucket_size{shader_usages.size() / num_workers};
399 precompiled_programs.insert({usage, std::move(shader)}); 427 std::vector<std::unique_ptr<Core::Frontend::GraphicsContext>> contexts(num_workers);
428 std::vector<std::thread> threads(num_workers);
429 for (std::size_t i = 0; i < num_workers; ++i) {
430 const bool is_last_worker = i + 1 == num_workers;
431 const std::size_t start{bucket_size * i};
432 const std::size_t end{is_last_worker ? shader_usages.size() : start + bucket_size};
433
434 // On some platforms the shared context has to be created from the GUI thread
435 contexts[i] = emu_window.CreateSharedContext();
436 threads[i] = std::thread(Worker, contexts[i].get(), start, end);
437 }
438 for (auto& thread : threads) {
439 thread.join();
440 }
400 441
401 if (callback) 442 if (compilation_failed) {
402 callback(VideoCore::LoadCallbackStage::Build, i + 1, usages.size()); 443 // Invalidate the precompiled cache if a shader dumped shader was rejected
444 disk_cache.InvalidatePrecompiled();
445 dumps.clear();
446 precompiled_cache_altered = true;
447 return;
448 }
449 if (stop_loading) {
450 return;
403 } 451 }
404 452
405 // TODO(Rodrigo): Do state tracking for transferable shaders and do a dummy draw before 453 // TODO(Rodrigo): Do state tracking for transferable shaders and do a dummy draw before
406 // precompiling them 454 // precompiling them
407 455
408 for (std::size_t i = 0; i < usages.size(); ++i) { 456 for (std::size_t i = 0; i < shader_usages.size(); ++i) {
409 const auto& usage{usages[i]}; 457 const auto& usage{shader_usages[i]};
410 if (dumps.find(usage) == dumps.end()) { 458 if (dumps.find(usage) == dumps.end()) {
411 const auto& program = precompiled_programs.at(usage); 459 const auto& program{precompiled_programs.at(usage)};
412 disk_cache.SaveDump(usage, program->handle); 460 disk_cache.SaveDump(usage, program->handle);
413 precompiled_cache_altered = true; 461 precompiled_cache_altered = true;
414 } 462 }
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index 31b979987..64e5a5594 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -22,7 +22,11 @@
22 22
23namespace Core { 23namespace Core {
24class System; 24class System;
25} // namespace Core 25}
26
27namespace Core::Frontend {
28class EmuWindow;
29}
26 30
27namespace OpenGL { 31namespace OpenGL {
28 32
@@ -111,7 +115,7 @@ private:
111class ShaderCacheOpenGL final : public RasterizerCache<Shader> { 115class ShaderCacheOpenGL final : public RasterizerCache<Shader> {
112public: 116public:
113 explicit ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system, 117 explicit ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system,
114 const Device& device); 118 Core::Frontend::EmuWindow& emu_window, const Device& device);
115 119
116 /// Loads disk cache for the current game 120 /// Loads disk cache for the current game
117 void LoadDiskCache(const std::atomic_bool& stop_loading, 121 void LoadDiskCache(const std::atomic_bool& stop_loading,
@@ -133,13 +137,13 @@ private:
133 CachedProgram GeneratePrecompiledProgram(const ShaderDiskCacheDump& dump, 137 CachedProgram GeneratePrecompiledProgram(const ShaderDiskCacheDump& dump,
134 const std::set<GLenum>& supported_formats); 138 const std::set<GLenum>& supported_formats);
135 139
140 Core::Frontend::EmuWindow& emu_window;
136 const Device& device; 141 const Device& device;
137
138 std::array<Shader, Maxwell::MaxShaderProgram> last_shaders;
139
140 ShaderDiskCacheOpenGL disk_cache; 142 ShaderDiskCacheOpenGL disk_cache;
143
141 PrecompiledShaders precompiled_shaders; 144 PrecompiledShaders precompiled_shaders;
142 PrecompiledPrograms precompiled_programs; 145 PrecompiledPrograms precompiled_programs;
146 std::array<Shader, Maxwell::MaxShaderProgram> last_shaders;
143}; 147};
144 148
145} // namespace OpenGL 149} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index d69cba9c3..3451d321d 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -97,8 +97,8 @@ static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, cons
97 return matrix; 97 return matrix;
98} 98}
99 99
100RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& window, Core::System& system) 100RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system)
101 : VideoCore::RendererBase{window}, system{system} {} 101 : VideoCore::RendererBase{emu_window}, emu_window{emu_window}, system{system} {}
102 102
103RendererOpenGL::~RendererOpenGL() = default; 103RendererOpenGL::~RendererOpenGL() = default;
104 104
@@ -265,7 +265,7 @@ void RendererOpenGL::CreateRasterizer() {
265 } 265 }
266 // Initialize sRGB Usage 266 // Initialize sRGB Usage
267 OpenGLState::ClearsRGBUsed(); 267 OpenGLState::ClearsRGBUsed();
268 rasterizer = std::make_unique<RasterizerOpenGL>(system, screen_info); 268 rasterizer = std::make_unique<RasterizerOpenGL>(system, emu_window, screen_info);
269} 269}
270 270
271void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, 271void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index 6cbf9d2cb..4aebf2321 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -45,7 +45,7 @@ struct ScreenInfo {
45 45
46class RendererOpenGL : public VideoCore::RendererBase { 46class RendererOpenGL : public VideoCore::RendererBase {
47public: 47public:
48 explicit RendererOpenGL(Core::Frontend::EmuWindow& window, Core::System& system); 48 explicit RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system);
49 ~RendererOpenGL() override; 49 ~RendererOpenGL() override;
50 50
51 /// Swap buffers (render frame) 51 /// Swap buffers (render frame)
@@ -77,6 +77,7 @@ private:
77 void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a, 77 void LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a,
78 const TextureInfo& texture); 78 const TextureInfo& texture);
79 79
80 Core::Frontend::EmuWindow& emu_window;
80 Core::System& system; 81 Core::System& system;
81 82
82 OpenGLState state; 83 OpenGLState state;
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index c2783d684..eeee603d1 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -91,25 +91,25 @@ void EmuThread::run() {
91 91
92class GGLContext : public Core::Frontend::GraphicsContext { 92class GGLContext : public Core::Frontend::GraphicsContext {
93public: 93public:
94 explicit GGLContext(QOpenGLContext* shared_context) 94 explicit GGLContext(QOpenGLContext* shared_context) : shared_context{shared_context} {
95 : context{std::make_unique<QOpenGLContext>(shared_context)} { 95 context.setFormat(shared_context->format());
96 surface.setFormat(shared_context->format()); 96 context.setShareContext(shared_context);
97 surface.create(); 97 context.create();
98 } 98 }
99 99
100 void MakeCurrent() override { 100 void MakeCurrent() override {
101 context->makeCurrent(&surface); 101 context.makeCurrent(shared_context->surface());
102 } 102 }
103 103
104 void DoneCurrent() override { 104 void DoneCurrent() override {
105 context->doneCurrent(); 105 context.doneCurrent();
106 } 106 }
107 107
108 void SwapBuffers() override {} 108 void SwapBuffers() override {}
109 109
110private: 110private:
111 std::unique_ptr<QOpenGLContext> context; 111 QOpenGLContext* shared_context;
112 QOffscreenSurface surface; 112 QOpenGLContext context;
113}; 113};
114 114
115// This class overrides paintEvent and resizeEvent to prevent the GUI thread from stealing GL 115// This class overrides paintEvent and resizeEvent to prevent the GUI thread from stealing GL
@@ -358,7 +358,7 @@ void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height) {
358} 358}
359 359
360std::unique_ptr<Core::Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const { 360std::unique_ptr<Core::Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const {
361 return std::make_unique<GGLContext>(shared_context.get()); 361 return std::make_unique<GGLContext>(context.get());
362} 362}
363 363
364void GRenderWindow::InitRenderTarget() { 364void GRenderWindow::InitRenderTarget() {