diff --git a/Engine/source/gfx/gl/gfxGLDevice.cpp b/Engine/source/gfx/gl/gfxGLDevice.cpp index 8019f21bf..8ec644b8a 100644 --- a/Engine/source/gfx/gl/gfxGLDevice.cpp +++ b/Engine/source/gfx/gl/gfxGLDevice.cpp @@ -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); diff --git a/Engine/source/gfx/gl/gfxGLTextureManager.cpp b/Engine/source/gfx/gl/gfxGLTextureManager.cpp index ca0a958f3..c6c73fbee 100644 --- a/Engine/source/gfx/gl/gfxGLTextureManager.cpp +++ b/Engine/source/gfx/gl/gfxGLTextureManager.cpp @@ -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 *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* 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) diff --git a/Engine/source/gfx/gl/gfxGLTextureObject.cpp b/Engine/source/gfx/gl/gfxGLTextureObject.cpp index 651059d34..81ca6fa9d 100644 --- a/Engine/source/gfx/gl/gfxGLTextureObject.cpp +++ b/Engine/source/gfx/gl/gfxGLTextureObject.cpp @@ -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() diff --git a/Engine/source/gfx/gl/gfxGLUtils.h b/Engine/source/gfx/gl/gfxGLUtils.h index 2218836b0..928cf98e3 100644 --- a/Engine/source/gfx/gl/gfxGLUtils.h +++ b/Engine/source/gfx/gl/gfxGLUtils.h @@ -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; diff --git a/Engine/source/gfx/gl/sdl/gfxGLDevice.sdl.cpp b/Engine/source/gfx/gl/sdl/gfxGLDevice.sdl.cpp index 1bb34d4f2..a81c0334c 100644 --- a/Engine/source/gfx/gl/sdl/gfxGLDevice.sdl.cpp +++ b/Engine/source/gfx/gl/sdl/gfxGLDevice.sdl.cpp @@ -103,9 +103,17 @@ void GFXGLDevice::enumerateAdapters( Vector &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 ) { diff --git a/Engine/source/platformSDL/sdlPlatformGL.cpp b/Engine/source/platformSDL/sdlPlatformGL.cpp index fd55727b8..22e719f58 100644 --- a/Engine/source/platformSDL/sdlPlatformGL.cpp +++ b/Engine/source/platformSDL/sdlPlatformGL.cpp @@ -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