//
// This file is part of Open CASCADE Technology software library.
//
-// This library is free software; you can redistribute it and / or modify it
-// under the terms of the GNU Lesser General Public version 2.1 as published
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
// commercial license or contractual agreement.
#include <OpenGl_FrameBuffer.hxx>
+#include <OpenGl_ArbFBO.hxx>
+#include <NCollection_AlignedAllocator.hxx>
#include <Standard_Assert.hxx>
+#include <TCollection_ExtendedString.hxx>
-IMPLEMENT_STANDARD_HANDLE (OpenGl_FrameBuffer, OpenGl_Resource)
-IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameBuffer, OpenGl_Resource)
+IMPLEMENT_STANDARD_RTTIEXT(OpenGl_FrameBuffer,OpenGl_Resource)
-static inline bool isOddNumber (const GLsizei theNumber)
+namespace
{
- return theNumber & 0x01;
+ //! 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;
+ }
}
-static inline GLsizei getEvenNumber (const GLsizei theNumber)
+// =======================================================================
+// function : getDepthDataFormat
+// purpose :
+// =======================================================================
+bool OpenGl_FrameBuffer::getDepthDataFormat (GLint theTextFormat,
+ GLenum& thePixelFormat,
+ GLenum& theDataType)
{
- return isOddNumber (theNumber) ? (theNumber + 1) : theNumber;
+ switch (theTextFormat)
+ {
+ 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;
+ }
+ }
+ return false;
}
-//! Notice - 0 is not power of two here
-static inline bool isPowerOfTwo (const GLsizei theNumber)
+// =======================================================================
+// function : getColorDataFormat
+// purpose :
+// =======================================================================
+bool OpenGl_FrameBuffer::getColorDataFormat (const Handle(OpenGl_Context)& theGlContext,
+ GLint theTextFormat,
+ GLenum& thePixelFormat,
+ GLenum& theDataType)
{
- return !(theNumber & (theNumber - 1));
+ switch (theTextFormat)
+ {
+ 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_UNSIGNED_BYTE;
+ return true;
+ }
+ case GL_RGB8:
+ case GL_RGB:
+ {
+ thePixelFormat = GL_RGB;
+ theDataType = GL_UNSIGNED_BYTE;
+ return true;
+ }
+ }
+ return false;
}
// =======================================================================
// function : OpenGl_FrameBuffer
// purpose :
// =======================================================================
-OpenGl_FrameBuffer::OpenGl_FrameBuffer (GLint theTextureFormat)
-: mySizeX (0),
- mySizeY (0),
+OpenGl_FrameBuffer::OpenGl_FrameBuffer()
+: myInitVPSizeX (0),
+ myInitVPSizeY (0),
myVPSizeX (0),
myVPSizeY (0),
- myTextFormat (theTextureFormat),
- myGlTextureId (NO_TEXTURE),
+ myNbSamples (0),
+ myDepthFormat (GL_DEPTH24_STENCIL8),
myGlFBufferId (NO_FRAMEBUFFER),
- myGlDepthRBId (NO_RENDERBUFFER),
- myGlStencilRBId (NO_RENDERBUFFER)
+ myGlColorRBufferId (NO_RENDERBUFFER),
+ myGlDepthRBufferId (NO_RENDERBUFFER),
+ myIsOwnBuffer (false),
+ myIsOwnDepth (false),
+ myDepthStencilTexture (new OpenGl_Texture())
{
- //
+ myColorFormats.Append (GL_RGBA8);
+ myColorTextures.Append (new OpenGl_Texture());
}
// =======================================================================
// purpose :
// =======================================================================
Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
- const GLsizei theViewportSizeX,
- const GLsizei theViewportSizeY,
- const GLboolean toForcePowerOfTwo)
+ const GLsizei theSizeX,
+ const GLsizei theSizeY,
+ const GLint theColorFormat,
+ const GLint theDepthFormat,
+ const GLsizei theNbSamples)
+{
+ OpenGl_ColorFormats aColorFormats;
+
+ aColorFormats.Append (theColorFormat);
+
+ return Init (theGlContext, theSizeX, theSizeY, aColorFormats, theDepthFormat, theNbSamples);
+}
+
+// =======================================================================
+// function : Init
+// purpose :
+// =======================================================================
+Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
+ const GLsizei theSizeX,
+ const GLsizei theSizeY,
+ const OpenGl_ColorFormats& theColorFormats,
+ const Handle(OpenGl_Texture)& theDepthStencilTexture,
+ const GLsizei theNbSamples)
{
- if (theGlContext->extFBO == NULL)
+ myColorFormats = theColorFormats;
+
+ OpenGl_TextureArray aTextures (myColorTextures);
+ if (!myColorTextures.IsEmpty())
+ {
+ for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
+ {
+ aTextureIt.Value()->Release (theGlContext.operator->());
+ }
+ myColorTextures.Clear();
+ }
+ for (Standard_Integer aLength = 0; aLength < myColorFormats.Length(); ++aLength)
+ {
+ myColorTextures.Append (aLength < aTextures.Length() ? aTextures.Value (aLength) : new OpenGl_Texture());
+ }
+
+ myDepthFormat = theDepthStencilTexture->GetFormat();
+ myNbSamples = theNbSamples;
+ if (theGlContext->arbFBO == NULL)
{
return Standard_False;
}
// clean up previous state
Release (theGlContext.operator->());
+ if (myColorFormats.IsEmpty()
+ && myDepthFormat == 0)
+ {
+ return Standard_False;
+ }
+
+ myDepthStencilTexture = theDepthStencilTexture;
+ myIsOwnDepth = false;
+ myIsOwnBuffer = true;
- // upscale width/height if numbers are odd
- if (toForcePowerOfTwo)
+ // setup viewport sizes as is
+ myVPSizeX = theSizeX;
+ myVPSizeY = theSizeY;
+ const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
+ const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
+
+ // Create the textures (will be used as color buffer and depth-stencil buffer)
+ if (theNbSamples != 0)
{
- mySizeX = OpenGl_Context::GetPowerOfTwo (theViewportSizeX, theGlContext->MaxTextureSize());
- mySizeY = OpenGl_Context::GetPowerOfTwo (theViewportSizeY, theGlContext->MaxTextureSize());
+ for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
+ {
+ const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
+ const GLint aColorFormat = myColorFormats (aColorBufferIdx);
+ if (aColorFormat != 0
+ && !aColorTexture->Init2DMultisample (theGlContext, theNbSamples,
+ aColorFormat, aSizeX, aSizeY))
+ {
+ Release (theGlContext.operator->());
+ return Standard_False;
+ }
+ }
}
else
{
- mySizeX = getEvenNumber (theViewportSizeX);
- mySizeY = getEvenNumber (theViewportSizeY);
+ for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
+ {
+ GLenum aPixelFormat = 0;
+ GLenum aDataType = 0;
+ const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
+ const GLint aColorFormat = myColorFormats (aColorBufferIdx);
+ if (aColorFormat != 0
+ && getColorDataFormat (theGlContext, aColorFormat, aPixelFormat, aDataType)
+ && !aColorTexture->Init (theGlContext, aColorFormat,
+ aPixelFormat, aDataType,
+ aSizeX, aSizeY, Graphic3d_TOT_2D))
+ {
+ Release (theGlContext.operator->());
+ return Standard_False;
+ }
+ }
}
- // setup viewport sizes as is
- myVPSizeX = theViewportSizeX;
- myVPSizeY = theViewportSizeY;
+ // Build FBO and setup it as texture
+ theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
+ theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
- // Create the texture (will be used as color buffer)
- if (!initTrashTexture (theGlContext))
+ for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
{
- if (!isPowerOfTwo (mySizeX) || !isPowerOfTwo (mySizeY))
+ const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
+ if (aColorTexture->IsValid())
{
- return Init (theGlContext, theViewportSizeX, theViewportSizeY, GL_TRUE);
+ theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + aColorBufferIdx,
+ aColorTexture->GetTarget(), aColorTexture->TextureId(), 0);
}
+ }
+ if (myDepthStencilTexture->IsValid())
+ {
+ #ifdef GL_DEPTH_STENCIL_ATTACHMENT
+ theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
+ myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
+ #else
+ theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
+ theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+ myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
+ #endif
+ }
+ if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+ {
Release (theGlContext.operator->());
return Standard_False;
}
- if (!theGlContext->extPDS)
+ UnbindBuffer (theGlContext);
+ return Standard_True;
+}
+
+// =======================================================================
+// function : Init
+// purpose :
+// =======================================================================
+Standard_Boolean OpenGl_FrameBuffer::Init (const Handle(OpenGl_Context)& theGlContext,
+ const GLsizei theSizeX,
+ const GLsizei theSizeY,
+ const OpenGl_ColorFormats& theColorFormats,
+ const GLint theDepthFormat,
+ const GLsizei theNbSamples)
+{
+ myColorFormats = theColorFormats;
+
+ OpenGl_TextureArray aTextures (myColorTextures);
+ if (!myColorTextures.IsEmpty())
+ {
+ for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
+ {
+ aTextureIt.Value()->Release (theGlContext.operator->());
+ }
+ myColorTextures.Clear();
+ }
+ for (Standard_Integer aLength = 0; aLength < myColorFormats.Length(); ++aLength)
{
- // Create RenderBuffer to be used as depth buffer
- theGlContext->extFBO->glGenRenderbuffersEXT (1, &myGlDepthRBId);
- theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, myGlDepthRBId);
- theGlContext->extFBO->glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, mySizeX, mySizeY);
+ myColorTextures.Append (aLength < aTextures.Length() ? aTextures.Value (aLength) : new OpenGl_Texture());
+ }
+
+ myDepthFormat = theDepthFormat;
+ myNbSamples = theNbSamples;
+ myInitVPSizeX = theSizeX;
+ myInitVPSizeY = theSizeY;
+ if (theGlContext->arbFBO == NULL)
+ {
+ return Standard_False;
+ }
- // Create RenderBuffer to be used as stencil buffer
- theGlContext->extFBO->glGenRenderbuffersEXT (1, &myGlStencilRBId);
- theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, myGlStencilRBId);
- theGlContext->extFBO->glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX, mySizeX, mySizeY);
+ // clean up previous state
+ Release (theGlContext.operator->());
+ if (myColorFormats.IsEmpty()
+ && myDepthFormat == 0)
+ {
+ return Standard_False;
+ }
+
+ myIsOwnBuffer = true;
+ myIsOwnDepth = true;
+
+ // setup viewport sizes as is
+ myVPSizeX = theSizeX;
+ myVPSizeY = theSizeY;
+ const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
+ const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
+ bool hasStencilRB = false;
+
+ // Create the textures (will be used as color buffer and depth-stencil buffer)
+ if (theNbSamples != 0)
+ {
+ for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
+ {
+ const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
+ const GLint aColorFormat = myColorFormats (aColorBufferIdx);
+ if (aColorFormat != 0
+ && !aColorTexture->Init2DMultisample (theGlContext, theNbSamples, aColorFormat, aSizeX, aSizeY))
+ {
+ Release (theGlContext.operator->());
+ return Standard_False;
+ }
+ }
+ if (myDepthFormat != 0
+ && !myDepthStencilTexture->Init2DMultisample (theGlContext, theNbSamples, myDepthFormat, aSizeX, aSizeY))
+ {
+ Release (theGlContext.operator->());
+ return Standard_False;
+ }
}
else
{
- // Create combined depth stencil buffer
- theGlContext->extFBO->glGenRenderbuffersEXT (1, &myGlDepthRBId);
- theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, myGlDepthRBId);
- theGlContext->extFBO->glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, mySizeX, mySizeY);
- myGlStencilRBId = myGlDepthRBId;
+ GLenum aPixelFormat = 0;
+ GLenum aDataType = 0;
+
+ for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
+ {
+ const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
+ const GLint aColorFormat = myColorFormats (aColorBufferIdx);
+ if (aColorFormat != 0
+ && getColorDataFormat (theGlContext, aColorFormat, aPixelFormat, aDataType)
+ && !aColorTexture->Init (theGlContext, aColorFormat,
+ aPixelFormat, aDataType,
+ aSizeX, aSizeY, Graphic3d_TOT_2D))
+ {
+ Release (theGlContext.operator->());
+ return Standard_False;
+ }
+ }
+
+ // extensions (GL_OES_packed_depth_stencil, GL_OES_depth_texture) + GL version might be used to determine supported formats
+ // instead of just trying to create such texture
+ if (myDepthFormat != 0
+ && getDepthDataFormat (myDepthFormat, aPixelFormat, aDataType)
+ && !myDepthStencilTexture->Init (theGlContext, myDepthFormat,
+ aPixelFormat, aDataType,
+ aSizeX, aSizeY, Graphic3d_TOT_2D))
+ {
+ TCollection_ExtendedString aMsg = TCollection_ExtendedString()
+ + "Warning! Depth textures are not supported by hardware!";
+ theGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
+ GL_DEBUG_TYPE_PORTABILITY,
+ 0,
+ GL_DEBUG_SEVERITY_HIGH,
+ aMsg);
+
+ hasStencilRB = aPixelFormat == GL_DEPTH_STENCIL
+ && theGlContext->extPDS;
+ GLint aDepthStencilFormat = hasStencilRB
+ ? GL_DEPTH24_STENCIL8
+ : GL_DEPTH_COMPONENT16;
+
+ theGlContext->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
+ theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
+ theGlContext->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, aDepthStencilFormat, aSizeX, aSizeY);
+ theGlContext->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
+ }
}
// Build FBO and setup it as texture
- theGlContext->extFBO->glGenFramebuffersEXT (1, &myGlFBufferId);
- theGlContext->extFBO->glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, myGlFBufferId);
- glEnable (GL_TEXTURE_2D);
- glBindTexture (GL_TEXTURE_2D, myGlTextureId);
- theGlContext->extFBO->glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, myGlTextureId, 0);
- theGlContext->extFBO->glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, myGlDepthRBId);
- theGlContext->extFBO->glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, myGlStencilRBId);
- if (theGlContext->extFBO->glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
- {
- if (!isPowerOfTwo (mySizeX) || !isPowerOfTwo (mySizeY))
+ theGlContext->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
+ theGlContext->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
+ for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
+ {
+ const Handle(OpenGl_Texture)& aColorTexture = myColorTextures (aColorBufferIdx);
+ if (aColorTexture->IsValid())
{
- return Init (theGlContext, theViewportSizeX, theViewportSizeY, GL_TRUE);
+ theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + aColorBufferIdx,
+ aColorTexture->GetTarget(), aColorTexture->TextureId(), 0);
}
+ }
+ if (myDepthStencilTexture->IsValid())
+ {
+ #ifdef GL_DEPTH_STENCIL_ATTACHMENT
+ theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
+ myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
+ #else
+ theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
+ theGlContext->arbFBO->glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+ myDepthStencilTexture->GetTarget(), myDepthStencilTexture->TextureId(), 0);
+ #endif
+ }
+ else if (myGlDepthRBufferId != NO_RENDERBUFFER)
+ {
+ #ifdef GL_DEPTH_STENCIL_ATTACHMENT
+ theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, hasStencilRB ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT,
+ GL_RENDERBUFFER, myGlDepthRBufferId);
+ #else
+ theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ GL_RENDERBUFFER, myGlDepthRBufferId);
+ if (hasStencilRB)
+ {
+ theGlContext->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+ GL_RENDERBUFFER, myGlDepthRBufferId);
+ }
+ #endif
+ }
+ if (theGlContext->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+ {
Release (theGlContext.operator->());
return Standard_False;
}
- UnbindBuffer (theGlContext);
- UnbindTexture (theGlContext);
- theGlContext->extFBO->glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, NO_RENDERBUFFER);
+ UnbindBuffer (theGlContext);
return Standard_True;
}
// =======================================================================
-// function : Release
+// function : InitLazy
+// purpose :
+// =======================================================================
+Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
+ const GLsizei theViewportSizeX,
+ const GLsizei theViewportSizeY,
+ const GLint theColorFormat,
+ const GLint theDepthFormat,
+ const GLsizei theNbSamples)
+{
+ OpenGl_ColorFormats aColorFormats;
+
+ aColorFormats.Append (theColorFormat);
+
+ return InitLazy (theGlContext, theViewportSizeX, theViewportSizeY, aColorFormats, theDepthFormat, theNbSamples);
+}
+
+// =======================================================================
+// function : InitLazy
// purpose :
// =======================================================================
-void OpenGl_FrameBuffer::Release (const OpenGl_Context* theGlCtx)
+Standard_Boolean OpenGl_FrameBuffer::InitLazy (const Handle(OpenGl_Context)& theGlContext,
+ const GLsizei theViewportSizeX,
+ const GLsizei theViewportSizeY,
+ const OpenGl_ColorFormats& theColorFormats,
+ const GLint theDepthFormat,
+ const GLsizei theNbSamples)
{
- if (isValidDepthBuffer()
- || isValidStencilBuffer()
- || isValidTexture()
- || isValidFrameBuffer())
+ if (myVPSizeX == theViewportSizeX
+ && myVPSizeY == theViewportSizeY
+ && myColorFormats == theColorFormats
+ && myDepthFormat == theDepthFormat
+ && myNbSamples == theNbSamples)
{
- // application can not handle this case by exception - this is bug in code
- Standard_ASSERT_RETURN (theGlCtx != NULL,
- "OpenGl_FrameBuffer destroyed without GL context! Possible GPU memory leakage...",);
+ return IsValid();
}
- if (isValidStencilBuffer())
+
+ return Init (theGlContext, theViewportSizeX, theViewportSizeY, theColorFormats, theDepthFormat, theNbSamples);
+}
+
+// =======================================================================
+// function : InitWithRB
+// purpose :
+// =======================================================================
+Standard_Boolean OpenGl_FrameBuffer::InitWithRB (const Handle(OpenGl_Context)& theGlCtx,
+ const GLsizei theSizeX,
+ const GLsizei theSizeY,
+ const GLint theColorFormat,
+ const GLint theDepthFormat,
+ const GLuint theColorRBufferFromWindow)
+{
+ myColorFormats.Clear();
+ myColorFormats.Append (theColorFormat);
+ if (!myColorTextures.IsEmpty())
{
- if (theGlCtx->IsValid()
- && myGlStencilRBId != myGlDepthRBId)
+ Handle(OpenGl_Texture) aTexutre = myColorTextures.First();
+ for (OpenGl_TextureArray::Iterator aTextureIt (myColorTextures); aTextureIt.More(); aTextureIt.Next())
{
- theGlCtx->extFBO->glDeleteRenderbuffersEXT (1, &myGlStencilRBId);
+ aTextureIt.Value()->Release (theGlCtx.operator->());
}
- myGlStencilRBId = NO_RENDERBUFFER;
+ myColorTextures.Clear();
+ myColorTextures.Append (aTexutre);
}
- if (isValidDepthBuffer())
+
+ myDepthFormat = theDepthFormat;
+ myNbSamples = 0;
+ myInitVPSizeX = theSizeX;
+ myInitVPSizeY = theSizeY;
+ if (theGlCtx->arbFBO == NULL)
{
- if (theGlCtx->IsValid())
- {
- theGlCtx->extFBO->glDeleteRenderbuffersEXT (1, &myGlDepthRBId);
- }
- myGlDepthRBId = NO_RENDERBUFFER;
+ return Standard_False;
+ }
+
+ // clean up previous state
+ Release (theGlCtx.operator->());
+
+ myIsOwnBuffer = true;
+ myIsOwnDepth = true;
+
+ // setup viewport sizes as is
+ myVPSizeX = theSizeX;
+ myVPSizeY = theSizeY;
+ const Standard_Integer aSizeX = theSizeX > 0 ? theSizeX : 2;
+ const Standard_Integer aSizeY = theSizeY > 0 ? theSizeY : 2;
+
+ // Create the render-buffers
+ if (theColorRBufferFromWindow != NO_RENDERBUFFER)
+ {
+ myGlColorRBufferId = theColorRBufferFromWindow;
}
- if (isValidTexture())
+ else if (theColorFormat != 0)
{
- if (theGlCtx->IsValid())
- {
- glDeleteTextures (1, &myGlTextureId);
- }
- myGlTextureId = NO_TEXTURE;
+ theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlColorRBufferId);
+ theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlColorRBufferId);
+ theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, theColorFormat, aSizeX, aSizeY);
}
- mySizeX = mySizeY = myVPSizeX = myVPSizeY = 0;
- if (isValidFrameBuffer())
+
+ bool hasStencilRB = false;
+ if (myDepthFormat != 0)
{
- if (theGlCtx->IsValid())
+ GLenum aPixelFormat = 0;
+ GLenum aDataType = 0;
+ getDepthDataFormat (myDepthFormat, aPixelFormat, aDataType);
+ hasStencilRB = aPixelFormat == GL_DEPTH_STENCIL;
+
+ theGlCtx->arbFBO->glGenRenderbuffers (1, &myGlDepthRBufferId);
+ theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, myGlDepthRBufferId);
+ theGlCtx->arbFBO->glRenderbufferStorage (GL_RENDERBUFFER, myDepthFormat, aSizeX, aSizeY);
+ theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
+ }
+
+ // create FBO
+ theGlCtx->arbFBO->glGenFramebuffers (1, &myGlFBufferId);
+ theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
+ theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_RENDERBUFFER, myGlColorRBufferId);
+ if (myGlDepthRBufferId != NO_RENDERBUFFER)
+ {
+ #ifdef GL_DEPTH_STENCIL_ATTACHMENT
+ theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, hasStencilRB ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT,
+ GL_RENDERBUFFER, myGlDepthRBufferId);
+ #else
+ theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ GL_RENDERBUFFER, myGlDepthRBufferId);
+ if (hasStencilRB)
{
- theGlCtx->extFBO->glDeleteFramebuffersEXT (1, &myGlFBufferId);
+ theGlCtx->arbFBO->glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+ GL_RENDERBUFFER, myGlDepthRBufferId);
}
- myGlFBufferId = NO_FRAMEBUFFER;
+ #endif
}
+ if (theGlCtx->arbFBO->glCheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+ {
+ UnbindBuffer (theGlCtx);
+ Release (theGlCtx.operator->());
+ return Standard_False;
+ }
+
+ UnbindBuffer (theGlCtx);
+ return Standard_True;
}
// =======================================================================
-// function : isProxySuccess
+// function : InitWrapper
// purpose :
// =======================================================================
-Standard_Boolean OpenGl_FrameBuffer::isProxySuccess() const
+Standard_Boolean OpenGl_FrameBuffer::InitWrapper (const Handle(OpenGl_Context)& theGlCtx)
{
- // use proxy to check texture could be created or not
- glTexImage2D (GL_PROXY_TEXTURE_2D,
- 0, // LOD number: 0 - base image level; n is the nth mipmap reduction image
- myTextFormat, // internalformat
- mySizeX, mySizeY, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- GLint aTestParamX (0), aTestParamY (0);
- glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestParamX);
- glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestParamY);
- return aTestParamX != 0 && aTestParamY != 0;
+ myNbSamples = 0;
+ if (theGlCtx->arbFBO == NULL)
+ {
+ return Standard_False;
+ }
+
+ // clean up previous state
+ Release (theGlCtx.operator->());
+
+ GLint anFbo = GLint(NO_FRAMEBUFFER);
+ ::glGetIntegerv (GL_FRAMEBUFFER_BINDING, &anFbo);
+ if (anFbo == GLint(NO_FRAMEBUFFER))
+ {
+ return Standard_False;
+ }
+
+ GLint aColorType = 0;
+ GLint aColorId = 0;
+ GLint aDepthType = 0;
+ GLint aDepthId = 0;
+ theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aColorType);
+ theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &aDepthType);
+
+ myGlFBufferId = GLuint(anFbo);
+ myIsOwnBuffer = false;
+ myIsOwnDepth = false;
+ if (aColorType == GL_RENDERBUFFER)
+ {
+ theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aColorId);
+ myGlColorRBufferId = aColorId;
+ }
+ else if (aColorType != GL_NONE)
+ {
+ TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), color attachment of unsupported type has been skipped!";
+ theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
+ GL_DEBUG_TYPE_ERROR,
+ 0,
+ GL_DEBUG_SEVERITY_HIGH,
+ aMsg);
+ }
+
+ if (aDepthType == GL_RENDERBUFFER)
+ {
+ theGlCtx->arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &aDepthId);
+ myGlDepthRBufferId = aDepthId;
+ }
+ else if (aDepthType != GL_NONE)
+ {
+ TCollection_ExtendedString aMsg = "OpenGl_FrameBuffer::InitWrapper(), depth attachment of unsupported type has been skipped!";
+ theGlCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
+ GL_DEBUG_TYPE_ERROR,
+ 0,
+ GL_DEBUG_SEVERITY_HIGH,
+ aMsg);
+ }
+
+ // retrieve dimensions
+ GLuint aRBuffer = myGlColorRBufferId != NO_RENDERBUFFER ? myGlColorRBufferId : myGlDepthRBufferId;
+ if (aRBuffer != NO_RENDERBUFFER)
+ {
+ theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, aRBuffer);
+ theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &myVPSizeX);
+ theGlCtx->arbFBO->glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &myVPSizeY);
+ theGlCtx->arbFBO->glBindRenderbuffer (GL_RENDERBUFFER, NO_RENDERBUFFER);
+ }
+
+ return aRBuffer != NO_RENDERBUFFER;
}
// =======================================================================
-// function : initTrashTexture
+// function : Release
// purpose :
// =======================================================================
-Standard_Boolean OpenGl_FrameBuffer::initTrashTexture (const Handle(OpenGl_Context)& theGlContext)
+void OpenGl_FrameBuffer::Release (OpenGl_Context* theGlCtx)
{
- // Check texture size is fit dimension maximum
- GLint aMaxTexDim = 2048;
- glGetIntegerv (GL_MAX_TEXTURE_SIZE, &aMaxTexDim);
- if (mySizeX > aMaxTexDim || mySizeY > aMaxTexDim)
+ if (isValidFrameBuffer())
{
- return Standard_False;
+ // application can not handle this case by exception - this is bug in code
+ Standard_ASSERT_RETURN (theGlCtx != NULL,
+ "OpenGl_FrameBuffer destroyed without GL context! Possible GPU memory leakage...",);
+ if (theGlCtx->IsValid()
+ && myIsOwnBuffer)
+ {
+ theGlCtx->arbFBO->glDeleteFramebuffers (1, &myGlFBufferId);
+ if (myGlColorRBufferId != NO_RENDERBUFFER)
+ {
+ theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlColorRBufferId);
+ }
+ if (myGlDepthRBufferId != NO_RENDERBUFFER)
+ {
+ theGlCtx->arbFBO->glDeleteRenderbuffers (1, &myGlDepthRBufferId);
+ }
+ }
+ myGlFBufferId = NO_FRAMEBUFFER;
+ myGlColorRBufferId = NO_RENDERBUFFER;
+ myGlDepthRBufferId = NO_RENDERBUFFER;
+ myIsOwnBuffer = false;
}
- // generate new id
- glEnable (GL_TEXTURE_2D);
- if (!isValidTexture())
+ for (Standard_Integer aColorBufferIdx = 0; aColorBufferIdx < myColorTextures.Length(); ++aColorBufferIdx)
{
- glGenTextures (1, &myGlTextureId); // Create The Texture
+ myColorTextures (aColorBufferIdx)->Release (theGlCtx);
}
- glBindTexture (GL_TEXTURE_2D, myGlTextureId);
-
- // texture interpolation parameters - could be overridden later
- glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- if (!isProxySuccess())
+ if (myIsOwnDepth)
{
- Release (theGlContext.operator->());
- return Standard_False;
+ myDepthStencilTexture->Release (theGlCtx);
+ myIsOwnDepth = false;
}
- glTexImage2D (GL_TEXTURE_2D,
- 0, // LOD number: 0 - base image level; n is the nth mipmap reduction image
- myTextFormat, // internalformat
- mySizeX, mySizeY, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL); // NULL pointer supported from OpenGL 1.1
- return Standard_True;
+ myVPSizeX = 0;
+ myVPSizeY = 0;
}
// =======================================================================
// function : SetupViewport
// purpose :
// =======================================================================
-void OpenGl_FrameBuffer::SetupViewport (const Handle(OpenGl_Context)& /*theGlCtx*/)
+void OpenGl_FrameBuffer::SetupViewport (const Handle(OpenGl_Context)& theGlCtx)
{
- glViewport (0, 0, myVPSizeX, myVPSizeY);
+ const Standard_Integer aViewport[4] = { 0, 0, myVPSizeX, myVPSizeY };
+ theGlCtx->ResizeViewport (aViewport);
}
// =======================================================================
// =======================================================================
void OpenGl_FrameBuffer::BindBuffer (const Handle(OpenGl_Context)& theGlCtx)
{
- theGlCtx->extFBO->glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, myGlFBufferId);
+ theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, myGlFBufferId);
+}
+
+// =======================================================================
+// function : BindDrawBuffer
+// purpose :
+// =======================================================================
+void OpenGl_FrameBuffer::BindDrawBuffer (const Handle(OpenGl_Context)& theGlCtx)
+{
+ theGlCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, myGlFBufferId);
+}
+
+// =======================================================================
+// function : BindReadBuffer
+// purpose :
+// =======================================================================
+void OpenGl_FrameBuffer::BindReadBuffer (const Handle(OpenGl_Context)& theGlCtx)
+{
+ theGlCtx->arbFBO->glBindFramebuffer (GL_READ_FRAMEBUFFER, myGlFBufferId);
}
// =======================================================================
// =======================================================================
void OpenGl_FrameBuffer::UnbindBuffer (const Handle(OpenGl_Context)& theGlCtx)
{
- theGlCtx->extFBO->glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, NO_FRAMEBUFFER);
+ if (!theGlCtx->DefaultFrameBuffer().IsNull()
+ && theGlCtx->DefaultFrameBuffer().operator->() != this)
+ {
+ theGlCtx->DefaultFrameBuffer()->BindBuffer (theGlCtx);
+ }
+ else
+ {
+ theGlCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, NO_FRAMEBUFFER);
+ }
}
// =======================================================================
-// function : BindTexture
+// function : getAligned
// purpose :
// =======================================================================
-void OpenGl_FrameBuffer::BindTexture (const Handle(OpenGl_Context)& /*theGlCtx*/)
+inline Standard_Size getAligned (const Standard_Size theNumber,
+ const Standard_Size theAlignment)
{
- glEnable (GL_TEXTURE_2D); // needed only for fixed pipeline rendering
- glBindTexture (GL_TEXTURE_2D, myGlTextureId);
+ 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 : UnbindTexture
+// function : BufferDump
// purpose :
// =======================================================================
-void OpenGl_FrameBuffer::UnbindTexture (const Handle(OpenGl_Context)& /*theGlCtx*/)
+Standard_Boolean OpenGl_FrameBuffer::BufferDump (const Handle(OpenGl_Context)& theGlCtx,
+ const Handle(OpenGl_FrameBuffer)& theFbo,
+ Image_PixMap& theImage,
+ Graphic3d_BufferType theBufferType)
{
- glBindTexture (GL_TEXTURE_2D, NO_TEXTURE);
- glDisable (GL_TEXTURE_2D); // needed only for fixed pipeline rendering
+ 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;
}