Skip to content

Commit

Permalink
OpenGL Renderer: Fix various rendering bugs.
Browse files Browse the repository at this point in the history
- Fix a potential unaligned access crashing bug in ES when clear images are to be rendered.
- Fix an ES bug where clear images would fail to render when MSAA is enabled.
- Fix a legacy OpenGL bug where toon table colors were not ignoring their alpha bit, according to GBATEK.
  • Loading branch information
rogerman committed Jul 24, 2024
1 parent f323dc4 commit e2a25e2
Show file tree
Hide file tree
Showing 6 changed files with 392 additions and 54 deletions.
57 changes: 26 additions & 31 deletions desmume/src/OGLRender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,27 +38,6 @@
#include "./utils/colorspacehandler/colorspacehandler_SSE2.h"
#endif

#if defined(OPENGL_VARIANT_STANDARD)
#if MSB_FIRST
#define OGL_TEXTURE_SRC_CI_COLOR GL_UNSIGNED_SHORT_1_5_5_5_REV
#define OGL_TEXTURE_SRC_CI_FOG GL_UNSIGNED_INT_8_8_8_8_REV
#define OGL_TEXTURE_SRC_EDGE_COLOR GL_UNSIGNED_INT_8_8_8_8
#define OGL_TEXTURE_SRC_TOON_TABLE GL_UNSIGNED_SHORT_1_5_5_5_REV
#else
#define OGL_TEXTURE_SRC_CI_COLOR GL_UNSIGNED_SHORT_1_5_5_5_REV
#define OGL_TEXTURE_SRC_CI_FOG GL_UNSIGNED_INT_8_8_8_8_REV
#define OGL_TEXTURE_SRC_EDGE_COLOR GL_UNSIGNED_INT_8_8_8_8_REV
#define OGL_TEXTURE_SRC_TOON_TABLE GL_UNSIGNED_SHORT_1_5_5_5_REV
#endif
#elif defined(OPENGL_VARIANT_ES)
#define OGL_TEXTURE_SRC_CI_COLOR GL_UNSIGNED_BYTE
#define OGL_TEXTURE_SRC_CI_FOG GL_UNSIGNED_BYTE
#define OGL_TEXTURE_SRC_EDGE_COLOR GL_UNSIGNED_BYTE
#define OGL_TEXTURE_SRC_TOON_TABLE GL_UNSIGNED_BYTE
#else
#error Unknown OpenGL variant.
#endif

typedef struct
{
unsigned int major;
Expand Down Expand Up @@ -1229,7 +1208,7 @@ GPU3DInterface gpu3Dgl_3_2 = {
// OpenGL ES 3.0 (this is the only version of ES that is supported right now)
GPU3DInterface gpu3Dgl_ES_3_0 = {
"OpenGL ES 3.0",
OpenGLRendererCreate<OpenGLVariantID_ES_3_0>,
OpenGLRendererCreate<OpenGLVariantID_ES3_3_0>,
OpenGLRendererDestroy
};

Expand Down Expand Up @@ -1270,7 +1249,7 @@ OpenGLRenderer::OpenGLRenderer()
_emulateDepthLEqualPolygonFacing = false;

// Init OpenGL rendering states
ref = (OGLRenderRef *)malloc(sizeof(OGLRenderRef));
ref = (OGLRenderRef *)malloc_alignedPage(sizeof(OGLRenderRef));
memset(ref, 0, sizeof(OGLRenderRef));

_mappedFramebuffer = NULL;
Expand All @@ -1294,7 +1273,7 @@ OpenGLRenderer::~OpenGLRenderer()
free_aligned(this->_workingTextureUnpackBuffer);

// Destroy OpenGL rendering states
free(this->ref);
free_aligned(this->ref);
this->ref = NULL;
}

Expand Down Expand Up @@ -2771,18 +2750,18 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

glActiveTexture(GL_TEXTURE0);

CACHE_ALIGN GLint tempClearImageBuffer[GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT];
memset(tempClearImageBuffer, 0, sizeof(tempClearImageBuffer));

glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_CIColor);
glBindTexture(GL_TEXTURE_2D, OGLRef.texCIColorID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_RGBA, OGL_TEXTURE_SRC_CI_COLOR, tempClearImageBuffer);

glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_CIDepth);
glBindTexture(GL_TEXTURE_2D, OGLRef.texCIDepthStencilID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
Expand All @@ -2791,6 +2770,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8_EXT, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, tempClearImageBuffer);

glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_CIFogAttr);
glBindTexture(GL_TEXTURE_2D, OGLRef.texCIFogAttrID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
Expand All @@ -2813,7 +2793,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs()
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, OGLRef.texGDepthStencilID, 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, OGLRef.texGDepthStencilID, 0);

if (glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE)
if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
{
INFO("OpenGL: Failed to create FBOs!\n");
this->DestroyFBOs();
Expand Down Expand Up @@ -2931,6 +2911,7 @@ void OpenGLRenderer_1_2::DestroyFBOs()

OGLRef.fboClearImageID = 0;
OGLRef.fboRenderID = 0;
OGLRef.fboRenderMutableID = 0;
OGLRef.fboColorOutMainID = 0;
OGLRef.fboColorOutWorkingID = 0;
OGLRef.texCIColorID = 0;
Expand Down Expand Up @@ -3309,6 +3290,18 @@ void OpenGLRenderer_1_2::DestroyGeometryZeroDstAlphaProgram()
OGLRef.fragShaderGeometryZeroDstAlphaID = 0;
}

Render3DError OpenGLRenderer_1_2::CreateClearImageProgram(const char *vsCString, const char *fsCString)
{
Render3DError error = OGLERROR_NOERR;
// TODO: Add support for ancient GPUs that support shaders but not GL_EXT_framebuffer_blit.
return error;
}

void OpenGLRenderer_1_2::DestroyClearImageProgram()
{
// Do nothing for now.
}

Render3DError OpenGLRenderer_1_2::CreateEdgeMarkProgram(const bool isMultisample, const char *vtxShaderCString, const char *fragShaderCString)
{
Render3DError error = OGLERROR_NOERR;
Expand Down Expand Up @@ -3825,11 +3818,10 @@ Render3DError OpenGLRenderer_1_2::UploadClearImage(const u16 *__restrict colorBu
const bool didDepthStencilChange = (memcmp(OGLRef.workingCIDepthStencilBuffer[this->_clearImageIndex], OGLRef.workingCIDepthStencilBuffer[this->_clearImageIndex ^ 0x01], GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * sizeof(GLuint)) != 0);
const bool didFogAttributesChange = this->_enableFog && this->_deviceInfo.isFogSupported && (memcmp(OGLRef.workingCIFogAttributesBuffer[this->_clearImageIndex], OGLRef.workingCIFogAttributesBuffer[this->_clearImageIndex ^ 0x01], GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * sizeof(GLuint)) != 0);

glActiveTexture(GL_TEXTURE0);

if (didColorChange)
{
memcpy(OGLRef.workingCIColorBuffer16, colorBuffer, GPU_FRAMEBUFFER_NATIVE_WIDTH * GPU_FRAMEBUFFER_NATIVE_HEIGHT * sizeof(u16));
glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_CIColor);
glBindTexture(GL_TEXTURE_2D, OGLRef.texCIColorID);

if (OGL_TEXTURE_SRC_CI_COLOR == GL_UNSIGNED_BYTE)
Expand All @@ -3845,16 +3837,19 @@ Render3DError OpenGLRenderer_1_2::UploadClearImage(const u16 *__restrict colorBu

if (didDepthStencilChange)
{
glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_CIDepth);
glBindTexture(GL_TEXTURE_2D, OGLRef.texCIDepthStencilID);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, OGLRef.workingCIDepthStencilBuffer[this->_clearImageIndex]);
}

if (didFogAttributesChange)
{
glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_CIFogAttr);
glBindTexture(GL_TEXTURE_2D, OGLRef.texCIFogAttrID);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT, GL_RGBA, OGL_TEXTURE_SRC_CI_FOG, OGLRef.workingCIFogAttributesBuffer[this->_clearImageIndex]);
}

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);

