Improve error checks in COpenGL3DriverBase

This commit is contained in:
sfan5 2024-04-12 12:18:41 +02:00
parent 7a6ca85081
commit 13e271c6cb
6 changed files with 99 additions and 31 deletions

@ -15,6 +15,8 @@
#include "COGLESExtensionHandler.h" #include "COGLESExtensionHandler.h"
#include "IContextManager.h" #include "IContextManager.h"
#define TEST_GL_ERROR(cls) (cls)->testGLError(__LINE__)
namespace irr namespace irr
{ {
namespace video namespace video

@ -174,9 +174,7 @@ public:
AssignedTextures[i] = GL_COLOR_ATTACHMENT0 + i; AssignedTextures[i] = GL_COLOR_ATTACHMENT0 + i;
GLenum textarget = currentTexture->getType() == ETT_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_POSITIVE_X + (int)CubeSurfaces[i]; GLenum textarget = currentTexture->getType() == ETT_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_POSITIVE_X + (int)CubeSurfaces[i];
Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, AssignedTextures[i], textarget, textureID, 0); Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, AssignedTextures[i], textarget, textureID, 0);
#ifdef _DEBUG TEST_GL_ERROR(Driver);
Driver->testGLError(__LINE__);
#endif
} else if (AssignedTextures[i] != GL_NONE) { } else if (AssignedTextures[i] != GL_NONE) {
AssignedTextures[i] = GL_NONE; AssignedTextures[i] = GL_NONE;
Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, AssignedTextures[i], GL_TEXTURE_2D, 0, 0); Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, AssignedTextures[i], GL_TEXTURE_2D, 0, 0);
@ -239,9 +237,7 @@ public:
AssignedDepth = false; AssignedDepth = false;
AssignedStencil = false; AssignedStencil = false;
} }
#ifdef _DEBUG TEST_GL_ERROR(Driver);
Driver->testGLError(__LINE__);
#endif
RequestDepthStencilUpdate = false; RequestDepthStencilUpdate = false;
} }
@ -261,9 +257,7 @@ public:
Driver->irrGlDrawBuffers(bufferCount, AssignedTextures.pointer()); Driver->irrGlDrawBuffers(bufferCount, AssignedTextures.pointer());
} }
#ifdef _DEBUG TEST_GL_ERROR(Driver);
Driver->testGLError(__LINE__);
#endif
} }
#ifdef _DEBUG #ifdef _DEBUG

