diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index d5032b4328..ddc62bc975 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -106,8 +106,14 @@ RendererVulkan::~RendererVulkan() { } void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { + render_window.PollEvents(); + + if (!framebuffer) { + return; + } + const auto& layout = render_window.GetFramebufferLayout(); - if (framebuffer && layout.width > 0 && layout.height > 0 && render_window.IsShown()) { + if (layout.width > 0 && layout.height > 0 && render_window.IsShown()) { const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset; const bool use_accelerated = rasterizer->AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride); @@ -128,13 +134,16 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { blit_screen->Recreate(); } - render_window.SwapBuffers(); rasterizer->TickFrame(); } render_window.PollEvents(); } +void RendererVulkan::TryPresent(int /*timeout_ms*/) { + // TODO (bunnei): ImplementMe +} + bool RendererVulkan::Init() { PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr{}; render_window.RetrieveVulkanHandlers(&vkGetInstanceProcAddr, &instance, &surface); @@ -262,4 +271,4 @@ void RendererVulkan::Report() const { telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions); } -} // namespace Vulkan \ No newline at end of file +} // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index a472c5dc93..f513397f0e 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -36,14 +36,10 @@ public: explicit RendererVulkan(Core::Frontend::EmuWindow& window, Core::System& system); ~RendererVulkan() override; - /// Swap buffers (render frame) - void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; - - /// Initialize the renderer bool Init() override; - - /// Shutdown the renderer void ShutDown() override; + void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; + void TryPresent(int timeout_ms) override; private: std::optional CreateDebugCallback( diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 99e0ac61e4..704c5ecdd6 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -147,88 +147,129 @@ private: QOffscreenSurface* surface; }; -OpenGLWindow::OpenGLWindow(QWindow* parent, QWidget* event_handler, QOpenGLContext* shared_context) - : QWindow(parent), event_handler(event_handler), - context(new QOpenGLContext(shared_context->parent())) { +class ChildRenderWindow : public QWindow { +public: + ChildRenderWindow(QWindow* parent, QWidget* event_handler) + : QWindow{parent}, event_handler{event_handler} {} - // disable vsync for any shared contexts - auto format = shared_context->format(); - format.setSwapInterval(Settings::values.use_vsync ? 1 : 0); - this->setFormat(format); + virtual ~ChildRenderWindow() = default; - context->setShareContext(shared_context); - context->setScreen(this->screen()); - context->setFormat(format); - context->create(); + virtual void Present() = 0; - setSurfaceType(QWindow::OpenGLSurface); - - // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, - // WA_DontShowOnScreen, WA_DeleteOnClose -} - -OpenGLWindow::~OpenGLWindow() { - context->doneCurrent(); -} - -void OpenGLWindow::Present() { - if (!isExposed()) - return; - - context->makeCurrent(this); - Core::System::GetInstance().Renderer().TryPresent(100); - context->swapBuffers(this); - auto f = context->versionFunctions(); - f->glFinish(); - QWindow::requestUpdate(); -} - -bool OpenGLWindow::event(QEvent* event) { - switch (event->type()) { - case QEvent::UpdateRequest: - Present(); - return true; - case QEvent::MouseButtonPress: - case QEvent::MouseButtonRelease: - case QEvent::MouseButtonDblClick: - case QEvent::MouseMove: - case QEvent::KeyPress: - case QEvent::KeyRelease: - case QEvent::FocusIn: - case QEvent::FocusOut: - case QEvent::FocusAboutToChange: - case QEvent::Enter: - case QEvent::Leave: - case QEvent::Wheel: - case QEvent::TabletMove: - case QEvent::TabletPress: - case QEvent::TabletRelease: - case QEvent::TabletEnterProximity: - case QEvent::TabletLeaveProximity: - case QEvent::TouchBegin: - case QEvent::TouchUpdate: - case QEvent::TouchEnd: - case QEvent::InputMethodQuery: - case QEvent::TouchCancel: - return QCoreApplication::sendEvent(event_handler, event); - case QEvent::Drop: - GetMainWindow()->DropAction(static_cast(event)); - return true; - case QEvent::DragResponse: - case QEvent::DragEnter: - case QEvent::DragLeave: - case QEvent::DragMove: - GetMainWindow()->AcceptDropEvent(static_cast(event)); - return true; - default: - return QWindow::event(event); +protected: + bool event(QEvent* event) override { + switch (event->type()) { + case QEvent::UpdateRequest: + Present(); + return true; + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + case QEvent::KeyPress: + case QEvent::KeyRelease: + case QEvent::FocusIn: + case QEvent::FocusOut: + case QEvent::FocusAboutToChange: + case QEvent::Enter: + case QEvent::Leave: + case QEvent::Wheel: + case QEvent::TabletMove: + case QEvent::TabletPress: + case QEvent::TabletRelease: + case QEvent::TabletEnterProximity: + case QEvent::TabletLeaveProximity: + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + case QEvent::InputMethodQuery: + case QEvent::TouchCancel: + return QCoreApplication::sendEvent(event_handler, event); + case QEvent::Drop: + GetMainWindow()->DropAction(static_cast(event)); + return true; + case QEvent::DragResponse: + case QEvent::DragEnter: + case QEvent::DragLeave: + case QEvent::DragMove: + GetMainWindow()->AcceptDropEvent(static_cast(event)); + return true; + default: + return QWindow::event(event); + } } -} -void OpenGLWindow::exposeEvent(QExposeEvent* event) { - QWindow::requestUpdate(); - QWindow::exposeEvent(event); -} + void exposeEvent(QExposeEvent* event) override { + QWindow::requestUpdate(); + QWindow::exposeEvent(event); + } + +private: + QWidget* event_handler{}; +}; + +class OpenGLWindow final : public ChildRenderWindow { +public: + OpenGLWindow(QWindow* parent, QWidget* event_handler, QOpenGLContext* shared_context) + : ChildRenderWindow{parent, event_handler}, + context(new QOpenGLContext(shared_context->parent())) { + + // disable vsync for any shared contexts + auto format = shared_context->format(); + format.setSwapInterval(Settings::values.use_vsync ? 1 : 0); + this->setFormat(format); + + context->setShareContext(shared_context); + context->setScreen(this->screen()); + context->setFormat(format); + context->create(); + + setSurfaceType(QWindow::OpenGLSurface); + + // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, + // WA_DontShowOnScreen, WA_DeleteOnClose + } + + ~OpenGLWindow() override { + context->doneCurrent(); + } + + void Present() override { + if (!isExposed()) { + return; + } + + context->makeCurrent(this); + Core::System::GetInstance().Renderer().TryPresent(100); + context->swapBuffers(this); + auto f = context->versionFunctions(); + f->glFinish(); + QWindow::requestUpdate(); + } + +private: + QOpenGLContext* context{}; +}; + +#ifdef HAS_VULKAN +class VulkanWindow final : public ChildRenderWindow { +public: + VulkanWindow(QWindow* parent, QWidget* event_handler, QVulkanInstance* instance) + : ChildRenderWindow{parent, event_handler} { + setSurfaceType(QSurface::SurfaceType::VulkanSurface); + setVulkanInstance(instance); + } + + ~VulkanWindow() override = default; + + void Present() override { + // TODO(bunnei): ImplementMe + } + +private: + QWidget* event_handler{}; +}; +#endif GRenderWindow::GRenderWindow(QWidget* parent_, EmuThread* emu_thread) : QWidget(parent_), emu_thread(emu_thread) { @@ -251,11 +292,15 @@ GRenderWindow::~GRenderWindow() { } void GRenderWindow::MakeCurrent() { - core_context->MakeCurrent(); + if (core_context) { + core_context->MakeCurrent(); + } } void GRenderWindow::DoneCurrent() { - core_context->DoneCurrent(); + if (core_context) { + core_context->DoneCurrent(); + } } void GRenderWindow::PollEvents() { @@ -274,7 +319,7 @@ void GRenderWindow::RetrieveVulkanHandlers(void* get_instance_proc_addr, void* i #ifdef HAS_VULKAN const auto instance_proc_addr = vk_instance->getInstanceProcAddr("vkGetInstanceProcAddr"); const VkInstance instance_copy = vk_instance->vkInstance(); - const VkSurfaceKHR surface_copy = vk_instance->surfaceForWindow(child); + const VkSurfaceKHR surface_copy = vk_instance->surfaceForWindow(child_window); std::memcpy(get_instance_proc_addr, &instance_proc_addr, sizeof(instance_proc_addr)); std::memcpy(instance, &instance_copy, sizeof(instance_copy)); @@ -535,7 +580,6 @@ bool GRenderWindow::InitializeOpenGL() { layout()->addWidget(child_widget); core_context = CreateSharedContext(); - resize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height); return true; } @@ -565,7 +609,14 @@ bool GRenderWindow::InitializeVulkan() { return false; } - child = new GVKWidgetInternal(this, vk_instance.get()); + GMainWindow* parent = GetMainWindow(); + QWindow* parent_win_handle = parent ? parent->windowHandle() : nullptr; + child_window = new VulkanWindow(parent_win_handle, this, vk_instance.get()); + child_window->create(); + child_widget = createWindowContainer(child_window, this); + child_widget->resize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height); + layout()->addWidget(child_widget); + return true; #else QMessageBox::critical(this, tr("Vulkan not available!"), diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 37bc4f0437..6710a6e7f2 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -27,14 +27,6 @@ class QOpenGLContext; class QVulkanInstance; #endif -class GWidgetInternal; -class GGLWidgetInternal; -class GVKWidgetInternal; -class GMainWindow; -class GRenderWindow; -class QSurface; -class QOpenGLContext; - namespace VideoCore { enum class LoadCallbackStage; } @@ -123,24 +115,6 @@ signals: void LoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total); }; -class OpenGLWindow : public QWindow { - Q_OBJECT -public: - explicit OpenGLWindow(QWindow* parent, QWidget* event_handler, QOpenGLContext* shared_context); - - ~OpenGLWindow(); - - void Present(); - -protected: - bool event(QEvent* event) override; - void exposeEvent(QExposeEvent* event) override; - -private: - QOpenGLContext* context; - QWidget* event_handler; -}; - class GRenderWindow : public QWidget, public Core::Frontend::EmuWindow { Q_OBJECT 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 f5f6675b58..abcc581651 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp @@ -160,4 +160,6 @@ bool EmuWindow_SDL2_VK::UseStandardLayers(PFN_vkGetInstanceProcAddr vkGetInstanc }) != layers.end(); } -void EmuWindow_SDL2_VK::Present() {} +void EmuWindow_SDL2_VK::Present() { + // TODO (bunnei): ImplementMe +}