From b37d69e5e1033d7de7c8a2c3cbcfe55144c17de2 Mon Sep 17 00:00:00 2001 From: James Rowe Date: Tue, 24 Mar 2020 20:58:49 -0600 Subject: Frontend/GPU: Refactor context management Changes the GraphicsContext to be managed by the GPU core. This eliminates the need for the frontends to fool around with tricky MakeCurrent/DoneCurrent calls that are dependent on the settings (such as async gpu option). This also refactors out the need to use QWidget::fromWindowContainer as that caused issues with focus and input handling. Now we use a regular QWidget and just access the native windowHandle() directly. Another change is removing the debug tool setting in FrameMailbox. Instead of trying to block the frontend until a new frame is ready, the core will now take over presentation and draw directly to the window if the renderer detects that its hooked by NSight or RenderDoc Lastly, since it was in the way, I removed ScopeAcquireWindowContext and replaced it with a simple subclass in GraphicsContext that achieves the same result --- src/core/core.cpp | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) (limited to 'src/core/core.cpp') diff --git a/src/core/core.cpp b/src/core/core.cpp index 2185081262..6cc4a08121 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -24,7 +24,6 @@ #include "core/file_sys/sdmc_factory.h" #include "core/file_sys/vfs_concat.h" #include "core/file_sys/vfs_real.h" -#include "core/frontend/scope_acquire_context.h" #include "core/gdbstub/gdbstub.h" #include "core/hardware_interrupt_manager.h" #include "core/hle/kernel/client_port.h" @@ -168,13 +167,9 @@ struct System::Impl { Service::Init(service_manager, system); GDBStub::Init(); - renderer = VideoCore::CreateRenderer(emu_window, system); - if (!renderer->Init()) { - return ResultStatus::ErrorVideoCore; - } interrupt_manager = std::make_unique(system); - gpu_core = VideoCore::CreateGPU(system); - renderer->Rasterizer().SetupDirtyFlags(); + gpu_core = VideoCore::CreateGPU(emu_window, system); + gpu_core->Renderer().Rasterizer().SetupDirtyFlags(); is_powered_on = true; exit_lock = false; @@ -186,7 +181,6 @@ struct System::Impl { ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath) { - Core::Frontend::ScopeAcquireContext acquire_context{emu_window}; app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath)); if (!app_loader) { @@ -216,10 +210,6 @@ struct System::Impl { AddGlueRegistrationForProcess(*app_loader, *main_process); kernel.MakeCurrentProcess(main_process.get()); - // Main process has been loaded and been made current. - // Begin GPU and CPU execution. - gpu_core->Start(); - // Initialize cheat engine if (cheat_engine) { cheat_engine->Initialize(); @@ -277,7 +267,6 @@ struct System::Impl { } // Shutdown emulation session - renderer.reset(); GDBStub::Shutdown(); Service::Shutdown(); service_manager.reset(); @@ -353,7 +342,6 @@ struct System::Impl { Service::FileSystem::FileSystemController fs_controller; /// AppLoader used to load the current executing application std::unique_ptr app_loader; - std::unique_ptr renderer; std::unique_ptr gpu_core; std::unique_ptr interrupt_manager; Memory::Memory memory; @@ -536,11 +524,11 @@ const Core::Hardware::InterruptManager& System::InterruptManager() const { } VideoCore::RendererBase& System::Renderer() { - return *impl->renderer; + return impl->gpu_core->Renderer(); } const VideoCore::RendererBase& System::Renderer() const { - return *impl->renderer; + return impl->gpu_core->Renderer(); } Kernel::KernelCore& System::Kernel() { -- cgit v1.2.3 From c935a1a47547b45fb361c2faa16a87a12f893714 Mon Sep 17 00:00:00 2001 From: James Rowe Date: Tue, 24 Mar 2020 22:57:36 -0600 Subject: Address review and fix broken yuzu-tester build --- src/core/core.cpp | 4 +- src/core/frontend/emu_window.h | 2 +- src/video_core/renderer_opengl/gl_shader_cache.cpp | 2 +- src/video_core/renderer_opengl/renderer_opengl.cpp | 6 +- src/video_core/video_core.cpp | 4 +- src/yuzu/bootmanager.cpp | 97 +++++++--------------- src/yuzu/bootmanager.h | 9 +- src/yuzu_cmd/yuzu.cpp | 4 +- .../emu_window/emu_window_sdl2_hide.cpp | 42 +++++++--- src/yuzu_tester/emu_window/emu_window_sdl2_hide.h | 9 +- src/yuzu_tester/yuzu.cpp | 6 +- 11 files changed, 83 insertions(+), 102 deletions(-) (limited to 'src/core/core.cpp') diff --git a/src/core/core.cpp b/src/core/core.cpp index 6cc4a08121..26a580cb73 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -169,6 +169,9 @@ struct System::Impl { interrupt_manager = std::make_unique(system); gpu_core = VideoCore::CreateGPU(emu_window, system); + if (!gpu_core) { + return ResultStatus::ErrorVideoCore; + } gpu_core->Renderer().Rasterizer().SetupDirtyFlags(); is_powered_on = true; @@ -181,7 +184,6 @@ struct System::Impl { ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath) { - app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath)); if (!app_loader) { LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index bb283d8444..72294d4d85 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -30,7 +30,7 @@ public: class Scoped { public: - Scoped(GraphicsContext& context_) : context(context_) { + explicit Scoped(GraphicsContext& context_) : context(context_) { context.MakeCurrent(); } ~Scoped() { diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 8f59e04425..046ee55a59 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -305,6 +305,7 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, } const std::vector gl_cache = disk_cache.LoadPrecompiled(); + const auto supported_formats = GetSupportedFormats(); // Track if precompiled cache was altered during loading to know if we have to // serialize the virtual precompiled cache file back to the hard drive @@ -327,7 +328,6 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, const auto worker = [&](Core::Frontend::GraphicsContext* context, std::size_t begin, std::size_t end) { const auto scope = context->Acquire(); - const auto supported_formats = GetSupportedFormats(); for (std::size_t i = begin; i < end; ++i) { if (stop_loading) { diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 6f08803c12..f1a28cc210 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -7,7 +7,9 @@ #include #include #include + #include + #include "common/assert.h" #include "common/logging/log.h" #include "common/microprofile.h" @@ -313,8 +315,8 @@ public: RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system, Core::Frontend::GraphicsContext& context) - : VideoCore::RendererBase{emu_window}, emu_window{emu_window}, system{system}, frame_mailbox{}, - has_debug_tool{HasDebugTool()}, context{context} {} + : VideoCore::RendererBase{emu_window}, emu_window{emu_window}, system{system}, + frame_mailbox{}, context{context}, has_debug_tool{HasDebugTool()} {} RendererOpenGL::~RendererOpenGL() = default; diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index fd9fec0186..f60bdc60a5 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp @@ -30,7 +30,7 @@ std::unique_ptr CreateRenderer(Core::Frontend::EmuWindo return nullptr; } } -} // namespace +} // Anonymous namespace namespace VideoCore { @@ -39,7 +39,7 @@ std::unique_ptr CreateGPU(Core::Frontend::EmuWindow& emu_window, Cor const auto scope = context->Acquire(); auto renderer = CreateRenderer(emu_window, system, *context); if (!renderer->Init()) { - return {}; + return nullptr; } if (Settings::values.use_asynchronous_gpu_emulation) { diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index d120ee8187..4e9ced8baf 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -42,6 +42,10 @@ EmuThread::~EmuThread() = default; void EmuThread::run() { MicroProfileOnThreadCreate("EmuThread"); + // Main process has been loaded. Make the context current to this thread and begin GPU and CPU + // execution. + Core::System::GetInstance().GPU().Start(); + emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); Core::System::GetInstance().Renderer().Rasterizer().LoadDiskResources( @@ -51,10 +55,6 @@ void EmuThread::run() { emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0); - // Main process has been loaded. Make the context current to this thread and begin GPU and CPU - // execution. - Core::System::GetInstance().GPU().Start(); - // Holds whether the cpu was running during the last iteration, // so that the DebugModeLeft signal can be emitted before the // next execution step @@ -152,7 +152,7 @@ public: if (is_current) { return; } - context->makeCurrent(surface); + is_current = context->makeCurrent(surface); } void DoneCurrent() override { @@ -160,7 +160,11 @@ public: is_current = false; } - QOpenGLContext* GetShareContext() const { + QOpenGLContext* GetShareContext() { + return context.get(); + } + + const QOpenGLContext* GetShareContext() const { return context.get(); } @@ -177,13 +181,15 @@ class DummyContext : public Core::Frontend::GraphicsContext {}; class RenderWidget : public QWidget { public: - RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) { + explicit RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) { setAttribute(Qt::WA_NativeWindow); setAttribute(Qt::WA_PaintOnScreen); } virtual ~RenderWidget() = default; + /// Called on the UI thread when this Widget is ready to draw + /// Dervied classes can override this to draw the latest frame. virtual void Present() {} void paintEvent(QPaintEvent* event) override { @@ -191,56 +197,6 @@ public: update(); } - void resizeEvent(QResizeEvent* ev) override { - render_window->resize(ev->size()); - render_window->OnFramebufferSizeChanged(); - } - - void keyPressEvent(QKeyEvent* event) override { - InputCommon::GetKeyboard()->PressKey(event->key()); - } - - void keyReleaseEvent(QKeyEvent* event) override { - InputCommon::GetKeyboard()->ReleaseKey(event->key()); - } - - void mousePressEvent(QMouseEvent* event) override { - if (event->source() == Qt::MouseEventSynthesizedBySystem) - return; // touch input is handled in TouchBeginEvent - - const auto pos{event->pos()}; - if (event->button() == Qt::LeftButton) { - const auto [x, y] = render_window->ScaleTouch(pos); - render_window->TouchPressed(x, y); - } else if (event->button() == Qt::RightButton) { - InputCommon::GetMotionEmu()->BeginTilt(pos.x(), pos.y()); - } - } - - void mouseMoveEvent(QMouseEvent* event) override { - if (event->source() == Qt::MouseEventSynthesizedBySystem) - return; // touch input is handled in TouchUpdateEvent - - const auto pos{event->pos()}; - const auto [x, y] = render_window->ScaleTouch(pos); - render_window->TouchMoved(x, y); - InputCommon::GetMotionEmu()->Tilt(pos.x(), pos.y()); - } - - void mouseReleaseEvent(QMouseEvent* event) override { - if (event->source() == Qt::MouseEventSynthesizedBySystem) - return; // touch input is handled in TouchEndEvent - - if (event->button() == Qt::LeftButton) - render_window->TouchReleased(); - else if (event->button() == Qt::RightButton) - InputCommon::GetMotionEmu()->EndTilt(); - } - - std::pair GetSize() const { - return std::make_pair(width(), height()); - } - QPaintEngine* paintEngine() const override { return nullptr; } @@ -276,6 +232,7 @@ private: std::unique_ptr context{}; }; +#ifdef HAS_VULKAN class VulkanRenderWidget : public RenderWidget { public: explicit VulkanRenderWidget(GRenderWindow* parent, QVulkanInstance* instance) @@ -284,6 +241,7 @@ public: windowHandle()->setVulkanInstance(instance); } }; +#endif GRenderWindow::GRenderWindow(GMainWindow* parent_, EmuThread* emu_thread) : QWidget(parent_), emu_thread(emu_thread) { @@ -358,7 +316,7 @@ qreal GRenderWindow::windowPixelRatio() const { return devicePixelRatio(); } -std::pair GRenderWindow::ScaleTouch(const QPointF pos) const { +std::pair GRenderWindow::ScaleTouch(const QPointF& pos) const { const qreal pixel_ratio = windowPixelRatio(); return {static_cast(std::max(std::round(pos.x() * pixel_ratio), qreal{0.0})), static_cast(std::max(std::round(pos.y() * pixel_ratio), qreal{0.0}))}; @@ -378,8 +336,10 @@ void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { } void GRenderWindow::mousePressEvent(QMouseEvent* event) { - if (event->source() == Qt::MouseEventSynthesizedBySystem) - return; // touch input is handled in TouchBeginEvent + // touch input is handled in TouchBeginEvent + if (event->source() == Qt::MouseEventSynthesizedBySystem) { + return; + } auto pos = event->pos(); if (event->button() == Qt::LeftButton) { @@ -391,8 +351,10 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) { } void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { - if (event->source() == Qt::MouseEventSynthesizedBySystem) - return; // touch input is handled in TouchUpdateEvent + // touch input is handled in TouchUpdateEvent + if (event->source() == Qt::MouseEventSynthesizedBySystem) { + return; + } auto pos = event->pos(); const auto [x, y] = ScaleTouch(pos); @@ -401,13 +363,16 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { } void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { - if (event->source() == Qt::MouseEventSynthesizedBySystem) - return; // touch input is handled in TouchEndEvent + // touch input is handled in TouchEndEvent + if (event->source() == Qt::MouseEventSynthesizedBySystem) { + return; + } - if (event->button() == Qt::LeftButton) + if (event->button() == Qt::LeftButton) { this->TouchReleased(); - else if (event->button() == Qt::RightButton) + } else if (event->button() == Qt::RightButton) { InputCommon::GetMotionEmu()->EndTilt(); + } } void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) { diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 3739ec7ed0..d69078df12 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -7,11 +7,12 @@ #include #include #include -#include + #include #include #include #include + #include "common/thread.h" #include "core/core.h" #include "core/frontend/emu_window.h" @@ -84,8 +85,8 @@ private: bool exec_step = false; bool running = false; std::atomic_bool stop_run{false}; - std::mutex running_mutex = {}; - std::condition_variable running_cv = {}; + std::mutex running_mutex; + std::condition_variable running_cv; signals: /** @@ -154,7 +155,7 @@ public: void CaptureScreenshot(u32 res_scale, const QString& screenshot_path); - std::pair ScaleTouch(const QPointF pos) const; + std::pair ScaleTouch(const QPointF& pos) const; public slots: void OnEmulationStarting(EmuThread* emu_thread); diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index e5db7d819a..4d2ea7e9e9 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -230,11 +230,11 @@ int main(int argc, char** argv) { system.TelemetrySession().AddField(Telemetry::FieldType::App, "Frontend", "SDL"); - system.Renderer().Rasterizer().LoadDiskResources(); - // Core is loaded, start the GPU (makes the GPU contexts current to this thread) system.GPU().Start(); + system.Renderer().Rasterizer().LoadDiskResources(); + std::thread render_thread([&emu_window] { emu_window->Present(); }); while (emu_window->IsOpen()) { system.RunLoop(); diff --git a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp index a1bdb1a12b..a837430cc3 100644 --- a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp +++ b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp @@ -102,8 +102,6 @@ EmuWindow_SDL2_Hide::EmuWindow_SDL2_Hide() { LOG_INFO(Frontend, "yuzu-tester Version: {} | {}-{}", Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc); Settings::LogSettings(); - - DoneCurrent(); } EmuWindow_SDL2_Hide::~EmuWindow_SDL2_Hide() { @@ -114,14 +112,6 @@ EmuWindow_SDL2_Hide::~EmuWindow_SDL2_Hide() { void EmuWindow_SDL2_Hide::PollEvents() {} -void EmuWindow_SDL2_Hide::MakeCurrent() { - SDL_GL_MakeCurrent(render_window, gl_context); -} - -void EmuWindow_SDL2_Hide::DoneCurrent() { - SDL_GL_MakeCurrent(render_window, nullptr); -} - bool EmuWindow_SDL2_Hide::IsShown() const { return false; } @@ -129,3 +119,35 @@ bool EmuWindow_SDL2_Hide::IsShown() const { void EmuWindow_SDL2_Hide::RetrieveVulkanHandlers(void*, void*, void*) const { UNREACHABLE(); } + +class SDLGLContext : public Core::Frontend::GraphicsContext { +public: + explicit SDLGLContext() { + // create a hidden window to make the shared context against + window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0, + SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL); + context = SDL_GL_CreateContext(window); + } + + ~SDLGLContext() { + DoneCurrent(); + SDL_GL_DeleteContext(context); + SDL_DestroyWindow(window); + } + + void MakeCurrent() override { + SDL_GL_MakeCurrent(window, context); + } + + void DoneCurrent() override { + SDL_GL_MakeCurrent(window, nullptr); + } + +private: + SDL_Window* window; + SDL_GLContext context; +}; + +std::unique_ptr EmuWindow_SDL2_Hide::CreateSharedContext() const { + return std::make_unique(); +} diff --git a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h index b13e153099..9f5d04fca7 100644 --- a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h +++ b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h @@ -16,12 +16,6 @@ public: /// Polls window events void PollEvents() override; - /// Makes the graphics context current for the caller thread - void MakeCurrent() override; - - /// Releases the GL context from the caller thread - void DoneCurrent() override; - /// Whether the screen is being shown or not. bool IsShown() const override; @@ -29,8 +23,7 @@ public: void RetrieveVulkanHandlers(void* get_instance_proc_addr, void* instance, void* surface) const override; - /// Whether the window is still open, and a close request hasn't yet been sent - bool IsOpen() const; + std::unique_ptr CreateSharedContext() const override; private: /// Whether the GPU and driver supports the OpenGL extension required diff --git a/src/yuzu_tester/yuzu.cpp b/src/yuzu_tester/yuzu.cpp index 94ad50cb33..676e70ebd7 100644 --- a/src/yuzu_tester/yuzu.cpp +++ b/src/yuzu_tester/yuzu.cpp @@ -164,11 +164,6 @@ int main(int argc, char** argv) { std::unique_ptr emu_window{std::make_unique()}; - if (!Settings::values.use_multi_core) { - // Single core mode must acquire OpenGL context for entire emulation session - emu_window->MakeCurrent(); - } - bool finished = false; int return_value = 0; const auto callback = [&finished, @@ -257,6 +252,7 @@ int main(int argc, char** argv) { system.TelemetrySession().AddField(Telemetry::FieldType::App, "Frontend", "SDLHideTester"); + system.GPU().Start(); system.Renderer().Rasterizer().LoadDiskResources(); while (!finished) { -- cgit v1.2.3