@ -59,6 +59,18 @@ public:
if (!InternalFormat) if (!InternalFormat)
return; return;
#ifdef _DEBUG
char lbuf[128];
snprintf_irr(lbuf, sizeof(lbuf),
"COpenGLCoreTexture: Type = %d Size = %dx%d (%dx%d) ColorFormat = %d (%d)%s -> %#06x %#06x %#06x%s",
(int)Type, Size.Width, Size.Height, OriginalSize.Width, OriginalSize.Height,
(int)ColorFormat, (int)OriginalColorFormat,
HasMipMaps ? " +Mip" : "",
InternalFormat, PixelFormat, PixelType, Converter ? " (c)" : ""
);
os::Printer::log(lbuf, ELL_DEBUG);
#endif
const core::array<IImage *> *tmpImages = &images; const core::array<IImage *> *tmpImages = &images;
if (KeepImage || OriginalSize != Size || OriginalColorFormat != ColorFormat) { if (KeepImage || OriginalSize != Size || OriginalColorFormat != ColorFormat) {
@ -104,6 +116,8 @@ public:
} }
#endif #endif
TEST_GL_ERROR(Driver);
for (u32 i = 0; i < (*tmpImages).size(); ++i) for (u32 i = 0; i < (*tmpImages).size(); ++i)
uploadTexture(true, i, 0, (*tmpImages)[i]->getData()); uploadTexture(true, i, 0, (*tmpImages)[i]->getData());
@ -124,7 +138,7 @@ public:
Driver->getCacheHandler()->getTextureCache().set(0, prevTexture); Driver->getCacheHandler()->getTextureCache().set(0, prevTexture);
Driver->testGLError(__LINE__); TEST_GL_ERROR(Driver);
} }
COpenGLCoreTexture(const io::path &name, const core::dimension2d<u32> &size, E_TEXTURE_TYPE type, ECOLOR_FORMAT format, TOpenGLDriver *driver) : COpenGLCoreTexture(const io::path &name, const core::dimension2d<u32> &size, E_TEXTURE_TYPE type, ECOLOR_FORMAT format, TOpenGLDriver *driver) :
@ -155,6 +169,16 @@ public:
return; return;
} }
#ifdef _DEBUG
char lbuf[100];
snprintf_irr(lbuf, sizeof(lbuf),
"COpenGLCoreTexture: RTT Type = %d Size = %dx%d ColorFormat = %d -> %#06x %#06x %#06x%s",
(int)Type, Size.Width, Size.Height, (int)ColorFormat,
InternalFormat, PixelFormat, PixelType, Converter ? " (c)" : ""
);
os::Printer::log(lbuf, ELL_DEBUG);
#endif
GL.GenTextures(1, &TextureName); GL.GenTextures(1, &TextureName);
const COpenGLCoreTexture *prevTexture = Driver->getCacheHandler()->getTextureCache().get(0); const COpenGLCoreTexture *prevTexture = Driver->getCacheHandler()->getTextureCache().get(0);
@ -188,7 +212,7 @@ public:
} }
Driver->getCacheHandler()->getTextureCache().set(0, prevTexture); Driver->getCacheHandler()->getTextureCache().set(0, prevTexture);
if (Driver->testGLError(__LINE__)) { if (TEST_GL_ERROR(Driver)) {
char msg[256]; char msg[256];
snprintf_irr(msg, 256, "COpenGLCoreTexture: InternalFormat:0x%04x PixelFormat:0x%04x", (int)InternalFormat, (int)PixelFormat); snprintf_irr(msg, 256, "COpenGLCoreTexture: InternalFormat:0x%04x PixelFormat:0x%04x", (int)InternalFormat, (int)PixelFormat);
os::Printer::log(msg, ELL_ERROR); os::Printer::log(msg, ELL_ERROR);
@ -241,7 +265,7 @@ public:
IImage *tmpImage = LockImage; // not sure yet if the size required by glGetTexImage is always correct, if not we might have to allocate a different tmpImage and convert colors later on. IImage *tmpImage = LockImage; // not sure yet if the size required by glGetTexImage is always correct, if not we might have to allocate a different tmpImage and convert colors later on.
Driver->getCacheHandler()->getTextureCache().set(0, this); Driver->getCacheHandler()->getTextureCache().set(0, this);
Driver->testGLError(__LINE__); TEST_GL_ERROR(Driver);
GLenum tmpTextureType = TextureType; GLenum tmpTextureType = TextureType;
@ -252,7 +276,7 @@ public:
} }
GL.GetTexImage(tmpTextureType, MipLevelStored, PixelFormat, PixelType, tmpImage->getData()); GL.GetTexImage(tmpTextureType, MipLevelStored, PixelFormat, PixelType, tmpImage->getData());
Driver->testGLError(__LINE__); TEST_GL_ERROR(Driver);
if (IsRenderTarget && lockFlags == ETLF_FLIP_Y_UP_RTT) { if (IsRenderTarget && lockFlags == ETLF_FLIP_Y_UP_RTT) {
const s32 pitch = tmpImage->getPitch(); const s32 pitch = tmpImage->getPitch();
@ -334,7 +358,7 @@ public:
} }
} }
Driver->testGLError(__LINE__); TEST_GL_ERROR(Driver);
} }
return (LockImage) ? getLockImageData(MipLevelStored) : 0; return (LockImage) ? getLockImageData(MipLevelStored) : 0;
@ -392,6 +416,7 @@ public:
} while (width != 1 || height != 1); } while (width != 1 || height != 1);
} else { } else {
Driver->irrGlGenerateMipmap(TextureType); Driver->irrGlGenerateMipmap(TextureType);
TEST_GL_ERROR(Driver);
} }
Driver->getCacheHandler()->getTextureCache().set(0, prevTexture); Driver->getCacheHandler()->getTextureCache().set(0, prevTexture);
@ -544,7 +569,7 @@ protected:
GL.TexImage2D(tmpTextureType, level, InternalFormat, width, height, 0, PixelFormat, PixelType, tmpData); GL.TexImage2D(tmpTextureType, level, InternalFormat, width, height, 0, PixelFormat, PixelType, tmpData);
else else
GL.TexSubImage2D(tmpTextureType, level, 0, 0, width, height, PixelFormat, PixelType, tmpData); GL.TexSubImage2D(tmpTextureType, level, 0, 0, width, height, PixelFormat, PixelType, tmpData);
Driver->testGLError(__LINE__); TEST_GL_ERROR(Driver);
break; break;
default: default:
break; break;
@ -561,7 +586,7 @@ protected:
Driver->irrGlCompressedTexImage2D(tmpTextureType, level, InternalFormat, width, height, 0, dataSize, data); Driver->irrGlCompressedTexImage2D(tmpTextureType, level, InternalFormat, width, height, 0, dataSize, data);
else else
Driver->irrGlCompressedTexSubImage2D(tmpTextureType, level, 0, 0, width, height, PixelFormat, dataSize, data); Driver->irrGlCompressedTexSubImage2D(tmpTextureType, level, 0, 0, width, height, PixelFormat, dataSize, data);
Driver->testGLError(__LINE__); TEST_GL_ERROR(Driver);
break; break;
default: default:
break; break;

