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_GlCore32.hxx>
20 #include <Graphic3d_TextureParams.hxx>
21 #include <TCollection_ExtendedString.hxx>
22 #include <Standard_Assert.hxx>
23 #include <Image_PixMap.hxx>
26 //! Simple class to reset unpack alignment settings
27 struct OpenGl_UnpackAlignmentSentry
30 //! Reset unpack alignment settings to safe values
33 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
34 #if !defined(GL_ES_VERSION_2_0)
35 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
39 ~OpenGl_UnpackAlignmentSentry()
46 // =======================================================================
47 // function : OpenGl_Texture
49 // =======================================================================
50 OpenGl_Texture::OpenGl_Texture (const Handle(Graphic3d_TextureParams)& theParams)
52 myTextureId (NO_TEXTURE),
53 myTarget (GL_TEXTURE_2D),
56 myTextFormat (GL_RGBA),
57 myHasMipmaps (Standard_False),
61 if (myParams.IsNull())
63 myParams = new Graphic3d_TextureParams();
67 // =======================================================================
68 // function : ~OpenGl_Texture
70 // =======================================================================
71 OpenGl_Texture::~OpenGl_Texture()
76 // =======================================================================
77 // function : HasMipmaps
79 // =======================================================================
80 const Standard_Boolean OpenGl_Texture::HasMipmaps() const
85 // =======================================================================
86 // function : GetParams
88 // =======================================================================
89 const Handle(Graphic3d_TextureParams)& OpenGl_Texture::GetParams() const
94 // =======================================================================
95 // function : SetParams
97 // =======================================================================
98 void OpenGl_Texture::SetParams (const Handle(Graphic3d_TextureParams)& theParams)
100 myParams = theParams;
103 // =======================================================================
106 // =======================================================================
107 bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& )
109 if (myTextureId == NO_TEXTURE)
111 glGenTextures (1, &myTextureId);
113 return myTextureId != NO_TEXTURE;
116 // =======================================================================
117 // function : Release
119 // =======================================================================
120 void OpenGl_Texture::Release (OpenGl_Context* theGlCtx)
122 if (myTextureId == NO_TEXTURE)
127 // application can not handle this case by exception - this is bug in code
128 Standard_ASSERT_RETURN (theGlCtx != NULL,
129 "OpenGl_Texture destroyed without GL context! Possible GPU memory leakage...",);
131 if (theGlCtx->IsValid())
133 glDeleteTextures (1, &myTextureId);
135 myTextureId = NO_TEXTURE;
136 mySizeX = mySizeY = 0;
139 // =======================================================================
142 // =======================================================================
143 void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
144 const GLenum theTextureUnit) const
146 if (theCtx->core15fwd != NULL)
148 theCtx->core15fwd->glActiveTexture (theTextureUnit);
150 glBindTexture (myTarget, myTextureId);
153 // =======================================================================
156 // =======================================================================
157 void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
158 const GLenum theTextureUnit) const
160 if (theCtx->core15fwd != NULL)
162 theCtx->core15fwd->glActiveTexture (theTextureUnit);
164 glBindTexture (myTarget, NO_TEXTURE);
167 //=======================================================================
168 //function : GetDataFormat
170 //=======================================================================
171 bool OpenGl_Texture::GetDataFormat (const Handle(OpenGl_Context)& theCtx,
172 const Image_PixMap& theData,
173 GLint& theTextFormat,
174 GLenum& thePixelFormat,
177 theTextFormat = GL_RGBA8;
180 switch (theData.Format())
182 case Image_PixMap::ImgGrayF:
184 if (theCtx->core11 == NULL)
186 theTextFormat = GL_R8; // GL_R32F
187 thePixelFormat = GL_RED;
191 theTextFormat = GL_LUMINANCE8;
192 thePixelFormat = GL_LUMINANCE;
194 theDataType = GL_FLOAT;
197 case Image_PixMap::ImgAlphaF:
199 if (theCtx->core11 == NULL)
201 theTextFormat = GL_R8; // GL_R32F
202 thePixelFormat = GL_RED;
206 theTextFormat = GL_ALPHA8;
207 thePixelFormat = GL_ALPHA;
209 theDataType = GL_FLOAT;
212 case Image_PixMap::ImgRGBAF:
214 theTextFormat = GL_RGBA8; // GL_RGBA32F
215 thePixelFormat = GL_RGBA;
216 theDataType = GL_FLOAT;
219 case Image_PixMap::ImgBGRAF:
221 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
225 theTextFormat = GL_RGBA8; // GL_RGBA32F
226 thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA
227 theDataType = GL_FLOAT;
230 case Image_PixMap::ImgRGBF:
232 theTextFormat = GL_RGB8; // GL_RGB32F
233 thePixelFormat = GL_RGB;
234 theDataType = GL_FLOAT;
237 case Image_PixMap::ImgBGRF:
239 #if !defined(GL_ES_VERSION_2_0)
240 theTextFormat = GL_RGB8; // GL_RGB32F
241 thePixelFormat = GL_BGR; // equals to GL_BGR_EXT
242 theDataType = GL_FLOAT;
248 case Image_PixMap::ImgRGBA:
250 theTextFormat = GL_RGBA8;
251 thePixelFormat = GL_RGBA;
252 theDataType = GL_UNSIGNED_BYTE;
255 case Image_PixMap::ImgBGRA:
257 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
261 theTextFormat = GL_RGBA8;
262 thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA
263 theDataType = GL_UNSIGNED_BYTE;
266 case Image_PixMap::ImgRGB32:
268 theTextFormat = GL_RGB8;
269 thePixelFormat = GL_RGBA;
270 theDataType = GL_UNSIGNED_BYTE;
273 case Image_PixMap::ImgBGR32:
275 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
279 theTextFormat = GL_RGB8;
280 thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA
281 theDataType = GL_UNSIGNED_BYTE;
284 case Image_PixMap::ImgRGB:
286 theTextFormat = GL_RGB8;
287 thePixelFormat = GL_RGB;
288 theDataType = GL_UNSIGNED_BYTE;
291 case Image_PixMap::ImgBGR:
293 #if !defined(GL_ES_VERSION_2_0)
294 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
298 theTextFormat = GL_RGB8;
299 thePixelFormat = GL_BGR; // equals to GL_BGR_EXT
300 theDataType = GL_UNSIGNED_BYTE;
306 case Image_PixMap::ImgGray:
308 if (theCtx->core11 == NULL)
310 theTextFormat = GL_R8;
311 thePixelFormat = GL_RED;
315 theTextFormat = GL_LUMINANCE8;
316 thePixelFormat = GL_LUMINANCE;
318 theDataType = GL_UNSIGNED_BYTE;
321 case Image_PixMap::ImgAlpha:
323 if (theCtx->core11 == NULL)
325 theTextFormat = GL_R8;
326 thePixelFormat = GL_RED;
330 theTextFormat = GL_ALPHA8;
331 thePixelFormat = GL_ALPHA;
333 theDataType = GL_UNSIGNED_BYTE;
336 case Image_PixMap::ImgUNKNOWN:
344 // =======================================================================
347 // =======================================================================
348 bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
349 const Standard_Integer theTextFormat,
350 const GLenum thePixelFormat,
351 const GLenum theDataType,
352 const Standard_Integer theSizeX,
353 const Standard_Integer theSizeY,
354 const Graphic3d_TypeOfTexture theType,
355 const Image_PixMap* theImage)
357 if (!Create (theCtx))
359 Release (theCtx.operator->());
363 if (theImage != NULL)
365 myIsAlpha = theImage->Format() == Image_PixMap::ImgAlpha
366 || theImage->Format() == Image_PixMap::ImgAlphaF;
370 myIsAlpha = thePixelFormat == GL_ALPHA;
373 myHasMipmaps = Standard_False;
374 myTextFormat = thePixelFormat;
375 #if !defined(GL_ES_VERSION_2_0)
376 const GLint anIntFormat = theTextFormat;
378 // ES does not support sized formats and format conversions - them detected from data type
379 const GLint anIntFormat = thePixelFormat;
381 const GLsizei aWidth = theSizeX;
382 const GLsizei aHeight = theSizeY;
383 const GLsizei aMaxSize = theCtx->MaxTextureSize();
385 if (aWidth > aMaxSize || aHeight > aMaxSize)
387 TCollection_ExtendedString aWarnMessage = TCollection_ExtendedString ("Error: Texture dimension - ")
388 + aWidth + "x" + aHeight + " exceeds hardware limits (" + aMaxSize + "x" + aMaxSize + ")";
390 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage);
391 Release (theCtx.operator->());
394 #if !defined(GL_ES_VERSION_2_0)
395 else if (!theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW)
397 // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications
398 // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT!
399 // Trying to create NPOT textures on such hardware will not fail
400 // but driver will fall back into software rendering,
401 const GLsizei aWidthP2 = OpenGl_Context::GetPowerOfTwo (aWidth, aMaxSize);
402 const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (aHeight, aMaxSize);
404 if (aWidth != aWidthP2 || (theType != Graphic3d_TOT_1D && aHeight != aHeightP2))
406 TCollection_ExtendedString aWarnMessage =
407 TCollection_ExtendedString ("Error: NPOT Textures (") + aWidth + "x" + aHeight + ") are not supported by hardware.";
409 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage);
411 Release (theCtx.operator->());
416 else if (!theCtx->IsGlGreaterEqual (3, 0) && theType == Graphic3d_TOT_2D_MIPMAP)
418 // Mipmap NPOT textures are not supported by OpenGL ES 2.0.
419 const GLsizei aWidthP2 = OpenGl_Context::GetPowerOfTwo (aWidth, aMaxSize);
420 const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (aHeight, aMaxSize);
422 if (aWidth != aWidthP2 || aHeight != aHeightP2)
424 TCollection_ExtendedString aWarnMessage =
425 TCollection_ExtendedString ("Error: Mipmap NPOT Textures (") + aWidth + "x" + aHeight + ") are not supported by OpenGL ES 2.0";
427 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage);
429 Release (theCtx.operator->());
435 const GLenum aFilter = (myParams->Filter() == Graphic3d_TOTF_NEAREST) ? GL_NEAREST : GL_LINEAR;
436 const GLenum aWrapMode = myParams->IsRepeat() ? GL_REPEAT : theCtx->TextureWrapClamp();
438 #if !defined(GL_ES_VERSION_2_0)
439 GLint aTestWidth = 0;
440 GLint aTestHeight = 0;
442 GLvoid* aDataPtr = (theImage != NULL) ? (GLvoid* )theImage->Data() : NULL;
444 // setup the alignment
445 OpenGl_UnpackAlignmentSentry anUnpackSentry;
446 (void)anUnpackSentry; // avoid compiler warning
448 if (aDataPtr != NULL)
450 const GLint anAligment = Min ((GLint )theImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
451 glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
453 #if !defined(GL_ES_VERSION_2_0)
454 // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension
455 const GLint anExtraBytes = GLint(theImage->RowExtraBytes());
456 const GLint aPixelsWidth = GLint(theImage->SizeRowBytes() / theImage->SizePixelBytes());
457 glPixelStorei (GL_UNPACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0);
463 case Graphic3d_TOT_1D:
465 #if !defined(GL_ES_VERSION_2_0)
466 myTarget = GL_TEXTURE_1D;
468 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, aFilter);
469 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, aFilter);
470 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, aWrapMode);
472 // use proxy to check texture could be created or not
473 glTexImage1D (GL_PROXY_TEXTURE_1D, 0, anIntFormat,
475 thePixelFormat, theDataType, NULL);
476 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
479 // no memory or broken input parameters
481 Release (theCtx.operator->());
485 glTexImage1D (GL_TEXTURE_1D, 0, anIntFormat,
487 thePixelFormat, theDataType, aDataPtr);
488 if (glGetError() != GL_NO_ERROR)
491 Release (theCtx.operator->());
501 Release (theCtx.operator->());
505 case Graphic3d_TOT_2D:
507 myTarget = GL_TEXTURE_2D;
509 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, aFilter);
510 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, aFilter);
511 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, aWrapMode);
512 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, aWrapMode);
514 #if !defined(GL_ES_VERSION_2_0)
515 // use proxy to check texture could be created or not
516 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat,
518 thePixelFormat, theDataType, NULL);
519 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
520 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
521 if (aTestWidth == 0 || aTestHeight == 0)
523 // no memory or broken input parameters
525 Release (theCtx.operator->());
530 glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
532 thePixelFormat, theDataType, aDataPtr);
533 if (glGetError() != GL_NO_ERROR)
536 Release (theCtx.operator->());
546 case Graphic3d_TOT_2D_MIPMAP:
548 myTarget = GL_TEXTURE_2D;
549 myHasMipmaps = Standard_True;
551 GLenum aFilterMin = aFilter;
552 aFilterMin = GL_NEAREST_MIPMAP_NEAREST;
553 if (myParams->Filter() == Graphic3d_TOTF_BILINEAR)
555 aFilterMin = GL_LINEAR_MIPMAP_NEAREST;
557 else if (myParams->Filter() == Graphic3d_TOTF_TRILINEAR)
559 aFilterMin = GL_LINEAR_MIPMAP_LINEAR;
563 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, aFilterMin);
564 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, aFilter);
565 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, aWrapMode);
566 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, aWrapMode);
568 #if !defined(GL_ES_VERSION_2_0)
569 // use proxy to check texture could be created or not
570 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat,
572 thePixelFormat, theDataType, NULL);
573 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
574 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
575 if (aTestWidth == 0 || aTestHeight == 0)
577 // no memory or broken input parameters
579 Release (theCtx.operator->());
584 // upload main picture
585 glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
587 thePixelFormat, theDataType, theImage->Data());
588 if (glGetError() != GL_NO_ERROR)
591 Release (theCtx.operator->());
598 if (theCtx->arbFBO != NULL)
601 //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
602 theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
604 if (glGetError() != GL_NO_ERROR)
607 Release (theCtx.operator->());
613 const TCollection_ExtendedString aWarnMessage ("Warning: generating mipmaps requires GL_ARB_framebuffer_object extension which is missing.");
615 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage);
618 Release (theCtx.operator->());
627 Release (theCtx.operator->());
633 // =======================================================================
636 // =======================================================================
637 bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
638 const Image_PixMap& theImage,
639 const Graphic3d_TypeOfTexture theType)
641 if (theImage.IsEmpty())
643 Release (theCtx.operator->());
650 if (!GetDataFormat (theCtx, theImage, aTextFormat, aPixelFormat, aDataType))
652 Release (theCtx.operator->());
657 aTextFormat, aPixelFormat, aDataType,
658 (Standard_Integer)theImage.SizeX(),
659 (Standard_Integer)theImage.SizeY(),
663 // =======================================================================
664 // function : Init2DMultisample
666 // =======================================================================
667 bool OpenGl_Texture::Init2DMultisample (const Handle(OpenGl_Context)& theCtx,
668 const GLsizei theNbSamples,
669 const GLint theTextFormat,
670 const GLsizei theSizeX,
671 const GLsizei theSizeY)
674 || theNbSamples > theCtx->MaxMsaaSamples()
680 const GLsizei aNbSamples = OpenGl_Context::GetPowerOfTwo (theNbSamples, theCtx->MaxMsaaSamples());
681 myTarget = GL_TEXTURE_2D_MULTISAMPLE;
682 if(theSizeX > theCtx->MaxTextureSize()
683 || theSizeY > theCtx->MaxTextureSize())
689 //myTextFormat = theTextFormat;
690 #if !defined(GL_ES_VERSION_2_0)
691 if (theCtx->Functions()->glTexStorage2DMultisample != NULL)
693 theCtx->Functions()->glTexStorage2DMultisample (myTarget, aNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
697 theCtx->Functions()->glTexImage2DMultisample (myTarget, aNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
700 theCtx->Functions() ->glTexStorage2DMultisample (myTarget, aNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
702 if (theCtx->core11fwd->glGetError() != GL_NO_ERROR)
715 // =======================================================================
716 // function : InitRectangle
718 // =======================================================================
719 bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
720 const Standard_Integer theSizeX,
721 const Standard_Integer theSizeY,
722 const OpenGl_TextureFormat& theFormat)
724 if (!Create (theCtx) || !theCtx->IsGlGreaterEqual (3, 0))
729 #if !defined(GL_ES_VERSION_2_0)
730 myTarget = GL_TEXTURE_RECTANGLE;
732 const GLsizei aSizeX = Min (theCtx->MaxTextureSize(), theSizeX);
733 const GLsizei aSizeY = Min (theCtx->MaxTextureSize(), theSizeY);
734 const GLenum aFilter = (myParams->Filter() == Graphic3d_TOTF_NEAREST) ? GL_NEAREST : GL_LINEAR;
735 const GLenum aWrapMode = myParams->IsRepeat() ? GL_REPEAT : theCtx->TextureWrapClamp();
738 glTexParameteri (myTarget, GL_TEXTURE_MIN_FILTER, aFilter);
739 glTexParameteri (myTarget, GL_TEXTURE_MAG_FILTER, aFilter);
740 glTexParameteri (myTarget, GL_TEXTURE_WRAP_S, aWrapMode);
741 glTexParameteri (myTarget, GL_TEXTURE_WRAP_T, aWrapMode);
743 const GLint anIntFormat = theFormat.Internal();
744 myTextFormat = theFormat.Format();
746 glTexImage2D (GL_PROXY_TEXTURE_RECTANGLE,
756 GLint aTestSizeX = 0;
757 GLint aTestSizeY = 0;
759 glGetTexLevelParameteriv (
760 GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH, &aTestSizeX);
761 glGetTexLevelParameteriv (
762 GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
764 if (aTestSizeX == 0 || aTestSizeY == 0)
770 glTexImage2D (myTarget,
780 if (glGetError() != GL_NO_ERROR)