diff --git a/src/video_core/renderer_opengl/frame_dumper_opengl.cpp b/src/video_core/renderer_opengl/frame_dumper_opengl.cpp index 3122de2f7..c7892a5f2 100644 --- a/src/video_core/renderer_opengl/frame_dumper_opengl.cpp +++ b/src/video_core/renderer_opengl/frame_dumper_opengl.cpp @@ -52,14 +52,15 @@ void FrameDumperOpenGL::PresentLoop() { LOG_DEBUG(Render_OpenGL, "Reloading present frame"); mailbox->ReloadPresentFrame(frame, layout.width, layout.height); } - glWaitSync(frame->render_fence, 0, GL_TIMEOUT_IGNORED); + + frame->render_fence.Wait(); glBindFramebuffer(GL_READ_FRAMEBUFFER, frame->present.handle); glBindBuffer(GL_PIXEL_PACK_BUFFER, pbos[current_pbo].handle); glReadPixels(0, 0, layout.width, layout.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0); // Insert fence for the main thread to block on - frame->present_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + frame->present_fence.Create(); glFlush(); // Bind the previous PBO and read the pixels diff --git a/src/video_core/renderer_opengl/gl_resource_manager.cpp b/src/video_core/renderer_opengl/gl_resource_manager.cpp index 9585f4786..716ca1750 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.cpp +++ b/src/video_core/renderer_opengl/gl_resource_manager.cpp @@ -199,6 +199,38 @@ void OGLBuffer::Release() { handle = 0; } +void OGLSync::Create() { + if (handle != 0) + return; + + handle = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); +} + +void OGLSync::Release() { + if (!handle) { + return; + } + + glDeleteSync(handle); + handle = 0; +} + +void OGLSync::WaitHost() { + if (!handle) { + return; + } + + glClientWaitSync(handle, 0, GL_TIMEOUT_IGNORED); +} + +void OGLSync::Wait() { + if (!handle) { + return; + } + + glWaitSync(handle, 0, GL_TIMEOUT_IGNORED); +} + void OGLVertexArray::Create() { if (handle != 0) return; diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h index b8c8f5bc9..223570a4e 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.h +++ b/src/video_core/renderer_opengl/gl_resource_manager.h @@ -143,6 +143,36 @@ public: GLuint handle = 0; }; +class OGLSync final : private NonCopyable { +public: + OGLSync() = default; + + OGLSync(OGLSync&& o) noexcept : handle(std::exchange(o.handle, nullptr)) {} + + ~OGLSync() { + Release(); + } + OGLSync& operator=(OGLSync&& o) noexcept { + Release(); + handle = std::exchange(o.handle, nullptr); + return *this; + } + + /// Creates a new internal OpenGL resource and stores the handle + void Create(); + + /// Deletes the internal OpenGL resource + void Release(); + + /// Causes the host to wait for the OpenGL semaphore + void WaitHost(); + + /// Causes the GPU to wait for the OpenGL semaphore + void Wait(); + + GLsync handle = 0; +}; + class OGLPipeline : private NonCopyable { public: OGLPipeline() = default; diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 3afec6d4c..3927b987c 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -499,22 +499,14 @@ void RendererOpenGL::RenderToMailbox(const Layout::FramebufferLayout& layout, // 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); - } + frame->present_fence.WaitHost(); - // delete the draw fence if the frame wasn't presented - if (frame->render_fence) { - glDeleteSync(frame->render_fence); - frame->render_fence = nullptr; - } + // Delete the draw fence if the frame wasn't presented + frame->render_fence.Release(); // 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 = nullptr; - } + frame->present_fence.Wait(); + frame->present_fence.Release(); } { @@ -529,7 +521,7 @@ void RendererOpenGL::RenderToMailbox(const Layout::FramebufferLayout& layout, state.Apply(); DrawScreens(layout, flipped); // 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); + frame->render_fence.Create(); glFlush(); mailbox->ReleaseRenderFrame(frame); } @@ -1152,7 +1144,9 @@ void RendererOpenGL::TryPresent(int timeout_ms, bool is_secondary) { LOG_DEBUG(Render_OpenGL, "Reloading present frame"); window.mailbox->ReloadPresentFrame(frame, layout.width, layout.height); } - glWaitSync(frame->render_fence, 0, GL_TIMEOUT_IGNORED); + + frame->render_fence.Wait(); + // 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 @@ -1164,12 +1158,10 @@ void RendererOpenGL::TryPresent(int timeout_ms, bool is_secondary) { GL_COLOR_BUFFER_BIT, GL_LINEAR); // Delete the fence if we're re-presenting to avoid leaking fences - if (frame->present_fence) { - glDeleteSync(frame->present_fence); - } + frame->present_fence.Release(); - /* insert fence for the main thread to block on */ - frame->present_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + // Insert fence for the main thread to block on + frame->present_fence.Create(); glFlush(); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 0cd2e7089..070929fe4 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -24,8 +24,8 @@ struct Frame { 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 + OpenGL::OGLSync render_fence{}; /// Fence created on the render thread + OpenGL::OGLSync present_fence{}; /// Fence created on the presentation thread }; } // namespace Frontend