@ -22,6 +22,8 @@ class CIrrDeviceMacOSX;
#include "COpenGLExtensionHandler.h" #include "COpenGLExtensionHandler.h"
#include "IContextManager.h" #include "IContextManager.h"
#define TEST_GL_ERROR(cls) (cls)->testGLError(__LINE__)
namespace irr namespace irr
{ {

@ -134,7 +134,18 @@ void APIENTRY COpenGL3DriverBase::debugCb(GLenum source, GLenum type, GLuint id,
void COpenGL3DriverBase::debugCb(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message) void COpenGL3DriverBase::debugCb(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message)
{ {
printf("%04x %04x %x %x %.*s\n", source, type, id, severity, length, message); // shader compiler can be very noisy
if (source == GL_DEBUG_SOURCE_SHADER_COMPILER && severity == GL_DEBUG_SEVERITY_NOTIFICATION)
return;
ELOG_LEVEL ll = ELL_INFORMATION;
if (severity == GL_DEBUG_SEVERITY_HIGH)
ll = ELL_ERROR;
else if (severity == GL_DEBUG_SEVERITY_MEDIUM)
ll = ELL_WARNING;
char buf[256];
snprintf_irr(buf, sizeof(buf), "%04x %04x %.*s", source, type, length, message);
os::Printer::log("GL", buf, ll);
} }
COpenGL3DriverBase::COpenGL3DriverBase(const SIrrlichtCreationParameters &params, io::IFileSystem *io, IContextManager *contextManager) : COpenGL3DriverBase::COpenGL3DriverBase(const SIrrlichtCreationParameters &params, io::IFileSystem *io, IContextManager *contextManager) :
@ -283,7 +294,7 @@ bool COpenGL3DriverBase::genericDriverInit(const core::dimension2d<u32> &screenS
// This fixes problems with intermediate changes to the material during texture load. // This fixes problems with intermediate changes to the material during texture load.
ResetRenderStates = true; ResetRenderStates = true;
testGLError(__LINE__); TEST_GL_ERROR(this);
return true; return true;
} }
@ -514,7 +525,7 @@ bool COpenGL3DriverBase::updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuff
GL.BindBuffer(GL_ARRAY_BUFFER, 0); GL.BindBuffer(GL_ARRAY_BUFFER, 0);
return (!testGLError(__LINE__)); return (!TEST_GL_ERROR(this));
} }
bool COpenGL3DriverBase::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer) bool COpenGL3DriverBase::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer)
@ -571,7 +582,7 @@ bool COpenGL3DriverBase::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffe
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
return (!testGLError(__LINE__)); return (!TEST_GL_ERROR(this));
} }
//! updates hardware buffer if needed //! updates hardware buffer if needed
@ -845,7 +856,7 @@ void COpenGL3DriverBase::draw2DImage(const video::ITexture *texture, const core:
if (clipRect) if (clipRect)
GL.Disable(GL_SCISSOR_TEST); GL.Disable(GL_SCISSOR_TEST);
testGLError(__LINE__); TEST_GL_ERROR(this);
} }
void COpenGL3DriverBase::draw2DImage(const video::ITexture *texture, u32 layer, bool flip) void COpenGL3DriverBase::draw2DImage(const video::ITexture *texture, u32 layer, bool flip)
@ -1126,28 +1137,60 @@ void COpenGL3DriverBase::setMaterial(const SMaterial &material)
} }
//! prints error if an error happened. //! prints error if an error happened.
bool COpenGL3DriverBase::testGLError(int code) bool COpenGL3DriverBase::testGLError(const char *file, int line)
{ {
if (!EnableErrorTest) if (!EnableErrorTest)
return false; return false;
GLenum g = GL.GetError(); GLenum g = GL.GetError();
const char *err = nullptr;
switch (g) { switch (g) {
case GL_NO_ERROR: case GL_NO_ERROR:
return false; return false;
case GL_INVALID_ENUM: case GL_INVALID_ENUM:
os::Printer::log("GL_INVALID_ENUM", core::stringc(code).c_str(), ELL_ERROR); err = "GL_INVALID_ENUM";
break; break;
case GL_INVALID_VALUE: case GL_INVALID_VALUE:
os::Printer::log("GL_INVALID_VALUE", core::stringc(code).c_str(), ELL_ERROR); err = "GL_INVALID_VALUE";
break; break;
case GL_INVALID_OPERATION: case GL_INVALID_OPERATION:
os::Printer::log("GL_INVALID_OPERATION", core::stringc(code).c_str(), ELL_ERROR); err = "GL_INVALID_OPERATION";
break;
case GL_STACK_OVERFLOW:
err = "GL_STACK_OVERFLOW";
break;
case GL_STACK_UNDERFLOW:
err = "GL_STACK_UNDERFLOW";
break; break;
case GL_OUT_OF_MEMORY: case GL_OUT_OF_MEMORY:
os::Printer::log("GL_OUT_OF_MEMORY", core::stringc(code).c_str(), ELL_ERROR); err = "GL_OUT_OF_MEMORY";
break; break;
case GL_INVALID_FRAMEBUFFER_OPERATION:
err = "GL_INVALID_FRAMEBUFFER_OPERATION";
break;
#ifdef GL_VERSION_4_5
case GL_CONTEXT_LOST:
err = "GL_CONTEXT_LOST";
break;
#endif
}; };
// Empty the error queue, see <https://www.khronos.org/opengl/wiki/OpenGL_Error>
bool multiple = false;
while (GL.GetError() != GL_NO_ERROR)
multiple = true;
// basename
for (char sep : {'/', '\\'}) {
const char *tmp = strrchr(file, sep);
if (tmp)
file = tmp+1;
}
char buf[80];
snprintf_irr(buf, sizeof(buf), "%s %s:%d%s",
err, file, line, multiple ? " (older errors exist)" : "");
os::Printer::log(buf, ELL_ERROR);
return true; return true;
} }
@ -1797,7 +1840,7 @@ IImage *COpenGL3DriverBase::createScreenShot(video::ECOLOR_FORMAT format, video:
} }
GL.ReadPixels(0, 0, ScreenSize.Width, ScreenSize.Height, internalformat, type, pixels); GL.ReadPixels(0, 0, ScreenSize.Width, ScreenSize.Height, internalformat, type, pixels);
testGLError(__LINE__); TEST_GL_ERROR(this);
// opengl images are horizontally flipped, so we have to fix that here. // opengl images are horizontally flipped, so we have to fix that here.
const s32 pitch = newImage->getPitch(); const s32 pitch = newImage->getPitch();
@ -1825,11 +1868,10 @@ IImage *COpenGL3DriverBase::createScreenShot(video::ECOLOR_FORMAT format, video:
} }
} }
if (testGLError(__LINE__)) { if (TEST_GL_ERROR(this)) {
newImage->drop(); newImage->drop();
return 0; return 0;
} }
testGLError(__LINE__);
return newImage; return newImage;
} }

