Merge pull request #4692 from ReinUsesLisp/remove-vsync
renderer_opengl: Remove emulated mailbox presentation
This commit is contained in:
		
						commit
						a2eb44db82
					
				| @ -46,11 +46,6 @@ public: | ||||
|     /// Finalize rendering the guest frame and draw into the presentation texture
 | ||||
|     virtual void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) = 0; | ||||
| 
 | ||||
|     /// Draws the latest frame to the window waiting timeout_ms for a frame to arrive (Renderer
 | ||||
|     /// specific implementation)
 | ||||
|     /// Returns true if a frame was drawn
 | ||||
|     virtual bool TryPresent(int timeout_ms) = 0; | ||||
| 
 | ||||
|     // Getter/setter functions:
 | ||||
|     // ------------------------
 | ||||
| 
 | ||||
|  | ||||
| @ -32,20 +32,6 @@ namespace OpenGL { | ||||
| 
 | ||||
| namespace { | ||||
| 
 | ||||
| constexpr std::size_t SWAP_CHAIN_SIZE = 3; | ||||
| 
 | ||||
| struct Frame { | ||||
|     u32 width{};                      /// Width of the frame (to detect resize)
 | ||||
|     u32 height{};                     /// Height of the frame
 | ||||
|     bool color_reloaded{};            /// Texture attachment was recreated (ie: resized)
 | ||||
|     OpenGL::OGLRenderbuffer color{};  /// Buffer shared between the render/present FBO
 | ||||
|     OpenGL::OGLFramebuffer render{};  /// FBO created on the render thread
 | ||||
|     OpenGL::OGLFramebuffer present{}; /// FBO created on the present thread
 | ||||
|     GLsync render_fence{};            /// Fence created on the render thread
 | ||||
|     GLsync present_fence{};           /// Fence created on the presentation thread
 | ||||
|     bool is_srgb{};                   /// Framebuffer is sRGB or RGB
 | ||||
| }; | ||||
| 
 | ||||
| constexpr GLint PositionLocation = 0; | ||||
| constexpr GLint TexCoordLocation = 1; | ||||
| constexpr GLint ModelViewMatrixLocation = 0; | ||||
| @ -58,24 +44,6 @@ struct ScreenRectVertex { | ||||
|     std::array<GLfloat, 2> tex_coord; | ||||
| }; | ||||
| 
 | ||||
| /// Returns true if any debug tool is attached
 | ||||
| bool HasDebugTool() { | ||||
|     const bool nsight = std::getenv("NVTX_INJECTION64_PATH") || std::getenv("NSIGHT_LAUNCHED"); | ||||
|     if (nsight) { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     GLint num_extensions; | ||||
|     glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions); | ||||
|     for (GLuint index = 0; index < static_cast<GLuint>(num_extensions); ++index) { | ||||
|         const auto name = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, index)); | ||||
|         if (!std::strcmp(name, "GL_EXT_debug_tool")) { | ||||
|             return true; | ||||
|         } | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Defines a 1:1 pixel ortographic projection matrix with (0,0) on the top-left | ||||
|  * corner and (width, height) on the lower-bottom. | ||||
| @ -159,135 +127,15 @@ void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severit | ||||
| 
 | ||||
| } // Anonymous namespace
 | ||||
| 
 | ||||
| /**
 | ||||
|  * For smooth Vsync rendering, we want to always present the latest frame that the core generates, | ||||
|  * but also make sure that rendering happens at the pace that the frontend dictates. This is a | ||||
|  * helper class that the renderer uses to sync frames between the render thread and the presentation | ||||
|  * thread | ||||
|  */ | ||||
| class FrameMailbox { | ||||
| public: | ||||
|     std::mutex swap_chain_lock; | ||||
|     std::condition_variable present_cv; | ||||
|     std::array<Frame, SWAP_CHAIN_SIZE> swap_chain{}; | ||||
|     std::queue<Frame*> free_queue; | ||||
|     std::deque<Frame*> present_queue; | ||||
|     Frame* previous_frame{}; | ||||
| 
 | ||||
|     FrameMailbox() { | ||||
|         for (auto& frame : swap_chain) { | ||||
|             free_queue.push(&frame); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     ~FrameMailbox() { | ||||
|         // lock the mutex and clear out the present and free_queues and notify any people who are
 | ||||
|         // blocked to prevent deadlock on shutdown
 | ||||
|         std::scoped_lock lock{swap_chain_lock}; | ||||
|         std::queue<Frame*>().swap(free_queue); | ||||
|         present_queue.clear(); | ||||
|         present_cv.notify_all(); | ||||
|     } | ||||
| 
 | ||||
|     void ReloadPresentFrame(Frame* frame, u32 height, u32 width) { | ||||
|         frame->present.Release(); | ||||
|         frame->present.Create(); | ||||
|         GLint previous_draw_fbo{}; | ||||
|         glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &previous_draw_fbo); | ||||
|         glBindFramebuffer(GL_FRAMEBUFFER, frame->present.handle); | ||||
|         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, | ||||
|                                   frame->color.handle); | ||||
|         if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { | ||||
|             LOG_CRITICAL(Render_OpenGL, "Failed to recreate present FBO!"); | ||||
|         } | ||||
|         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, previous_draw_fbo); | ||||
|         frame->color_reloaded = false; | ||||
|     } | ||||
| 
 | ||||
|     void ReloadRenderFrame(Frame* frame, u32 width, u32 height) { | ||||
|         // Recreate the color texture attachment
 | ||||
|         frame->color.Release(); | ||||
|         frame->color.Create(); | ||||
|         const GLenum internal_format = frame->is_srgb ? GL_SRGB8 : GL_RGB8; | ||||
|         glNamedRenderbufferStorage(frame->color.handle, internal_format, width, height); | ||||
| 
 | ||||
|         // Recreate the FBO for the render target
 | ||||
|         frame->render.Release(); | ||||
|         frame->render.Create(); | ||||
|         glBindFramebuffer(GL_FRAMEBUFFER, frame->render.handle); | ||||
|         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, | ||||
|                                   frame->color.handle); | ||||
|         if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { | ||||
|             LOG_CRITICAL(Render_OpenGL, "Failed to recreate render FBO!"); | ||||
|         } | ||||
| 
 | ||||
|         frame->width = width; | ||||
|         frame->height = height; | ||||
|         frame->color_reloaded = true; | ||||
|     } | ||||
| 
 | ||||
