opengl debug

committing to test on windows with proper debug output
This commit is contained in:
marauder2k7 2026-03-01 12:18:30 +00:00
parent 19d8a5525d
commit 6449d22d7f
6 changed files with 270 additions and 84 deletions

View file

@ -91,19 +91,74 @@ void loadGLExtensions(void *context)
GL::gglPerformExtensionBinds(context);
}
void STDCALL glDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
const GLchar *message, const void *userParam)
void APIENTRY glDebugCallback(
GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar* message,
const void* userParam)
{
// JTH [11/24/2016]: This is a temporary fix so that we do not get spammed for redundant fbo changes.
// This only happens on Intel cards. This should be looked into sometime in the near future.
if (dStrStartsWith(message, "API_ID_REDUNDANT_FBO"))
// Ignore non-significant notifications (optional)
if (severity == GL_DEBUG_SEVERITY_NOTIFICATION)
return;
const char* srcStr = "UNKNOWN";
const char* typeStr = "UNKNOWN";
const char* sevStr = "UNKNOWN";
switch (source)
{
case GL_DEBUG_SOURCE_API: srcStr = "API"; break;
case GL_DEBUG_SOURCE_WINDOW_SYSTEM: srcStr = "WINDOW"; break;
case GL_DEBUG_SOURCE_SHADER_COMPILER: srcStr = "SHADER"; break;
case GL_DEBUG_SOURCE_THIRD_PARTY: srcStr = "THIRD_PARTY"; break;
case GL_DEBUG_SOURCE_APPLICATION: srcStr = "APP"; break;
case GL_DEBUG_SOURCE_OTHER: srcStr = "OTHER"; break;
}
switch (type)
{
case GL_DEBUG_TYPE_ERROR: typeStr = "ERROR"; break;
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: typeStr = "DEPRECATED"; break;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: typeStr = "UNDEFINED"; break;
case GL_DEBUG_TYPE_PORTABILITY: typeStr = "PORTABILITY"; break;
case GL_DEBUG_TYPE_PERFORMANCE: typeStr = "PERFORMANCE"; break;
case GL_DEBUG_TYPE_MARKER: typeStr = "MARKER"; break;
case GL_DEBUG_TYPE_PUSH_GROUP: typeStr = "PUSH"; break;
case GL_DEBUG_TYPE_POP_GROUP: typeStr = "POP"; break;
case GL_DEBUG_TYPE_OTHER: typeStr = "OTHER"; break;
}
switch (severity)
{
case GL_DEBUG_SEVERITY_HIGH: sevStr = "HIGH"; break;
case GL_DEBUG_SEVERITY_MEDIUM: sevStr = "MEDIUM"; break;
case GL_DEBUG_SEVERITY_LOW: sevStr = "LOW"; break;
case GL_DEBUG_SEVERITY_NOTIFICATION: sevStr = "NOTIFY"; break;
}
// Filter known noisy IDs here if needed
// Example:
// if (id == 131185) return;
if (severity == GL_DEBUG_SEVERITY_HIGH)
Con::errorf("OPENGL: %s", message);
{
Con::errorf("OPENGL [%s][%s][%s][%u]: %s",
sevStr, srcStr, typeStr, id, message);
AssertFatal(false, "OpenGL HIGH severity error.");
}
else if (severity == GL_DEBUG_SEVERITY_MEDIUM)
Con::warnf("OPENGL: %s", message);
else if (severity == GL_DEBUG_SEVERITY_LOW)
Con::printf("OPENGL: %s", message);
{
Con::warnf("OPENGL [%s][%s][%s][%u]: %s",
sevStr, srcStr, typeStr, id, message);
}
else
{
Con::printf("OPENGL [%s][%s][%s][%u]: %s",
sevStr, srcStr, typeStr, id, message);
}
}
void STDCALL glAmdDebugCallback(GLuint id, GLenum category, GLenum severity, GLsizei length,
@ -157,27 +212,34 @@ void GFXGLDevice::initGLState()
#endif
#if TORQUE_DEBUG
if( gglHasExtension(ARB_debug_output) )
{
glEnable(GL_DEBUG_OUTPUT);
glDebugMessageCallbackARB(glDebugCallback, NULL);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
GLuint unusedIds = 0;
glDebugMessageControlARB(GL_DONT_CARE,
GL_DONT_CARE,
GL_DONT_CARE,
0,
&unusedIds,
GL_TRUE);
}
else if(gglHasExtension(AMD_debug_output))
{
glEnable(GL_DEBUG_OUTPUT);
glDebugMessageCallbackAMD(glAmdDebugCallback, NULL);
//glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
GLuint unusedIds = 0;
glDebugMessageEnableAMD(GL_DONT_CARE, GL_DONT_CARE, 0,&unusedIds, GL_TRUE);
}
bool debugInitialized = false;
int flags;
glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
{
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallback(glDebugCallback, nullptr);
glDebugMessageControl(
GL_DONT_CARE,
GL_DONT_CARE,
GL_DONT_CARE,
0,
nullptr,
GL_TRUE);
Con::printf("OpenGL debug output enabled.");
debugInitialized = true;
}
if (!debugInitialized)
{
Con::warnf("OpenGL debug output NOT available.");
}
#endif
PlatformGL::setVSync(smEnableVSync);

View file

@ -175,7 +175,7 @@ void GFXGLTextureManager::innerCreateTexture( GFXGLTextureObject *retTex,
//calculate num mipmaps
if(retTex->mMipLevels == 0)
retTex->mMipLevels = getMaxMipmaps(width, height, 1);
glTexParameteri(binding, GL_TEXTURE_MAX_LEVEL, retTex->mMipLevels-1 );
bool hasTexStorage = false;
@ -364,34 +364,83 @@ void GFXGLTextureManager::innerCreateTexture( GFXGLTextureObject *retTex,
// loadTexture - GBitmap
//-----------------------------------------------------------------------------
static void _textureUpload(const S32 width, const S32 height,const S32 bytesPerPixel,const GFXGLTextureObject* texture, const GFXFormat fmt, const U8* data,const S32 mip=0, const U32 face = 0, Swizzle<U8, 4> *pSwizzle = NULL)
static void _textureUpload(
const S32 width,
const S32 height,
const S32 bytesPerPixel,
const GFXGLTextureObject* texture,
const GFXFormat fmt,
const U8* data,
const S32 mip = 0,
const U32 face = 0,
Swizzle<U8, 4>* pSwizzle = NULL)
{
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture->getBuffer());
U32 bufSize = width * height * bytesPerPixel;
glBufferData(GL_PIXEL_UNPACK_BUFFER, bufSize, NULL, GL_STREAM_DRAW);
const GLenum target = texture->getBinding();
if(pSwizzle)
{
PROFILE_SCOPE(Swizzle32_Upload);
U8* pboMemory = (U8*)dMalloc(bufSize);
pSwizzle->ToBuffer(pboMemory, data, bufSize);
glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, bufSize, pboMemory);
dFree(pboMemory);
}
else
{
PROFILE_SCOPE(SwizzleNull_Upload);
glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, bufSize, data);
}
// Save pixel store state
GLint prevUnpackAlign;
glGetIntegerv(GL_UNPACK_ALIGNMENT, &prevUnpackAlign);
if(texture->getBinding() == GL_TEXTURE_CUBE_MAP)
glTexSubImage2D(GFXGLFaceType[face], mip, 0, 0, width, height, GFXGLTextureFormat[fmt], GFXGLTextureType[fmt], NULL);
else if (texture->getBinding() == GL_TEXTURE_2D)
glTexSubImage2D(texture->getBinding(), mip, 0, 0, width, height, GFXGLTextureFormat[fmt], GFXGLTextureType[fmt], NULL);
else
glTexSubImage1D(texture->getBinding(), mip, 0, (width > 1 ? width : height), GFXGLTextureFormat[fmt], GFXGLTextureType[fmt], NULL);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
const U32 bufSize = width * height * bytesPerPixel;
const U8* uploadPtr = data;
U8* tempBuffer = nullptr;
if (pSwizzle)
{
tempBuffer = (U8*)dMalloc(bufSize);
pSwizzle->ToBuffer(tempBuffer, data, bufSize);
uploadPtr = tempBuffer;
}
if (target == GL_TEXTURE_CUBE_MAP)
{
glTexSubImage2D(
GFXGLFaceType[face],
mip,
0, 0,
width, height,
GFXGLTextureFormat[fmt],
GFXGLTextureType[fmt],
uploadPtr
);
}
else if (target == GL_TEXTURE_2D)
{
glTexSubImage2D(
GL_TEXTURE_2D,
mip,
0, 0,
width, height,
GFXGLTextureFormat[fmt],
GFXGLTextureType[fmt],
uploadPtr
);
}
else if (target == GL_TEXTURE_1D)
{
glTexSubImage1D(
GL_TEXTURE_1D,
mip,
0,
width,
GFXGLTextureFormat[fmt],
GFXGLTextureType[fmt],
uploadPtr
);
}
if (tempBuffer)
dFree(tempBuffer);
// Restore state
glPixelStorei(GL_UNPACK_ALIGNMENT, prevUnpackAlign);
#ifdef TORQUE_DEBUG
glCheckErrors();
#endif
}
bool GFXGLTextureManager::_loadTexture(GFXTextureObject *aTexture, GBitmap *pDL)

