aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRSDuck <RSDuck@users.noreply.github.com>2021-02-02 15:31:32 +0100
committerRSDuck <RSDuck@users.noreply.github.com>2021-02-02 15:33:45 +0100
commit40aae154cf77e0611057a05702f28d9cf17b08f4 (patch)
treefaefea325f6fc7beabf7cbf073310296981bec4b
parentb5e601bb88858b124b0cc41a4ee7eb6896dee8d3 (diff)
prevent race condition around framebuffers
-rw-r--r--src/GPU.h2
-rw-r--r--src/GPU_OpenGL.cpp67
-rw-r--r--src/frontend/qt_sdl/main.cpp101
-rw-r--r--src/frontend/qt_sdl/main.h4
4 files changed, 106 insertions, 68 deletions
diff --git a/src/GPU.h b/src/GPU.h
index 3a254df..2fc15f4 100644
--- a/src/GPU.h
+++ b/src/GPU.h
@@ -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);