|     Frame* GetRenderFrame() { | ||||
|         std::unique_lock lock{swap_chain_lock}; | ||||
| 
 | ||||
|         // If theres no free frames, we will reuse the oldest render frame
 | ||||
|         if (free_queue.empty()) { | ||||
|             auto frame = present_queue.back(); | ||||
|             present_queue.pop_back(); | ||||
|             return frame; | ||||
|         } | ||||
| 
 | ||||
|         Frame* frame = free_queue.front(); | ||||
|         free_queue.pop(); | ||||
|         return frame; | ||||
|     } | ||||
| 
 | ||||
|     void ReleaseRenderFrame(Frame* frame) { | ||||
|         std::unique_lock lock{swap_chain_lock}; | ||||
|         present_queue.push_front(frame); | ||||
|         present_cv.notify_one(); | ||||
|     } | ||||
| 
 | ||||
|     Frame* TryGetPresentFrame(int timeout_ms) { | ||||
|         std::unique_lock lock{swap_chain_lock}; | ||||
|         // wait for new entries in the present_queue
 | ||||
|         present_cv.wait_for(lock, std::chrono::milliseconds(timeout_ms), | ||||
|                             [&] { return !present_queue.empty(); }); | ||||
|         if (present_queue.empty()) { | ||||
|             // timed out waiting for a frame to draw so return the previous frame
 | ||||
|             return previous_frame; | ||||
|         } | ||||
| 
 | ||||
|         // free the previous frame and add it back to the free queue
 | ||||
|         if (previous_frame) { | ||||
|             free_queue.push(previous_frame); | ||||
|         } | ||||
| 
 | ||||
|         // the newest entries are pushed to the front of the queue
 | ||||
|         Frame* frame = present_queue.front(); | ||||
|         present_queue.pop_front(); | ||||
|         // remove all old entries from the present queue and move them back to the free_queue
 | ||||
|         for (auto f : present_queue) { | ||||
|             free_queue.push(f); | ||||
|         } | ||||
|         present_queue.clear(); | ||||
|         previous_frame = frame; | ||||
|         return frame; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_, | ||||
|                                Core::Frontend::EmuWindow& emu_window_, | ||||
|                                Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_, | ||||
|                                std::unique_ptr<Core::Frontend::GraphicsContext> context) | ||||
|     : RendererBase{emu_window_, std::move(context)}, telemetry_session{telemetry_session_}, | ||||
|       emu_window{emu_window_}, cpu_memory{cpu_memory_}, gpu{gpu_}, program_manager{device}, | ||||
|       has_debug_tool{HasDebugTool()} {} | ||||
|       emu_window{emu_window_}, cpu_memory{cpu_memory_}, gpu{gpu_}, program_manager{device} {} | ||||
| 
 | ||||
