summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2019-05-24 22:42:08 -0400
committerGravatar GitHub2019-05-24 22:42:08 -0400
commit68c9c9222d97cbebf7f26096a839a8767123c50f (patch)
tree1600a463f4653f335789cf3e2207c656797073c6 /src
parentMerge pull request #2485 from ReinUsesLisp/generic-memory (diff)
parentgl_shader_cache: Fix clang strict standard build issues (diff)
downloadyuzu-68c9c9222d97cbebf7f26096a839a8767123c50f.tar.gz
yuzu-68c9c9222d97cbebf7f26096a839a8767123c50f.tar.xz
yuzu-68c9c9222d97cbebf7f26096a839a8767123c50f.zip
Merge pull request #2358 from ReinUsesLisp/parallel-shader
gl_shader_cache: Use shared contexts to build shaders in parallel at boot
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.cpp117
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h14
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.cpp8
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.h7
-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
9 files changed, 122 insertions, 62 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..7ee1c99c0 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,107 @@ 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, const std::vector<ShaderDiskCacheUsage>& shader_usages,
386 const ShaderDumpsMap& dumps) {
387 context->MakeCurrent();
388 SCOPE_EXIT({ return context->DoneCurrent(); });
383 389
384 CachedProgram shader; 390 for (std::size_t i = begin; i < end; ++i) {
385 if (dump_it != dumps.end()) { 391 if (stop_loading || compilation_failed) {
386 // If the shader is dumped, attempt to load it with 392 return;
387 shader = GeneratePrecompiledProgram(dump_it->second, supported_formats); 393 }
394 const auto& usage{shader_usages[i]};
395 LOG_INFO(Render_OpenGL, "Building shader {:016x} (index {} of {})",
396 usage.unique_identifier, i, shader_usages.size());
397
398 const auto& unspecialized{unspecialized_shaders.at(usage.unique_identifier)};
399 const auto dump{dumps.find(usage)};
400
401 CachedProgram shader;
402 if (dump != dumps.end()) {
403 // If the shader is dumped, attempt to load it with
404 shader = GeneratePrecompiledProgram(dump->second, supported_formats);
405 if (!shader) {
406 compilation_failed = true;
407 return;
408 }
409 }
388 if (!shader) { 410 if (!shader) {
389 // Invalidate the precompiled cache if a shader dumped shader was rejected 411 shader = SpecializeShader(unspecialized.code, unspecialized.entries,
390 disk_cache.InvalidatePrecompiled(); 412 unspecialized.program_type, usage.bindings,
391 precompiled_cache_altered = true; 413 usage.primitive, true);
392 dumps.clear();
393 } 414 }
415
416 std::scoped_lock lock(mutex);
417 if (callback) {
418 callback(VideoCore::LoadCallbackStage::Build, ++built_shaders,
419 shader_usages.size());
420 }
421
422 precompiled_programs.emplace(usage, std::move(shader));
394 } 423 }
395 if (!shader) { 424 };
396 shader = SpecializeShader(unspec.code, unspec.entries, unspec.program_type, 425
397 usage.bindings, usage.primitive, true); 426 const auto num_workers{static_cast<std::size_t>(std::thread::hardware_concurrency() + 1)};
398 } 427 const std::size_t bucket_size{shader_usages.size() / num_workers};
399 precompiled_programs.insert({usage, std::move(shader)}); 428 std::vector<std::unique_ptr<Core::Frontend::GraphicsContext>> contexts(num_workers);
429 std::vector<std::thread> threads(num_workers);
430 for (std::size_t i = 0; i < num_workers; ++i) {
431 const bool is_last_worker = i + 1 == num_workers;
432 const std::size_t start{bucket_size * i};
433 const std::size_t end{is_last_worker ? shader_usages.size() : start + bucket_size};
434
435 // On some platforms the shared context has to be created from the GUI thread
436 contexts[i] = emu_window.CreateSharedContext();
437 threads[i] = std::thread(Worker, contexts[i].get(), start, end, shader_usages, dumps);
438 }
439 for (auto& thread : threads) {
440 thread.join();
441 }
400 442
401 if (callback) 443 if (compilation_failed) {
402 callback(VideoCore::LoadCallbackStage::Build, i + 1, usages.size()); 444 // Invalidate the precompiled cache if a shader dumped shader was rejected
445 disk_cache.InvalidatePrecompiled();
446 dumps.clear();
447 precompiled_cache_altered = true;
448 return;
449 }
450 if (stop_loading) {
451 return;
403 } 452 }
404 453
405 // TODO(Rodrigo): Do state tracking for transferable shaders and do a dummy draw before 454 // TODO(Rodrigo): Do state tracking for transferable shaders and do a dummy draw before
406 // precompiling them 455 // precompiling them
407 456
408 for (std::size_t i = 0; i < usages.size(); ++i) { 457 for (std::size_t i = 0; i < shader_usages.size(); ++i) {
409 const auto& usage{usages[i]}; 458 const auto& usage{shader_usages[i]};
410 if (dumps.find(usage) == dumps.end()) { 459 if (dumps.find(usage) == dumps.end()) {
411 const auto& program = precompiled_programs.at(usage); 460 const auto& program{precompiled_programs.at(usage)};
412 disk_cache.SaveDump(usage, program->handle); 461 disk_cache.SaveDump(usage, program->handle);
413 precompiled_cache_altered = true; 462 precompiled_cache_altered = true;
414 } 463 }
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/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
index fba9c594a..ee4a45ca2 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
@@ -183,8 +183,7 @@ ShaderDiskCacheOpenGL::LoadTransferable() {
183 return {{raws, usages}}; 183 return {{raws, usages}};
184} 184}
185 185
186std::pair<std::unordered_map<u64, ShaderDiskCacheDecompiled>, 186std::pair<std::unordered_map<u64, ShaderDiskCacheDecompiled>, ShaderDumpsMap>
187 std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump>>
188ShaderDiskCacheOpenGL::LoadPrecompiled() { 187ShaderDiskCacheOpenGL::LoadPrecompiled() {
189 if (!IsUsable()) 188 if (!IsUsable())
190 return {}; 189 return {};
@@ -208,8 +207,7 @@ ShaderDiskCacheOpenGL::LoadPrecompiled() {
208 return *result; 207 return *result;
209} 208}
210 209
211std::optional<std::pair<std::unordered_map<u64, ShaderDiskCacheDecompiled>, 210std::optional<std::pair<std::unordered_map<u64, ShaderDiskCacheDecompiled>, ShaderDumpsMap>>
212 std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump>>>
213ShaderDiskCacheOpenGL::LoadPrecompiledFile(FileUtil::IOFile& file) { 211ShaderDiskCacheOpenGL::LoadPrecompiledFile(FileUtil::IOFile& file) {
214 // Read compressed file from disk and decompress to virtual precompiled cache file 212 // Read compressed file from disk and decompress to virtual precompiled cache file
215 std::vector<u8> compressed(file.GetSize()); 213 std::vector<u8> compressed(file.GetSize());
@@ -230,7 +228,7 @@ ShaderDiskCacheOpenGL::LoadPrecompiledFile(FileUtil::IOFile& file) {
230 } 228 }
231 229
232 std::unordered_map<u64, ShaderDiskCacheDecompiled> decompiled; 230 std::unordered_map<u64, ShaderDiskCacheDecompiled> decompiled;
233 std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump> dumps; 231 ShaderDumpsMap dumps;
234 while (precompiled_cache_virtual_file_offset < precompiled_cache_virtual_file.GetSize()) { 232 while (precompiled_cache_virtual_file_offset < precompiled_cache_virtual_file.GetSize()) {
235 PrecompiledEntryKind kind{}; 233 PrecompiledEntryKind kind{};
236 if (!LoadObjectFromPrecompiled(kind)) { 234 if (!LoadObjectFromPrecompiled(kind)) {
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.h b/src/video_core/renderer_opengl/gl_shader_disk_cache.h
index 2da0a4a23..ecd72ba58 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.h
@@ -33,6 +33,11 @@ namespace OpenGL {
33using ProgramCode = std::vector<u64>; 33using ProgramCode = std::vector<u64>;
34using Maxwell = Tegra::Engines::Maxwell3D::Regs; 34using Maxwell = Tegra::Engines::Maxwell3D::Regs;
35 35
36struct ShaderDiskCacheUsage;
37struct ShaderDiskCacheDump;
38
39using ShaderDumpsMap = std::unordered_map<ShaderDiskCacheUsage, ShaderDiskCacheDump>;
40
36/// Allocated bindings used by an OpenGL shader program 41/// Allocated bindings used by an OpenGL shader program
37struct BaseBindings { 42struct BaseBindings {
38 u32 cbuf{}; 43 u32 cbuf{};
@@ -294,4 +299,4 @@ private:
294 bool tried_to_load{}; 299 bool tried_to_load{};
295}; 300};
296 301
297} // namespace OpenGL \ No newline at end of file 302} // 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() {