prevent race condition around framebuffers
This commit is contained in:
parent
b5e601bb88
commit
40aae154cf
|
@ -563,7 +563,7 @@ void SetRenderSettings(RenderSettings& settings);
|
||||||
|
|
||||||
void Stop();
|
void Stop();
|
||||||
void RenderFrame();
|
void RenderFrame();
|
||||||
void BindOutputTexture();
|
void BindOutputTexture(int buf);
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -49,8 +49,8 @@ struct CompVertex
|
||||||
CompVertex CompVertices[2 * 3*2];
|
CompVertex CompVertices[2 * 3*2];
|
||||||
|
|
||||||
GLuint CompScreenInputTex;
|
GLuint CompScreenInputTex;
|
||||||
GLuint CompScreenOutputTex;
|
GLuint CompScreenOutputTex[2];
|
||||||
GLuint CompScreenOutputFB;
|
GLuint CompScreenOutputFB[2];
|
||||||
|
|
||||||
|
|
||||||
bool Init()
|
bool Init()
|
||||||
|
@ -118,7 +118,7 @@ bool Init()
|
||||||
glEnableVertexAttribArray(1); // texcoord
|
glEnableVertexAttribArray(1); // texcoord
|
||||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(CompVertex), (void*)(offsetof(CompVertex, Texcoord)));
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(CompVertex), (void*)(offsetof(CompVertex, Texcoord)));
|
||||||
|
|
||||||
glGenFramebuffers(1, &CompScreenOutputFB);
|
glGenFramebuffers(2, CompScreenOutputFB);
|
||||||
|
|
||||||
glGenTextures(1, &CompScreenInputTex);
|
glGenTextures(1, &CompScreenInputTex);
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
@ -129,12 +129,15 @@ bool Init()
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
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);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8UI, 256*3 + 1, 192*2, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
|
||||||
glGenTextures(1, &CompScreenOutputTex);
|
glGenTextures(2, CompScreenOutputTex);
|
||||||
glBindTexture(GL_TEXTURE_2D, CompScreenOutputTex);
|
for (int i = 0; i < 2; 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);
|
glBindTexture(GL_TEXTURE_2D, CompScreenOutputTex[i]);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
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);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
|
@ -143,9 +146,9 @@ bool Init()
|
||||||
|
|
||||||
void DeInit()
|
void DeInit()
|
||||||
{
|
{
|
||||||
glDeleteFramebuffers(1, &CompScreenOutputFB);
|
glDeleteFramebuffers(2, CompScreenOutputFB);
|
||||||
glDeleteTextures(1, &CompScreenInputTex);
|
glDeleteTextures(1, &CompScreenInputTex);
|
||||||
glDeleteTextures(1, &CompScreenOutputTex);
|
glDeleteTextures(2, CompScreenOutputTex);
|
||||||
|
|
||||||
glDeleteVertexArrays(1, &CompVertexArrayID);
|
glDeleteVertexArrays(1, &CompVertexArrayID);
|
||||||
glDeleteBuffers(1, &CompVertexBufferID);
|
glDeleteBuffers(1, &CompVertexBufferID);
|
||||||
|
@ -167,30 +170,41 @@ void SetRenderSettings(RenderSettings& settings)
|
||||||
ScreenW = 256 * scale;
|
ScreenW = 256 * scale;
|
||||||
ScreenH = (384+2) * scale;
|
ScreenH = (384+2) * scale;
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, CompScreenOutputTex);
|
for (int i = 0; i < 2; i++)
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW, ScreenH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
{
|
||||||
// fill the padding
|
glBindTexture(GL_TEXTURE_2D, CompScreenOutputTex[i]);
|
||||||
u8 zeroPixels[ScreenW*2*scale*4];
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ScreenW, ScreenH, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||||
memset(zeroPixels, 0, sizeof(zeroPixels));
|
// fill the padding
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192*scale, ScreenW, 2*scale, GL_RGBA, GL_UNSIGNED_BYTE, zeroPixels);
|
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};
|
GLenum fbassign[] = {GL_COLOR_ATTACHMENT0};
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, CompScreenOutputFB);
|
glBindFramebuffer(GL_FRAMEBUFFER, CompScreenOutputFB[i]);
|
||||||
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, CompScreenOutputTex, 0);
|
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, CompScreenOutputTex[i], 0);
|
||||||
glDrawBuffers(1, fbassign);
|
glDrawBuffers(1, fbassign);
|
||||||
|
}
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stop()
|
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()
|
void RenderFrame()
|
||||||
{
|
{
|
||||||
|
int frontbuf = GPU::FrontBuffer;
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, CompScreenOutputFB);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, CompScreenOutputFB[frontbuf]);
|
||||||
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
glDisable(GL_STENCIL_TEST);
|
glDisable(GL_STENCIL_TEST);
|
||||||
|
@ -208,7 +222,6 @@ void RenderFrame()
|
||||||
// TODO: support setting this midframe, if ever needed
|
// TODO: support setting this midframe, if ever needed
|
||||||
glUniform1i(Comp3DXPosLoc[0], ((int)GPU3D::RenderXPos << 23) >> 23);
|
glUniform1i(Comp3DXPosLoc[0], ((int)GPU3D::RenderXPos << 23) >> 23);
|
||||||
|
|
||||||
int frontbuf = GPU::FrontBuffer;
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D, CompScreenInputTex);
|
glBindTexture(GL_TEXTURE_2D, CompScreenInputTex);
|
||||||
|
|
||||||
|
@ -228,9 +241,9 @@ void RenderFrame()
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 4*3);
|
glDrawArrays(GL_TRIANGLES, 0, 4*3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BindOutputTexture()
|
void BindOutputTexture(int buf)
|
||||||
{
|
{
|
||||||
glBindTexture(GL_TEXTURE_2D, CompScreenOutputTex);
|
glBindTexture(GL_TEXTURE_2D, CompScreenOutputTex[buf]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -490,13 +490,18 @@ void EmuThread::run()
|
||||||
// emulate
|
// emulate
|
||||||
u32 nlines = NDS::RunFrame();
|
u32 nlines = NDS::RunFrame();
|
||||||
|
|
||||||
|
FrontBufferLock.lock();
|
||||||
#ifdef OGLRENDERER_ENABLED
|
#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)
|
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
|
#endif
|
||||||
|
FrontBuffer = GPU::FrontBuffer;
|
||||||
|
FrontBufferLock.unlock();
|
||||||
|
|
||||||
#ifdef MELONCAP
|
#ifdef MELONCAP
|
||||||
MelonCap::Update();
|
MelonCap::Update();
|
||||||
|
@ -824,11 +829,17 @@ void ScreenPanelNative::paintEvent(QPaintEvent* event)
|
||||||
// fill background
|
// fill background
|
||||||
painter.fillRect(event->rect(), QColor::fromRgb(0, 0, 0));
|
painter.fillRect(event->rect(), QColor::fromRgb(0, 0, 0));
|
||||||
|
|
||||||
int frontbuf = GPU::FrontBuffer;
|
emuThread->FrontBufferLock.lock();
|
||||||
if (!GPU::Framebuffer[frontbuf][0] || !GPU::Framebuffer[frontbuf][1]) return;
|
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[0].scanLine(0), GPU::Framebuffer[frontbuf][0], 256*192*4);
|
||||||
memcpy(screen[1].scanLine(0), GPU::Framebuffer[frontbuf][1], 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);
|
painter.setRenderHint(QPainter::SmoothPixmapTransform, Config::ScreenFilter!=0);
|
||||||
|
|
||||||
|
@ -988,53 +999,63 @@ void ScreenPanelGL::paintGL()
|
||||||
|
|
||||||
glViewport(0, 0, w*factor, h*factor);
|
glViewport(0, 0, w*factor, h*factor);
|
||||||
|
|
||||||
screenShader->bind();
|
if (emuThread)
|
||||||
|
|
||||||
screenShader->setUniformValue("uScreenSize", (float)w*factor, (float)h*factor);
|
|
||||||
|
|
||||||
int frontbuf = GPU::FrontBuffer;
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
|
|
||||||
#ifdef OGLRENDERER_ENABLED
|
|
||||||
if (GPU::Renderer != 0)
|
|
||||||
{
|
{
|
||||||
// hardware-accelerated render
|
screenShader->bind();
|
||||||
GPU::GLCompositor::BindOutputTexture();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
// regular render
|
|
||||||
glBindTexture(GL_TEXTURE_2D, screenTexture);
|
|
||||||
|
|
||||||
if (GPU::Framebuffer[frontbuf][0] && GPU::Framebuffer[frontbuf][1])
|
screenShader->setUniformValue("uScreenSize", (float)w*factor, (float)h*factor);
|
||||||
|
|
||||||
|
emuThread->FrontBufferLock.lock();
|
||||||
|
int frontbuf = emuThread->FrontBuffer;
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
#ifdef OGLRENDERER_ENABLED
|
||||||
|
if (GPU::Renderer != 0)
|
||||||
{
|
{
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 192, GL_RGBA,
|
// hardware-accelerated render
|
||||||
GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][0]);
|
GPU::GLCompositor::BindOutputTexture(frontbuf);
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192+2, 256, 192, GL_RGBA,
|
|
||||||
GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][1]);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
// regular render
|
||||||
|
glBindTexture(GL_TEXTURE_2D, screenTexture);
|
||||||
|
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, screenVertexBuffer);
|
||||||
|
glBindVertexArray(screenVertexArray);
|
||||||
|
|
||||||
|
GLint transloc = screenShader->uniformLocation("uTransform");
|
||||||
|
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, screenVertexBuffer);
|
|
||||||
glBindVertexArray(screenVertexArray);
|
|
||||||
|
|
||||||
GLint transloc = screenShader->uniformLocation("uTransform");
|
|
||||||
|
|
||||||
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::Update(this);
|
||||||
OSD::DrawGL(this, w*factor, h*factor);
|
OSD::DrawGL(this, w*factor, h*factor);
|
||||||
|
|
||||||
|
if (emuThread)
|
||||||
|
{
|
||||||
|
glFinish();
|
||||||
|
emuThread->FrontBufferLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenPanelGL::resizeEvent(QResizeEvent* event)
|
void ScreenPanelGL::resizeEvent(QResizeEvent* event)
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QActionGroup>
|
#include <QActionGroup>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <QMutex>
|
||||||
|
|
||||||
#include <QOffscreenSurface>
|
#include <QOffscreenSurface>
|
||||||
#include <QOpenGLWidget>
|
#include <QOpenGLWidget>
|
||||||
|
@ -59,6 +60,9 @@ public:
|
||||||
|
|
||||||
bool emuIsRunning();
|
bool emuIsRunning();
|
||||||
|
|
||||||
|
int FrontBuffer = 0;
|
||||||
|
QMutex FrontBufferLock;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void windowUpdate();
|
void windowUpdate();
|
||||||
void windowTitleChange(QString title);
|
void windowTitleChange(QString title);
|
||||||
|
|
Loading…
Reference in New Issue