return OGLERROR_NOERR;
Expand Down Expand Up @@ -4419,7 +4414,7 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D_State &renderState, co

if (OGL_TEXTURE_SRC_TOON_TABLE == GL_UNSIGNED_BYTE)
{
ColorspaceConvertBuffer5551To8888<false, false, BESwapDst>(renderState.toonTable16, OGLRef.toonTable32, 32);
ColorspaceConvertBuffer555xTo8888Opaque<false, false, BESwapDst>(renderState.toonTable16, OGLRef.toonTable32, 32);
glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 32, GL_RGBA, OGL_TEXTURE_SRC_TOON_TABLE, OGLRef.toonTable32);
}
else
Expand Down Expand Up @@ -5693,7 +5688,7 @@ Render3DError OpenGLRenderer_2_0::BeginRender(const GFX3D_State &renderState, co

if (OGL_TEXTURE_SRC_TOON_TABLE == GL_UNSIGNED_BYTE)
{
ColorspaceConvertBuffer5551To8888<false, false, BESwapDst>(renderState.toonTable16, OGLRef.toonTable32, 32);
ColorspaceConvertBuffer555xTo8888Opaque<false, false, BESwapDst>(renderState.toonTable16, OGLRef.toonTable32, 32);
glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 32, GL_RGBA, OGL_TEXTURE_SRC_TOON_TABLE, OGLRef.toonTable32);
}
else
Expand Down
48 changes: 46 additions & 2 deletions desmume/src/OGLRender.h
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,27 @@ EXTERNOGLEXT(PFNGLDELETERENDERBUFFERSEXTPROC, glDeleteRenderbuffersEXT)
#define OGL_CI_FOGATTRIBUTES_ATTACHMENT_ID GL_COLOR_ATTACHMENT1_EXT
#endif

#if defined(OPENGL_VARIANT_STANDARD)
#if MSB_FIRST
#define OGL_TEXTURE_SRC_CI_COLOR GL_UNSIGNED_SHORT_1_5_5_5_REV
#define OGL_TEXTURE_SRC_CI_FOG GL_UNSIGNED_INT_8_8_8_8_REV
#define OGL_TEXTURE_SRC_EDGE_COLOR GL_UNSIGNED_INT_8_8_8_8
#define OGL_TEXTURE_SRC_TOON_TABLE GL_UNSIGNED_SHORT_1_5_5_5_REV
#else
#define OGL_TEXTURE_SRC_CI_COLOR GL_UNSIGNED_SHORT_1_5_5_5_REV
#define OGL_TEXTURE_SRC_CI_FOG GL_UNSIGNED_INT_8_8_8_8_REV
#define OGL_TEXTURE_SRC_EDGE_COLOR GL_UNSIGNED_INT_8_8_8_8_REV
#define OGL_TEXTURE_SRC_TOON_TABLE GL_UNSIGNED_SHORT_1_5_5_5_REV
#endif
#elif defined(OPENGL_VARIANT_ES)
#define OGL_TEXTURE_SRC_CI_COLOR GL_UNSIGNED_BYTE
#define OGL_TEXTURE_SRC_CI_FOG GL_UNSIGNED_BYTE
#define OGL_TEXTURE_SRC_EDGE_COLOR GL_UNSIGNED_BYTE
#define OGL_TEXTURE_SRC_TOON_TABLE GL_UNSIGNED_BYTE
#else
#error Unknown OpenGL variant.
#endif