| RendererOpenGL::~RendererOpenGL() = default; | ||||
| 
 | ||||
| MICROPROFILE_DEFINE(OpenGL_RenderFrame, "OpenGL", "Render Frame", MP_RGB(128, 128, 64)); | ||||
| MICROPROFILE_DEFINE(OpenGL_WaitPresent, "OpenGL", "Wait For Present", MP_RGB(128, 128, 128)); | ||||
| 
 | ||||
| void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | ||||
|     if (!framebuffer) { | ||||
|         return; | ||||
| @ -296,79 +144,34 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | ||||
|     PrepareRendertarget(framebuffer); | ||||
|     RenderScreenshot(); | ||||
| 
 | ||||
|     Frame* frame; | ||||
|     { | ||||
|         MICROPROFILE_SCOPE(OpenGL_WaitPresent); | ||||
|     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); | ||||
|     DrawScreen(emu_window.GetFramebufferLayout()); | ||||
| 
 | ||||
|         frame = frame_mailbox->GetRenderFrame(); | ||||
|     ++m_current_frame; | ||||
| 
 | ||||
|         // Clean up sync objects before drawing
 | ||||
| 
 | ||||
|         // INTEL driver workaround. We can't delete the previous render sync object until we are
 | ||||
|         // sure that the presentation is done
 | ||||
|         if (frame->present_fence) { | ||||
|             glClientWaitSync(frame->present_fence, 0, GL_TIMEOUT_IGNORED); | ||||
|         } | ||||
| 
 | ||||
|         // delete the draw fence if the frame wasn't presented
 | ||||
|         if (frame->render_fence) { | ||||
|             glDeleteSync(frame->render_fence); | ||||
|             frame->render_fence = 0; | ||||
|         } | ||||
| 
 | ||||
|         // wait for the presentation to be done
 | ||||
|         if (frame->present_fence) { | ||||
|             glWaitSync(frame->present_fence, 0, GL_TIMEOUT_IGNORED); | ||||
|             glDeleteSync(frame->present_fence); | ||||
|             frame->present_fence = 0; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     { | ||||
|         MICROPROFILE_SCOPE(OpenGL_RenderFrame); | ||||
|         const auto& layout = render_window.GetFramebufferLayout(); | ||||
| 
 | ||||
|         // Recreate the frame if the size of the window has changed
 | ||||
|         if (layout.width != frame->width || layout.height != frame->height || | ||||
|             screen_info.display_srgb != frame->is_srgb) { | ||||
|             LOG_DEBUG(Render_OpenGL, "Reloading render frame"); | ||||
|             frame->is_srgb = screen_info.display_srgb; | ||||
|             frame_mailbox->ReloadRenderFrame(frame, layout.width, layout.height); | ||||
|         } | ||||
|         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frame->render.handle); | ||||
|         DrawScreen(layout); | ||||
|         // Create a fence for the frontend to wait on and swap this frame to OffTex
 | ||||
|         frame->render_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); | ||||
|         glFlush(); | ||||
|         frame_mailbox->ReleaseRenderFrame(frame); | ||||
|         m_current_frame++; | ||||
|         rasterizer->TickFrame(); | ||||
|     } | ||||
|     rasterizer->TickFrame(); | ||||
| 
 | ||||
|     render_window.PollEvents(); | ||||
|     if (has_debug_tool) { | ||||
|         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); | ||||
|         Present(0); | ||||
|         context->SwapBuffers(); | ||||
|     } | ||||
|     context->SwapBuffers(); | ||||
| } | ||||
| 
 | ||||
