From 776302d46bf1036875e115d78b54be9ebb8600d9 Mon Sep 17 00:00:00 2001 From: kgv Date: Fri, 29 Jan 2021 03:34:16 +0300 Subject: [PATCH] 0032093: Visualization, TKOpenGl - loading texture in BGR format fails in OpenGL ES Graphic3d_TextureRoot::convertToCompatible() - fixed handling of Image_Format_BGR and Image_Format_BGRA formats. OpenGl_Texture - added error message for unsupported pixel format; error messages have been extended by resource id. OpenGl_Texture::InitCubeMap() now does not release cubemap on mipmaps generation failure. Image_PixMap::ImageFormatToString() - added method returning name of pixel format. --- src/Graphic3d/Graphic3d_TextureRoot.cxx | 19 +++-- src/Image/Image_PixMap.cxx | 97 +++++++++++++++++-------- src/Image/Image_PixMap.hxx | 8 +- src/OpenGl/OpenGl_Texture.cxx | 49 +++++++++---- 4 files changed, 124 insertions(+), 49 deletions(-) diff --git a/src/Graphic3d/Graphic3d_TextureRoot.cxx b/src/Graphic3d/Graphic3d_TextureRoot.cxx index 5911201b38..a89f32dabe 100644 --- a/src/Graphic3d/Graphic3d_TextureRoot.cxx +++ b/src/Graphic3d/Graphic3d_TextureRoot.cxx @@ -221,13 +221,20 @@ void Graphic3d_TextureRoot::convertToCompatible (const Handle(Image_SupportedFor return; } - if ((theImage->Format() == Image_Format_BGR32 - || theImage->Format() == Image_Format_BGR32)) + switch (theImage->Format()) { - Image_PixMap::SwapRgbaBgra (*theImage); - theImage->SetFormat (theImage->Format() == Image_Format_BGR32 - ? Image_Format_RGB32 - : Image_Format_RGBA); + // BGR formats are unsupported in OpenGL ES, only RGB + case Image_Format_BGR: + Image_PixMap::SwapRgbaBgra (*theImage); + theImage->SetFormat (Image_Format_RGB); + break; + case Image_Format_BGRA: + case Image_Format_BGR32: + Image_PixMap::SwapRgbaBgra (*theImage); + theImage->SetFormat (theImage->Format() == Image_Format_BGR32 ? Image_Format_RGB32 : Image_Format_RGBA); + break; + default: + break; } } diff --git a/src/Image/Image_PixMap.cxx b/src/Image/Image_PixMap.cxx index 8358edf261..15d2fad63f 100644 --- a/src/Image/Image_PixMap.cxx +++ b/src/Image/Image_PixMap.cxx @@ -20,6 +20,55 @@ #include +namespace +{ + //! Structure defining image pixel format description. + struct Image_FormatInfo + { + const char* Name; //!< string representation + int Format; //!< enumeration name + unsigned int NbComponents; //!< number of components + unsigned int PixelSize; //!< bytes per pixel + + Image_FormatInfo (Image_Format theFormat, const char* theName, unsigned int theNbComponents, Standard_Size thePixelSize) + : Name (theName), Format (theFormat), NbComponents (theNbComponents), PixelSize ((unsigned int )thePixelSize) {} + + Image_FormatInfo (Image_CompressedFormat theFormat, const char* theName, unsigned int theNbComponents, Standard_Size thePixelSize) + : Name (theName), Format (theFormat), NbComponents (theNbComponents), PixelSize ((unsigned int )thePixelSize) {} + }; + + #define ImageFormatInfo(theName, theNbComponents, thePixelSize) \ + Image_FormatInfo(Image_Format_##theName, #theName, theNbComponents, thePixelSize) + + #define CompressedImageFormatInfo(theName, theNbComponents, thePixelSize) \ + Image_FormatInfo(Image_CompressedFormat_##theName, #theName, theNbComponents, thePixelSize) + + //! Table of image pixel formats. + static const Image_FormatInfo Image_Table_ImageFormats[Image_CompressedFormat_NB] = + { + ImageFormatInfo(UNKNOWN, 0, 1), + ImageFormatInfo(Gray, 1, 1), + ImageFormatInfo(Alpha, 1, 1), + ImageFormatInfo(RGB, 3, 3), + ImageFormatInfo(BGR, 3, 3), + ImageFormatInfo(RGB32, 3, 4), + ImageFormatInfo(BGR32, 3, 4), + ImageFormatInfo(RGBA, 4, 4), + ImageFormatInfo(BGRA, 4, 4), + ImageFormatInfo(GrayF, 1, sizeof(float)), + ImageFormatInfo(AlphaF, 1, sizeof(float)), + ImageFormatInfo(RGF, 2, sizeof(float) * 2), + ImageFormatInfo(RGBF, 3, sizeof(float) * 3), + ImageFormatInfo(BGRF, 3, sizeof(float) * 3), + ImageFormatInfo(RGBAF, 4, sizeof(float) * 4), + ImageFormatInfo(BGRAF, 4, sizeof(float) * 4), + CompressedImageFormatInfo(RGB_S3TC_DXT1, 3, 1), // DXT1 uses circa half a byte per pixel (64 bits per 4x4 block) + CompressedImageFormatInfo(RGBA_S3TC_DXT1, 4, 1), + CompressedImageFormatInfo(RGBA_S3TC_DXT3, 4, 1), // DXT3/5 uses circa 1 byte per pixel (128 bits per 4x4 block) + CompressedImageFormatInfo(RGBA_S3TC_DXT5, 4, 1) + }; +} + IMPLEMENT_STANDARD_RTTIEXT(Image_PixMap,Standard_Transient) // ======================================================================= @@ -32,6 +81,24 @@ const Handle(NCollection_BaseAllocator)& Image_PixMap::DefaultAllocator() return THE_ALLOC; } +// ======================================================================= +// function : ImageFormatToString +// purpose : +// ======================================================================= +Standard_CString Image_PixMap::ImageFormatToString (Image_Format theFormat) +{ + return Image_Table_ImageFormats[theFormat].Name; +} + +// ======================================================================= +// function : ImageFormatToString +// purpose : +// ======================================================================= +Standard_CString Image_PixMap::ImageFormatToString (Image_CompressedFormat theFormat) +{ + return Image_Table_ImageFormats[theFormat].Name; +} + // ======================================================================= // function : Image_PixMap // purpose : @@ -57,35 +124,7 @@ Image_PixMap::~Image_PixMap() // ======================================================================= Standard_Size Image_PixMap::SizePixelBytes (const Image_Format thePixelFormat) { - switch (thePixelFormat) - { - case Image_Format_GrayF: - case Image_Format_AlphaF: - return sizeof(float); - case Image_Format_RGF: - return sizeof(float) * 2; - case Image_Format_RGBAF: - case Image_Format_BGRAF: - return sizeof(float) * 4; - case Image_Format_RGBF: - case Image_Format_BGRF: - return sizeof(float) * 3; - case Image_Format_RGBA: - case Image_Format_BGRA: - return 4; - case Image_Format_RGB32: - case Image_Format_BGR32: - return 4; - case Image_Format_RGB: - case Image_Format_BGR: - return 3; - case Image_Format_Gray: - case Image_Format_Alpha: - return 1; - case Image_Format_UNKNOWN: - return 1; - } - return 1; + return Image_Table_ImageFormats[thePixelFormat].PixelSize; } // ======================================================================= diff --git a/src/Image/Image_PixMap.hxx b/src/Image/Image_PixMap.hxx index 4f696e65ef..a043f8894a 100644 --- a/src/Image/Image_PixMap.hxx +++ b/src/Image/Image_PixMap.hxx @@ -16,7 +16,7 @@ #ifndef _Image_PixMap_H__ #define _Image_PixMap_H__ -#include +#include #include #include #include @@ -54,6 +54,12 @@ public: //! Return default image data allocator. Standard_EXPORT static const Handle(NCollection_BaseAllocator)& DefaultAllocator(); + //! Return string representation of pixel format. + Standard_EXPORT static Standard_CString ImageFormatToString (Image_Format theFormat); + + //! Return string representation of compressed pixel format. + Standard_EXPORT static Standard_CString ImageFormatToString (Image_CompressedFormat theFormat); + public: // high-level API Image_Format Format() const { return myImgFormat; } diff --git a/src/OpenGl/OpenGl_Texture.cxx b/src/OpenGl/OpenGl_Texture.cxx index 050aa5edbc..2bf73d553f 100644 --- a/src/OpenGl/OpenGl_Texture.cxx +++ b/src/OpenGl/OpenGl_Texture.cxx @@ -234,7 +234,7 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, || theSizeXY.y() < 1) { theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, - "Error: texture of 0 size cannot be created."); + TCollection_AsciiString ("Error: texture of 0 size cannot be created [") + myResourceId +"]"); Release (theCtx.get()); return false; } @@ -286,7 +286,7 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, && !theCtx->arbTexFloat) { theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, - "Error: floating-point textures are not supported by hardware."); + TCollection_AsciiString ("Error: floating-point textures are not supported by hardware [") + myResourceId +"]"); Release (theCtx.get()); return false; } @@ -297,7 +297,8 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, { theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, TCollection_AsciiString ("Error: Texture dimension - ") + theSizeXY.x() + "x" + theSizeXY.y() - + " exceeds hardware limits (" + aMaxSize + "x" + aMaxSize + ")"); + + " exceeds hardware limits (" + aMaxSize + "x" + aMaxSize + ")" + + " [" + myResourceId +"]"); Release (theCtx.get()); return false; } @@ -315,7 +316,7 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, { theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, TCollection_AsciiString ("Error: NPOT Textures (") + theSizeXY.x() + "x" + theSizeXY.y() + ")" - " are not supported by hardware."); + " are not supported by hardware [" + myResourceId +"]"); Release (theCtx.get()); return false; } @@ -331,7 +332,7 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, { theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, TCollection_AsciiString ("Error: Mipmap NPOT Textures (") + theSizeXY.x() + "x" + theSizeXY.y() + ")" - " are not supported by OpenGL ES 2.0"); + " are not supported by OpenGL ES 2.0 [" + myResourceId +"]"); Release (theCtx.get()); return false; } @@ -407,7 +408,7 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, return true; #else theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, - "Error: 1D textures are not supported by hardware."); + TCollection_AsciiString ( "Error: 1D textures are not supported by hardware [") + myResourceId +"]"); Release (theCtx.get()); return false; #endif @@ -466,7 +467,8 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, + " IF: " + OpenGl_TextureFormat::FormatFormat (anIntFormat) + " PF: " + OpenGl_TextureFormat::FormatFormat (theFormat.PixelFormat()) + " DT: " + OpenGl_TextureFormat::FormatDataType (theFormat.DataType()) - + " can not be created with error " + OpenGl_Context::FormatGlError (anErr) + "."); + + " can not be created with error " + OpenGl_Context::FormatGlError (anErr) + + " [" + myResourceId +"]"); Unbind (theCtx); Release (theCtx.get()); return false; @@ -484,8 +486,20 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, if (anErr != GL_NO_ERROR) { myMaxMipLevel = 0; - theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, - "Warning: generating mipmaps requires GL_ARB_framebuffer_object extension which is missing."); + #if defined(GL_ES_VERSION_2_0) + if (theFormat.InternalFormat() == GL_RGB8 + || theFormat.InternalFormat() == GL_SRGB8) + { + theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, + TCollection_AsciiString ("Warning: generating mipmaps requires color-renderable format, while giving ") + + OpenGl_TextureFormat::FormatFormat (anIntFormat) + " [" + myResourceId +"]"); + } + else + #endif + { + theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, + TCollection_AsciiString ("Warning: generating mipmaps has failed [") + myResourceId +"]"); + } } } @@ -522,6 +536,9 @@ bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindFormat (theCtx, theImage.Format(), theIsColorMap); if (!aFormat.IsValid()) { + theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, + TCollection_AsciiString ("Error: No suitable texture format for ") + Image_PixMap::ImageFormatToString (theImage.Format()) + " image format" + + " [" + myResourceId +"]"); Release (theCtx.get()); return false; } @@ -600,6 +617,9 @@ bool OpenGl_Texture::InitCompressed (const Handle(OpenGl_Context)& theCtx, const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindCompressedFormat (theCtx, theImage.CompressedFormat(), theIsColorMap); if (!aFormat.IsValid()) { + theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, + TCollection_AsciiString ("Error: No suitable texture format for ") + Image_PixMap::ImageFormatToString (theImage.CompressedFormat()) + " image format " + + " [" + myResourceId +"]"); Release (theCtx.get()); return false; } @@ -978,6 +998,9 @@ bool OpenGl_Texture::InitCubeMap (const Handle(OpenGl_Context)& theCtx, } if (!aFormat.IsValid()) { + theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, + TCollection_AsciiString ("Error: No suitable texture format for ") + Image_PixMap::ImageFormatToString (theFormat) + " image format" + + " [" + myResourceId +"]"); Unbind(theCtx); Release(theCtx.get()); return false; @@ -1115,10 +1138,10 @@ bool OpenGl_Texture::InitCubeMap (const Handle(OpenGl_Context)& theCtx, if (anErr != GL_NO_ERROR) { theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, - TCollection_AsciiString ("Unable to generate mipmap of cubemap. Error ") + OpenGl_Context::FormatGlError (anErr)); - Unbind (theCtx); - Release (theCtx.get()); - return false; + TCollection_AsciiString ("Unable to generate mipmap of cubemap with format ") + + OpenGl_TextureFormat::FormatFormat (anIntFormat) + + ", error " + OpenGl_Context::FormatGlError (anErr)); + myMaxMipLevel = 0; } }