enum OpenGLVariantID
{
OpenGLVariantID_Unknown = 0,
Expand All @@ -394,7 +415,18 @@ enum OpenGLVariantID
OpenGLVariantID_Legacy_2_1 = 0x1021,
OpenGLVariantID_CoreProfile_3_2 = 0x2032,
OpenGLVariantID_StandardAuto = 0x3000,
OpenGLVariantID_ES_3_0 = 0x4030
OpenGLVariantID_ES3_Auto = 0x4000,
OpenGLVariantID_ES3_3_0 = 0x4030,
OpenGLVariantID_ES_Auto = 0x6000
};

enum OpenGLVariantFamily
{
OpenGLVariantFamily_Standard = (3 << 12),
OpenGLVariantFamily_Legacy = (1 << 12),
OpenGLVariantFamily_CoreProfile = (1 << 13),
OpenGLVariantFamily_ES = (3 << 14),
OpenGLVariantFamily_ES3 = (1 << 14)
};

enum OGLVertexAttributeID
Expand All @@ -413,7 +445,10 @@ enum OGLTextureUnitID
OGLTextureUnitID_GPolyID,
OGLTextureUnitID_FogAttr,
OGLTextureUnitID_PolyStates,
OGLTextureUnitID_LookupTable
OGLTextureUnitID_LookupTable,
OGLTextureUnitID_CIColor,
OGLTextureUnitID_CIDepth,
OGLTextureUnitID_CIFogAttr
};

enum OGLBindingPointID
Expand Down Expand Up @@ -640,6 +675,7 @@ struct OGLRenderRef
GLuint fboRenderMutableID;
GLuint fboColorOutMainID;
GLuint fboColorOutWorkingID;
GLuint fboMSClearImageID;
GLuint fboMSIntermediateColorOutMainID;
GLuint fboMSIntermediateRenderID;
GLuint fboMSIntermediateRenderMutableID;
Expand All @@ -655,6 +691,10 @@ struct OGLRenderRef
GLuint fragShaderGeometryZeroDstAlphaID;
GLuint programGeometryZeroDstAlphaID;

GLuint vsClearImageID;
GLuint fsClearImageID;
GLuint pgClearImageID;

GLuint vtxShaderMSGeometryZeroDstAlphaID;
GLuint fragShaderMSGeometryZeroDstAlphaID;
GLuint programMSGeometryZeroDstAlphaID;
Expand Down Expand Up @@ -896,6 +936,8 @@ class OpenGLRenderer : public Render3D

virtual Render3DError CreateGeometryPrograms() = 0;
virtual void DestroyGeometryPrograms() = 0;
virtual Render3DError CreateClearImageProgram(const char *vsCString, const char *fsCString) = 0;
virtual void DestroyClearImageProgram() = 0;
virtual Render3DError CreateGeometryZeroDstAlphaProgram(const char *vtxShaderCString, const char *fragShaderCString) = 0;
virtual void DestroyGeometryZeroDstAlphaProgram() = 0;
virtual Render3DError CreateEdgeMarkProgram(const bool isMultisample, const char *vtxShaderCString, const char *fragShaderCString) = 0;
Expand Down Expand Up @@ -972,6 +1014,8 @@ class OpenGLRenderer_1_2 : public OpenGLRenderer

virtual Render3DError CreateGeometryPrograms();
virtual void DestroyGeometryPrograms();
virtual Render3DError CreateClearImageProgram(const char *vsCString, const char *fsCString);
virtual void DestroyClearImageProgram();
virtual Render3DError CreateGeometryZeroDstAlphaProgram(const char *vtxShaderCString, const char *fragShaderCString);
virtual void DestroyGeometryZeroDstAlphaProgram();
virtual Render3DError CreateEdgeMarkProgram(const bool isMultisample, const char *vtxShaderCString, const char *fragShaderCString);
Expand Down
Loading

0 comments on commit e2a25e2

Please sign in to comment.