| void RendererOpenGL::PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer) { | ||||
|     if (framebuffer) { | ||||
|         // If framebuffer is provided, reload it from memory to a texture
 | ||||
|         if (screen_info.texture.width != static_cast<GLsizei>(framebuffer->width) || | ||||
|             screen_info.texture.height != static_cast<GLsizei>(framebuffer->height) || | ||||
|             screen_info.texture.pixel_format != framebuffer->pixel_format || | ||||
|             gl_framebuffer_data.empty()) { | ||||
|             // Reallocate texture if the framebuffer size has changed.
 | ||||
|             // This is expected to not happen very often and hence should not be a
 | ||||
|             // performance problem.
 | ||||
|             ConfigureFramebufferTexture(screen_info.texture, *framebuffer); | ||||
|         } | ||||
| 
 | ||||
|         // Load the framebuffer from memory, draw it to the screen, and swap buffers
 | ||||
|         LoadFBToScreenInfo(*framebuffer); | ||||
|     if (!framebuffer) { | ||||
|         return; | ||||
|     } | ||||
|     // If framebuffer is provided, reload it from memory to a texture
 | ||||
|     if (screen_info.texture.width != static_cast<GLsizei>(framebuffer->width) || | ||||
|         screen_info.texture.height != static_cast<GLsizei>(framebuffer->height) || | ||||
|         screen_info.texture.pixel_format != framebuffer->pixel_format || | ||||
|         gl_framebuffer_data.empty()) { | ||||
|         // Reallocate texture if the framebuffer size has changed.
 | ||||
|         // This is expected to not happen very often and hence should not be a
 | ||||
|         // performance problem.
 | ||||
|         ConfigureFramebufferTexture(screen_info.texture, *framebuffer); | ||||
|     } | ||||
| 
 | ||||
|     // Load the framebuffer from memory, draw it to the screen, and swap buffers
 | ||||
|     LoadFBToScreenInfo(*framebuffer); | ||||
| } | ||||
| 
 | ||||
| void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuffer) { | ||||
| @ -418,8 +221,6 @@ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color | ||||
| } | ||||
| 
 | ||||