View file

@ -102,36 +102,79 @@ GFXLockedRect* GFXGLTextureObject::lock(U32 mipLevel /*= 0*/, RectI* inRect /*=
void GFXGLTextureObject::unlock(U32 mipLevel /*= 0*/, U32 faceIndex /*= 0*/)
{
if(!mLockedRect.bits)
return;
if (!mLockedRect.bits)
return;
// I know this is in unlock, but in GL we actually do our submission in unlock.
PROFILE_SCOPE(GFXGLTextureObject_lockRT);
PROFILE_SCOPE(GFXGLTextureObject_unlock);
PRESERVE_TEXTURE(mBinding);
glBindTexture(mBinding, mHandle);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mBuffer);
glBufferData(GL_PIXEL_UNPACK_BUFFER, (mLockedRectRect.extent.x + 1) * (mLockedRectRect.extent.y + 1) * mBytesPerTexel, mFrameAllocatorPtr, GL_STREAM_DRAW);
S32 z = getDepth();
if (mBinding == GL_TEXTURE_3D)
glTexSubImage3D(mBinding, mipLevel, mLockedRectRect.point.x, mLockedRectRect.point.y, z,
mLockedRectRect.extent.x, mLockedRectRect.extent.y, z, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], NULL);
else if(mBinding == GL_TEXTURE_2D)
glTexSubImage2D(mBinding, mipLevel, mLockedRectRect.point.x, mLockedRectRect.point.y,
mLockedRectRect.extent.x, mLockedRectRect.extent.y, GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], NULL);
else if(mBinding == GL_TEXTURE_1D)
glTexSubImage1D(mBinding, mipLevel, (mLockedRectRect.point.x > 1 ? mLockedRectRect.point.x : mLockedRectRect.point.y),
(mLockedRectRect.extent.x > 1 ? mLockedRectRect.extent.x : mLockedRectRect.extent.y), GFXGLTextureFormat[mFormat], GFXGLTextureType[mFormat], NULL);
PRESERVE_TEXTURE(mBinding);
glBindTexture(mBinding, mHandle);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
// --- Save pixel store state ---
GLint prevUnpackAlign;
glGetIntegerv(GL_UNPACK_ALIGNMENT, &prevUnpackAlign);
mLockedRect.bits = NULL;
#if TORQUE_DEBUG
AssertFatal(mFrameAllocatorMarkGuard == FrameAllocator::getWaterMark(), "");
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
const U32 width = mLockedRectRect.extent.x;
const U32 height = mLockedRectRect.extent.y;
const U32 depth = getDepth();
if (mBinding == GL_TEXTURE_3D)
{
glTexSubImage3D(
mBinding,
mipLevel,
mLockedRectRect.point.x,
mLockedRectRect.point.y,
0,
width,
height,
depth,
GFXGLTextureFormat[mFormat],
GFXGLTextureType[mFormat],
mLockedRect.bits
);
}
else if (mBinding == GL_TEXTURE_2D)
{
glTexSubImage2D(
mBinding,
mipLevel,
mLockedRectRect.point.x,
mLockedRectRect.point.y,
width,
height,
GFXGLTextureFormat[mFormat],
GFXGLTextureType[mFormat],
mLockedRect.bits
);
}
else if (mBinding == GL_TEXTURE_1D)
{
glTexSubImage1D(
mBinding,
mipLevel,
mLockedRectRect.point.x,
width,
GFXGLTextureFormat[mFormat],
GFXGLTextureType[mFormat],
mLockedRect.bits
);
}
// --- Restore state ---
glPixelStorei(GL_UNPACK_ALIGNMENT, prevUnpackAlign);
mLockedRect.bits = NULL;
FrameAllocator::setWaterMark(mFrameAllocatorMark);
mFrameAllocatorMark = 0;
mFrameAllocatorPtr = NULL;
#ifdef TORQUE_DEBUG
glCheckErrors();
#endif
FrameAllocator::setWaterMark(mFrameAllocatorMark);
mFrameAllocatorMark = 0;
mFrameAllocatorPtr = NULL;
}
void GFXGLTextureObject::release()

