diff options
author | RSDuck <RSDuck@users.noreply.github.com> | 2021-02-02 15:31:32 +0100 |
---|---|---|
committer | RSDuck <RSDuck@users.noreply.github.com> | 2021-02-02 15:33:45 +0100 |
commit | 40aae154cf77e0611057a05702f28d9cf17b08f4 (patch) | |
tree | faefea325f6fc7beabf7cbf073310296981bec4b | |
parent | b5e601bb88858b124b0cc41a4ee7eb6896dee8d3 (diff) |
prevent race condition around framebuffers
-rw-r--r-- | src/GPU.h | 2 | ||||
-rw-r--r-- | src/GPU_OpenGL.cpp | 67 | ||||
-rw-r--r-- | src/frontend/qt_sdl/main.cpp | 101 | ||||
-rw-r--r-- | src/frontend/qt_sdl/main.h | 4 |
4 files changed, 106 insertions, 68 deletions
@@ -563,7 +563,7 @@ void SetRenderSettings(RenderSettings& settings); void Stop(); void RenderFrame(); -void BindOutputTexture(); +void BindOutputTexture(int buf); } #endif diff --git a/src/GPU_OpenGL.cpp b/src/GPU_OpenGL.cpp index 59ced93..e7ab1f7 100644 --- a/src/GPU_OpenGL.cpp +++ b/src/GPU_OpenGL.cpp @@ -49,8 +49,8 @@ struct CompVertex CompVertex CompVertices[2 * 3*2]; GLuint CompScreenInputTex; -GLuint CompScreenOutputTex; -GLuint CompScreenOutputFB; +GLuint CompScreenOutputTex[2]; +GLuint CompScreenOutputFB[2]; bool Init() @@ -118,7 +118,7 @@ bool Init() glEnableVertexAttribArray(1); // texcoord glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(CompVertex), (void*)(offsetof(CompVertex, Texcoord))); - glGenFramebuffers(1, &CompScreenOutputFB); + glGenFramebuffers(2, CompScreenOutputFB); glGenTextures(1, &CompScreenInputTex); glActiveTexture(GL_TEXTURE0); @@ -129,12 +129,15 @@ bool Init() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8UI, 256*3 + 1, 192*2, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, NULL); - glGenTextures(1, &CompScreenOutputTex); - glBindTexture(GL_TEXTURE_2D, CompScreenOutputTex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glGenTextures(2, CompScreenOutputTex); + for (int i = 0; i < 2; i++) + { + glBindTexture(GL_TEXTURE_2D, CompScreenOutputTex[i]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -143,9 +146,9 @@ bool Init() void DeInit() { - glDeleteFramebuffers(1, &CompScreenOutputFB); + glDeleteFramebuffers(2, CompScreenOutputFB); glDeleteTextures(1, &CompScreenInputTex); - glDeleteTextures(1, &CompScreenOutputTex); + glDeleteTextures(2, CompScreenOutputTex); glDeleteVertexArrays(1, &CompVertexArrayID); glDeleteBuffers(1, &CompVertexBufferID); @@ -167,30 +170,41 @@ void SetRenderSettings(RenderSettings& settings) ScreenW = 256 * scale; ScreenH = (384+2) * scale; - glBindTexture(GL_TEXTURE_2D, CompScreenOutputTex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW, ScreenH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - // fill the padding - u8 zeroPixels[ScreenW*2*scale*4]; - memset(zeroPixels, 0, sizeof(zeroPixels)); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192*scale, ScreenW, 2*scale, GL_RGBA, GL_UNSIGNED_BYTE, zeroPixels); - - GLenum fbassign[] = {GL_COLOR_ATTACHMENT0}; - glBindFramebuffer(GL_FRAMEBUFFER, CompScreenOutputFB); - glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, CompScreenOutputTex, 0); - glDrawBuffers(1, fbassign); + for (int i = 0; i < 2; i++) + { + glBindTexture(GL_TEXTURE_2D, CompScreenOutputTex[i]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW, ScreenH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + // fill the padding + u8 zeroPixels[ScreenW*2*scale*4]; + memset(zeroPixels, 0, sizeof(zeroPixels)); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192*scale, ScreenW, 2*scale, GL_RGBA, GL_UNSIGNED_BYTE, zeroPixels); + + GLenum fbassign[] = {GL_COLOR_ATTACHMENT0}; + glBindFramebuffer(GL_FRAMEBUFFER, CompScreenOutputFB[i]); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, CompScreenOutputTex[i], 0); + glDrawBuffers(1, fbassign); + } glBindFramebuffer(GL_FRAMEBUFFER, 0); } void Stop() { - RenderFrame(); + for (int i = 0; i < 2; i++) + { + int frontbuf = GPU::FrontBuffer; + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, CompScreenOutputFB[frontbuf]); + + glClear(GL_COLOR_BUFFER_BIT); + } } void RenderFrame() { + int frontbuf = GPU::FrontBuffer; glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, CompScreenOutputFB); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, CompScreenOutputFB[frontbuf]); glDisable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST); @@ -208,7 +222,6 @@ void RenderFrame() // TODO: support setting this midframe, if ever needed glUniform1i(Comp3DXPosLoc[0], ((int)GPU3D::RenderXPos << 23) >> 23); - int frontbuf = GPU::FrontBuffer; glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, CompScreenInputTex); @@ -228,9 +241,9 @@ void RenderFrame() glDrawArrays(GL_TRIANGLES, 0, 4*3); } -void BindOutputTexture() +void BindOutputTexture(int buf) { - glBindTexture(GL_TEXTURE_2D, CompScreenOutputTex); + glBindTexture(GL_TEXTURE_2D, CompScreenOutputTex[buf]); } } diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index 6766252..5aa4959 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -490,13 +490,18 @@ void EmuThread::run() // emulate u32 nlines = NDS::RunFrame(); + FrontBufferLock.lock(); #ifdef OGLRENDERER_ENABLED - // this is hacky but this is the easiest way to call - // this function without dealling with a ton of - // macro mess if (videoRenderer == 1) - epoxy_glFlush(); + { + // this is hacky but this is the easiest way to call + // this function without dealling with a ton of + // macro mess + epoxy_glFinish(); + } #endif + FrontBuffer = GPU::FrontBuffer; + FrontBufferLock.unlock(); #ifdef MELONCAP MelonCap::Update(); @@ -824,11 +829,17 @@ void ScreenPanelNative::paintEvent(QPaintEvent* event) // fill background painter.fillRect(event->rect(), QColor::fromRgb(0, 0, 0)); - int frontbuf = GPU::FrontBuffer; - if (!GPU::Framebuffer[frontbuf][0] || !GPU::Framebuffer[frontbuf][1]) return; + emuThread->FrontBufferLock.lock(); + int frontbuf = emuThread->FrontBuffer; + if (!GPU::Framebuffer[frontbuf][0] || !GPU::Framebuffer[frontbuf][1]) + { + emuThread->FrontBufferLock.unlock(); + return; + } memcpy(screen[0].scanLine(0), GPU::Framebuffer[frontbuf][0], 256*192*4); memcpy(screen[1].scanLine(0), GPU::Framebuffer[frontbuf][1], 256*192*4); + emuThread->FrontBufferLock.unlock(); painter.setRenderHint(QPainter::SmoothPixmapTransform, Config::ScreenFilter!=0); @@ -988,53 +999,63 @@ void ScreenPanelGL::paintGL() glViewport(0, 0, w*factor, h*factor); - screenShader->bind(); + if (emuThread) + { + screenShader->bind(); - screenShader->setUniformValue("uScreenSize", (float)w*factor, (float)h*factor); + screenShader->setUniformValue("uScreenSize", (float)w*factor, (float)h*factor); - int frontbuf = GPU::FrontBuffer; - glActiveTexture(GL_TEXTURE0); + emuThread->FrontBufferLock.lock(); + int frontbuf = emuThread->FrontBuffer; + glActiveTexture(GL_TEXTURE0); -#ifdef OGLRENDERER_ENABLED - if (GPU::Renderer != 0) - { - // hardware-accelerated render - GPU::GLCompositor::BindOutputTexture(); - } - else -#endif - { - // regular render - glBindTexture(GL_TEXTURE_2D, screenTexture); - - if (GPU::Framebuffer[frontbuf][0] && GPU::Framebuffer[frontbuf][1]) + #ifdef OGLRENDERER_ENABLED + if (GPU::Renderer != 0) { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 192, GL_RGBA, - GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][0]); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192+2, 256, 192, GL_RGBA, - GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][1]); + // hardware-accelerated render + GPU::GLCompositor::BindOutputTexture(frontbuf); } - } + else + #endif + { + // regular render + glBindTexture(GL_TEXTURE_2D, screenTexture); - GLint filter = Config::ScreenFilter ? GL_LINEAR : GL_NEAREST; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); + if (GPU::Framebuffer[frontbuf][0] && GPU::Framebuffer[frontbuf][1]) + { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 192, GL_RGBA, + GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][0]); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192+2, 256, 192, GL_RGBA, + GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][1]); + } + } - glBindBuffer(GL_ARRAY_BUFFER, screenVertexBuffer); - glBindVertexArray(screenVertexArray); + GLint filter = Config::ScreenFilter ? GL_LINEAR : GL_NEAREST; + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); - GLint transloc = screenShader->uniformLocation("uTransform"); + glBindBuffer(GL_ARRAY_BUFFER, screenVertexBuffer); + glBindVertexArray(screenVertexArray); - for (int i = 0; i < numScreens; i++) - { - glUniformMatrix2x3fv(transloc, 1, GL_TRUE, screenMatrix[i]); - glDrawArrays(GL_TRIANGLES, screenKind[i] == 0 ? 0 : 2*3, 2*3); - } + GLint transloc = screenShader->uniformLocation("uTransform"); - screenShader->release(); + for (int i = 0; i < numScreens; i++) + { + glUniformMatrix2x3fv(transloc, 1, GL_TRUE, screenMatrix[i]); + glDrawArrays(GL_TRIANGLES, screenKind[i] == 0 ? 0 : 2*3, 2*3); + } + + screenShader->release(); + } OSD::Update(this); OSD::DrawGL(this, w*factor, h*factor); + + if (emuThread) + { + glFinish(); + emuThread->FrontBufferLock.unlock(); + } } void ScreenPanelGL::resizeEvent(QResizeEvent* event) diff --git a/src/frontend/qt_sdl/main.h b/src/frontend/qt_sdl/main.h index c226fbc..9bfcd0a 100644 --- a/src/frontend/qt_sdl/main.h +++ b/src/frontend/qt_sdl/main.h @@ -26,6 +26,7 @@ #include <QImage> #include <QActionGroup> #include <QTimer> +#include <QMutex> #include <QOffscreenSurface> #include <QOpenGLWidget> @@ -59,6 +60,9 @@ public: bool emuIsRunning(); + int FrontBuffer = 0; + QMutex FrontBufferLock; + signals: void windowUpdate(); void windowTitleChange(QString title); |