#include <OpenGl_FrameBuffer.hxx>
#include <OpenGl_ArbFBO.hxx>
+#include <NCollection_AlignedAllocator.hxx>
#include <Standard_Assert.hxx>
#include <TCollection_ExtendedString.hxx>
namespace
{
+ //! Checks whether two format arrays are equal or not.
+ static bool operator== (const OpenGl_ColorFormats& theFmt1,
+ const OpenGl_ColorFormats& theFmt2)
+ {
+ if (theFmt1.Length() != theFmt2.Length())
+ return false;
+ OpenGl_ColorFormats::Iterator anIt1 (theFmt1);
+ OpenGl_ColorFormats::Iterator anIt2 (theFmt1);
+ for (; anIt1.More(); anIt1.Next(), anIt2.Next())
+ {
+ if (anIt1.Value() != anIt2.Value())
+ return false;
+ }
+ return true;
+ }
+}
- //! Determine data type from texture sized format.
- static bool getDepthDataFormat (GLint theTextFormat,
- GLenum& thePixelFormat,
- GLenum& theDataType)
+// =======================================================================
+// function : getDepthDataFormat
+// purpose :
+// =======================================================================
+bool OpenGl_FrameBuffer::getDepthDataFormat (GLint theTextFormat,
+ GLenum& thePixelFormat,
+ GLenum& theDataType)
+{
+ switch (theTextFormat)
{
- switch (theTextFormat)
+ case GL_DEPTH24_STENCIL8:
{
- case GL_DEPTH24_STENCIL8:
- {
- thePixelFormat = GL_DEPTH_STENCIL;
- theDataType = GL_UNSIGNED_INT_24_8;
- return true;
- }
- case GL_DEPTH32F_STENCIL8:
- {
- thePixelFormat = GL_DEPTH_STENCIL;
- theDataType = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
- return true;
- }
- case GL_DEPTH_COMPONENT16:
- {
- thePixelFormat = GL_DEPTH_COMPONENT;
- theDataType = GL_UNSIGNED_SHORT;
- return true;
- }
- case GL_DEPTH_COMPONENT24:
- {
- thePixelFormat = GL_DEPTH_COMPONENT;
- theDataType = GL_UNSIGNED_INT;
- return true;
- }
- case GL_DEPTH_COMPONENT32F:
- {
- thePixelFormat = GL_DEPTH_COMPONENT;
- theDataType = GL_FLOAT;
- return true;
- }
+ thePixelFormat = GL_DEPTH_STENCIL;
+ theDataType = GL_UNSIGNED_INT_24_8;
+ return true;
+ }
+ case GL_DEPTH32F_STENCIL8:
+ {
+ thePixelFormat = GL_DEPTH_STENCIL;
+ theDataType = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
+ return true;
+ }
+ case GL_DEPTH_COMPONENT16:
+ {
+ thePixelFormat = GL_DEPTH_COMPONENT;
+ theDataType = GL_UNSIGNED_SHORT;
+ return true;
+ }
+ case GL_DEPTH_COMPONENT24:
+ {
+ thePixelFormat = GL_DEPTH_COMPONENT;
+ theDataType = GL_UNSIGNED_INT;
+ return true;
+ }
+ case GL_DEPTH_COMPONENT32F:
+ {
+ thePixelFormat = GL_DEPTH_COMPONENT;
+ theDataType = GL_FLOAT;
+ return true;
}
- return false;
}
+ return false;
+}
- //! Determine data type from texture sized format.
- static bool getColorDataFormat (const Handle(OpenGl_Context)& theGlContext,
- GLint theTextFormat,
- GLenum& thePixelFormat,
- GLenum& theDataType)
+// =======================================================================
+// function : getColorDataFormat
+// purpose :
+// =======================================================================
+bool OpenGl_FrameBuffer::getColorDataFormat (const Handle(OpenGl_Context)& theGlContext,
+ GLint theTextFormat,
+ GLenum& thePixelFormat,
+ GLenum& theDataType)
+{
+ switch (theTextFormat)
{
- switch (theTextFormat)
+ case GL_RGBA32F:
{
- case GL_RGBA32F:
- {
- thePixelFormat = GL_RGBA;
- theDataType = GL_FLOAT;
- return true;
- }
- case GL_R32F:
- {
- thePixelFormat = GL_RED;
- theDataType = GL_FLOAT;
- return true;
- }
- case GL_RGBA16F:
- {
- thePixelFormat = GL_RGBA;
- theDataType = GL_HALF_FLOAT;
- if (theGlContext->hasHalfFloatBuffer == OpenGl_FeatureInExtensions)
- {
- #if defined(GL_ES_VERSION_2_0)
- theDataType = GL_HALF_FLOAT_OES;
- #else
- theDataType = GL_FLOAT;
- #endif
- }
- return true;
- }
- case GL_R16F:
- {
- thePixelFormat = GL_RED;
- theDataType = GL_HALF_FLOAT;
- if (theGlContext->hasHalfFloatBuffer == OpenGl_FeatureInExtensions)
- {
- #if defined(GL_ES_VERSION_2_0)
- theDataType = GL_HALF_FLOAT_OES;
- #else
- theDataType = GL_FLOAT;
- #endif
- }
- return true;
- }
- case GL_RGBA8:
- case GL_RGBA:
+ thePixelFormat = GL_RGBA;
+ theDataType = GL_FLOAT;
+ return true;
+ }
+ case GL_R32F:
+ {
+ thePixelFormat = GL_RED;
+ theDataType = GL_FLOAT;
+ return true;
+ }
+ case GL_RGBA16F:
+ {
+ thePixelFormat = GL_RGBA;
+ theDataType = GL_HALF_FLOAT;
+ if (theGlContext->hasHalfFloatBuffer == OpenGl_FeatureInExtensions)
{
- thePixelFormat = GL_RGBA;
- theDataType = GL_UNSIGNED_BYTE;
- return true;
+ #if defined(GL_ES_VERSION_2_0)
+ theDataType = GL_HALF_FLOAT_OES;
+ #else
+ theDataType = GL_FLOAT;
+ #endif
}
- case GL_RGB8:
- case GL_RGB:
+ return true;
+ }
+ case GL_R16F:
+ {
+ thePixelFormat = GL_RED;
+ theDataType = GL_HALF_FLOAT;
+ if (theGlContext->hasHalfFloatBuffer == OpenGl_FeatureInExtensions)
{
- thePixelFormat = GL_RGB;
- theDataType = GL_UNSIGNED_BYTE;
- return true;
+ #if defined(GL_ES_VERSION_2_0)
+ theDataType = GL_HALF_FLOAT_OES;
+ #else
+ theDataType = GL_FLOAT;
+ #endif
}
+ return true;
}
- return false;
- }
-
- //! Checks whether two format arrays are equal or not.
- static bool operator== (const OpenGl_ColorFormats& theFmt1,
- const OpenGl_ColorFormats& theFmt2)
- {
- if (theFmt1.Length() != theFmt2.Length())
- return false;
- OpenGl_ColorFormats::Iterator anIt1 (theFmt1);
- OpenGl_ColorFormats::Iterator anIt2 (theFmt1);
- for (; anIt1.More(); anIt1.Next(), anIt2.Next())
+ case GL_RGBA8:
+ case GL_RGBA:
{
- if (anIt1.Value() != anIt2.Value())
- return false;
+ thePixelFormat = GL_RGBA;
+ theDataType = GL_UNSIGNED_BYTE;
+ return true;
+ }
+ case GL_RGB8:
+ case GL_RGB:
+ {
+ thePixelFormat = GL_RGB;
+ theDataType = GL_UNSIGNED_BYTE;
+ return true;
}
- return true;
}
+ return false;
}
// =======================================================================
myGlColorRBufferId (NO_RENDERBUFFER),
myGlDepthRBufferId (NO_RENDERBUFFER),
myIsOwnBuffer (false),
+ myIsOwnDepth (false),
myDepthStencilTexture (new OpenGl_Texture())
{
myColorFormats.Append (GL_RGBA8);
theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, NO_FRAMEBUFFER);
}
}
+
+// =======================================================================
+// function : getAligned
+// purpose :
+// =======================================================================
+inline Standard_Size getAligned (const Standard_Size theNumber,
+ const Standard_Size theAlignment)
+{
+ return theNumber + theAlignment - 1 - (theNumber - 1) % theAlignment;
+}
+
+template<typename T>
+inline void convertRowFromRgba (T* theRgbRow,
+ const Image_ColorRGBA* theRgbaRow,
+ const Standard_Size theWidth)
+{
+ for (Standard_Size aCol = 0; aCol < theWidth; ++aCol)
+ {
+ const Image_ColorRGBA& anRgba = theRgbaRow[aCol];
+ T& anRgb = theRgbRow[aCol];
+ anRgb.r() = anRgba.r();
+ anRgb.g() = anRgba.g();
+ anRgb.b() = anRgba.b();
+ }
+}
+
+// =======================================================================
+// function : BufferDump
+// purpose :
+// =======================================================================
+Standard_Boolean OpenGl_FrameBuffer::BufferDump (const Handle(OpenGl_Context)& theGlCtx,
+ const Handle(OpenGl_FrameBuffer)& theFbo,
+ Image_PixMap& theImage,
+ Graphic3d_BufferType theBufferType)
+{
+ if (theGlCtx.IsNull()
+ || theImage.IsEmpty())
+ {
+ return Standard_False;
+ }
+
+ GLenum aFormat = 0;
+ GLenum aType = 0;
+ bool toSwapRgbaBgra = false;
+ bool toConvRgba2Rgb = false;
+ switch (theImage.Format())
+ {
+ #if !defined(GL_ES_VERSION_2_0)
+ case Image_Format_Gray:
+ aFormat = GL_DEPTH_COMPONENT;
+ aType = GL_UNSIGNED_BYTE;
+ break;
+ case Image_Format_GrayF:
+ aFormat = GL_DEPTH_COMPONENT;
+ aType = GL_FLOAT;
+ break;
+ case Image_Format_RGB:
+ aFormat = GL_RGB;
+ aType = GL_UNSIGNED_BYTE;
+ break;
+ case Image_Format_BGR:
+ aFormat = GL_BGR;
+ aType = GL_UNSIGNED_BYTE;
+ break;
+ case Image_Format_BGRA:
+ case Image_Format_BGR32:
+ aFormat = GL_BGRA;
+ aType = GL_UNSIGNED_BYTE;
+ break;
+ case Image_Format_BGRF:
+ aFormat = GL_BGR;
+ aType = GL_FLOAT;
+ break;
+ case Image_Format_BGRAF:
+ aFormat = GL_BGRA;
+ aType = GL_FLOAT;
+ break;
+ #else
+ case Image_Format_Gray:
+ case Image_Format_GrayF:
+ case Image_Format_BGRF:
+ case Image_Format_BGRAF:
+ return Standard_False;
+ case Image_Format_BGRA:
+ case Image_Format_BGR32:
+ aFormat = GL_RGBA;
+ aType = GL_UNSIGNED_BYTE;
+ toSwapRgbaBgra = true;
+ break;
+ case Image_Format_BGR:
+ case Image_Format_RGB:
+ aFormat = GL_RGBA;
+ aType = GL_UNSIGNED_BYTE;
+ toConvRgba2Rgb = true;
+ break;
+ #endif
+ case Image_Format_RGBA:
+ case Image_Format_RGB32:
+ aFormat = GL_RGBA;
+ aType = GL_UNSIGNED_BYTE;
+ break;
+ case Image_Format_RGBF:
+ aFormat = GL_RGB;
+ aType = GL_FLOAT;
+ break;
+ case Image_Format_RGBAF:
+ aFormat = GL_RGBA;
+ aType = GL_FLOAT;
+ break;
+ case Image_Format_Alpha:
+ case Image_Format_AlphaF:
+ return Standard_False; // GL_ALPHA is no more supported in core context
+ case Image_Format_UNKNOWN:
+ return Standard_False;
+ }
+
+ if (aFormat == 0)
+ {
+ return Standard_False;
+ }
+
+#if !defined(GL_ES_VERSION_2_0)
+ GLint aReadBufferPrev = GL_BACK;
+ if (theBufferType == Graphic3d_BT_Depth
+ && aFormat != GL_DEPTH_COMPONENT)
+ {
+ return Standard_False;
+ }
+#else
+ (void )theBufferType;
+#endif
+
+ // bind FBO if used
+ if (!theFbo.IsNull() && theFbo->IsValid())
+ {
+ theFbo->BindBuffer (theGlCtx);
+ }
+ else
+ {
+ #if !defined(GL_ES_VERSION_2_0)
+ glGetIntegerv (GL_READ_BUFFER, &aReadBufferPrev);
+ GLint aDrawBufferPrev = GL_BACK;
+ glGetIntegerv (GL_DRAW_BUFFER, &aDrawBufferPrev);
+ glReadBuffer (aDrawBufferPrev);
+ #endif
+ }
+
+ // setup alignment
+ const GLint anAligment = Min (GLint(theImage.MaxRowAligmentBytes()), 8); // limit to 8 bytes for OpenGL
+ glPixelStorei (GL_PACK_ALIGNMENT, anAligment);
+ bool isBatchCopy = !theImage.IsTopDown();
+
+ const GLint anExtraBytes = GLint(theImage.RowExtraBytes());
+ GLint aPixelsWidth = GLint(theImage.SizeRowBytes() / theImage.SizePixelBytes());
+ Standard_Size aSizeRowBytesEstim = getAligned (theImage.SizePixelBytes() * aPixelsWidth, anAligment);
+ if (anExtraBytes < anAligment)
+ {
+ aPixelsWidth = 0;
+ }
+ else if (aSizeRowBytesEstim != theImage.SizeRowBytes())
+ {
+ aPixelsWidth = 0;
+ isBatchCopy = false;
+ }
+#if !defined(GL_ES_VERSION_2_0)
+ glPixelStorei (GL_PACK_ROW_LENGTH, aPixelsWidth);
+#else
+ if (aPixelsWidth != 0)
+ {
+ isBatchCopy = false;
+ }
+#endif
+ if (toConvRgba2Rgb)
+ {
+ Handle(NCollection_BaseAllocator) anAlloc = new NCollection_AlignedAllocator (16);
+ const Standard_Size aRowSize = theImage.SizeX() * 4;
+ NCollection_Buffer aRowBuffer (anAlloc);
+ if (!aRowBuffer.Allocate (aRowSize))
+ {
+ return Standard_False;
+ }
+
+ for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
+ {
+ // Image_PixMap rows indexation always starts from the upper corner
+ // while order in memory depends on the flag and processed by ChangeRow() method
+ glReadPixels (0, GLint(theImage.SizeY() - aRow - 1), GLsizei (theImage.SizeX()), 1, aFormat, aType, aRowBuffer.ChangeData());
+ const Image_ColorRGBA* aRowDataRgba = (const Image_ColorRGBA* )aRowBuffer.Data();
+ if (theImage.Format() == Image_Format_BGR)
+ {
+ convertRowFromRgba ((Image_ColorBGR* )theImage.ChangeRow (aRow), aRowDataRgba, theImage.SizeX());
+ }
+ else
+ {
+ convertRowFromRgba ((Image_ColorRGB* )theImage.ChangeRow (aRow), aRowDataRgba, theImage.SizeX());
+ }
+ }
+ }
+ else if (!isBatchCopy)
+ {
+ // copy row by row
+ for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
+ {
+ // Image_PixMap rows indexation always starts from the upper corner
+ // while order in memory depends on the flag and processed by ChangeRow() method
+ glReadPixels (0, GLint(theImage.SizeY() - aRow - 1), GLsizei (theImage.SizeX()), 1, aFormat, aType, theImage.ChangeRow (aRow));
+ }
+ }
+ else
+ {
+ glReadPixels (0, 0, GLsizei (theImage.SizeX()), GLsizei (theImage.SizeY()), aFormat, aType, theImage.ChangeData());
+ }
+ const bool hasErrors = theGlCtx->ResetErrors (true);
+
+ glPixelStorei (GL_PACK_ALIGNMENT, 1);
+#if !defined(GL_ES_VERSION_2_0)
+ glPixelStorei (GL_PACK_ROW_LENGTH, 0);
+#endif
+
+ if (!theFbo.IsNull() && theFbo->IsValid())
+ {
+ theFbo->UnbindBuffer (theGlCtx);
+ }
+ else
+ {
+ #if !defined(GL_ES_VERSION_2_0)
+ glReadBuffer (aReadBufferPrev);
+ #endif
+ }
+
+ if (toSwapRgbaBgra)
+ {
+ Image_PixMap::SwapRgbaBgra (theImage);
+ }
+
+ return !hasErrors;
+}
+
+// =======================================================================
+// function : EstimatedDataSize
+// purpose :
+// =======================================================================
+Standard_Size OpenGl_FrameBuffer::EstimatedDataSize() const
+{
+ if (!IsValid())
+ {
+ return 0;
+ }
+
+ Standard_Size aSize = 0;
+ for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
+ {
+ aSize += aTextureIt.Value()->EstimatedDataSize();
+ }
+ if (!myDepthStencilTexture.IsNull())
+ {
+ aSize += myDepthStencilTexture->EstimatedDataSize();
+ }
+ if (myGlColorRBufferId != NO_RENDERBUFFER
+ && !myColorFormats.IsEmpty())
+ {
+ aSize += OpenGl_Texture::PixelSizeOfPixelFormat (myColorFormats.First()) * myInitVPSizeX * myInitVPSizeY;
+ }
+ if (myGlDepthRBufferId != NO_RENDERBUFFER)
+ {
+ aSize += OpenGl_Texture::PixelSizeOfPixelFormat (myDepthFormat) * myInitVPSizeX * myInitVPSizeY;
+ }
+ return aSize;
+}