View file

@ -28,6 +28,32 @@
#include "gfx/gl/gfxGLStateCache.h"
#include "gfx/bitmap/imageUtils.h"
inline const char* glGetErrorString(GLenum error)
{
switch (error)
{
case GL_NO_ERROR: return "No Error";
case GL_INVALID_ENUM: return "Invalid Enum";
case GL_INVALID_VALUE: return "Invalid Value";
case GL_INVALID_OPERATION: return "Invalid Operation";
case GL_INVALID_FRAMEBUFFER_OPERATION: return "Invalid Framebuffer Operation";
case GL_OUT_OF_MEMORY: return "Out of Memory";
case GL_STACK_UNDERFLOW: return "Stack Underflow";
case GL_STACK_OVERFLOW: return "Stack Overflow";
case GL_CONTEXT_LOST: return "Context Lost";
default: return "Unknown Error";
}
}
inline void _glCheckErrors(const char *filename, int line)
{
GLenum err;
while ((err = glGetError()) != GL_NO_ERROR)
Con::printf("OpenGL Error: %s (%d) [%u] %s\n", filename, line, err, glGetErrorString(err));
}
#define glCheckErrors() _glCheckErrors(__FILE__, __LINE__)
inline U32 getMaxMipmaps(U32 width, U32 height, U32 depth)
{
return getMax( getBinLog2(depth), getMax(getBinLog2(width), getBinLog2(height))) + 1;

View file

@ -103,9 +103,17 @@ void GFXGLDevice::enumerateAdapters( Vector<GFXAdapter*> &adapterList )
}
SDL_ClearError();
U32 debugFlag = 0;
#ifdef TORQUE_DEBUG
debugFlag |= SDL_GL_CONTEXT_DEBUG_FLAG;
#endif
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, debugFlag);
SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 1);
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
#ifdef TORQUE_GL_SOFTWARE
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 0);
#endif
SDL_GLContext tempContext = SDL_GL_CreateContext( tempWindow );
if( !tempContext )
{

View file

@ -19,12 +19,10 @@ namespace PlatformGL
#ifdef TORQUE_DEBUG
debugFlag |= SDL_GL_CONTEXT_DEBUG_FLAG;
#endif
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, majorOGL);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minorOGL);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, debugFlag);
SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 1);
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
#ifdef TORQUE_GL_SOFTWARE
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 0);
#endif