diff options
Diffstat (limited to 'src')
29 files changed, 361 insertions, 418 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index b31a0328c..29a267957 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -131,8 +131,6 @@ add_library(core STATIC | |||
| 131 | frontend/framebuffer_layout.cpp | 131 | frontend/framebuffer_layout.cpp |
| 132 | frontend/framebuffer_layout.h | 132 | frontend/framebuffer_layout.h |
| 133 | frontend/input.h | 133 | frontend/input.h |
| 134 | frontend/scope_acquire_context.cpp | ||
| 135 | frontend/scope_acquire_context.h | ||
| 136 | gdbstub/gdbstub.cpp | 134 | gdbstub/gdbstub.cpp |
| 137 | gdbstub/gdbstub.h | 135 | gdbstub/gdbstub.h |
| 138 | hardware_interrupt_manager.cpp | 136 | hardware_interrupt_manager.cpp |
diff --git a/src/core/core.cpp b/src/core/core.cpp index 218508126..6cc4a0812 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -24,7 +24,6 @@ | |||
| 24 | #include "core/file_sys/sdmc_factory.h" | 24 | #include "core/file_sys/sdmc_factory.h" |
| 25 | #include "core/file_sys/vfs_concat.h" | 25 | #include "core/file_sys/vfs_concat.h" |
| 26 | #include "core/file_sys/vfs_real.h" | 26 | #include "core/file_sys/vfs_real.h" |
| 27 | #include "core/frontend/scope_acquire_context.h" | ||
| 28 | #include "core/gdbstub/gdbstub.h" | 27 | #include "core/gdbstub/gdbstub.h" |
| 29 | #include "core/hardware_interrupt_manager.h" | 28 | #include "core/hardware_interrupt_manager.h" |
| 30 | #include "core/hle/kernel/client_port.h" | 29 | #include "core/hle/kernel/client_port.h" |
| @@ -168,13 +167,9 @@ struct System::Impl { | |||
| 168 | Service::Init(service_manager, system); | 167 | Service::Init(service_manager, system); |
| 169 | GDBStub::Init(); | 168 | GDBStub::Init(); |
| 170 | 169 | ||
| 171 | renderer = VideoCore::CreateRenderer(emu_window, system); | ||
| 172 | if (!renderer->Init()) { | ||
| 173 | return ResultStatus::ErrorVideoCore; | ||
| 174 | } | ||
| 175 | interrupt_manager = std::make_unique<Core::Hardware::InterruptManager>(system); | 170 | interrupt_manager = std::make_unique<Core::Hardware::InterruptManager>(system); |
| 176 | gpu_core = VideoCore::CreateGPU(system); | 171 | gpu_core = VideoCore::CreateGPU(emu_window, system); |
| 177 | renderer->Rasterizer().SetupDirtyFlags(); | 172 | gpu_core->Renderer().Rasterizer().SetupDirtyFlags(); |
| 178 | 173 | ||
| 179 | is_powered_on = true; | 174 | is_powered_on = true; |
| 180 | exit_lock = false; | 175 | exit_lock = false; |
| @@ -186,7 +181,6 @@ struct System::Impl { | |||
| 186 | 181 | ||
| 187 | ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, | 182 | ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, |
| 188 | const std::string& filepath) { | 183 | const std::string& filepath) { |
| 189 | Core::Frontend::ScopeAcquireContext acquire_context{emu_window}; | ||
| 190 | 184 | ||
| 191 | app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath)); | 185 | app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath)); |
| 192 | if (!app_loader) { | 186 | if (!app_loader) { |
| @@ -216,10 +210,6 @@ struct System::Impl { | |||
| 216 | AddGlueRegistrationForProcess(*app_loader, *main_process); | 210 | AddGlueRegistrationForProcess(*app_loader, *main_process); |
| 217 | kernel.MakeCurrentProcess(main_process.get()); | 211 | kernel.MakeCurrentProcess(main_process.get()); |
| 218 | 212 | ||
| 219 | // Main process has been loaded and been made current. | ||
| 220 | // Begin GPU and CPU execution. | ||
| 221 | gpu_core->Start(); | ||
| 222 | |||
| 223 | // Initialize cheat engine | 213 | // Initialize cheat engine |
| 224 | if (cheat_engine) { | 214 | if (cheat_engine) { |
| 225 | cheat_engine->Initialize(); | 215 | cheat_engine->Initialize(); |
| @@ -277,7 +267,6 @@ struct System::Impl { | |||
| 277 | } | 267 | } |
| 278 | 268 | ||
| 279 | // Shutdown emulation session | 269 | // Shutdown emulation session |
| 280 | renderer.reset(); | ||
| 281 | GDBStub::Shutdown(); | 270 | GDBStub::Shutdown(); |
| 282 | Service::Shutdown(); | 271 | Service::Shutdown(); |
| 283 | service_manager.reset(); | 272 | service_manager.reset(); |
| @@ -353,7 +342,6 @@ struct System::Impl { | |||
| 353 | Service::FileSystem::FileSystemController fs_controller; | 342 | Service::FileSystem::FileSystemController fs_controller; |
| 354 | /// AppLoader used to load the current executing application | 343 | /// AppLoader used to load the current executing application |
| 355 | std::unique_ptr<Loader::AppLoader> app_loader; | 344 | std::unique_ptr<Loader::AppLoader> app_loader; |
| 356 | std::unique_ptr<VideoCore::RendererBase> renderer; | ||
| 357 | std::unique_ptr<Tegra::GPU> gpu_core; | 345 | std::unique_ptr<Tegra::GPU> gpu_core; |
| 358 | std::unique_ptr<Hardware::InterruptManager> interrupt_manager; | 346 | std::unique_ptr<Hardware::InterruptManager> interrupt_manager; |
| 359 | Memory::Memory memory; | 347 | Memory::Memory memory; |
| @@ -536,11 +524,11 @@ const Core::Hardware::InterruptManager& System::InterruptManager() const { | |||
| 536 | } | 524 | } |
| 537 | 525 | ||
| 538 | VideoCore::RendererBase& System::Renderer() { | 526 | VideoCore::RendererBase& System::Renderer() { |
| 539 | return *impl->renderer; | 527 | return impl->gpu_core->Renderer(); |
| 540 | } | 528 | } |
| 541 | 529 | ||
| 542 | const VideoCore::RendererBase& System::Renderer() const { | 530 | const VideoCore::RendererBase& System::Renderer() const { |
| 543 | return *impl->renderer; | 531 | return impl->gpu_core->Renderer(); |
| 544 | } | 532 | } |
| 545 | 533 | ||
| 546 | Kernel::KernelCore& System::Kernel() { | 534 | Kernel::KernelCore& System::Kernel() { |
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index 5eb87fb63..bb283d844 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h | |||
| @@ -13,19 +13,39 @@ | |||
| 13 | namespace Core::Frontend { | 13 | namespace Core::Frontend { |
| 14 | 14 | ||
| 15 | /** | 15 | /** |
| 16 | * Represents a graphics context that can be used for background computation or drawing. If the | 16 | * Represents a drawing context that supports graphics operations. |
| 17 | * graphics backend doesn't require the context, then the implementation of these methods can be | ||
| 18 | * stubs | ||
| 19 | */ | 17 | */ |
| 20 | class GraphicsContext { | 18 | class GraphicsContext { |
| 21 | public: | 19 | public: |
| 22 | virtual ~GraphicsContext(); | 20 | virtual ~GraphicsContext(); |
| 23 | 21 | ||
| 22 | /// Inform the driver to swap the front/back buffers and present the current image | ||
| 23 | virtual void SwapBuffers() {} | ||
| 24 | |||
| 24 | /// Makes the graphics context current for the caller thread | 25 | /// Makes the graphics context current for the caller thread |
| 25 | virtual void MakeCurrent() = 0; | 26 | virtual void MakeCurrent() {} |
| 26 | 27 | ||
| 27 | /// Releases (dunno if this is the "right" word) the context from the caller thread | 28 | /// Releases (dunno if this is the "right" word) the context from the caller thread |
| 28 | virtual void DoneCurrent() = 0; | 29 | virtual void DoneCurrent() {} |
| 30 | |||
| 31 | class Scoped { | ||
| 32 | public: | ||
| 33 | Scoped(GraphicsContext& context_) : context(context_) { | ||
| 34 | context.MakeCurrent(); | ||
| 35 | } | ||
| 36 | ~Scoped() { | ||
| 37 | context.DoneCurrent(); | ||
| 38 | } | ||
| 39 | |||
| 40 | private: | ||
| 41 | GraphicsContext& context; | ||
| 42 | }; | ||
| 43 | |||
| 44 | /// Calls MakeCurrent on the context and calls DoneCurrent when the scope for the returned value | ||
| 45 | /// ends | ||
| 46 | Scoped Acquire() { | ||
| 47 | return Scoped{*this}; | ||
| 48 | } | ||
| 29 | }; | 49 | }; |
| 30 | 50 | ||
| 31 | /** | 51 | /** |
| @@ -46,7 +66,7 @@ public: | |||
| 46 | * - DO NOT TREAT THIS CLASS AS A GUI TOOLKIT ABSTRACTION LAYER. That's not what it is. Please | 66 | * - DO NOT TREAT THIS CLASS AS A GUI TOOLKIT ABSTRACTION LAYER. That's not what it is. Please |
| 47 | * re-read the upper points again and think about it if you don't see this. | 67 | * re-read the upper points again and think about it if you don't see this. |
| 48 | */ | 68 | */ |
| 49 | class EmuWindow : public GraphicsContext { | 69 | class EmuWindow { |
| 50 | public: | 70 | public: |
| 51 | /// Data structure to store emuwindow configuration | 71 | /// Data structure to store emuwindow configuration |
| 52 | struct WindowConfig { | 72 | struct WindowConfig { |
| @@ -60,17 +80,9 @@ public: | |||
| 60 | virtual void PollEvents() = 0; | 80 | virtual void PollEvents() = 0; |
| 61 | 81 | ||
| 62 | /** | 82 | /** |
| 63 | * Returns a GraphicsContext that the frontend provides that is shared with the emu window. This | 83 | * Returns a GraphicsContext that the frontend provides to be used for rendering. |
| 64 | * context can be used from other threads for background graphics computation. If the frontend | ||
| 65 | * is using a graphics backend that doesn't need anything specific to run on a different thread, | ||
| 66 | * then it can use a stubbed implemenation for GraphicsContext. | ||
| 67 | * | ||
| 68 | * If the return value is null, then the core should assume that the frontend cannot provide a | ||
| 69 | * Shared Context | ||
| 70 | */ | 84 | */ |
| 71 | virtual std::unique_ptr<GraphicsContext> CreateSharedContext() const { | 85 | virtual std::unique_ptr<GraphicsContext> CreateSharedContext() const = 0; |
| 72 | return nullptr; | ||
| 73 | } | ||
| 74 | 86 | ||
| 75 | /// Returns if window is shown (not minimized) | 87 | /// Returns if window is shown (not minimized) |
| 76 | virtual bool IsShown() const = 0; | 88 | virtual bool IsShown() const = 0; |
diff --git a/src/core/frontend/scope_acquire_context.cpp b/src/core/frontend/scope_acquire_context.cpp deleted file mode 100644 index 878c3157c..000000000 --- a/src/core/frontend/scope_acquire_context.cpp +++ /dev/null | |||
| @@ -1,18 +0,0 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/frontend/emu_window.h" | ||
| 6 | #include "core/frontend/scope_acquire_context.h" | ||
| 7 | |||
| 8 | namespace Core::Frontend { | ||
| 9 | |||
| 10 | ScopeAcquireContext::ScopeAcquireContext(Core::Frontend::GraphicsContext& context) | ||
| 11 | : context{context} { | ||
| 12 | context.MakeCurrent(); | ||
| 13 | } | ||
| 14 | ScopeAcquireContext::~ScopeAcquireContext() { | ||
| 15 | context.DoneCurrent(); | ||
| 16 | } | ||
| 17 | |||
| 18 | } // namespace Core::Frontend | ||
diff --git a/src/core/frontend/scope_acquire_context.h b/src/core/frontend/scope_acquire_context.h deleted file mode 100644 index 7a65c0623..000000000 --- a/src/core/frontend/scope_acquire_context.h +++ /dev/null | |||
| @@ -1,23 +0,0 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | namespace Core::Frontend { | ||
| 10 | |||
| 11 | class GraphicsContext; | ||
| 12 | |||
| 13 | /// Helper class to acquire/release window context within a given scope | ||
| 14 | class ScopeAcquireContext : NonCopyable { | ||
| 15 | public: | ||
| 16 | explicit ScopeAcquireContext(Core::Frontend::GraphicsContext& context); | ||
| 17 | ~ScopeAcquireContext(); | ||
| 18 | |||
| 19 | private: | ||
| 20 | Core::Frontend::GraphicsContext& context; | ||
| 21 | }; | ||
| 22 | |||
| 23 | } // namespace Core::Frontend | ||
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index e8f763ce9..8acf2eda2 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include "core/core.h" | 7 | #include "core/core.h" |
| 8 | #include "core/core_timing.h" | 8 | #include "core/core_timing.h" |
| 9 | #include "core/core_timing_util.h" | 9 | #include "core/core_timing_util.h" |
| 10 | #include "core/frontend/emu_window.h" | ||
| 10 | #include "core/memory.h" | 11 | #include "core/memory.h" |
| 11 | #include "video_core/engines/fermi_2d.h" | 12 | #include "video_core/engines/fermi_2d.h" |
| 12 | #include "video_core/engines/kepler_compute.h" | 13 | #include "video_core/engines/kepler_compute.h" |
| @@ -16,14 +17,15 @@ | |||
| 16 | #include "video_core/gpu.h" | 17 | #include "video_core/gpu.h" |
| 17 | #include "video_core/memory_manager.h" | 18 | #include "video_core/memory_manager.h" |
| 18 | #include "video_core/renderer_base.h" | 19 | #include "video_core/renderer_base.h" |
| 20 | #include "video_core/video_core.h" | ||
| 19 | 21 | ||
| 20 | namespace Tegra { | 22 | namespace Tegra { |
| 21 | 23 | ||
| 22 | MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192)); | 24 | MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192)); |
| 23 | 25 | ||
| 24 | GPU::GPU(Core::System& system, VideoCore::RendererBase& renderer, bool is_async) | 26 | GPU::GPU(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer_, bool is_async) |
| 25 | : system{system}, renderer{renderer}, is_async{is_async} { | 27 | : system{system}, renderer{std::move(renderer_)}, is_async{is_async} { |
| 26 | auto& rasterizer{renderer.Rasterizer()}; | 28 | auto& rasterizer{renderer->Rasterizer()}; |
| 27 | memory_manager = std::make_unique<Tegra::MemoryManager>(system, rasterizer); | 29 | memory_manager = std::make_unique<Tegra::MemoryManager>(system, rasterizer); |
| 28 | dma_pusher = std::make_unique<Tegra::DmaPusher>(*this); | 30 | dma_pusher = std::make_unique<Tegra::DmaPusher>(*this); |
| 29 | maxwell_3d = std::make_unique<Engines::Maxwell3D>(system, rasterizer, *memory_manager); | 31 | maxwell_3d = std::make_unique<Engines::Maxwell3D>(system, rasterizer, *memory_manager); |
| @@ -137,7 +139,7 @@ u64 GPU::GetTicks() const { | |||
| 137 | } | 139 | } |
| 138 | 140 | ||
| 139 | void GPU::FlushCommands() { | 141 | void GPU::FlushCommands() { |
| 140 | renderer.Rasterizer().FlushCommands(); | 142 | renderer->Rasterizer().FlushCommands(); |
| 141 | } | 143 | } |
| 142 | 144 | ||
| 143 | // Note that, traditionally, methods are treated as 4-byte addressable locations, and hence | 145 | // Note that, traditionally, methods are treated as 4-byte addressable locations, and hence |
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 64acb17df..ced9d7e28 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h | |||
| @@ -25,8 +25,11 @@ inline u8* FromCacheAddr(CacheAddr cache_addr) { | |||
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | namespace Core { | 27 | namespace Core { |
| 28 | class System; | 28 | namespace Frontend { |
| 29 | class EmuWindow; | ||
| 29 | } | 30 | } |
| 31 | class System; | ||
| 32 | } // namespace Core | ||
| 30 | 33 | ||
| 31 | namespace VideoCore { | 34 | namespace VideoCore { |
| 32 | class RendererBase; | 35 | class RendererBase; |
| @@ -129,7 +132,8 @@ class MemoryManager; | |||
| 129 | 132 | ||
| 130 | class GPU { | 133 | class GPU { |
| 131 | public: | 134 | public: |
| 132 | explicit GPU(Core::System& system, VideoCore::RendererBase& renderer, bool is_async); | 135 | explicit GPU(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer, |
| 136 | bool is_async); | ||
| 133 | 137 | ||
| 134 | virtual ~GPU(); | 138 | virtual ~GPU(); |
| 135 | 139 | ||
| @@ -174,6 +178,14 @@ public: | |||
| 174 | /// Returns a reference to the GPU DMA pusher. | 178 | /// Returns a reference to the GPU DMA pusher. |
| 175 | Tegra::DmaPusher& DmaPusher(); | 179 | Tegra::DmaPusher& DmaPusher(); |
| 176 | 180 | ||
| 181 | VideoCore::RendererBase& Renderer() { | ||
| 182 | return *renderer; | ||
| 183 | } | ||
| 184 | |||
| 185 | const VideoCore::RendererBase& Renderer() const { | ||
| 186 | return *renderer; | ||
| 187 | } | ||
| 188 | |||
| 177 | // Waits for the GPU to finish working | 189 | // Waits for the GPU to finish working |
| 178 | virtual void WaitIdle() const = 0; | 190 | virtual void WaitIdle() const = 0; |
| 179 | 191 | ||
| @@ -287,7 +299,7 @@ private: | |||
| 287 | protected: | 299 | protected: |
| 288 | std::unique_ptr<Tegra::DmaPusher> dma_pusher; | 300 | std::unique_ptr<Tegra::DmaPusher> dma_pusher; |
| 289 | Core::System& system; | 301 | Core::System& system; |
| 290 | VideoCore::RendererBase& renderer; | 302 | std::unique_ptr<VideoCore::RendererBase> renderer; |
| 291 | 303 | ||
| 292 | private: | 304 | private: |
| 293 | std::unique_ptr<Tegra::MemoryManager> memory_manager; | 305 | std::unique_ptr<Tegra::MemoryManager> memory_manager; |
diff --git a/src/video_core/gpu_asynch.cpp b/src/video_core/gpu_asynch.cpp index 04222d060..925be8d7b 100644 --- a/src/video_core/gpu_asynch.cpp +++ b/src/video_core/gpu_asynch.cpp | |||
| @@ -10,13 +10,16 @@ | |||
| 10 | 10 | ||
| 11 | namespace VideoCommon { | 11 | namespace VideoCommon { |
| 12 | 12 | ||
| 13 | GPUAsynch::GPUAsynch(Core::System& system, VideoCore::RendererBase& renderer) | 13 | GPUAsynch::GPUAsynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer_, |
| 14 | : GPU(system, renderer, true), gpu_thread{system} {} | 14 | std::unique_ptr<Core::Frontend::GraphicsContext>&& context) |
| 15 | : GPU(system, std::move(renderer_), true), gpu_thread{system}, gpu_context(std::move(context)), | ||
| 16 | cpu_context(renderer->GetRenderWindow().CreateSharedContext()) {} | ||
| 15 | 17 | ||
| 16 | GPUAsynch::~GPUAsynch() = default; | 18 | GPUAsynch::~GPUAsynch() = default; |
| 17 | 19 | ||
| 18 | void GPUAsynch::Start() { | 20 | void GPUAsynch::Start() { |
| 19 | gpu_thread.StartThread(renderer, *dma_pusher); | 21 | cpu_context->MakeCurrent(); |
| 22 | gpu_thread.StartThread(*renderer, *gpu_context, *dma_pusher); | ||
| 20 | } | 23 | } |
| 21 | 24 | ||
| 22 | void GPUAsynch::PushGPUEntries(Tegra::CommandList&& entries) { | 25 | void GPUAsynch::PushGPUEntries(Tegra::CommandList&& entries) { |
diff --git a/src/video_core/gpu_asynch.h b/src/video_core/gpu_asynch.h index 1241ade1d..265c62758 100644 --- a/src/video_core/gpu_asynch.h +++ b/src/video_core/gpu_asynch.h | |||
| @@ -7,6 +7,10 @@ | |||
| 7 | #include "video_core/gpu.h" | 7 | #include "video_core/gpu.h" |
| 8 | #include "video_core/gpu_thread.h" | 8 | #include "video_core/gpu_thread.h" |
| 9 | 9 | ||
| 10 | namespace Core::Frontend { | ||
| 11 | class GraphicsContext; | ||
| 12 | } | ||
| 13 | |||
| 10 | namespace VideoCore { | 14 | namespace VideoCore { |
| 11 | class RendererBase; | 15 | class RendererBase; |
| 12 | } // namespace VideoCore | 16 | } // namespace VideoCore |
| @@ -16,7 +20,8 @@ namespace VideoCommon { | |||
| 16 | /// Implementation of GPU interface that runs the GPU asynchronously | 20 | /// Implementation of GPU interface that runs the GPU asynchronously |
| 17 | class GPUAsynch final : public Tegra::GPU { | 21 | class GPUAsynch final : public Tegra::GPU { |
| 18 | public: | 22 | public: |
| 19 | explicit GPUAsynch(Core::System& system, VideoCore::RendererBase& renderer); | 23 | explicit GPUAsynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer, |
| 24 | std::unique_ptr<Core::Frontend::GraphicsContext>&& context); | ||
| 20 | ~GPUAsynch() override; | 25 | ~GPUAsynch() override; |
| 21 | 26 | ||
| 22 | void Start() override; | 27 | void Start() override; |
| @@ -32,6 +37,8 @@ protected: | |||
| 32 | 37 | ||
| 33 | private: | 38 | private: |
| 34 | GPUThread::ThreadManager gpu_thread; | 39 | GPUThread::ThreadManager gpu_thread; |
| 40 | std::unique_ptr<Core::Frontend::GraphicsContext> cpu_context; | ||
| 41 | std::unique_ptr<Core::Frontend::GraphicsContext> gpu_context; | ||
| 35 | }; | 42 | }; |
| 36 | 43 | ||
| 37 | } // namespace VideoCommon | 44 | } // namespace VideoCommon |
diff --git a/src/video_core/gpu_synch.cpp b/src/video_core/gpu_synch.cpp index d48221077..bd5278a5c 100644 --- a/src/video_core/gpu_synch.cpp +++ b/src/video_core/gpu_synch.cpp | |||
| @@ -7,12 +7,15 @@ | |||
| 7 | 7 | ||
| 8 | namespace VideoCommon { | 8 | namespace VideoCommon { |
| 9 | 9 | ||
| 10 | GPUSynch::GPUSynch(Core::System& system, VideoCore::RendererBase& renderer) | 10 | GPUSynch::GPUSynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer, |
| 11 | : GPU(system, renderer, false) {} | 11 | std::unique_ptr<Core::Frontend::GraphicsContext>&& context) |
| 12 | : GPU(system, std::move(renderer), false), context{std::move(context)} {} | ||
| 12 | 13 | ||
| 13 | GPUSynch::~GPUSynch() = default; | 14 | GPUSynch::~GPUSynch() = default; |
| 14 | 15 | ||
| 15 | void GPUSynch::Start() {} | 16 | void GPUSynch::Start() { |
| 17 | context->MakeCurrent(); | ||
| 18 | } | ||
| 16 | 19 | ||
| 17 | void GPUSynch::PushGPUEntries(Tegra::CommandList&& entries) { | 20 | void GPUSynch::PushGPUEntries(Tegra::CommandList&& entries) { |
| 18 | dma_pusher->Push(std::move(entries)); | 21 | dma_pusher->Push(std::move(entries)); |
| @@ -20,19 +23,19 @@ void GPUSynch::PushGPUEntries(Tegra::CommandList&& entries) { | |||
| 20 | } | 23 | } |
| 21 | 24 | ||
| 22 | void GPUSynch::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | 25 | void GPUSynch::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { |
| 23 | renderer.SwapBuffers(framebuffer); | 26 | renderer->SwapBuffers(framebuffer); |
| 24 | } | 27 | } |
| 25 | 28 | ||
| 26 | void GPUSynch::FlushRegion(CacheAddr addr, u64 size) { | 29 | void GPUSynch::FlushRegion(CacheAddr addr, u64 size) { |
| 27 | renderer.Rasterizer().FlushRegion(addr, size); | 30 | renderer->Rasterizer().FlushRegion(addr, size); |
| 28 | } | 31 | } |
| 29 | 32 | ||
| 30 | void GPUSynch::InvalidateRegion(CacheAddr addr, u64 size) { | 33 | void GPUSynch::InvalidateRegion(CacheAddr addr, u64 size) { |
| 31 | renderer.Rasterizer().InvalidateRegion(addr, size); | 34 | renderer->Rasterizer().InvalidateRegion(addr, size); |
| 32 | } | 35 | } |
| 33 | 36 | ||
| 34 | void GPUSynch::FlushAndInvalidateRegion(CacheAddr addr, u64 size) { | 37 | void GPUSynch::FlushAndInvalidateRegion(CacheAddr addr, u64 size) { |
| 35 | renderer.Rasterizer().FlushAndInvalidateRegion(addr, size); | 38 | renderer->Rasterizer().FlushAndInvalidateRegion(addr, size); |
| 36 | } | 39 | } |
| 37 | 40 | ||
| 38 | } // namespace VideoCommon | 41 | } // namespace VideoCommon |
diff --git a/src/video_core/gpu_synch.h b/src/video_core/gpu_synch.h index c71baee89..866a94c8c 100644 --- a/src/video_core/gpu_synch.h +++ b/src/video_core/gpu_synch.h | |||
| @@ -6,6 +6,10 @@ | |||
| 6 | 6 | ||
| 7 | #include "video_core/gpu.h" | 7 | #include "video_core/gpu.h" |
| 8 | 8 | ||
| 9 | namespace Core::Frontend { | ||
| 10 | class GraphicsContext; | ||
| 11 | } | ||
| 12 | |||
| 9 | namespace VideoCore { | 13 | namespace VideoCore { |
| 10 | class RendererBase; | 14 | class RendererBase; |
| 11 | } // namespace VideoCore | 15 | } // namespace VideoCore |
| @@ -15,7 +19,8 @@ namespace VideoCommon { | |||
| 15 | /// Implementation of GPU interface that runs the GPU synchronously | 19 | /// Implementation of GPU interface that runs the GPU synchronously |
| 16 | class GPUSynch final : public Tegra::GPU { | 20 | class GPUSynch final : public Tegra::GPU { |
| 17 | public: | 21 | public: |
| 18 | explicit GPUSynch(Core::System& system, VideoCore::RendererBase& renderer); | 22 | explicit GPUSynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer, |
| 23 | std::unique_ptr<Core::Frontend::GraphicsContext>&& context); | ||
| 19 | ~GPUSynch() override; | 24 | ~GPUSynch() override; |
| 20 | 25 | ||
| 21 | void Start() override; | 26 | void Start() override; |
| @@ -29,6 +34,9 @@ public: | |||
| 29 | protected: | 34 | protected: |
| 30 | void TriggerCpuInterrupt([[maybe_unused]] u32 syncpoint_id, | 35 | void TriggerCpuInterrupt([[maybe_unused]] u32 syncpoint_id, |
| 31 | [[maybe_unused]] u32 value) const override {} | 36 | [[maybe_unused]] u32 value) const override {} |
| 37 | |||
| 38 | private: | ||
| 39 | std::unique_ptr<Core::Frontend::GraphicsContext> context; | ||
| 32 | }; | 40 | }; |
| 33 | 41 | ||
| 34 | } // namespace VideoCommon | 42 | } // namespace VideoCommon |
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp index b1088af3d..270c7ae0d 100644 --- a/src/video_core/gpu_thread.cpp +++ b/src/video_core/gpu_thread.cpp | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 6 | #include "common/microprofile.h" | 6 | #include "common/microprofile.h" |
| 7 | #include "core/core.h" | 7 | #include "core/core.h" |
| 8 | #include "core/frontend/scope_acquire_context.h" | 8 | #include "core/frontend/emu_window.h" |
| 9 | #include "video_core/dma_pusher.h" | 9 | #include "video_core/dma_pusher.h" |
| 10 | #include "video_core/gpu.h" | 10 | #include "video_core/gpu.h" |
| 11 | #include "video_core/gpu_thread.h" | 11 | #include "video_core/gpu_thread.h" |
| @@ -14,8 +14,8 @@ | |||
| 14 | namespace VideoCommon::GPUThread { | 14 | namespace VideoCommon::GPUThread { |
| 15 | 15 | ||
| 16 | /// Runs the GPU thread | 16 | /// Runs the GPU thread |
| 17 | static void RunThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher, | 17 | static void RunThread(VideoCore::RendererBase& renderer, Core::Frontend::GraphicsContext& context, |
| 18 | SynchState& state) { | 18 | Tegra::DmaPusher& dma_pusher, SynchState& state) { |
| 19 | MicroProfileOnThreadCreate("GpuThread"); | 19 | MicroProfileOnThreadCreate("GpuThread"); |
| 20 | 20 | ||
| 21 | // Wait for first GPU command before acquiring the window context | 21 | // Wait for first GPU command before acquiring the window context |
| @@ -27,7 +27,7 @@ static void RunThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_p | |||
| 27 | return; | 27 | return; |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | Core::Frontend::ScopeAcquireContext acquire_context{renderer.GetRenderWindow()}; | 30 | auto current_context = context.Acquire(); |
| 31 | 31 | ||
| 32 | CommandDataContainer next; | 32 | CommandDataContainer next; |
| 33 | while (state.is_running) { | 33 | while (state.is_running) { |
| @@ -62,8 +62,11 @@ ThreadManager::~ThreadManager() { | |||
| 62 | thread.join(); | 62 | thread.join(); |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | void ThreadManager::StartThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher) { | 65 | void ThreadManager::StartThread(VideoCore::RendererBase& renderer, |
| 66 | thread = std::thread{RunThread, std::ref(renderer), std::ref(dma_pusher), std::ref(state)}; | 66 | Core::Frontend::GraphicsContext& context, |
| 67 | Tegra::DmaPusher& dma_pusher) { | ||
| 68 | thread = std::thread{RunThread, std::ref(renderer), std::ref(context), std::ref(dma_pusher), | ||
| 69 | std::ref(state)}; | ||
| 67 | } | 70 | } |
| 68 | 71 | ||
| 69 | void ThreadManager::SubmitList(Tegra::CommandList&& entries) { | 72 | void ThreadManager::SubmitList(Tegra::CommandList&& entries) { |
diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h index 882e2d9c7..be36c580e 100644 --- a/src/video_core/gpu_thread.h +++ b/src/video_core/gpu_thread.h | |||
| @@ -10,7 +10,6 @@ | |||
| 10 | #include <optional> | 10 | #include <optional> |
| 11 | #include <thread> | 11 | #include <thread> |
| 12 | #include <variant> | 12 | #include <variant> |
| 13 | |||
| 14 | #include "common/threadsafe_queue.h" | 13 | #include "common/threadsafe_queue.h" |
| 15 | #include "video_core/gpu.h" | 14 | #include "video_core/gpu.h" |
| 16 | 15 | ||
| @@ -20,6 +19,9 @@ class DmaPusher; | |||
| 20 | } // namespace Tegra | 19 | } // namespace Tegra |
| 21 | 20 | ||
| 22 | namespace Core { | 21 | namespace Core { |
| 22 | namespace Frontend { | ||
| 23 | class GraphicsContext; | ||
| 24 | } | ||
| 23 | class System; | 25 | class System; |
| 24 | } // namespace Core | 26 | } // namespace Core |
| 25 | 27 | ||
| @@ -99,7 +101,8 @@ public: | |||
| 99 | ~ThreadManager(); | 101 | ~ThreadManager(); |
| 100 | 102 | ||
| 101 | /// Creates and starts the GPU thread. | 103 | /// Creates and starts the GPU thread. |
| 102 | void StartThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher); | 104 | void StartThread(VideoCore::RendererBase& renderer, Core::Frontend::GraphicsContext& context, |
| 105 | Tegra::DmaPusher& dma_pusher); | ||
| 103 | 106 | ||
| 104 | /// Push GPU command entries to be processed | 107 | /// Push GPU command entries to be processed |
| 105 | void SubmitList(Tegra::CommandList&& entries); | 108 | void SubmitList(Tegra::CommandList&& entries); |
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index 5ec99a126..1d85219b6 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h | |||
| @@ -46,7 +46,8 @@ public: | |||
| 46 | 46 | ||
| 47 | /// Draws the latest frame to the window waiting timeout_ms for a frame to arrive (Renderer | 47 | /// Draws the latest frame to the window waiting timeout_ms for a frame to arrive (Renderer |
| 48 | /// specific implementation) | 48 | /// specific implementation) |
| 49 | virtual void TryPresent(int timeout_ms) = 0; | 49 | /// Returns true if a frame was drawn |
| 50 | virtual bool TryPresent(int timeout_ms) = 0; | ||
| 50 | 51 | ||
| 51 | // Getter/setter functions: | 52 | // Getter/setter functions: |
| 52 | // ------------------------ | 53 | // ------------------------ |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index e3d31c3eb..8f59e0442 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -305,7 +305,6 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, | |||
| 305 | } | 305 | } |
| 306 | 306 | ||
| 307 | const std::vector gl_cache = disk_cache.LoadPrecompiled(); | 307 | const std::vector gl_cache = disk_cache.LoadPrecompiled(); |
| 308 | const auto supported_formats = GetSupportedFormats(); | ||
| 309 | 308 | ||
| 310 | // Track if precompiled cache was altered during loading to know if we have to | 309 | // Track if precompiled cache was altered during loading to know if we have to |
| 311 | // serialize the virtual precompiled cache file back to the hard drive | 310 | // serialize the virtual precompiled cache file back to the hard drive |
| @@ -327,8 +326,8 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, | |||
| 327 | 326 | ||
| 328 | const auto worker = [&](Core::Frontend::GraphicsContext* context, std::size_t begin, | 327 | const auto worker = [&](Core::Frontend::GraphicsContext* context, std::size_t begin, |
| 329 | std::size_t end) { | 328 | std::size_t end) { |
| 330 | context->MakeCurrent(); | 329 | const auto scope = context->Acquire(); |
| 331 | SCOPE_EXIT({ return context->DoneCurrent(); }); | 330 | const auto supported_formats = GetSupportedFormats(); |
| 332 | 331 | ||
| 333 | for (std::size_t i = begin; i < end; ++i) { | 332 | for (std::size_t i = begin; i < end; ++i) { |
| 334 | if (stop_loading) { | 333 | if (stop_loading) { |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index fca5e3ec0..6f08803c1 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -7,9 +7,7 @@ | |||
| 7 | #include <cstdlib> | 7 | #include <cstdlib> |
| 8 | #include <cstring> | 8 | #include <cstring> |
| 9 | #include <memory> | 9 | #include <memory> |
| 10 | |||
| 11 | #include <glad/glad.h> | 10 | #include <glad/glad.h> |
| 12 | |||
| 13 | #include "common/assert.h" | 11 | #include "common/assert.h" |
| 14 | #include "common/logging/log.h" | 12 | #include "common/logging/log.h" |
| 15 | #include "common/microprofile.h" | 13 | #include "common/microprofile.h" |
| @@ -30,8 +28,6 @@ namespace OpenGL { | |||
| 30 | 28 | ||
| 31 | namespace { | 29 | namespace { |
| 32 | 30 | ||
| 33 | // If the size of this is too small, it ends up creating a soft cap on FPS as the renderer will have | ||
| 34 | // to wait on available presentation frames. | ||
| 35 | constexpr std::size_t SWAP_CHAIN_SIZE = 3; | 31 | constexpr std::size_t SWAP_CHAIN_SIZE = 3; |
| 36 | 32 | ||
| 37 | struct Frame { | 33 | struct Frame { |
| @@ -214,7 +210,7 @@ public: | |||
| 214 | std::deque<Frame*> present_queue; | 210 | std::deque<Frame*> present_queue; |
| 215 | Frame* previous_frame{}; | 211 | Frame* previous_frame{}; |
| 216 | 212 | ||
| 217 | FrameMailbox() : has_debug_tool{HasDebugTool()} { | 213 | FrameMailbox() { |
| 218 | for (auto& frame : swap_chain) { | 214 | for (auto& frame : swap_chain) { |
| 219 | free_queue.push(&frame); | 215 | free_queue.push(&frame); |
| 220 | } | 216 | } |
| @@ -285,13 +281,9 @@ public: | |||
| 285 | std::unique_lock lock{swap_chain_lock}; | 281 | std::unique_lock lock{swap_chain_lock}; |
| 286 | present_queue.push_front(frame); | 282 | present_queue.push_front(frame); |
| 287 | present_cv.notify_one(); | 283 | present_cv.notify_one(); |
| 288 | |||
| 289 | DebugNotifyNextFrame(); | ||
| 290 | } | 284 | } |
| 291 | 285 | ||
| 292 | Frame* TryGetPresentFrame(int timeout_ms) { | 286 | Frame* TryGetPresentFrame(int timeout_ms) { |
| 293 | DebugWaitForNextFrame(); | ||
| 294 | |||
| 295 | std::unique_lock lock{swap_chain_lock}; | 287 | std::unique_lock lock{swap_chain_lock}; |
| 296 | // wait for new entries in the present_queue | 288 | // wait for new entries in the present_queue |
| 297 | present_cv.wait_for(lock, std::chrono::milliseconds(timeout_ms), | 289 | present_cv.wait_for(lock, std::chrono::milliseconds(timeout_ms), |
| @@ -317,38 +309,12 @@ public: | |||
| 317 | previous_frame = frame; | 309 | previous_frame = frame; |
| 318 | return frame; | 310 | return frame; |
| 319 | } | 311 | } |
| 320 | |||
| 321 | private: | ||
| 322 | std::mutex debug_synch_mutex; | ||
| 323 | std::condition_variable debug_synch_condition; | ||
| 324 | std::atomic_int frame_for_debug{}; | ||
| 325 | const bool has_debug_tool; // When true, using a GPU debugger, so keep frames in lock-step | ||
| 326 | |||
| 327 | /// Signal that a new frame is available (called from GPU thread) | ||
| 328 | void DebugNotifyNextFrame() { | ||
| 329 | if (!has_debug_tool) { | ||
| 330 | return; | ||
| 331 | } | ||
| 332 | frame_for_debug++; | ||
| 333 | std::lock_guard lock{debug_synch_mutex}; | ||
| 334 | debug_synch_condition.notify_one(); | ||
| 335 | } | ||
| 336 | |||
| 337 | /// Wait for a new frame to be available (called from presentation thread) | ||
| 338 | void DebugWaitForNextFrame() { | ||
| 339 | if (!has_debug_tool) { | ||
| 340 | return; | ||
| 341 | } | ||
| 342 | const int last_frame = frame_for_debug; | ||
| 343 | std::unique_lock lock{debug_synch_mutex}; | ||
| 344 | debug_synch_condition.wait(lock, | ||
| 345 | [this, last_frame] { return frame_for_debug > last_frame; }); | ||
| 346 | } | ||
| 347 | }; | 312 | }; |
| 348 | 313 | ||
| 349 | RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system) | 314 | RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system, |
| 350 | : VideoCore::RendererBase{emu_window}, emu_window{emu_window}, system{system}, | 315 | Core::Frontend::GraphicsContext& context) |
| 351 | frame_mailbox{std::make_unique<FrameMailbox>()} {} | 316 | : VideoCore::RendererBase{emu_window}, emu_window{emu_window}, system{system}, frame_mailbox{}, |
| 317 | has_debug_tool{HasDebugTool()}, context{context} {} | ||
| 352 | 318 | ||
| 353 | RendererOpenGL::~RendererOpenGL() = default; | 319 | RendererOpenGL::~RendererOpenGL() = default; |
| 354 | 320 | ||
| @@ -356,8 +322,6 @@ MICROPROFILE_DEFINE(OpenGL_RenderFrame, "OpenGL", "Render Frame", MP_RGB(128, 12 | |||
| 356 | MICROPROFILE_DEFINE(OpenGL_WaitPresent, "OpenGL", "Wait For Present", MP_RGB(128, 128, 128)); | 322 | MICROPROFILE_DEFINE(OpenGL_WaitPresent, "OpenGL", "Wait For Present", MP_RGB(128, 128, 128)); |
| 357 | 323 | ||
| 358 | void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | 324 | void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { |
| 359 | render_window.PollEvents(); | ||
| 360 | |||
| 361 | if (!framebuffer) { | 325 | if (!framebuffer) { |
| 362 | return; | 326 | return; |
| 363 | } | 327 | } |
| @@ -413,6 +377,13 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 413 | m_current_frame++; | 377 | m_current_frame++; |
| 414 | rasterizer->TickFrame(); | 378 | rasterizer->TickFrame(); |
| 415 | } | 379 | } |
| 380 | |||
| 381 | render_window.PollEvents(); | ||
| 382 | if (has_debug_tool) { | ||
| 383 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); | ||
| 384 | Present(0); | ||
| 385 | context.SwapBuffers(); | ||
| 386 | } | ||
| 416 | } | 387 | } |
| 417 | 388 | ||
| 418 | void RendererOpenGL::PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer) { | 389 | void RendererOpenGL::PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer) { |
| @@ -480,6 +451,8 @@ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color | |||
| 480 | } | 451 | } |
| 481 | 452 | ||
| 482 | void RendererOpenGL::InitOpenGLObjects() { | 453 | void RendererOpenGL::InitOpenGLObjects() { |
| 454 | frame_mailbox = std::make_unique<FrameMailbox>(); | ||
| 455 | |||
| 483 | glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, | 456 | glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, |
| 484 | 0.0f); | 457 | 0.0f); |
| 485 | 458 | ||
| @@ -692,12 +665,21 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | |||
| 692 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | 665 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| 693 | } | 666 | } |
| 694 | 667 | ||
| 695 | void RendererOpenGL::TryPresent(int timeout_ms) { | 668 | bool RendererOpenGL::TryPresent(int timeout_ms) { |
| 669 | if (has_debug_tool) { | ||
| 670 | LOG_DEBUG(Render_OpenGL, | ||
| 671 | "Skipping presentation because we are presenting on the main context"); | ||
| 672 | return false; | ||
| 673 | } | ||
| 674 | return Present(timeout_ms); | ||
| 675 | } | ||
| 676 | |||
| 677 | bool RendererOpenGL::Present(int timeout_ms) { | ||
| 696 | const auto& layout = render_window.GetFramebufferLayout(); | 678 | const auto& layout = render_window.GetFramebufferLayout(); |
| 697 | auto frame = frame_mailbox->TryGetPresentFrame(timeout_ms); | 679 | auto frame = frame_mailbox->TryGetPresentFrame(timeout_ms); |
| 698 | if (!frame) { | 680 | if (!frame) { |
| 699 | LOG_DEBUG(Render_OpenGL, "TryGetPresentFrame returned no frame to present"); | 681 | LOG_DEBUG(Render_OpenGL, "TryGetPresentFrame returned no frame to present"); |
| 700 | return; | 682 | return false; |
| 701 | } | 683 | } |
| 702 | 684 | ||
| 703 | // Clearing before a full overwrite of a fbo can signal to drivers that they can avoid a | 685 | // Clearing before a full overwrite of a fbo can signal to drivers that they can avoid a |
| @@ -725,6 +707,7 @@ void RendererOpenGL::TryPresent(int timeout_ms) { | |||
| 725 | glFlush(); | 707 | glFlush(); |
| 726 | 708 | ||
| 727 | glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); | 709 | glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); |
| 710 | return true; | ||
| 728 | } | 711 | } |
| 729 | 712 | ||
| 730 | void RendererOpenGL::RenderScreenshot() { | 713 | void RendererOpenGL::RenderScreenshot() { |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 33073ce5b..50b647661 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h | |||
| @@ -55,13 +55,14 @@ class FrameMailbox; | |||
| 55 | 55 | ||
| 56 | class RendererOpenGL final : public VideoCore::RendererBase { | 56 | class RendererOpenGL final : public VideoCore::RendererBase { |
| 57 | public: | 57 | public: |
| 58 | explicit RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system); | 58 | explicit RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system, |
| 59 | Core::Frontend::GraphicsContext& context); | ||
| 59 | ~RendererOpenGL() override; | 60 | ~RendererOpenGL() override; |
| 60 | 61 | ||
| 61 | bool Init() override; | 62 | bool Init() override; |
| 62 | void ShutDown() override; | 63 | void ShutDown() override; |
| 63 | void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; | 64 | void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; |
| 64 | void TryPresent(int timeout_ms) override; | 65 | bool TryPresent(int timeout_ms) override; |
| 65 | 66 | ||
| 66 | private: | 67 | private: |
| 67 | /// Initializes the OpenGL state and creates persistent objects. | 68 | /// Initializes the OpenGL state and creates persistent objects. |
| @@ -89,8 +90,11 @@ private: | |||
| 89 | 90 | ||
| 90 | void PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer); | 91 | void PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer); |
| 91 | 92 | ||
| 93 | bool Present(int timeout_ms); | ||
| 94 | |||
| 92 | Core::Frontend::EmuWindow& emu_window; | 95 | Core::Frontend::EmuWindow& emu_window; |
| 93 | Core::System& system; | 96 | Core::System& system; |
| 97 | Core::Frontend::GraphicsContext& context; | ||
| 94 | 98 | ||
| 95 | StateTracker state_tracker{system}; | 99 | StateTracker state_tracker{system}; |
| 96 | 100 | ||
| @@ -115,6 +119,8 @@ private: | |||
| 115 | 119 | ||
| 116 | /// Frame presentation mailbox | 120 | /// Frame presentation mailbox |
| 117 | std::unique_ptr<FrameMailbox> frame_mailbox; | 121 | std::unique_ptr<FrameMailbox> frame_mailbox; |
| 122 | |||
| 123 | bool has_debug_tool = false; | ||
| 118 | }; | 124 | }; |
| 119 | 125 | ||
| 120 | } // namespace OpenGL | 126 | } // namespace OpenGL |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 42bb01418..6953aaafe 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -141,8 +141,9 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 141 | render_window.PollEvents(); | 141 | render_window.PollEvents(); |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | void RendererVulkan::TryPresent(int /*timeout_ms*/) { | 144 | bool RendererVulkan::TryPresent(int /*timeout_ms*/) { |
| 145 | // TODO (bunnei): ImplementMe | 145 | // TODO (bunnei): ImplementMe |
| 146 | return true; | ||
| 146 | } | 147 | } |
| 147 | 148 | ||
| 148 | bool RendererVulkan::Init() { | 149 | bool RendererVulkan::Init() { |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 3da08d2e4..d14384e79 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h | |||
| @@ -42,7 +42,7 @@ public: | |||
| 42 | bool Init() override; | 42 | bool Init() override; |
| 43 | void ShutDown() override; | 43 | void ShutDown() override; |
| 44 | void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; | 44 | void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; |
| 45 | void TryPresent(int timeout_ms) override; | 45 | bool TryPresent(int timeout_ms) override; |
| 46 | 46 | ||
| 47 | private: | 47 | private: |
| 48 | std::optional<vk::DebugUtilsMessengerEXT> CreateDebugCallback( | 48 | std::optional<vk::DebugUtilsMessengerEXT> CreateDebugCallback( |
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index a5f81a8a0..fd9fec018 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp | |||
| @@ -15,13 +15,13 @@ | |||
| 15 | #endif | 15 | #endif |
| 16 | #include "video_core/video_core.h" | 16 | #include "video_core/video_core.h" |
| 17 | 17 | ||
| 18 | namespace VideoCore { | 18 | namespace { |
| 19 | 19 | std::unique_ptr<VideoCore::RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window, | |
| 20 | std::unique_ptr<RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window, | 20 | Core::System& system, |
| 21 | Core::System& system) { | 21 | Core::Frontend::GraphicsContext& context) { |
| 22 | switch (Settings::values.renderer_backend) { | 22 | switch (Settings::values.renderer_backend) { |
| 23 | case Settings::RendererBackend::OpenGL: | 23 | case Settings::RendererBackend::OpenGL: |
| 24 | return std::make_unique<OpenGL::RendererOpenGL>(emu_window, system); | 24 | return std::make_unique<OpenGL::RendererOpenGL>(emu_window, system, context); |
| 25 | #ifdef HAS_VULKAN | 25 | #ifdef HAS_VULKAN |
| 26 | case Settings::RendererBackend::Vulkan: | 26 | case Settings::RendererBackend::Vulkan: |
| 27 | return std::make_unique<Vulkan::RendererVulkan>(emu_window, system); | 27 | return std::make_unique<Vulkan::RendererVulkan>(emu_window, system); |
| @@ -30,13 +30,23 @@ std::unique_ptr<RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_wind | |||
| 30 | return nullptr; | 30 | return nullptr; |
| 31 | } | 31 | } |
| 32 | } | 32 | } |
| 33 | } // namespace | ||
| 33 | 34 | ||
| 34 | std::unique_ptr<Tegra::GPU> CreateGPU(Core::System& system) { | 35 | namespace VideoCore { |
| 35 | if (Settings::values.use_asynchronous_gpu_emulation) { | 36 | |
| 36 | return std::make_unique<VideoCommon::GPUAsynch>(system, system.Renderer()); | 37 | std::unique_ptr<Tegra::GPU> CreateGPU(Core::Frontend::EmuWindow& emu_window, Core::System& system) { |
| 38 | auto context = emu_window.CreateSharedContext(); | ||
| 39 | const auto scope = context->Acquire(); | ||
| 40 | auto renderer = CreateRenderer(emu_window, system, *context); | ||
| 41 | if (!renderer->Init()) { | ||
| 42 | return {}; | ||
| 37 | } | 43 | } |
| 38 | 44 | ||
| 39 | return std::make_unique<VideoCommon::GPUSynch>(system, system.Renderer()); | 45 | if (Settings::values.use_asynchronous_gpu_emulation) { |
| 46 | return std::make_unique<VideoCommon::GPUAsynch>(system, std::move(renderer), | ||
| 47 | std::move(context)); | ||
| 48 | } | ||
| 49 | return std::make_unique<VideoCommon::GPUSynch>(system, std::move(renderer), std::move(context)); | ||
| 40 | } | 50 | } |
| 41 | 51 | ||
| 42 | u16 GetResolutionScaleFactor(const RendererBase& renderer) { | 52 | u16 GetResolutionScaleFactor(const RendererBase& renderer) { |
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h index b8e0ac372..f5c27125d 100644 --- a/src/video_core/video_core.h +++ b/src/video_core/video_core.h | |||
| @@ -22,17 +22,8 @@ namespace VideoCore { | |||
| 22 | 22 | ||
| 23 | class RendererBase; | 23 | class RendererBase; |
| 24 | 24 | ||
| 25 | /** | ||
| 26 | * Creates a renderer instance. | ||
| 27 | * | ||
| 28 | * @note The returned renderer instance is simply allocated. Its Init() | ||
| 29 | * function still needs to be called to fully complete its setup. | ||
| 30 | */ | ||
| 31 | std::unique_ptr<RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window, | ||
| 32 | Core::System& system); | ||
| 33 | |||
| 34 | /// Creates an emulated GPU instance using the given system context. | 25 | /// Creates an emulated GPU instance using the given system context. |
| 35 | std::unique_ptr<Tegra::GPU> CreateGPU(Core::System& system); | 26 | std::unique_ptr<Tegra::GPU> CreateGPU(Core::Frontend::EmuWindow& emu_window, Core::System& system); |
| 36 | 27 | ||
| 37 | u16 GetResolutionScaleFactor(const RendererBase& renderer); | 28 | u16 GetResolutionScaleFactor(const RendererBase& renderer); |
| 38 | 29 | ||
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index c3dbb1a88..d120ee818 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -10,9 +10,6 @@ | |||
| 10 | #include <QMessageBox> | 10 | #include <QMessageBox> |
| 11 | #include <QOffscreenSurface> | 11 | #include <QOffscreenSurface> |
| 12 | #include <QOpenGLContext> | 12 | #include <QOpenGLContext> |
| 13 | #include <QOpenGLFunctions> | ||
| 14 | #include <QOpenGLFunctions_4_3_Core> | ||
| 15 | #include <QOpenGLWindow> | ||
| 16 | #include <QPainter> | 13 | #include <QPainter> |
| 17 | #include <QScreen> | 14 | #include <QScreen> |
| 18 | #include <QStringList> | 15 | #include <QStringList> |
| @@ -29,7 +26,6 @@ | |||
| 29 | #include "common/scope_exit.h" | 26 | #include "common/scope_exit.h" |
| 30 | #include "core/core.h" | 27 | #include "core/core.h" |
| 31 | #include "core/frontend/framebuffer_layout.h" | 28 | #include "core/frontend/framebuffer_layout.h" |
| 32 | #include "core/frontend/scope_acquire_context.h" | ||
| 33 | #include "core/settings.h" | 29 | #include "core/settings.h" |
| 34 | #include "input_common/keyboard.h" | 30 | #include "input_common/keyboard.h" |
| 35 | #include "input_common/main.h" | 31 | #include "input_common/main.h" |
| @@ -39,27 +35,13 @@ | |||
| 39 | #include "yuzu/bootmanager.h" | 35 | #include "yuzu/bootmanager.h" |
| 40 | #include "yuzu/main.h" | 36 | #include "yuzu/main.h" |
| 41 | 37 | ||
| 42 | EmuThread::EmuThread(GRenderWindow& window) | 38 | EmuThread::EmuThread() = default; |
| 43 | : shared_context{window.CreateSharedContext()}, | ||
| 44 | context{(Settings::values.use_asynchronous_gpu_emulation && shared_context) ? *shared_context | ||
| 45 | : window} {} | ||
| 46 | 39 | ||
| 47 | EmuThread::~EmuThread() = default; | 40 | EmuThread::~EmuThread() = default; |
| 48 | 41 | ||
| 49 | static GMainWindow* GetMainWindow() { | ||
| 50 | for (QWidget* w : qApp->topLevelWidgets()) { | ||
| 51 | if (GMainWindow* main = qobject_cast<GMainWindow*>(w)) { | ||
| 52 | return main; | ||
| 53 | } | ||
| 54 | } | ||
| 55 | return nullptr; | ||
| 56 | } | ||
| 57 | |||
| 58 | void EmuThread::run() { | 42 | void EmuThread::run() { |
| 59 | MicroProfileOnThreadCreate("EmuThread"); | 43 | MicroProfileOnThreadCreate("EmuThread"); |
| 60 | 44 | ||
| 61 | Core::Frontend::ScopeAcquireContext acquire_context{context}; | ||
| 62 | |||
| 63 | emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); | 45 | emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); |
| 64 | 46 | ||
| 65 | Core::System::GetInstance().Renderer().Rasterizer().LoadDiskResources( | 47 | Core::System::GetInstance().Renderer().Rasterizer().LoadDiskResources( |
| @@ -69,6 +51,10 @@ void EmuThread::run() { | |||
| 69 | 51 | ||
| 70 | emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0); | 52 | emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0); |
| 71 | 53 | ||
| 54 | // Main process has been loaded. Make the context current to this thread and begin GPU and CPU | ||
| 55 | // execution. | ||
| 56 | Core::System::GetInstance().GPU().Start(); | ||
| 57 | |||
| 72 | // Holds whether the cpu was running during the last iteration, | 58 | // Holds whether the cpu was running during the last iteration, |
| 73 | // so that the DebugModeLeft signal can be emitted before the | 59 | // so that the DebugModeLeft signal can be emitted before the |
| 74 | // next execution step | 60 | // next execution step |
| @@ -111,162 +97,195 @@ void EmuThread::run() { | |||
| 111 | #endif | 97 | #endif |
| 112 | } | 98 | } |
| 113 | 99 | ||
| 114 | class GGLContext : public Core::Frontend::GraphicsContext { | 100 | class OpenGLSharedContext : public Core::Frontend::GraphicsContext { |
| 115 | public: | 101 | public: |
| 116 | explicit GGLContext(QOpenGLContext* shared_context) | 102 | /// Create the original context that should be shared from |
| 117 | : context(new QOpenGLContext(shared_context->parent())), | 103 | explicit OpenGLSharedContext(QSurface* surface) : surface(surface) { |
| 118 | surface(new QOffscreenSurface(nullptr)) { | 104 | QSurfaceFormat format; |
| 105 | format.setVersion(4, 3); | ||
| 106 | format.setProfile(QSurfaceFormat::CompatibilityProfile); | ||
| 107 | format.setOption(QSurfaceFormat::FormatOption::DeprecatedFunctions); | ||
| 108 | // TODO: expose a setting for buffer value (ie default/single/double/triple) | ||
| 109 | format.setSwapBehavior(QSurfaceFormat::DefaultSwapBehavior); | ||
| 110 | format.setSwapInterval(0); | ||
| 111 | |||
| 112 | context = std::make_unique<QOpenGLContext>(); | ||
| 113 | context->setFormat(format); | ||
| 114 | if (!context->create()) { | ||
| 115 | LOG_ERROR(Frontend, "Unable to create main openGL context"); | ||
| 116 | } | ||
| 117 | } | ||
| 118 | |||
| 119 | /// Create the shared contexts for rendering and presentation | ||
| 120 | explicit OpenGLSharedContext(QOpenGLContext* share_context, QSurface* main_surface = nullptr) { | ||
| 119 | 121 | ||
| 120 | // disable vsync for any shared contexts | 122 | // disable vsync for any shared contexts |
| 121 | auto format = shared_context->format(); | 123 | auto format = share_context->format(); |
| 122 | format.setSwapInterval(0); | 124 | format.setSwapInterval(main_surface ? Settings::values.use_vsync : 0); |
| 123 | 125 | ||
| 124 | context->setShareContext(shared_context); | 126 | context = std::make_unique<QOpenGLContext>(); |
| 127 | context->setShareContext(share_context); | ||
| 125 | context->setFormat(format); | 128 | context->setFormat(format); |
| 126 | context->create(); | 129 | if (!context->create()) { |
| 127 | surface->setParent(shared_context->parent()); | 130 | LOG_ERROR(Frontend, "Unable to create shared openGL context"); |
| 128 | surface->setFormat(format); | 131 | } |
| 129 | surface->create(); | 132 | |
| 133 | if (!main_surface) { | ||
| 134 | offscreen_surface = std::make_unique<QOffscreenSurface>(nullptr); | ||
| 135 | offscreen_surface->setFormat(format); | ||
| 136 | offscreen_surface->create(); | ||
| 137 | surface = offscreen_surface.get(); | ||
| 138 | } else { | ||
| 139 | surface = main_surface; | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | ~OpenGLSharedContext() { | ||
| 144 | context->doneCurrent(); | ||
| 145 | } | ||
| 146 | |||
| 147 | void SwapBuffers() override { | ||
| 148 | context->swapBuffers(surface); | ||
| 130 | } | 149 | } |
| 131 | 150 | ||
| 132 | void MakeCurrent() override { | 151 | void MakeCurrent() override { |
| 152 | if (is_current) { | ||
| 153 | return; | ||
| 154 | } | ||
| 133 | context->makeCurrent(surface); | 155 | context->makeCurrent(surface); |
| 134 | } | 156 | } |
| 135 | 157 | ||
| 136 | void DoneCurrent() override { | 158 | void DoneCurrent() override { |
| 137 | context->doneCurrent(); | 159 | context->doneCurrent(); |
| 160 | is_current = false; | ||
| 161 | } | ||
| 162 | |||
| 163 | QOpenGLContext* GetShareContext() const { | ||
| 164 | return context.get(); | ||
| 138 | } | 165 | } |
| 139 | 166 | ||
| 140 | private: | 167 | private: |
| 141 | QOpenGLContext* context; | 168 | // Avoid using Qt parent system here since we might move the QObjects to new threads |
| 142 | QOffscreenSurface* surface; | 169 | // As a note, this means we should avoid using slots/signals with the objects too |
| 170 | std::unique_ptr<QOpenGLContext> context; | ||
| 171 | std::unique_ptr<QOffscreenSurface> offscreen_surface{}; | ||
| 172 | QSurface* surface; | ||
| 173 | bool is_current = false; | ||
| 143 | }; | 174 | }; |
| 144 | 175 | ||
| 145 | class ChildRenderWindow : public QWindow { | 176 | class DummyContext : public Core::Frontend::GraphicsContext {}; |
| 177 | |||
| 178 | class RenderWidget : public QWidget { | ||
| 146 | public: | 179 | public: |
| 147 | ChildRenderWindow(QWindow* parent, QWidget* event_handler) | 180 | RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) { |
| 148 | : QWindow{parent}, event_handler{event_handler} {} | 181 | setAttribute(Qt::WA_NativeWindow); |
| 149 | 182 | setAttribute(Qt::WA_PaintOnScreen); | |
| 150 | virtual ~ChildRenderWindow() = default; | ||
| 151 | |||
| 152 | virtual void Present() = 0; | ||
| 153 | |||
| 154 | protected: | ||
| 155 | bool event(QEvent* event) override { | ||
| 156 | switch (event->type()) { | ||
| 157 | case QEvent::UpdateRequest: | ||
| 158 | Present(); | ||
| 159 | return true; | ||
| 160 | case QEvent::MouseButtonPress: | ||
| 161 | case QEvent::MouseButtonRelease: | ||
| 162 | case QEvent::MouseButtonDblClick: | ||
| 163 | case QEvent::MouseMove: | ||
| 164 | case QEvent::KeyPress: | ||
| 165 | case QEvent::KeyRelease: | ||
| 166 | case QEvent::FocusIn: | ||
| 167 | case QEvent::FocusOut: | ||
| 168 | case QEvent::FocusAboutToChange: | ||
| 169 | case QEvent::Enter: | ||
| 170 | case QEvent::Leave: | ||
| 171 | case QEvent::Wheel: | ||
| 172 | case QEvent::TabletMove: | ||
| 173 | case QEvent::TabletPress: | ||
| 174 | case QEvent::TabletRelease: | ||
| 175 | case QEvent::TabletEnterProximity: | ||
| 176 | case QEvent::TabletLeaveProximity: | ||
| 177 | case QEvent::TouchBegin: | ||
| 178 | case QEvent::TouchUpdate: | ||
| 179 | case QEvent::TouchEnd: | ||
| 180 | case QEvent::InputMethodQuery: | ||
| 181 | case QEvent::TouchCancel: | ||
| 182 | return QCoreApplication::sendEvent(event_handler, event); | ||
| 183 | case QEvent::Drop: | ||
| 184 | GetMainWindow()->DropAction(static_cast<QDropEvent*>(event)); | ||
| 185 | return true; | ||
| 186 | case QEvent::DragResponse: | ||
| 187 | case QEvent::DragEnter: | ||
| 188 | case QEvent::DragLeave: | ||
| 189 | case QEvent::DragMove: | ||
| 190 | GetMainWindow()->AcceptDropEvent(static_cast<QDropEvent*>(event)); | ||
| 191 | return true; | ||
| 192 | default: | ||
| 193 | return QWindow::event(event); | ||
| 194 | } | ||
| 195 | } | 183 | } |
| 196 | 184 | ||
| 197 | void exposeEvent(QExposeEvent* event) override { | 185 | virtual ~RenderWidget() = default; |
| 198 | QWindow::requestUpdate(); | 186 | |
| 199 | QWindow::exposeEvent(event); | 187 | virtual void Present() {} |
| 188 | |||
| 189 | void paintEvent(QPaintEvent* event) override { | ||
| 190 | Present(); | ||
| 191 | update(); | ||
| 200 | } | 192 | } |
| 201 | 193 | ||
| 202 | private: | 194 | void resizeEvent(QResizeEvent* ev) override { |
| 203 | QWidget* event_handler{}; | 195 | render_window->resize(ev->size()); |
| 204 | }; | 196 | render_window->OnFramebufferSizeChanged(); |
| 197 | } | ||
| 205 | 198 | ||
| 206 | class OpenGLWindow final : public ChildRenderWindow { | 199 | void keyPressEvent(QKeyEvent* event) override { |
| 207 | public: | 200 | InputCommon::GetKeyboard()->PressKey(event->key()); |
| 208 | OpenGLWindow(QWindow* parent, QWidget* event_handler, QOpenGLContext* shared_context) | 201 | } |
| 209 | : ChildRenderWindow{parent, event_handler}, | ||
| 210 | context(new QOpenGLContext(shared_context->parent())) { | ||
| 211 | 202 | ||
| 212 | // disable vsync for any shared contexts | 203 | void keyReleaseEvent(QKeyEvent* event) override { |
| 213 | auto format = shared_context->format(); | 204 | InputCommon::GetKeyboard()->ReleaseKey(event->key()); |
| 214 | format.setSwapInterval(Settings::values.use_vsync ? 1 : 0); | 205 | } |
| 215 | this->setFormat(format); | ||
| 216 | 206 | ||
| 217 | context->setShareContext(shared_context); | 207 | void mousePressEvent(QMouseEvent* event) override { |
| 218 | context->setScreen(this->screen()); | 208 | if (event->source() == Qt::MouseEventSynthesizedBySystem) |
| 219 | context->setFormat(format); | 209 | return; // touch input is handled in TouchBeginEvent |
| 220 | context->create(); | ||
| 221 | 210 | ||
| 222 | setSurfaceType(QWindow::OpenGLSurface); | 211 | const auto pos{event->pos()}; |
| 212 | if (event->button() == Qt::LeftButton) { | ||
| 213 | const auto [x, y] = render_window->ScaleTouch(pos); | ||
| 214 | render_window->TouchPressed(x, y); | ||
| 215 | } else if (event->button() == Qt::RightButton) { | ||
| 216 | InputCommon::GetMotionEmu()->BeginTilt(pos.x(), pos.y()); | ||
| 217 | } | ||
| 218 | } | ||
| 219 | |||
| 220 | void mouseMoveEvent(QMouseEvent* event) override { | ||
| 221 | if (event->source() == Qt::MouseEventSynthesizedBySystem) | ||
| 222 | return; // touch input is handled in TouchUpdateEvent | ||
| 223 | 223 | ||
| 224 | // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, | 224 | const auto pos{event->pos()}; |
| 225 | // WA_DontShowOnScreen, WA_DeleteOnClose | 225 | const auto [x, y] = render_window->ScaleTouch(pos); |
| 226 | render_window->TouchMoved(x, y); | ||
| 227 | InputCommon::GetMotionEmu()->Tilt(pos.x(), pos.y()); | ||
| 226 | } | 228 | } |
| 227 | 229 | ||
| 228 | ~OpenGLWindow() override { | 230 | void mouseReleaseEvent(QMouseEvent* event) override { |
| 229 | context->doneCurrent(); | 231 | if (event->source() == Qt::MouseEventSynthesizedBySystem) |
| 232 | return; // touch input is handled in TouchEndEvent | ||
| 233 | |||
| 234 | if (event->button() == Qt::LeftButton) | ||
| 235 | render_window->TouchReleased(); | ||
| 236 | else if (event->button() == Qt::RightButton) | ||
| 237 | InputCommon::GetMotionEmu()->EndTilt(); | ||
| 230 | } | 238 | } |
| 231 | 239 | ||
| 232 | void Present() override { | 240 | std::pair<unsigned, unsigned> GetSize() const { |
| 233 | if (!isExposed()) { | 241 | return std::make_pair(width(), height()); |
| 234 | return; | 242 | } |
| 235 | } | ||
| 236 | 243 | ||
| 237 | context->makeCurrent(this); | 244 | QPaintEngine* paintEngine() const override { |
| 238 | Core::System::GetInstance().Renderer().TryPresent(100); | 245 | return nullptr; |
| 239 | context->swapBuffers(this); | ||
| 240 | auto f = context->versionFunctions<QOpenGLFunctions_4_3_Core>(); | ||
| 241 | f->glFinish(); | ||
| 242 | QWindow::requestUpdate(); | ||
| 243 | } | 246 | } |
| 244 | 247 | ||
| 245 | private: | 248 | private: |
| 246 | QOpenGLContext* context{}; | 249 | GRenderWindow* render_window; |
| 247 | }; | 250 | }; |
| 248 | 251 | ||
| 249 | #ifdef HAS_VULKAN | 252 | class OpenGLRenderWidget : public RenderWidget { |
| 250 | class VulkanWindow final : public ChildRenderWindow { | ||
| 251 | public: | 253 | public: |
| 252 | VulkanWindow(QWindow* parent, QWidget* event_handler, QVulkanInstance* instance) | 254 | explicit OpenGLRenderWidget(GRenderWindow* parent) : RenderWidget(parent) { |
| 253 | : ChildRenderWindow{parent, event_handler} { | 255 | windowHandle()->setSurfaceType(QWindow::OpenGLSurface); |
| 254 | setSurfaceType(QSurface::SurfaceType::VulkanSurface); | ||
| 255 | setVulkanInstance(instance); | ||
| 256 | } | 256 | } |
| 257 | 257 | ||
| 258 | ~VulkanWindow() override = default; | 258 | void SetContext(std::unique_ptr<Core::Frontend::GraphicsContext>&& context_) { |
| 259 | context = std::move(context_); | ||
| 260 | } | ||
| 259 | 261 | ||
| 260 | void Present() override { | 262 | void Present() override { |
| 261 | // TODO(bunnei): ImplementMe | 263 | if (!isVisible()) { |
| 264 | return; | ||
| 265 | } | ||
| 266 | |||
| 267 | context->MakeCurrent(); | ||
| 268 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); | ||
| 269 | if (Core::System::GetInstance().Renderer().TryPresent(100)) { | ||
| 270 | context->SwapBuffers(); | ||
| 271 | glFinish(); | ||
| 272 | } | ||
| 262 | } | 273 | } |
| 263 | 274 | ||
| 264 | private: | 275 | private: |
| 265 | QWidget* event_handler{}; | 276 | std::unique_ptr<Core::Frontend::GraphicsContext> context{}; |
| 266 | }; | 277 | }; |
| 267 | #endif | ||
| 268 | 278 | ||
| 269 | GRenderWindow::GRenderWindow(QWidget* parent_, EmuThread* emu_thread) | 279 | class VulkanRenderWidget : public RenderWidget { |
| 280 | public: | ||
| 281 | explicit VulkanRenderWidget(GRenderWindow* parent, QVulkanInstance* instance) | ||
| 282 | : RenderWidget(parent) { | ||
| 283 | windowHandle()->setSurfaceType(QWindow::VulkanSurface); | ||
| 284 | windowHandle()->setVulkanInstance(instance); | ||
| 285 | } | ||
| 286 | }; | ||
| 287 | |||
| 288 | GRenderWindow::GRenderWindow(GMainWindow* parent_, EmuThread* emu_thread) | ||
| 270 | : QWidget(parent_), emu_thread(emu_thread) { | 289 | : QWidget(parent_), emu_thread(emu_thread) { |
| 271 | setWindowTitle(QStringLiteral("yuzu %1 | %2-%3") | 290 | setWindowTitle(QStringLiteral("yuzu %1 | %2-%3") |
| 272 | .arg(QString::fromUtf8(Common::g_build_name), | 291 | .arg(QString::fromUtf8(Common::g_build_name), |
| @@ -278,26 +297,13 @@ GRenderWindow::GRenderWindow(QWidget* parent_, EmuThread* emu_thread) | |||
| 278 | setLayout(layout); | 297 | setLayout(layout); |
| 279 | InputCommon::Init(); | 298 | InputCommon::Init(); |
| 280 | 299 | ||
| 281 | GMainWindow* parent = GetMainWindow(); | 300 | connect(this, &GRenderWindow::FirstFrameDisplayed, parent_, &GMainWindow::OnLoadComplete); |
| 282 | connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete); | ||
| 283 | } | 301 | } |
| 284 | 302 | ||
| 285 | GRenderWindow::~GRenderWindow() { | 303 | GRenderWindow::~GRenderWindow() { |
| 286 | InputCommon::Shutdown(); | 304 | InputCommon::Shutdown(); |
| 287 | } | 305 | } |
| 288 | 306 | ||
| 289 | void GRenderWindow::MakeCurrent() { | ||
| 290 | if (core_context) { | ||
| 291 | core_context->MakeCurrent(); | ||
| 292 | } | ||
| 293 | } | ||
| 294 | |||
| 295 | void GRenderWindow::DoneCurrent() { | ||
| 296 | if (core_context) { | ||
| 297 | core_context->DoneCurrent(); | ||
| 298 | } | ||
| 299 | } | ||
| 300 | |||
| 301 | void GRenderWindow::PollEvents() { | 307 | void GRenderWindow::PollEvents() { |
| 302 | if (!first_frame) { | 308 | if (!first_frame) { |
| 303 | first_frame = true; | 309 | first_frame = true; |
| @@ -309,21 +315,6 @@ bool GRenderWindow::IsShown() const { | |||
| 309 | return !isMinimized(); | 315 | return !isMinimized(); |
| 310 | } | 316 | } |
| 311 | 317 | ||
| 312 | void GRenderWindow::RetrieveVulkanHandlers(void* get_instance_proc_addr, void* instance, | ||
| 313 | void* surface) const { | ||
| 314 | #ifdef HAS_VULKAN | ||
| 315 | const auto instance_proc_addr = vk_instance->getInstanceProcAddr("vkGetInstanceProcAddr"); | ||
| 316 | const VkInstance instance_copy = vk_instance->vkInstance(); | ||
| 317 | const VkSurfaceKHR surface_copy = vk_instance->surfaceForWindow(child_window); | ||
| 318 | |||
| 319 | std::memcpy(get_instance_proc_addr, &instance_proc_addr, sizeof(instance_proc_addr)); | ||
| 320 | std::memcpy(instance, &instance_copy, sizeof(instance_copy)); | ||
| 321 | std::memcpy(surface, &surface_copy, sizeof(surface_copy)); | ||
| 322 | #else | ||
| 323 | UNREACHABLE_MSG("Executing Vulkan code without compiling Vulkan"); | ||
| 324 | #endif | ||
| 325 | } | ||
| 326 | |||
| 327 | // On Qt 5.0+, this correctly gets the size of the framebuffer (pixels). | 318 | // On Qt 5.0+, this correctly gets the size of the framebuffer (pixels). |
| 328 | // | 319 | // |
| 329 | // Older versions get the window size (density independent pixels), | 320 | // Older versions get the window size (density independent pixels), |
| @@ -474,9 +465,13 @@ void GRenderWindow::resizeEvent(QResizeEvent* event) { | |||
| 474 | 465 | ||
| 475 | std::unique_ptr<Core::Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const { | 466 | std::unique_ptr<Core::Frontend::GraphicsContext> GRenderWindow::CreateSharedContext() const { |
| 476 | if (Settings::values.renderer_backend == Settings::RendererBackend::OpenGL) { | 467 | if (Settings::values.renderer_backend == Settings::RendererBackend::OpenGL) { |
| 477 | return std::make_unique<GGLContext>(QOpenGLContext::globalShareContext()); | 468 | auto c = static_cast<OpenGLSharedContext*>(main_context.get()); |
| 469 | // Bind the shared contexts to the main surface in case the backend wants to take over | ||
| 470 | // presentation | ||
| 471 | return std::make_unique<OpenGLSharedContext>(c->GetShareContext(), | ||
| 472 | child_widget->windowHandle()); | ||
| 478 | } | 473 | } |
| 479 | return {}; | 474 | return std::make_unique<DummyContext>(); |
| 480 | } | 475 | } |
| 481 | 476 | ||
| 482 | bool GRenderWindow::InitRenderTarget() { | 477 | bool GRenderWindow::InitRenderTarget() { |
| @@ -497,14 +492,11 @@ bool GRenderWindow::InitRenderTarget() { | |||
| 497 | break; | 492 | break; |
| 498 | } | 493 | } |
| 499 | 494 | ||
| 495 | child_widget->resize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height); | ||
| 496 | layout()->addWidget(child_widget); | ||
| 500 | // Reset minimum required size to avoid resizing issues on the main window after restarting. | 497 | // Reset minimum required size to avoid resizing issues on the main window after restarting. |
| 501 | setMinimumSize(1, 1); | 498 | setMinimumSize(1, 1); |
| 502 | 499 | ||
| 503 | // Show causes the window to actually be created and the gl context as well, but we don't want | ||
| 504 | // the widget to be shown yet, so immediately hide it. | ||
| 505 | show(); | ||
| 506 | hide(); | ||
| 507 | |||
| 508 | resize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height); | 500 | resize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height); |
| 509 | 501 | ||
| 510 | OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size); | 502 | OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size); |
| @@ -523,9 +515,10 @@ bool GRenderWindow::InitRenderTarget() { | |||
| 523 | void GRenderWindow::ReleaseRenderTarget() { | 515 | void GRenderWindow::ReleaseRenderTarget() { |
| 524 | if (child_widget) { | 516 | if (child_widget) { |
| 525 | layout()->removeWidget(child_widget); | 517 | layout()->removeWidget(child_widget); |
| 526 | delete child_widget; | 518 | child_widget->deleteLater(); |
| 527 | child_widget = nullptr; | 519 | child_widget = nullptr; |
| 528 | } | 520 | } |
| 521 | main_context.reset(); | ||
| 529 | } | 522 | } |
| 530 | 523 | ||
| 531 | void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_path) { | 524 | void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_path) { |
| @@ -557,24 +550,13 @@ void GRenderWindow::OnMinimalClientAreaChangeRequest(std::pair<u32, u32> minimal | |||
| 557 | bool GRenderWindow::InitializeOpenGL() { | 550 | bool GRenderWindow::InitializeOpenGL() { |
| 558 | // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, | 551 | // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, |
| 559 | // WA_DontShowOnScreen, WA_DeleteOnClose | 552 | // WA_DontShowOnScreen, WA_DeleteOnClose |
| 560 | QSurfaceFormat fmt; | 553 | auto child = new OpenGLRenderWidget(this); |
| 561 | fmt.setVersion(4, 3); | 554 | child_widget = child; |
| 562 | fmt.setProfile(QSurfaceFormat::CompatibilityProfile); | 555 | child_widget->windowHandle()->create(); |
| 563 | fmt.setOption(QSurfaceFormat::FormatOption::DeprecatedFunctions); | 556 | auto context = std::make_shared<OpenGLSharedContext>(child->windowHandle()); |
| 564 | // TODO: expose a setting for buffer value (ie default/single/double/triple) | 557 | main_context = context; |
| 565 | fmt.setSwapBehavior(QSurfaceFormat::DefaultSwapBehavior); | 558 | child->SetContext( |
| 566 | fmt.setSwapInterval(0); | 559 | std::make_unique<OpenGLSharedContext>(context->GetShareContext(), child->windowHandle())); |
| 567 | QSurfaceFormat::setDefaultFormat(fmt); | ||
| 568 | |||
| 569 | GMainWindow* parent = GetMainWindow(); | ||
| 570 | QWindow* parent_win_handle = parent ? parent->windowHandle() : nullptr; | ||
| 571 | child_window = new OpenGLWindow(parent_win_handle, this, QOpenGLContext::globalShareContext()); | ||
| 572 | child_window->create(); | ||
| 573 | child_widget = createWindowContainer(child_window, this); | ||
| 574 | child_widget->resize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height); | ||
| 575 | layout()->addWidget(child_widget); | ||
| 576 | |||
| 577 | core_context = CreateSharedContext(); | ||
| 578 | 560 | ||
| 579 | return true; | 561 | return true; |
| 580 | } | 562 | } |
| @@ -604,13 +586,10 @@ bool GRenderWindow::InitializeVulkan() { | |||
| 604 | return false; | 586 | return false; |
| 605 | } | 587 | } |
| 606 | 588 | ||
| 607 | GMainWindow* parent = GetMainWindow(); | 589 | auto child = new VulkanRenderWidget(this, vk_instance.get()); |
| 608 | QWindow* parent_win_handle = parent ? parent->windowHandle() : nullptr; | 590 | child_widget = child; |
| 609 | child_window = new VulkanWindow(parent_win_handle, this, vk_instance.get()); | 591 | child_widget->windowHandle()->create(); |
| 610 | child_window->create(); | 592 | main_context = std::make_unique<DummyContext>(); |
| 611 | child_widget = createWindowContainer(child_window, this); | ||
| 612 | child_widget->resize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height); | ||
| 613 | layout()->addWidget(child_widget); | ||
| 614 | 593 | ||
| 615 | return true; | 594 | return true; |
| 616 | #else | 595 | #else |
| @@ -620,8 +599,24 @@ bool GRenderWindow::InitializeVulkan() { | |||
| 620 | #endif | 599 | #endif |
| 621 | } | 600 | } |
| 622 | 601 | ||
| 602 | void GRenderWindow::RetrieveVulkanHandlers(void* get_instance_proc_addr, void* instance, | ||
| 603 | void* surface) const { | ||
| 604 | #ifdef HAS_VULKAN | ||
| 605 | const auto instance_proc_addr = vk_instance->getInstanceProcAddr("vkGetInstanceProcAddr"); | ||
| 606 | const VkInstance instance_copy = vk_instance->vkInstance(); | ||
| 607 | const VkSurfaceKHR surface_copy = vk_instance->surfaceForWindow(child_widget->windowHandle()); | ||
| 608 | |||
| 609 | std::memcpy(get_instance_proc_addr, &instance_proc_addr, sizeof(instance_proc_addr)); | ||
| 610 | std::memcpy(instance, &instance_copy, sizeof(instance_copy)); | ||
| 611 | std::memcpy(surface, &surface_copy, sizeof(surface_copy)); | ||
| 612 | #else | ||
| 613 | UNREACHABLE_MSG("Executing Vulkan code without compiling Vulkan"); | ||
| 614 | #endif | ||
| 615 | } | ||
| 616 | |||
| 623 | bool GRenderWindow::LoadOpenGL() { | 617 | bool GRenderWindow::LoadOpenGL() { |
| 624 | Core::Frontend::ScopeAcquireContext acquire_context{*this}; | 618 | auto context = CreateSharedContext(); |
| 619 | auto scope = context->Acquire(); | ||
| 625 | if (!gladLoadGL()) { | 620 | if (!gladLoadGL()) { |
| 626 | QMessageBox::critical(this, tr("Error while initializing OpenGL 4.3!"), | 621 | QMessageBox::critical(this, tr("Error while initializing OpenGL 4.3!"), |
| 627 | tr("Your GPU may not support OpenGL 4.3, or you do not have the " | 622 | tr("Your GPU may not support OpenGL 4.3, or you do not have the " |
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 79b030304..3739ec7ed 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h | |||
| @@ -7,23 +7,20 @@ | |||
| 7 | #include <atomic> | 7 | #include <atomic> |
| 8 | #include <condition_variable> | 8 | #include <condition_variable> |
| 9 | #include <mutex> | 9 | #include <mutex> |
| 10 | 10 | #include <thread> | |
| 11 | #include <QImage> | 11 | #include <QImage> |
| 12 | #include <QThread> | 12 | #include <QThread> |
| 13 | #include <QWidget> | 13 | #include <QWidget> |
| 14 | #include <QWindow> | 14 | #include <QWindow> |
| 15 | |||
| 16 | #include "common/thread.h" | 15 | #include "common/thread.h" |
| 17 | #include "core/core.h" | 16 | #include "core/core.h" |
| 18 | #include "core/frontend/emu_window.h" | 17 | #include "core/frontend/emu_window.h" |
| 19 | 18 | ||
| 20 | class GRenderWindow; | 19 | class GRenderWindow; |
| 20 | class GMainWindow; | ||
| 21 | class QKeyEvent; | 21 | class QKeyEvent; |
| 22 | class QScreen; | ||
| 23 | class QTouchEvent; | 22 | class QTouchEvent; |
| 24 | class QStringList; | 23 | class QStringList; |
| 25 | class QSurface; | ||
| 26 | class QOpenGLContext; | ||
| 27 | #ifdef HAS_VULKAN | 24 | #ifdef HAS_VULKAN |
| 28 | class QVulkanInstance; | 25 | class QVulkanInstance; |
| 29 | #endif | 26 | #endif |
| @@ -36,7 +33,7 @@ class EmuThread final : public QThread { | |||
| 36 | Q_OBJECT | 33 | Q_OBJECT |
| 37 | 34 | ||
| 38 | public: | 35 | public: |
| 39 | explicit EmuThread(GRenderWindow& window); | 36 | explicit EmuThread(); |
| 40 | ~EmuThread() override; | 37 | ~EmuThread() override; |
| 41 | 38 | ||
| 42 | /** | 39 | /** |
| @@ -87,14 +84,8 @@ private: | |||
| 87 | bool exec_step = false; | 84 | bool exec_step = false; |
| 88 | bool running = false; | 85 | bool running = false; |
| 89 | std::atomic_bool stop_run{false}; | 86 | std::atomic_bool stop_run{false}; |
| 90 | std::mutex running_mutex; | 87 | std::mutex running_mutex = {}; |
| 91 | std::condition_variable running_cv; | 88 | std::condition_variable running_cv = {}; |
| 92 | |||
| 93 | /// Only used in asynchronous GPU mode | ||
| 94 | std::unique_ptr<Core::Frontend::GraphicsContext> shared_context; | ||
| 95 | |||
| 96 | /// This is shared_context in asynchronous GPU mode, core_context in synchronous GPU mode | ||
| 97 | Core::Frontend::GraphicsContext& context; | ||
| 98 | 89 | ||
| 99 | signals: | 90 | signals: |
| 100 | /** | 91 | /** |
| @@ -124,12 +115,10 @@ class GRenderWindow : public QWidget, public Core::Frontend::EmuWindow { | |||
| 124 | Q_OBJECT | 115 | Q_OBJECT |
| 125 | 116 | ||
| 126 | public: | 117 | public: |
| 127 | GRenderWindow(QWidget* parent, EmuThread* emu_thread); | 118 | GRenderWindow(GMainWindow* parent, EmuThread* emu_thread); |
| 128 | ~GRenderWindow() override; | 119 | ~GRenderWindow() override; |
| 129 | 120 | ||
| 130 | // EmuWindow implementation. | 121 | // EmuWindow implementation. |
| 131 | void MakeCurrent() override; | ||
| 132 | void DoneCurrent() override; | ||
| 133 | void PollEvents() override; | 122 | void PollEvents() override; |
| 134 | bool IsShown() const override; | 123 | bool IsShown() const override; |
| 135 | void RetrieveVulkanHandlers(void* get_instance_proc_addr, void* instance, | 124 | void RetrieveVulkanHandlers(void* get_instance_proc_addr, void* instance, |
| @@ -165,6 +154,8 @@ public: | |||
| 165 | 154 | ||
| 166 | void CaptureScreenshot(u32 res_scale, const QString& screenshot_path); | 155 | void CaptureScreenshot(u32 res_scale, const QString& screenshot_path); |
| 167 | 156 | ||
| 157 | std::pair<u32, u32> ScaleTouch(const QPointF pos) const; | ||
| 158 | |||
| 168 | public slots: | 159 | public slots: |
| 169 | void OnEmulationStarting(EmuThread* emu_thread); | 160 | void OnEmulationStarting(EmuThread* emu_thread); |
| 170 | void OnEmulationStopping(); | 161 | void OnEmulationStopping(); |
| @@ -176,7 +167,6 @@ signals: | |||
| 176 | void FirstFrameDisplayed(); | 167 | void FirstFrameDisplayed(); |
| 177 | 168 | ||
| 178 | private: | 169 | private: |
| 179 | std::pair<u32, u32> ScaleTouch(QPointF pos) const; | ||
| 180 | void TouchBeginEvent(const QTouchEvent* event); | 170 | void TouchBeginEvent(const QTouchEvent* event); |
| 181 | void TouchUpdateEvent(const QTouchEvent* event); | 171 | void TouchUpdateEvent(const QTouchEvent* event); |
| 182 | void TouchEndEvent(); | 172 | void TouchEndEvent(); |
| @@ -190,7 +180,10 @@ private: | |||
| 190 | 180 | ||
| 191 | EmuThread* emu_thread; | 181 | EmuThread* emu_thread; |
| 192 | 182 | ||
| 193 | std::unique_ptr<GraphicsContext> core_context; | 183 | // Main context that will be shared with all other contexts that are requested. |
| 184 | // If this is used in a shared context setting, then this should not be used directly, but | ||
| 185 | // should instead be shared from | ||
| 186 | std::shared_ptr<Core::Frontend::GraphicsContext> main_context; | ||
| 194 | 187 | ||
| 195 | #ifdef HAS_VULKAN | 188 | #ifdef HAS_VULKAN |
| 196 | std::unique_ptr<QVulkanInstance> vk_instance; | 189 | std::unique_ptr<QVulkanInstance> vk_instance; |
| @@ -201,12 +194,6 @@ private: | |||
| 201 | 194 | ||
| 202 | QByteArray geometry; | 195 | QByteArray geometry; |
| 203 | 196 | ||
| 204 | /// Native window handle that backs this presentation widget | ||
| 205 | QWindow* child_window = nullptr; | ||
| 206 | |||
| 207 | /// In order to embed the window into GRenderWindow, you need to use createWindowContainer to | ||
| 208 | /// put the child_window into a widget then add it to the layout. This child_widget can be | ||
| 209 | /// parented to GRenderWindow and use Qt's lifetime system | ||
| 210 | QWidget* child_widget = nullptr; | 197 | QWidget* child_widget = nullptr; |
| 211 | 198 | ||
| 212 | bool first_frame = false; | 199 | bool first_frame = false; |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 47615adfe..d7684e241 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -984,7 +984,7 @@ void GMainWindow::BootGame(const QString& filename) { | |||
| 984 | return; | 984 | return; |
| 985 | 985 | ||
| 986 | // Create and start the emulation thread | 986 | // Create and start the emulation thread |
| 987 | emu_thread = std::make_unique<EmuThread>(*render_window); | 987 | emu_thread = std::make_unique<EmuThread>(); |
| 988 | emit EmulationStarting(emu_thread.get()); | 988 | emit EmulationStarting(emu_thread.get()); |
| 989 | emu_thread->start(); | 989 | emu_thread->start(); |
| 990 | 990 | ||
| @@ -2375,7 +2375,6 @@ int main(int argc, char* argv[]) { | |||
| 2375 | 2375 | ||
| 2376 | // Enables the core to make the qt created contexts current on std::threads | 2376 | // Enables the core to make the qt created contexts current on std::threads |
| 2377 | QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity); | 2377 | QCoreApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity); |
| 2378 | QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); | ||
| 2379 | QApplication app(argc, argv); | 2378 | QApplication app(argc, argv); |
| 2380 | 2379 | ||
| 2381 | // Qt changes the locale and causes issues in float conversion using std::to_string() when | 2380 | // Qt changes the locale and causes issues in float conversion using std::to_string() when |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp index c0d373477..ee61179a0 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp | |||
| @@ -148,14 +148,6 @@ EmuWindow_SDL2_GL::~EmuWindow_SDL2_GL() { | |||
| 148 | SDL_GL_DeleteContext(window_context); | 148 | SDL_GL_DeleteContext(window_context); |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | void EmuWindow_SDL2_GL::MakeCurrent() { | ||
| 152 | core_context->MakeCurrent(); | ||
| 153 | } | ||
| 154 | |||
| 155 | void EmuWindow_SDL2_GL::DoneCurrent() { | ||
| 156 | core_context->DoneCurrent(); | ||
| 157 | } | ||
| 158 | |||
| 159 | void EmuWindow_SDL2_GL::RetrieveVulkanHandlers(void* get_instance_proc_addr, void* instance, | 151 | void EmuWindow_SDL2_GL::RetrieveVulkanHandlers(void* get_instance_proc_addr, void* instance, |
| 160 | void* surface) const { | 152 | void* surface) const { |
| 161 | // Should not have been called from OpenGL | 153 | // Should not have been called from OpenGL |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h index b80669ff0..e092021d7 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.h | |||
| @@ -13,8 +13,6 @@ public: | |||
| 13 | explicit EmuWindow_SDL2_GL(Core::System& system, bool fullscreen); | 13 | explicit EmuWindow_SDL2_GL(Core::System& system, bool fullscreen); |
| 14 | ~EmuWindow_SDL2_GL(); | 14 | ~EmuWindow_SDL2_GL(); |
| 15 | 15 | ||
| 16 | void MakeCurrent() override; | ||
| 17 | void DoneCurrent() override; | ||
| 18 | void Present() override; | 16 | void Present() override; |
| 19 | 17 | ||
| 20 | /// Ignored in OpenGL | 18 | /// Ignored in OpenGL |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp index abcc58165..46d053f04 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp | |||
| @@ -111,14 +111,6 @@ EmuWindow_SDL2_VK::~EmuWindow_SDL2_VK() { | |||
| 111 | vkDestroyInstance(vk_instance, nullptr); | 111 | vkDestroyInstance(vk_instance, nullptr); |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | void EmuWindow_SDL2_VK::MakeCurrent() { | ||
| 115 | // Unused on Vulkan | ||
| 116 | } | ||
| 117 | |||
| 118 | void EmuWindow_SDL2_VK::DoneCurrent() { | ||
| 119 | // Unused on Vulkan | ||
| 120 | } | ||
| 121 | |||
| 122 | void EmuWindow_SDL2_VK::RetrieveVulkanHandlers(void* get_instance_proc_addr, void* instance, | 114 | void EmuWindow_SDL2_VK::RetrieveVulkanHandlers(void* get_instance_proc_addr, void* instance, |
| 123 | void* surface) const { | 115 | void* surface) const { |
| 124 | const auto instance_proc_addr = vkGetInstanceProcAddr; | 116 | const auto instance_proc_addr = vkGetInstanceProcAddr; |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h index 1eb8c0868..3dd1f3f61 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.h | |||
| @@ -13,8 +13,6 @@ public: | |||
| 13 | explicit EmuWindow_SDL2_VK(Core::System& system, bool fullscreen); | 13 | explicit EmuWindow_SDL2_VK(Core::System& system, bool fullscreen); |
| 14 | ~EmuWindow_SDL2_VK(); | 14 | ~EmuWindow_SDL2_VK(); |
| 15 | 15 | ||
| 16 | void MakeCurrent() override; | ||
| 17 | void DoneCurrent() override; | ||
| 18 | void Present() override; | 16 | void Present() override; |
| 19 | void RetrieveVulkanHandlers(void* get_instance_proc_addr, void* instance, | 17 | void RetrieveVulkanHandlers(void* get_instance_proc_addr, void* instance, |
| 20 | void* surface) const override; | 18 | void* surface) const override; |
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index babf4c3a4..e5db7d819 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -232,15 +232,8 @@ int main(int argc, char** argv) { | |||
| 232 | 232 | ||
| 233 | system.Renderer().Rasterizer().LoadDiskResources(); | 233 | system.Renderer().Rasterizer().LoadDiskResources(); |
| 234 | 234 | ||
| 235 | // Acquire render context for duration of the thread if this is the rendering thread | 235 | // Core is loaded, start the GPU (makes the GPU contexts current to this thread) |
| 236 | if (!Settings::values.use_asynchronous_gpu_emulation) { | 236 | system.GPU().Start(); |
| 237 | emu_window->MakeCurrent(); | ||
| 238 | } | ||
| 239 | SCOPE_EXIT({ | ||
| 240 | if (!Settings::values.use_asynchronous_gpu_emulation) { | ||
| 241 | emu_window->DoneCurrent(); | ||
| 242 | } | ||
| 243 | }); | ||
| 244 | 237 | ||
| 245 | std::thread render_thread([&emu_window] { emu_window->Present(); }); | 238 | std::thread render_thread([&emu_window] { emu_window->Present(); }); |
| 246 | while (emu_window->IsOpen()) { | 239 | while (emu_window->IsOpen()) { |