renderer_opengl: Encapsulate sync objects in OGLSync
This commit is contained in:
@@ -52,14 +52,15 @@ void FrameDumperOpenGL::PresentLoop() {
|
|||||||
LOG_DEBUG(Render_OpenGL, "Reloading present frame");
|
LOG_DEBUG(Render_OpenGL, "Reloading present frame");
|
||||||
mailbox->ReloadPresentFrame(frame, layout.width, layout.height);
|
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);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, frame->present.handle);
|
||||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbos[current_pbo].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);
|
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
|
// Insert fence for the main thread to block on
|
||||||
frame->present_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
frame->present_fence.Create();
|
||||||
glFlush();
|
glFlush();
|
||||||
|
|
||||||
// Bind the previous PBO and read the pixels
|
// Bind the previous PBO and read the pixels
|
||||||
|
@@ -199,6 +199,38 @@ void OGLBuffer::Release() {
|
|||||||
handle = 0;
|
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() {
|
void OGLVertexArray::Create() {
|
||||||
if (handle != 0)
|
if (handle != 0)
|
||||||
return;
|
return;
|
||||||
|
@@ -143,6 +143,36 @@ public:
|
|||||||
GLuint handle = 0;
|
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 {
|
class OGLPipeline : private NonCopyable {
|
||||||
public:
|
public:
|
||||||
OGLPipeline() = default;
|
OGLPipeline() = default;
|
||||||
|
@@ -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
|
// INTEL driver workaround. We can't delete the previous render sync object until we are
|
||||||
// sure that the presentation is done
|
// sure that the presentation is done
|
||||||
if (frame->present_fence) {
|
frame->present_fence.WaitHost();
|
||||||
glClientWaitSync(frame->present_fence, 0, GL_TIMEOUT_IGNORED);
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete the draw fence if the frame wasn't presented
|
// Delete the draw fence if the frame wasn't presented
|
||||||
if (frame->render_fence) {
|
frame->render_fence.Release();
|
||||||
glDeleteSync(frame->render_fence);
|
|
||||||
frame->render_fence = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait for the presentation to be done
|
// wait for the presentation to be done
|
||||||
if (frame->present_fence) {
|
frame->present_fence.Wait();
|
||||||
glWaitSync(frame->present_fence, 0, GL_TIMEOUT_IGNORED);
|
frame->present_fence.Release();
|
||||||
glDeleteSync(frame->present_fence);
|
|
||||||
frame->present_fence = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -529,7 +521,7 @@ void RendererOpenGL::RenderToMailbox(const Layout::FramebufferLayout& layout,
|
|||||||
state.Apply();
|
state.Apply();
|
||||||
DrawScreens(layout, flipped);
|
DrawScreens(layout, flipped);
|
||||||
// Create a fence for the frontend to wait on and swap this frame to OffTex
|
// 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();
|
glFlush();
|
||||||
mailbox->ReleaseRenderFrame(frame);
|
mailbox->ReleaseRenderFrame(frame);
|
||||||
}
|
}
|
||||||
@@ -1152,7 +1144,9 @@ void RendererOpenGL::TryPresent(int timeout_ms, bool is_secondary) {
|
|||||||
LOG_DEBUG(Render_OpenGL, "Reloading present frame");
|
LOG_DEBUG(Render_OpenGL, "Reloading present frame");
|
||||||
window.mailbox->ReloadPresentFrame(frame, layout.width, layout.height);
|
window.mailbox->ReloadPresentFrame(frame, layout.width, layout.height);
|
||||||
}
|
}
|
||||||
glWaitSync(frame->render_fence, 0, GL_TIMEOUT_IGNORED);
|
|
||||||
|
frame->render_fence.Wait();
|
||||||
|
|
||||||
// INTEL workaround.
|
// INTEL workaround.
|
||||||
// Normally we could just delete the draw fence here, but due to driver bugs, we can just delete
|
// 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
|
// 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);
|
GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||||
|
|
||||||
// Delete the fence if we're re-presenting to avoid leaking fences
|
// Delete the fence if we're re-presenting to avoid leaking fences
|
||||||
if (frame->present_fence) {
|
frame->present_fence.Release();
|
||||||
glDeleteSync(frame->present_fence);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* insert fence for the main thread to block on */
|
// Insert fence for the main thread to block on
|
||||||
frame->present_fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
frame->present_fence.Create();
|
||||||
glFlush();
|
glFlush();
|
||||||
|
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||||
|
@@ -24,8 +24,8 @@ struct Frame {
|
|||||||
OpenGL::OGLRenderbuffer color{}; /// Buffer shared between the render/present FBO
|
OpenGL::OGLRenderbuffer color{}; /// Buffer shared between the render/present FBO
|
||||||
OpenGL::OGLFramebuffer render{}; /// FBO created on the render thread
|
OpenGL::OGLFramebuffer render{}; /// FBO created on the render thread
|
||||||
OpenGL::OGLFramebuffer present{}; /// FBO created on the present thread
|
OpenGL::OGLFramebuffer present{}; /// FBO created on the present thread
|
||||||
GLsync render_fence{}; /// Fence created on the render thread
|
OpenGL::OGLSync render_fence{}; /// Fence created on the render thread
|
||||||
GLsync present_fence{}; /// Fence created on the presentation thread
|
OpenGL::OGLSync present_fence{}; /// Fence created on the presentation thread
|
||||||
};
|
};
|
||||||
} // namespace Frontend
|
} // namespace Frontend
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user