@ -16,6 +16,8 @@
#include "ExtensionHandler.h" #include "ExtensionHandler.h"
#include "IContextManager.h" #include "IContextManager.h"
#define TEST_GL_ERROR(cls) (cls)->testGLError(__FILE__, __LINE__)
namespace irr namespace irr
{ {
namespace video namespace video
@ -221,8 +223,9 @@ public:
//! Returns an image created from the last rendered frame. //! Returns an image created from the last rendered frame.
IImage *createScreenShot(video::ECOLOR_FORMAT format = video::ECF_UNKNOWN, video::E_RENDER_TARGET target = video::ERT_FRAME_BUFFER) override; IImage *createScreenShot(video::ECOLOR_FORMAT format = video::ECF_UNKNOWN, video::E_RENDER_TARGET target = video::ERT_FRAME_BUFFER) override;
//! checks if an OpenGL error has happened and prints it (+ some internal code which is usually the line number) //! checks if an OpenGL error has happened and prints it, use via TEST_GL_ERROR().
bool testGLError(int code = 0); // Does *nothing* unless in debug mode.
bool testGLError(const char *file, int line);
//! Set/unset a clipping plane. //! Set/unset a clipping plane.
bool setClipPlane(u32 index, const core::plane3df &plane, bool enable = false) override; bool setClipPlane(u32 index, const core::plane3df &plane, bool enable = false) override;