1 // Created by: Kirill GAVRILOV
2 // Copyright (c) 2013-2014 OPEN CASCADE SAS
4 // This file is part of Open CASCADE Technology software library.
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
15 #include <OpenGl_Texture.hxx>
17 #include <OpenGl_ArbFBO.hxx>
18 #include <OpenGl_Context.hxx>
19 #include <OpenGl_GlCore45.hxx>
20 #include <OpenGl_Sampler.hxx>
21 #include <Graphic3d_TextureParams.hxx>
22 #include <TCollection_ExtendedString.hxx>
23 #include <Standard_Assert.hxx>
24 #include <Image_CompressedPixMap.hxx>
25 #include <Image_PixMap.hxx>
26 #include <Image_SupportedFormats.hxx>
30 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture, OpenGl_NamedResource)
35 //! Simple class to reset unpack alignment settings
36 struct OpenGl_UnpackAlignmentSentry
38 //! Reset unpack alignment settings to safe values
39 static void Reset (const OpenGl_Context& theCtx)
41 theCtx.core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
42 if (theCtx.hasUnpackRowLength)
44 theCtx.core11fwd->glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
48 OpenGl_UnpackAlignmentSentry (const Handle(OpenGl_Context)& theCtx)
49 : myCtx (theCtx.get()) {}
51 ~OpenGl_UnpackAlignmentSentry()
57 OpenGl_Context* myCtx;
60 //! Compute the upper mipmap level for complete mipmap set (e.g. till the 1x1 level).
61 static Standard_Integer computeUpperMipMapLevel (Standard_Integer theSize)
63 for (Standard_Integer aMipIter = 0;; ++aMipIter, theSize /= 2)
72 //! Compute the upper mipmap level for complete mipmap set (e.g. till the 1x1 level).
73 static Standard_Integer computeUpperMipMapLevel (Standard_Integer theSizeX, Standard_Integer theSizeY)
75 return computeUpperMipMapLevel (Max (theSizeX, theSizeY));
78 //! Compute size of the smallest defined mipmap level (for verbose messages).
79 static Graphic3d_Vec2i computeSmallestMipMapSize (const Graphic3d_Vec2i& theBaseSize, Standard_Integer theMaxLevel)
81 Graphic3d_Vec2i aMipSizeXY = theBaseSize;
82 for (Standard_Integer aMipIter = 0;; ++aMipIter)
84 if (aMipIter > theMaxLevel)
90 if (aMipSizeXY.x() == 0) { aMipSizeXY.x() = 1; }
91 if (aMipSizeXY.y() == 0) { aMipSizeXY.y() = 1; }
97 // =======================================================================
98 // function : OpenGl_Texture
100 // =======================================================================
101 OpenGl_Texture::OpenGl_Texture (const TCollection_AsciiString& theResourceId,
102 const Handle(Graphic3d_TextureParams)& theParams)
103 : OpenGl_NamedResource (theResourceId),
104 mySampler (new OpenGl_Sampler (theParams)),
106 myTextureId (NO_TEXTURE),
107 myTarget (GL_TEXTURE_2D),
111 myTextFormat (GL_RGBA),
112 mySizedFormat(GL_RGBA8),
121 // =======================================================================
122 // function : ~OpenGl_Texture
124 // =======================================================================
125 OpenGl_Texture::~OpenGl_Texture()
130 // =======================================================================
133 // =======================================================================
134 bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& theCtx)
136 if (myTextureId != NO_TEXTURE)
141 theCtx->core11fwd->glGenTextures (1, &myTextureId);
142 if (myTextureId == NO_TEXTURE)
147 //mySampler->Create (theCtx); // do not create sampler object by default
151 // =======================================================================
152 // function : Release
154 // =======================================================================
155 void OpenGl_Texture::Release (OpenGl_Context* theGlCtx)
157 mySampler->Release (theGlCtx);
158 if (myTextureId == NO_TEXTURE)
163 // application can not handle this case by exception - this is bug in code
164 Standard_ASSERT_RETURN (theGlCtx != NULL,
165 "OpenGl_Texture destroyed without GL context! Possible GPU memory leakage...",);
167 if (theGlCtx->IsValid())
169 theGlCtx->core11fwd->glDeleteTextures (1, &myTextureId);
171 myTextureId = NO_TEXTURE;
172 mySizeX = mySizeY = mySizeZ = 0;
175 // =======================================================================
176 // function : applyDefaultSamplerParams
178 // =======================================================================
179 void OpenGl_Texture::applyDefaultSamplerParams (const Handle(OpenGl_Context)& theCtx)
181 OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), NULL, myTarget, myMaxMipLevel);
182 if (mySampler->IsValid() && !mySampler->IsImmutable())
184 OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), mySampler.get(), myTarget, myMaxMipLevel);
188 // =======================================================================
191 // =======================================================================
192 void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
193 const Graphic3d_TextureUnit theTextureUnit) const
195 if (theCtx->core15fwd != NULL)
197 theCtx->core15fwd->glActiveTexture (GL_TEXTURE0 + theTextureUnit);
199 mySampler->Bind (theCtx, theTextureUnit);
200 theCtx->core11fwd->glBindTexture (myTarget, myTextureId);
203 // =======================================================================
206 // =======================================================================
207 void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
208 const Graphic3d_TextureUnit theTextureUnit) const
210 if (theCtx->core15fwd != NULL)
212 theCtx->core15fwd->glActiveTexture (GL_TEXTURE0 + theTextureUnit);
214 mySampler->Unbind (theCtx, theTextureUnit);
215 theCtx->core11fwd->glBindTexture (myTarget, NO_TEXTURE);
218 //=======================================================================
219 //function : InitSamplerObject
221 //=======================================================================
222 bool OpenGl_Texture::InitSamplerObject (const Handle(OpenGl_Context)& theCtx)
224 return myTextureId != NO_TEXTURE
225 && mySampler->Init (theCtx, *this);
228 // =======================================================================
231 // =======================================================================
232 bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
233 const OpenGl_TextureFormat& theFormat,
234 const Graphic3d_Vec2i& theSizeXY,
235 const Graphic3d_TypeOfTexture theType,
236 const Image_PixMap* theImage)
238 if (theSizeXY.x() < 1
239 || theSizeXY.y() < 1)
241 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
242 TCollection_AsciiString ("Error: texture of 0 size cannot be created [") + myResourceId +"]");
243 Release (theCtx.get());
247 const GLenum aTarget = (theType == Graphic3d_TOT_1D
248 && theCtx->GraphicsLibrary() != Aspect_GraphicsLibrary_OpenGLES)
251 const bool toPatchExisting = IsValid()
252 && myTextFormat == theFormat.PixelFormat()
253 && myTarget == aTarget
254 && HasMipmaps() == (theType == Graphic3d_TOT_2D_MIPMAP)
255 && mySizeX == theSizeXY.x()
256 && (mySizeY == theSizeXY.y() || theType == Graphic3d_TOT_1D);
257 if (!Create (theCtx))
259 Release (theCtx.get());
263 if (theImage != NULL)
265 myIsAlpha = theImage->Format() == Image_Format_Alpha
266 || theImage->Format() == Image_Format_AlphaF;
267 myIsTopDown = theImage->IsTopDown();
271 myIsAlpha = theFormat.PixelFormat() == GL_ALPHA;
274 myMaxMipLevel = theType == Graphic3d_TOT_2D_MIPMAP && theCtx->arbFBO != NULL
275 ? computeUpperMipMapLevel (theSizeXY.x(), theSizeXY.y())
277 myTextFormat = theFormat.PixelFormat();
278 mySizedFormat = theFormat.InternalFormat();
281 // ES 2.0 does not support sized formats and format conversions - them detected from data type
282 const GLint anIntFormat = (theCtx->GraphicsLibrary() != Aspect_GraphicsLibrary_OpenGLES
283 || theCtx->IsGlGreaterEqual (3, 0))
284 ? theFormat.InternalFormat()
285 : theFormat.PixelFormat();
287 if (theFormat.DataType() == GL_FLOAT
288 && !theCtx->arbTexFloat)
290 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
291 TCollection_AsciiString ("Error: floating-point textures are not supported by hardware [") + myResourceId +"]");
292 Release (theCtx.get());
296 const GLsizei aMaxSize = theCtx->MaxTextureSize();
297 if (theSizeXY.x() > aMaxSize
298 || theSizeXY.y() > aMaxSize)
300 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
301 TCollection_AsciiString ("Error: Texture dimension - ") + theSizeXY.x() + "x" + theSizeXY.y()
302 + " exceeds hardware limits (" + aMaxSize + "x" + aMaxSize + ")"
303 + " [" + myResourceId +"]");
304 Release (theCtx.get());
307 else if (theCtx->GraphicsLibrary() != Aspect_GraphicsLibrary_OpenGL
308 && !theCtx->IsGlGreaterEqual (3, 0)
311 // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications
312 // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT!
313 // Trying to create NPOT textures on such hardware will not fail
314 // but driver will fall back into software rendering,
315 const GLsizei aWidthP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.x(), aMaxSize);
316 const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.y(), aMaxSize);
317 if (theSizeXY.x() != aWidthP2
318 || (theType != Graphic3d_TOT_1D && theSizeXY.y() != aHeightP2))
320 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
321 TCollection_AsciiString ("Error: NPOT Textures (") + theSizeXY.x() + "x" + theSizeXY.y() + ")"
322 " are not supported by hardware [" + myResourceId +"]");
323 Release (theCtx.get());
327 else if (theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES
328 && !theCtx->IsGlGreaterEqual (3, 0)
329 && theType == Graphic3d_TOT_2D_MIPMAP)
331 // Mipmap NPOT textures are not supported by OpenGL ES 2.0.
332 const GLsizei aWidthP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.x(), aMaxSize);
333 const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.y(), aMaxSize);
334 if (theSizeXY.x() != aWidthP2
335 || theSizeXY.y() != aHeightP2)
337 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
338 TCollection_AsciiString ("Warning: Mipmap NPOT Textures (") + theSizeXY.x() + "x" + theSizeXY.y() + ")"
339 " are not supported by OpenGL ES 2.0 [" + myResourceId +"]");
344 GLint aTestWidth = 0, aTestHeight = 0;
345 GLvoid* aDataPtr = (theImage != NULL) ? (GLvoid* )theImage->Data() : NULL;
347 // setup the alignment
348 OpenGl_UnpackAlignmentSentry anUnpackSentry (theCtx);
349 (void)anUnpackSentry; // avoid compiler warning
351 if (aDataPtr != NULL)
353 const GLint anAligment = Min ((GLint )theImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
354 theCtx->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
355 const GLint anExtraBytes = GLint(theImage->RowExtraBytes());
356 const GLint aPixelsWidth = GLint(theImage->SizeRowBytes() / theImage->SizePixelBytes());
357 if (theCtx->hasUnpackRowLength)
359 theCtx->core11fwd->glPixelStorei (GL_UNPACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0);
361 else if (anExtraBytes >= anAligment)
363 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
364 TCollection_AsciiString ("Error: unsupported image stride within OpenGL ES 2.0 [") + myResourceId +"]");
365 Release (theCtx.get());
373 case Graphic3d_TOT_1D:
375 if (theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES)
377 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
378 TCollection_AsciiString ( "Error: 1D textures are not supported by hardware [") + myResourceId +"]");
379 Release (theCtx.get());
384 applyDefaultSamplerParams (theCtx);
387 theCtx->core11fwd->glTexSubImage1D (GL_TEXTURE_1D, 0, 0,
388 theSizeXY.x(), theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
393 // use proxy to check texture could be created or not
394 theCtx->core11fwd->glTexImage1D (GL_PROXY_TEXTURE_1D, 0, anIntFormat,
396 theFormat.PixelFormat(), theFormat.DataType(), NULL);
397 theCtx->core11fwd->glGetTexLevelParameteriv (GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
398 theCtx->core11fwd->glGetTexLevelParameteriv (GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
401 // no memory or broken input parameters
403 Release (theCtx.operator->());
407 theCtx->core11fwd->glTexImage1D (GL_TEXTURE_1D, 0, anIntFormat,
409 theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
410 if (theCtx->core11fwd->glGetError() != GL_NO_ERROR)
413 Release (theCtx.get());
417 mySizeX = theSizeXY.x();
423 case Graphic3d_TOT_2D:
424 case Graphic3d_TOT_2D_MIPMAP:
427 applyDefaultSamplerParams (theCtx);
430 theCtx->core11fwd->glTexSubImage2D (GL_TEXTURE_2D, 0,
432 theSizeXY.x(), theSizeXY.y(),
433 theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
435 if (myMaxMipLevel > 0)
438 theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
439 if (theCtx->core11fwd->glGetError() != GL_NO_ERROR)
449 if (theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGL)
451 // use proxy to check texture could be created or not
452 theCtx->core11fwd->glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat,
453 theSizeXY.x(), theSizeXY.y(), 0,
454 theFormat.PixelFormat(), theFormat.DataType(), NULL);
455 theCtx->core11fwd->glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
456 theCtx->core11fwd->glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
457 theCtx->core11fwd->glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
458 if (aTestWidth == 0 || aTestHeight == 0)
460 // no memory or broken input parameters
462 Release (theCtx.get());
467 theCtx->core11fwd->glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
468 theSizeXY.x(), theSizeXY.y(), 0,
469 theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
470 GLenum anErr = theCtx->core11fwd->glGetError();
471 if (anErr != GL_NO_ERROR)
473 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
474 TCollection_AsciiString ("Error: 2D texture ") + theSizeXY.x() + "x" + theSizeXY.y()
475 + " IF: " + OpenGl_TextureFormat::FormatFormat (anIntFormat)
476 + " PF: " + OpenGl_TextureFormat::FormatFormat (theFormat.PixelFormat())
477 + " DT: " + OpenGl_TextureFormat::FormatDataType (theFormat.DataType())
478 + " can not be created with error " + OpenGl_Context::FormatGlError (anErr)
479 + " [" + myResourceId +"]");
481 Release (theCtx.get());
485 mySizeX = theSizeXY.x();
486 mySizeY = theSizeXY.y();
488 if (myMaxMipLevel > 0)
491 //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
492 theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
493 anErr = theCtx->core11fwd->glGetError();
494 if (anErr != GL_NO_ERROR)
497 if (theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES
498 && (theFormat.InternalFormat() == GL_RGB8
499 || theFormat.InternalFormat() == GL_SRGB8))
501 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
502 TCollection_AsciiString ("Warning: generating mipmaps requires color-renderable format, while giving ")
503 + OpenGl_TextureFormat::FormatFormat (anIntFormat) + " [" + myResourceId +"]");
507 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
508 TCollection_AsciiString ("Warning: generating mipmaps has failed [") + myResourceId +"]");
516 case Graphic3d_TOT_CUBEMAP:
519 Release (theCtx.get());
524 Release (theCtx.get());
528 // =======================================================================
531 // =======================================================================
532 bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
533 const Image_PixMap& theImage,
534 const Graphic3d_TypeOfTexture theType,
535 const Standard_Boolean theIsColorMap)
537 if (theImage.IsEmpty())
539 Release (theCtx.get());
543 const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindFormat (theCtx, theImage.Format(), theIsColorMap);
544 if (!aFormat.IsValid())
546 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
547 TCollection_AsciiString ("Error: No suitable texture format for ") + Image_PixMap::ImageFormatToString (theImage.Format()) + " image format"
548 + " [" + myResourceId +"]");
549 Release (theCtx.get());
553 return Init (theCtx, aFormat, Graphic3d_Vec2i ((Standard_Integer)theImage.SizeX(), (Standard_Integer)theImage.SizeY()),
557 // =======================================================================
560 // =======================================================================
561 bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
562 const Handle(Graphic3d_TextureMap)& theTextureMap)
564 if (theTextureMap.IsNull())
569 switch (theTextureMap->Type())
571 case Graphic3d_TOT_CUBEMAP:
573 return InitCubeMap (theCtx, Handle(Graphic3d_CubeMap)::DownCast(theTextureMap),
574 0, Image_Format_RGB, false, theTextureMap->IsColorMap());
578 if (theCtx->SupportedTextureFormats()->HasCompressed()
579 && !theCtx->caps->compressedTexturesDisable)
581 if (Handle(Image_CompressedPixMap) aCompressed = theTextureMap->GetCompressedImage (theCtx->SupportedTextureFormats()))
583 return InitCompressed (theCtx, *aCompressed, theTextureMap->IsColorMap());
587 Handle(Image_PixMap) anImage = theTextureMap->GetImage (theCtx->SupportedTextureFormats());
588 if (anImage.IsNull())
592 return Init (theCtx, *anImage, theTextureMap->Type(), theTextureMap->IsColorMap());
597 // =======================================================================
598 // function : InitCompressed
600 // =======================================================================
601 bool OpenGl_Texture::InitCompressed (const Handle(OpenGl_Context)& theCtx,
602 const Image_CompressedPixMap& theImage,
603 const Standard_Boolean theIsColorMap)
605 if (theImage.SizeX() < 1
606 || theImage.SizeY() < 1
607 || theImage.FaceData().IsNull())
609 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
610 "Error: texture of 0 size cannot be created.");
611 Release (theCtx.get());
614 if (theImage.SizeX() > theCtx->MaxTextureSize()
615 || theImage.SizeY() > theCtx->MaxTextureSize())
617 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
618 TCollection_AsciiString ("Error: Texture dimension - ") + theImage.SizeX() + "x" + theImage.SizeY()
619 + " exceeds hardware limits (" + theCtx->MaxTextureSize() + "x" + theCtx->MaxTextureSize() + ")");
620 Release (theCtx.get());
624 const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindCompressedFormat (theCtx, theImage.CompressedFormat(), theIsColorMap);
625 if (!aFormat.IsValid())
627 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
628 TCollection_AsciiString ("Error: No suitable texture format for ") + Image_PixMap::ImageFormatToString (theImage.CompressedFormat()) + " image format "
629 + " [" + myResourceId +"]");
630 Release (theCtx.get());
634 if (!Create (theCtx))
639 myTarget = GL_TEXTURE_2D;
641 myTextFormat = aFormat.Format();
642 mySizedFormat = aFormat.Internal();
643 myIsTopDown = theImage.IsTopDown();
644 mySizeX = theImage.SizeX();
645 mySizeY = theImage.SizeY();
646 myMaxMipLevel = Max (theImage.MipMaps().Size() - 1, 0);
647 if (myMaxMipLevel > 0
648 && !theImage.IsCompleteMipMapSet())
650 const Graphic3d_Vec2i aMipSize = computeSmallestMipMapSize (Graphic3d_Vec2i (mySizeX, mySizeY), myMaxMipLevel);
651 if (!theCtx->HasTextureBaseLevel())
654 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0, GL_DEBUG_SEVERITY_MEDIUM,
655 TCollection_AsciiString ("Warning: compressed 2D texture ") + myResourceId + " " + mySizeX + "x" + mySizeY
656 + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y() + "; mipmaps will be ignored");
660 Message::SendTrace (TCollection_AsciiString ("Warning: compressed 2D texture ") + myResourceId + " " + mySizeX + "x" + mySizeY
661 + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y());
666 applyDefaultSamplerParams (theCtx);
668 // setup the alignment
669 OpenGl_UnpackAlignmentSentry::Reset (*theCtx);
671 Graphic3d_Vec2i aMipSizeXY (theImage.SizeX(), theImage.SizeY());
672 const Standard_Byte* aData = theImage.FaceData()->Data();
673 for (Standard_Integer aMipIter = 0; aMipIter <= myMaxMipLevel; ++aMipIter)
675 const Standard_Integer aMipLength = theImage.MipMaps().Value (aMipIter);
676 theCtx->Functions()->glCompressedTexImage2D (GL_TEXTURE_2D, aMipIter, mySizedFormat, aMipSizeXY.x(), aMipSizeXY.y(), 0, aMipLength, aData);
677 const GLenum aTexImgErr = theCtx->core11fwd->glGetError();
678 if (aTexImgErr != GL_NO_ERROR)
680 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
681 TCollection_AsciiString ("Error: 2D compressed texture ") + aMipSizeXY.x() + "x" + aMipSizeXY.y()
682 + " IF: " + OpenGl_TextureFormat::FormatFormat (aFormat.Internal())
683 + " PF: " + OpenGl_TextureFormat::FormatFormat (aFormat.PixelFormat())
684 + " DT: " + OpenGl_TextureFormat::FormatDataType (aFormat.DataType())
685 + " can not be created with error " + OpenGl_Context::FormatGlError (aTexImgErr) + ".");
687 Release (theCtx.get());
693 if (aMipSizeXY.x() == 0) { aMipSizeXY.x() = 1; }
694 if (aMipSizeXY.y() == 0) { aMipSizeXY.y() = 1; }
701 // =======================================================================
702 // function : Init2DMultisample
704 // =======================================================================
705 bool OpenGl_Texture::Init2DMultisample (const Handle(OpenGl_Context)& theCtx,
706 const Standard_Integer theNbSamples,
707 const Standard_Integer theTextFormat,
708 const Standard_Integer theSizeX,
709 const Standard_Integer theSizeY)
712 || theNbSamples > theCtx->MaxMsaaSamples()
715 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
716 TCollection_AsciiString ("Error: MSAA texture ") + theSizeX + "x" + theSizeY + "@" + myNbSamples
717 + " exceeds samples limit: " + theCtx->MaxMsaaSamples() + ".");
721 myNbSamples = OpenGl_Context::GetPowerOfTwo (theNbSamples, theCtx->MaxMsaaSamples());
722 myTarget = GL_TEXTURE_2D_MULTISAMPLE;
724 if(theSizeX > theCtx->MaxTextureSize()
725 || theSizeY > theCtx->MaxTextureSize())
727 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
728 TCollection_AsciiString ("Error: MSAA texture ") + theSizeX + "x" + theSizeY + "@" + myNbSamples
729 + " exceeds size limit: " + theCtx->MaxTextureSize() + "x" + theCtx->MaxTextureSize() + ".");
734 //myTextFormat = theTextFormat;
735 mySizedFormat = theTextFormat;
736 if (theCtx->HasTextureMultisampling()
737 && theCtx->Functions()->glTexStorage2DMultisample != NULL) // OpenGL 4.3
739 theCtx->Functions()->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
741 else if (theCtx->HasTextureMultisampling()
742 && theCtx->Functions()->glTexImage2DMultisample != NULL) // OpenGL 3.2
744 theCtx->Functions()->glTexImage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
748 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
749 "Error: MSAA textures are not supported by hardware.");
754 const GLenum aTexImgErr = theCtx->core11fwd->glGetError();
755 if (aTexImgErr != GL_NO_ERROR)
757 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
758 TCollection_AsciiString ("Error: MSAA texture ") + theSizeX + "x" + theSizeY + "@" + myNbSamples
759 + " IF: " + OpenGl_TextureFormat::FormatFormat (theTextFormat)
760 + " cannot be created with error " + OpenGl_Context::FormatGlError (aTexImgErr) + ".");
772 // =======================================================================
773 // function : InitRectangle
775 // =======================================================================
776 bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
777 const Standard_Integer theSizeX,
778 const Standard_Integer theSizeY,
779 const OpenGl_TextureFormat& theFormat)
781 if (!theCtx->IsGlGreaterEqual (3, 0)
783 || theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES)
788 myTarget = GL_TEXTURE_RECTANGLE;
792 const GLsizei aSizeX = Min (theCtx->MaxTextureSize(), theSizeX);
793 const GLsizei aSizeY = Min (theCtx->MaxTextureSize(), theSizeY);
796 applyDefaultSamplerParams (theCtx);
798 myTextFormat = theFormat.Format();
799 mySizedFormat = theFormat.Internal();
801 // setup the alignment
802 OpenGl_UnpackAlignmentSentry::Reset (*theCtx);
804 theCtx->core11fwd->glTexImage2D (GL_PROXY_TEXTURE_RECTANGLE, 0, mySizedFormat,
806 myTextFormat, GL_FLOAT, NULL);
808 GLint aTestSizeX = 0, aTestSizeY = 0;
809 theCtx->core11fwd->glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH, &aTestSizeX);
810 theCtx->core11fwd->glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
811 theCtx->core11fwd->glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
812 if (aTestSizeX == 0 || aTestSizeY == 0)
818 theCtx->core11fwd->glTexImage2D (myTarget, 0, mySizedFormat,
820 myTextFormat, GL_FLOAT, NULL);
821 if (theCtx->core11fwd->glGetError() != GL_NO_ERROR)
833 // =======================================================================
836 // =======================================================================
837 bool OpenGl_Texture::Init3D (const Handle(OpenGl_Context)& theCtx,
838 const OpenGl_TextureFormat& theFormat,
839 const Graphic3d_Vec3i& theSizeXYZ,
840 const void* thePixels)
842 if (theCtx->Functions()->glTexImage3D == NULL)
844 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
845 "Error: three-dimensional textures are not supported by hardware.");
854 myTarget = GL_TEXTURE_3D;
858 const Graphic3d_Vec3i aSizeXYZ = theSizeXYZ.cwiseMin (Graphic3d_Vec3i (theCtx->MaxTextureSize()));
859 if (aSizeXYZ != theSizeXYZ)
861 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
862 "Error: 3D texture dimensions exceed hardware limits.");
863 Release (theCtx.get());
869 if (theFormat.DataType() == GL_FLOAT
870 && !theCtx->arbTexFloat)
872 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
873 "Error: floating-point textures are not supported by hardware.");
874 Release (theCtx.get());
879 mySizedFormat = theFormat.InternalFormat();
881 // setup the alignment
882 OpenGl_UnpackAlignmentSentry::Reset (*theCtx);
884 if (theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGL)
886 theCtx->Functions()->glTexImage3D (GL_PROXY_TEXTURE_3D, 0, mySizedFormat,
887 aSizeXYZ.x(), aSizeXYZ.y(), aSizeXYZ.z(), 0,
888 theFormat.PixelFormat(), theFormat.DataType(), NULL);
890 NCollection_Vec3<GLint> aTestSizeXYZ;
891 theCtx->core11fwd->glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &aTestSizeXYZ.x());
892 theCtx->core11fwd->glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_HEIGHT, &aTestSizeXYZ.y());
893 theCtx->core11fwd->glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_DEPTH, &aTestSizeXYZ.z());
894 theCtx->core11fwd->glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
895 if (aTestSizeXYZ.x() == 0 || aTestSizeXYZ.y() == 0 || aTestSizeXYZ.z() == 0)
898 Release (theCtx.get());
903 applyDefaultSamplerParams (theCtx);
904 theCtx->Functions()->glTexImage3D (myTarget, 0, mySizedFormat,
905 aSizeXYZ.x(), aSizeXYZ.y(), aSizeXYZ.z(), 0,
906 theFormat.PixelFormat(), theFormat.DataType(), thePixels);
908 if (theCtx->core11fwd->glGetError() != GL_NO_ERROR)
911 Release (theCtx.get());
915 mySizeX = aSizeXYZ.x();
916 mySizeY = aSizeXYZ.y();
917 mySizeZ = aSizeXYZ.z();
923 // =======================================================================
924 // function : InitCubeMap
926 // =======================================================================
927 bool OpenGl_Texture::InitCubeMap (const Handle(OpenGl_Context)& theCtx,
928 const Handle(Graphic3d_CubeMap)& theCubeMap,
929 Standard_Size theSize,
930 Image_Format theFormat,
931 Standard_Boolean theToGenMipmap,
932 Standard_Boolean theIsColorMap)
934 if (!Create (theCtx))
936 Release (theCtx.get());
940 Handle(Image_PixMap) anImage;
941 Handle(Image_CompressedPixMap) aCompImage;
942 OpenGl_TextureFormat aFormat;
943 if (!theCubeMap.IsNull())
946 if (theCtx->SupportedTextureFormats()->HasCompressed()
947 && !theCtx->caps->compressedTexturesDisable)
949 aCompImage = theCubeMap->CompressedValue (theCtx->SupportedTextureFormats());
951 if (!aCompImage.IsNull())
953 aFormat = OpenGl_TextureFormat::FindCompressedFormat (theCtx, aCompImage->CompressedFormat(), theIsColorMap);
954 if (aFormat.IsValid())
956 theToGenMipmap = false;
957 theSize = aCompImage->SizeX();
958 theFormat = aCompImage->BaseFormat();
959 myMaxMipLevel = Max (aCompImage->MipMaps().Size() - 1, 0);
960 if (myMaxMipLevel > 0
961 && !aCompImage->IsCompleteMipMapSet())
963 const Graphic3d_Vec2i aMipSize = computeSmallestMipMapSize (Graphic3d_Vec2i (aCompImage->SizeX(), aCompImage->SizeY()), myMaxMipLevel);
964 if (!theCtx->HasTextureBaseLevel())
967 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0, GL_DEBUG_SEVERITY_MEDIUM,
968 TCollection_AsciiString ("Warning: Cubemap compressed texture ") + theCubeMap->GetId() + " " + aCompImage->SizeX() + "x" + aCompImage->SizeX()
969 + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y() + "; mipmaps will be ignored");
973 Message::SendTrace (TCollection_AsciiString ("Warning: Cubemap compressed texture ") + theCubeMap->GetId() + " " + aCompImage->SizeX() + "x" + aCompImage->SizeX()
974 + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y());
978 OpenGl_UnpackAlignmentSentry::Reset (*theCtx);
982 aCompImage.Nullify();
986 if (!aFormat.IsValid())
988 anImage = theCubeMap->Reset().Value (theCtx->SupportedTextureFormats());
989 if (anImage.IsNull())
991 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
992 "Unable to get the first side of cubemap");
993 Release(theCtx.get());
997 theSize = anImage->SizeX();
998 theFormat = anImage->Format();
999 theToGenMipmap = theCubeMap->HasMipmaps();
1000 myMaxMipLevel = theToGenMipmap ? computeUpperMipMapLevel ((Standard_Integer )theSize) : 0;
1003 myIsTopDown = theCubeMap->IsTopDown();
1007 myMaxMipLevel = theToGenMipmap ? computeUpperMipMapLevel ((Standard_Integer )theSize) : 0;
1010 if (!aFormat.IsValid())
1012 aFormat = OpenGl_TextureFormat::FindFormat (theCtx, theFormat, theIsColorMap);
1014 if (!aFormat.IsValid())
1016 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
1017 TCollection_AsciiString ("Error: No suitable texture format for ") + Image_PixMap::ImageFormatToString (theFormat) + " image format"
1018 + " [" + myResourceId +"]");
1020 Release(theCtx.get());
1025 && theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES
1026 && !theCtx->IsGlGreaterEqual (3, 0)
1027 && (aFormat.PixelFormat() == GL_SRGB_EXT
1028 || aFormat.PixelFormat() == GL_SRGB_ALPHA_EXT))
1030 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
1031 TCollection_AsciiString ("Warning, GL_EXT_sRGB disallows generation of mipmaps - fallback using non-sRGB format")
1032 + " [" + myResourceId +"]");
1033 aFormat.SetPixelFormat (aFormat.PixelFormat() == GL_SRGB_EXT ? GL_RGB : GL_RGBA);
1034 aFormat.SetInternalFormat(aFormat.PixelFormat() == GL_SRGB_EXT ? GL_RGB8 : GL_RGBA8);
1037 myTarget = GL_TEXTURE_CUBE_MAP;
1039 mySizeX = (GLsizei )theSize;
1040 mySizeY = (GLsizei )theSize;
1041 myTextFormat = aFormat.Format();
1042 mySizedFormat = aFormat.Internal();
1044 // ES 2.0 does not support sized formats and format conversions - them detected from data type
1045 const GLint anIntFormat = (theCtx->GraphicsLibrary() != Aspect_GraphicsLibrary_OpenGLES
1046 || theCtx->IsGlGreaterEqual (3, 0))
1047 ? aFormat.InternalFormat()
1048 : aFormat.PixelFormat();
1051 applyDefaultSamplerParams (theCtx);
1053 for (Standard_Integer i = 0; i < 6; ++i)
1055 const Standard_Byte* aData = NULL;
1057 if (!theCubeMap.IsNull())
1061 if (!aCompImage.IsNull())
1063 aCompImage = theCubeMap->CompressedValue (theCtx->SupportedTextureFormats());
1067 anImage = theCubeMap->Value (theCtx->SupportedTextureFormats());
1070 if (!aCompImage.IsNull())
1072 Graphic3d_Vec2i aMipSizeXY (mySizeX, mySizeY);
1073 aData = aCompImage->FaceData()->Data();
1074 for (Standard_Integer aMipIter = 0; aMipIter <= myMaxMipLevel; ++aMipIter)
1076 const Standard_Integer aMipLength = aCompImage->MipMaps().Value (aMipIter);
1077 theCtx->Functions()->glCompressedTexImage2D (GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, aMipIter, mySizedFormat, aMipSizeXY.x(), aMipSizeXY.y(), 0, aMipLength, aData);
1078 const GLenum aTexImgErr = theCtx->core11fwd->glGetError();
1079 if (aTexImgErr != GL_NO_ERROR)
1081 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
1082 TCollection_AsciiString ("Error: cubemap compressed texture ") + aMipSizeXY.x() + "x" + aMipSizeXY.y()
1083 + " IF: " + OpenGl_TextureFormat::FormatFormat (aFormat.Internal())
1084 + " PF: " + OpenGl_TextureFormat::FormatFormat (aFormat.PixelFormat())
1085 + " DT: " + OpenGl_TextureFormat::FormatDataType (aFormat.DataType())
1086 + " can not be created with error " + OpenGl_Context::FormatGlError (aTexImgErr) + ".");
1088 Release (theCtx.get());
1092 aData += aMipLength;
1094 if (aMipSizeXY.x() == 0) { aMipSizeXY.x() = 1; }
1095 if (aMipSizeXY.y() == 0) { aMipSizeXY.y() = 1; }
1102 if (!anImage.IsNull())
1104 const GLint anAligment = Min ((GLint)anImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
1105 const GLint anExtraBytes = GLint(anImage->RowExtraBytes());
1106 const GLint aPixelsWidth = GLint(anImage->SizeRowBytes() / anImage->SizePixelBytes());
1107 const GLint aRowLength = (anExtraBytes >= anAligment) ? aPixelsWidth : 0;
1108 if (theCtx->hasUnpackRowLength)
1110 theCtx->core11fwd->glPixelStorei (GL_UNPACK_ROW_LENGTH, aRowLength);
1114 && !theCtx->hasUnpackRowLength)
1116 Handle(Image_PixMap) aCopyImage = new Image_PixMap();
1117 aCopyImage->InitTrash (theFormat, theSize, theSize);
1118 const Standard_Size aRowBytesPacked = std::min (aCopyImage->SizeRowBytes(), anImage->SizeRowBytes());
1119 for (unsigned int y = 0; y < theSize; ++y)
1121 memcpy (aCopyImage->ChangeRow (y), anImage->ChangeRow (y), aRowBytesPacked);
1123 anImage = aCopyImage;
1124 const GLint anAligment2 = Min((GLint)anImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
1125 theCtx->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment2);
1129 theCtx->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
1132 aData = anImage->Data();
1136 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
1137 TCollection_AsciiString() + "Unable to get [" + i + "] side of cubemap");
1139 Release (theCtx.get());
1145 theCtx->core11fwd->glTexImage2D (GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0,
1147 GLsizei(theSize), GLsizei(theSize),
1148 0, aFormat.PixelFormat(), aFormat.DataType(),
1151 OpenGl_UnpackAlignmentSentry::Reset (*theCtx);
1153 const GLenum anErr = theCtx->core11fwd->glGetError();
1154 if (anErr != GL_NO_ERROR)
1156 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
1157 TCollection_AsciiString ("Error: cubemap side ") + (int )theSize + "x" + (int )theSize
1158 + " IF: " + OpenGl_TextureFormat::FormatFormat (anIntFormat)
1159 + " PF: " + OpenGl_TextureFormat::FormatFormat (aFormat.PixelFormat())
1160 + " DT: " + OpenGl_TextureFormat::FormatDataType (aFormat.DataType())
1161 + " can not be created with error " + OpenGl_Context::FormatGlError (anErr) + ".");
1163 Release (theCtx.get());
1168 if (theToGenMipmap && theCtx->arbFBO != NULL)
1170 theCtx->arbFBO->glGenerateMipmap (myTarget);
1171 const GLenum anErr = theCtx->core11fwd->glGetError();
1172 if (anErr != GL_NO_ERROR)
1174 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
1175 TCollection_AsciiString ("Unable to generate mipmap of cubemap with format ")
1176 + OpenGl_TextureFormat::FormatFormat (anIntFormat)
1177 + ", error " + OpenGl_Context::FormatGlError (anErr));
1182 Unbind (theCtx.get());
1186 // =======================================================================
1187 // function : PixelSizeOfPixelFormat
1189 // =======================================================================
1190 Standard_Size OpenGl_Texture::PixelSizeOfPixelFormat (Standard_Integer theInternalFormat)
1192 switch(theInternalFormat)
1194 // RED variations (GL_RED, OpenGL 3.0+)
1196 case GL_R8: return 1;
1197 case GL_R16: return 2;
1198 case GL_R16F: return 2;
1199 case GL_R32F: return 4;
1201 case GL_RGB: return 3;
1202 case GL_RGB8: return 3;
1203 case GL_RGB16: return 6;
1204 case GL_RGB16F: return 6;
1205 case GL_RGB32F: return 12;
1207 case GL_RGBA: return 4;
1208 case GL_RGBA8: return 4;
1209 case GL_RGB10_A2: return 4;
1210 case GL_RGBA12: return 6;
1211 case GL_RGBA16: return 8;
1212 case GL_RGBA16F: return 8;
1213 case GL_RGBA32F: return 16;
1215 case GL_BGRA_EXT: return 4;
1216 // ALPHA variations (deprecated)
1218 case GL_ALPHA8: return 1;
1219 case GL_ALPHA16: return 2;
1220 case GL_LUMINANCE: return 1;
1221 case GL_LUMINANCE_ALPHA: return 2;
1223 case GL_DEPTH24_STENCIL8: return 4;
1224 case GL_DEPTH32F_STENCIL8: return 8;
1225 case GL_DEPTH_COMPONENT16: return 2;
1226 case GL_DEPTH_COMPONENT24: return 3;
1227 case GL_DEPTH_COMPONENT32F: return 4;
1229 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: // DXT1 uses circa half a byte per pixel (64 bits per 4x4 block)
1230 case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
1231 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1232 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
1233 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: // DXT3/5 uses circa 1 byte per pixel (128 bits per 4x4 block)
1234 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
1235 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
1236 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
1242 // =======================================================================
1243 // function : EstimatedDataSize
1245 // =======================================================================
1246 Standard_Size OpenGl_Texture::EstimatedDataSize() const
1253 Standard_Size aSize = PixelSizeOfPixelFormat (mySizedFormat) * mySizeX * myNbSamples;
1256 aSize *= Standard_Size(mySizeY);
1260 aSize *= Standard_Size(mySizeZ);
1262 if (myTarget == GL_TEXTURE_CUBE_MAP)
1264 aSize *= 6; // cube sides
1266 if (myMaxMipLevel > 0)
1268 aSize = aSize + aSize / 3;
1273 // =======================================================================
1274 // function : ImageDump
1276 // =======================================================================
1277 bool OpenGl_Texture::ImageDump (Image_PixMap& theImage,
1278 const Handle(OpenGl_Context)& theCtx,
1279 Graphic3d_TextureUnit theTexUnit,
1280 Standard_Integer theLevel,
1281 Standard_Integer theCubeSide) const
1283 const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindSizedFormat (theCtx, mySizedFormat);
1286 || theCtx->GraphicsLibrary() == Aspect_GraphicsLibrary_OpenGLES // glGetTexImage() is unavailable in OpenGL ES
1288 || !aFormat.IsValid()
1289 || aFormat.ImageFormat() == Image_Format_UNKNOWN
1290 || (myTarget == GL_TEXTURE_CUBE_MAP
1291 && (theCubeSide < 0 || theCubeSide > 5)))
1296 GLenum aTarget = myTarget;
1297 Graphic3d_Vec2i aSize (mySizeX, mySizeY);
1298 if (myTarget == GL_TEXTURE_CUBE_MAP)
1300 aTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + theCubeSide;
1302 for (Standard_Integer aMipIter = 0; aMipIter < theLevel; ++aMipIter)
1305 if (aSize.x() == 0) { aSize.x() = 1; }
1306 if (aSize.y() == 0) { aSize.y() = 1; }
1308 if (!theImage.InitTrash (aFormat.ImageFormat(), aSize.x(), aSize.y()))
1313 const GLint anAligment = Min (GLint(theImage.MaxRowAligmentBytes()), 8); // limit to 8 bytes for OpenGL
1314 theCtx->core11fwd->glPixelStorei (GL_PACK_ALIGNMENT, anAligment);
1315 if (theCtx->hasPackRowLength)
1317 theCtx->core11fwd->glPixelStorei (GL_PACK_ROW_LENGTH, 0);
1319 // glGetTextureImage() allows avoiding to binding texture id, but apparently requires clean FBO binding state...
1320 //if (theCtx->core45 != NULL) { theCtx->core45->glGetTextureImage (myTextureId, theLevel, aFormat.PixelFormat(), aFormat.DataType(), (GLsizei )theImage.SizeBytes(), theImage.ChangeData()); } else
1322 Bind (theCtx, theTexUnit);
1323 theCtx->core11fwd->glGetTexImage (aTarget, theLevel, aFormat.PixelFormat(), aFormat.DataType(), theImage.ChangeData());
1324 Unbind (theCtx, theTexUnit);
1326 if (theImage.Format() != aFormat.ImageFormat())
1328 Image_PixMap::SwapRgbaBgra (theImage);
1331 const bool hasErrors = theCtx->ResetErrors (true);
1332 theCtx->core11fwd->glPixelStorei (GL_PACK_ALIGNMENT, 1);