| void RendererOpenGL::InitOpenGLObjects() { | ||||
|     frame_mailbox = std::make_unique<FrameMailbox>(); | ||||
| 
 | ||||
|     glClearColor(Settings::values.bg_red.GetValue(), Settings::values.bg_green.GetValue(), | ||||
|                  Settings::values.bg_blue.GetValue(), 0.0f); | ||||
| 
 | ||||
| @ -647,51 +448,6 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { | ||||
|     program_manager.RestoreGuestPipeline(); | ||||
| } | ||||
| 
 | ||||
| bool RendererOpenGL::TryPresent(int timeout_ms) { | ||||
|     if (has_debug_tool) { | ||||
|         LOG_DEBUG(Render_OpenGL, | ||||
|                   "Skipping presentation because we are presenting on the main context"); | ||||
|         return false; | ||||
|     } | ||||
|     return Present(timeout_ms); | ||||
| } | ||||
| 
 | ||||
| bool RendererOpenGL::Present(int timeout_ms) { | ||||
|     const auto& layout = render_window.GetFramebufferLayout(); | ||||
|     auto frame = frame_mailbox->TryGetPresentFrame(timeout_ms); | ||||
|     if (!frame) { | ||||
|         LOG_DEBUG(Render_OpenGL, "TryGetPresentFrame returned no frame to present"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     // Clearing before a full overwrite of a fbo can signal to drivers that they can avoid a
 | ||||
|     // readback since we won't be doing any blending
 | ||||
|     glClear(GL_COLOR_BUFFER_BIT); | ||||
| 
 | ||||
|     // Recreate the presentation FBO if the color attachment was changed
 | ||||
|     if (frame->color_reloaded) { | ||||
|         LOG_DEBUG(Render_OpenGL, "Reloading present frame"); | ||||
|         frame_mailbox->ReloadPresentFrame(frame, layout.width, layout.height); | ||||
|     } | ||||
|     glWaitSync(frame->render_fence, 0, GL_TIMEOUT_IGNORED); | ||||
|     // INTEL workaround.
 | ||||
|     // Normally we could just delete the draw fence here, but due to driver bugs, we can just delete
 | ||||
|     // it on the emulation thread without too much penalty
 | ||||
|     // glDeleteSync(frame.render_sync);
 | ||||
|     // frame.render_sync = 0;
 | ||||
| 
 | ||||
|     glBindFramebuffer(GL_READ_FRAMEBUFFER, frame->present.handle); | ||||
|     glBlitFramebuffer(0, 0, frame->width, frame->height, 0, 0, layout.width, layout.height, | ||||
|                       GL_COLOR_BUFFER_BIT, GL_LINEAR); | ||||
| 
 | ||||
|     // Insert fence for the main thread to block on
 | ||||
|     frame->present_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); | ||||
|     glFlush(); | ||||
| 
 | ||||
|     glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void RendererOpenGL::RenderScreenshot() { | ||||
|     if (!renderer_settings.screenshot_requested) { | ||||
|         return; | ||||
| @ -706,7 +462,7 @@ void RendererOpenGL::RenderScreenshot() { | ||||
|     screenshot_framebuffer.Create(); | ||||
|     glBindFramebuffer(GL_FRAMEBUFFER, screenshot_framebuffer.handle); | ||||
| 
 | ||||
|     Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout}; | ||||
|     const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout}; | ||||
| 
 | ||||
|     GLuint renderbuffer; | ||||
|     glGenRenderbuffers(1, &renderbuffer); | ||||
|  | ||||
| @ -55,14 +55,6 @@ struct ScreenInfo { | ||||
|     TextureInfo texture; | ||||
| }; | ||||
| 
 | ||||
| struct PresentationTexture { | ||||
|     u32 width = 0; | ||||
|     u32 height = 0; | ||||
|     OGLTexture texture; | ||||
| }; | ||||
| 
 | ||||
| class FrameMailbox; | ||||
| 
 | ||||
| class RendererOpenGL final : public VideoCore::RendererBase { | ||||
| public: | ||||
|     explicit RendererOpenGL(Core::TelemetrySession& telemetry_session, | ||||
| @ -74,7 +66,6 @@ public: | ||||
|     bool Init() override; | ||||
|     void ShutDown() override; | ||||
|     void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; | ||||
|     bool TryPresent(int timeout_ms) override; | ||||
| 
 | ||||
| private: | ||||
|     /// Initializes the OpenGL state and creates persistent objects.
 | ||||
| @ -102,8 +93,6 @@ private: | ||||
| 
 | ||||
|     void PrepareRendertarget(const Tegra::FramebufferConfig* framebuffer); | ||||
| 
 | ||||
|     bool Present(int timeout_ms); | ||||
| 
 | ||||
|     Core::TelemetrySession& telemetry_session; | ||||
|     Core::Frontend::EmuWindow& emu_window; | ||||
|     Core::Memory::Memory& cpu_memory; | ||||
| @ -134,11 +123,6 @@ private: | ||||
|     /// Used for transforming the framebuffer orientation
 | ||||
|     Tegra::FramebufferConfig::TransformFlags framebuffer_transform_flags{}; | ||||
|     Common::Rectangle<int> framebuffer_crop_rect; | ||||
| 
 | ||||
|     /// Frame presentation mailbox
 | ||||
|     std::unique_ptr<FrameMailbox> frame_mailbox; | ||||
| 
 | ||||
|     bool has_debug_tool = false; | ||||
| }; | ||||
| 
 | ||||
| } // namespace OpenGL
 | ||||
|  | ||||
| @ -283,11 +283,6 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | ||||
|     render_window.PollEvents(); | ||||
| } | ||||
| 
 | ||||
| bool RendererVulkan::TryPresent(int /*timeout_ms*/) { | ||||
|     // TODO (bunnei): ImplementMe
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool RendererVulkan::Init() { | ||||
|     library = OpenVulkanLibrary(); | ||||
|     instance = CreateInstance(library, dld, render_window.GetWindowInfo().type, | ||||
|  | ||||
| @ -55,7 +55,6 @@ public: | ||||
|     bool Init() override; | ||||
|     void ShutDown() override; | ||||
|     void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; | ||||
|     bool TryPresent(int timeout_ms) override; | ||||
| 
 | ||||
|     static std::vector<std::string> EnumerateDevices(); | ||||
| 
 | ||||
|  | ||||
| @ -218,15 +218,6 @@ public: | ||||
| 
 | ||||
|     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 { | ||||
|         Present(); | ||||
|         update(); | ||||
|     } | ||||
| 
 | ||||
|     QPaintEngine* paintEngine() const override { | ||||
|         return nullptr; | ||||
|     } | ||||
| @ -245,20 +236,8 @@ public: | ||||
|         context = std::move(context_); | ||||
|     } | ||||
| 
 | ||||
|     void Present() override { | ||||
|         if (!isVisible()) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         context->MakeCurrent(); | ||||
|         if (Core::System::GetInstance().Renderer().TryPresent(100)) { | ||||
|             context->SwapBuffers(); | ||||
|             glFinish(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     std::unique_ptr<Core::Frontend::GraphicsContext> context{}; | ||||
|     std::unique_ptr<Core::Frontend::GraphicsContext> context; | ||||
| }; | ||||
| 
 | ||||
| #ifdef HAS_VULKAN | ||||
|  | ||||
| @ -13,9 +13,8 @@ | ||||
| #include "input_common/sdl/sdl.h" | ||||
| #include "yuzu_cmd/emu_window/emu_window_sdl2.h" | ||||
| 
 | ||||
| EmuWindow_SDL2::EmuWindow_SDL2(Core::System& system, bool fullscreen, | ||||
|                                InputCommon::InputSubsystem* input_subsystem_) | ||||
|     : system{system}, input_subsystem{input_subsystem_} { | ||||
| EmuWindow_SDL2::EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem_) | ||||
|     : input_subsystem{input_subsystem_} { | ||||
|     if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) { | ||||
|         LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting..."); | ||||
|         exit(1); | ||||
|  | ||||
| @ -20,8 +20,7 @@ class InputSubsystem; | ||||
| 
 | ||||
| class EmuWindow_SDL2 : public Core::Frontend::EmuWindow { | ||||
| public: | ||||
|     explicit EmuWindow_SDL2(Core::System& system, bool fullscreen, | ||||
|                             InputCommon::InputSubsystem* input_subsystem); | ||||
|     explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem); | ||||
|     ~EmuWindow_SDL2(); | ||||
| 
 | ||||
|     /// Polls window events
 | ||||
| @ -33,9 +32,6 @@ public: | ||||
|     /// Returns if window is shown (not minimized)
 | ||||
|     bool IsShown() const override; | ||||
| 
 | ||||
|     /// Presents the next frame
 | ||||
|     virtual void Present() = 0; | ||||
| 
 | ||||
| protected: | ||||
|     /// Called by PollEvents when a key is pressed or released.
 | ||||
|     void OnKeyEvent(int key, u8 state); | ||||
| @ -67,9 +63,6 @@ protected: | ||||
|     /// Called when a configuration change affects the minimal size of the window
 | ||||
|     void OnMinimalClientAreaChangeRequest(std::pair<unsigned, unsigned> minimal_size) override; | ||||
| 
 | ||||
|     /// Instance of the system, used to access renderer for the presentation thread
 | ||||
|     Core::System& system; | ||||
| 
 | ||||
|     /// Is the window still open?
 | ||||
|     bool is_open = true; | ||||
| 
 | ||||
|  | ||||
| @ -87,9 +87,8 @@ bool EmuWindow_SDL2_GL::SupportsRequiredGLExtensions() { | ||||
|     return unsupported_ext.empty(); | ||||
| } | ||||
| 
 | ||||
| EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(Core::System& system, bool fullscreen, | ||||
|                                      InputCommon::InputSubsystem* input_subsystem) | ||||
|     : EmuWindow_SDL2{system, fullscreen, input_subsystem} { | ||||
| EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, bool fullscreen) | ||||
|     : EmuWindow_SDL2{input_subsystem} { | ||||
|     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); | ||||
|     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); | ||||
|     SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); | ||||
| @ -163,13 +162,3 @@ EmuWindow_SDL2_GL::~EmuWindow_SDL2_GL() { | ||||
| std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_GL::CreateSharedContext() const { | ||||
|     return std::make_unique<SDLGLContext>(); | ||||
| } | ||||
| 
 | ||||
| void EmuWindow_SDL2_GL::Present() { | ||||
|     SDL_GL_MakeCurrent(render_window, window_context); | ||||
|     SDL_GL_SetSwapInterval(Settings::values.use_vsync.GetValue() ? 1 : 0); | ||||
|     while (IsOpen()) { | ||||
|         system.Renderer().TryPresent(100); | ||||
|         SDL_GL_SwapWindow(render_window); | ||||
|     } | ||||
|     SDL_GL_MakeCurrent(render_window, nullptr); | ||||
| } | ||||
|  | ||||
| @ -14,12 +14,9 @@ class InputSubsystem; | ||||
| 
 | ||||
| class EmuWindow_SDL2_GL final : public EmuWindow_SDL2 { | ||||
| public: | ||||
|     explicit EmuWindow_SDL2_GL(Core::System& system, bool fullscreen, | ||||
|                                InputCommon::InputSubsystem* input_subsystem); | ||||
|     explicit EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, bool fullscreen); | ||||
|     ~EmuWindow_SDL2_GL(); | ||||
| 
 | ||||
|     void Present() override; | ||||
| 
 | ||||
|     std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; | ||||
| 
 | ||||
| private: | ||||
|  | ||||
| @ -19,9 +19,8 @@ | ||||
| #include <SDL.h> | ||||
| #include <SDL_syswm.h> | ||||
| 
 | ||||
| EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(Core::System& system, bool fullscreen, | ||||
|                                      InputCommon::InputSubsystem* input_subsystem) | ||||
|     : EmuWindow_SDL2{system, fullscreen, input_subsystem} { | ||||
| EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem) | ||||
|     : EmuWindow_SDL2{input_subsystem} { | ||||
|     const std::string window_title = fmt::format("yuzu {} | {}-{} (Vulkan)", Common::g_build_name, | ||||
|                                                  Common::g_scm_branch, Common::g_scm_desc); | ||||
|     render_window = | ||||
| @ -74,7 +73,3 @@ EmuWindow_SDL2_VK::~EmuWindow_SDL2_VK() = default; | ||||
| std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_VK::CreateSharedContext() const { | ||||
|     return std::make_unique<DummyContext>(); | ||||
| } | ||||
| 
 | ||||
| void EmuWindow_SDL2_VK::Present() { | ||||
|     // TODO (bunnei): ImplementMe
 | ||||
| } | ||||
|  | ||||
| @ -19,11 +19,8 @@ class InputSubsystem; | ||||
| 
 | ||||
| class EmuWindow_SDL2_VK final : public EmuWindow_SDL2 { | ||||
| public: | ||||
|     explicit EmuWindow_SDL2_VK(Core::System& system, bool fullscreen, | ||||
|                                InputCommon::InputSubsystem* input_subsystem); | ||||
|     ~EmuWindow_SDL2_VK(); | ||||
| 
 | ||||
|     void Present() override; | ||||
|     explicit EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsystem); | ||||
|     ~EmuWindow_SDL2_VK() override; | ||||
| 
 | ||||
|     std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; | ||||
| }; | ||||
|  | ||||
| @ -185,11 +185,11 @@ int main(int argc, char** argv) { | ||||
|     std::unique_ptr<EmuWindow_SDL2> emu_window; | ||||
|     switch (Settings::values.renderer_backend.GetValue()) { | ||||
|     case Settings::RendererBackend::OpenGL: | ||||
|         emu_window = std::make_unique<EmuWindow_SDL2_GL>(system, fullscreen, &input_subsystem); | ||||
|         emu_window = std::make_unique<EmuWindow_SDL2_GL>(&input_subsystem, fullscreen); | ||||
|         break; | ||||
|     case Settings::RendererBackend::Vulkan: | ||||
| #ifdef HAS_VULKAN | ||||
|         emu_window = std::make_unique<EmuWindow_SDL2_VK>(system, fullscreen, &input_subsystem); | ||||
|         emu_window = std::make_unique<EmuWindow_SDL2_VK>(&input_subsystem); | ||||
|         break; | ||||
| #else | ||||
|         LOG_CRITICAL(Frontend, "Vulkan backend has not been compiled!"); | ||||
| @ -240,14 +240,11 @@ int main(int argc, char** argv) { | ||||
|         system.CurrentProcess()->GetTitleID(), false, | ||||
|         [](VideoCore::LoadCallbackStage, size_t value, size_t total) {}); | ||||
| 
 | ||||
|     std::thread render_thread([&emu_window] { emu_window->Present(); }); | ||||
|     system.Run(); | ||||
|     while (emu_window->IsOpen()) { | ||||
|         std::this_thread::sleep_for(std::chrono::milliseconds(1)); | ||||
|     } | ||||
|     system.Pause(); | ||||
|     render_thread.join(); | ||||
| 
 | ||||
|     system.Shutdown(); | ||||
| 
 | ||||
|     detached_tasks.WaitForAllTasks(); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Rodrigo Locatti
						Rodrigo Locatti