c4de2537140c48472c7d2a0f92d30c25a2741d2b
[occt.git] / src / OpenGl / OpenGl_Texture.cxx
1 // Created by: Kirill GAVRILOV
2 // Copyright (c) 2013-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
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.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 #include <OpenGl_Texture.hxx>
16
17 #include <OpenGl_ArbFBO.hxx>
18 #include <OpenGl_Context.hxx>
19 #include <OpenGl_GlCore32.hxx>
20 #include <OpenGl_Sampler.hxx>
21 #include <Graphic3d_TextureParams.hxx>
22 #include <TCollection_ExtendedString.hxx>
23 #include <Standard_Assert.hxx>
24 #include <Image_PixMap.hxx>
25
26 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture, OpenGl_NamedResource)
27
28 //! Simple class to reset unpack alignment settings
29 struct OpenGl_UnpackAlignmentSentry
30 {
31
32   //! Reset unpack alignment settings to safe values
33   void Reset()
34   {
35     glPixelStorei (GL_UNPACK_ALIGNMENT,  1);
36   #if !defined(GL_ES_VERSION_2_0)
37     glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
38   #endif
39   }
40
41   ~OpenGl_UnpackAlignmentSentry()
42   {
43     Reset();
44   }
45
46 };
47
48 // =======================================================================
49 // function : OpenGl_Texture
50 // purpose  :
51 // =======================================================================
52 OpenGl_Texture::OpenGl_Texture (const TCollection_AsciiString& theResourceId,
53                                 const Handle(Graphic3d_TextureParams)& theParams)
54 : OpenGl_NamedResource (theResourceId),
55   mySampler (new OpenGl_Sampler (theParams)),
56   myRevision (0),
57   myTextureId (NO_TEXTURE),
58   myTarget (GL_TEXTURE_2D),
59   mySizeX (0),
60   mySizeY (0),
61   mySizeZ (0),
62   myTextFormat (GL_RGBA),
63   mySizedFormat(GL_RGBA8),
64   myNbSamples  (1),
65   myHasMipmaps (Standard_False),
66   myIsAlpha    (false)
67 {
68   //
69 }
70
71 // =======================================================================
72 // function : ~OpenGl_Texture
73 // purpose  :
74 // =======================================================================
75 OpenGl_Texture::~OpenGl_Texture()
76 {
77   Release (NULL);
78 }
79
80 // =======================================================================
81 // function : Create
82 // purpose  :
83 // =======================================================================
84 bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& theCtx)
85 {
86   if (myTextureId != NO_TEXTURE)
87   {
88     return true;
89   }
90
91   theCtx->core11fwd->glGenTextures (1, &myTextureId);
92   if (myTextureId == NO_TEXTURE)
93   {
94     return false;
95   }
96
97   //mySampler->Create (theCtx); // do not create sampler object by default
98   return true;
99 }
100
101 // =======================================================================
102 // function : Release
103 // purpose  :
104 // =======================================================================
105 void OpenGl_Texture::Release (OpenGl_Context* theGlCtx)
106 {
107   mySampler->Release (theGlCtx);
108   if (myTextureId == NO_TEXTURE)
109   {
110     return;
111   }
112
113   // application can not handle this case by exception - this is bug in code
114   Standard_ASSERT_RETURN (theGlCtx != NULL,
115     "OpenGl_Texture destroyed without GL context! Possible GPU memory leakage...",);
116
117   if (theGlCtx->IsValid())
118   {
119     glDeleteTextures (1, &myTextureId);
120   }
121   myTextureId = NO_TEXTURE;
122   mySizeX = mySizeY = mySizeZ = 0;
123 }
124
125 // =======================================================================
126 // function : applyDefaultSamplerParams
127 // purpose  :
128 // =======================================================================
129 void OpenGl_Texture::applyDefaultSamplerParams (const Handle(OpenGl_Context)& theCtx)
130 {
131   OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), NULL, myTarget, myHasMipmaps);
132   if (mySampler->IsValid() && !mySampler->IsImmutable())
133   {
134     OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), mySampler.get(), myTarget, myHasMipmaps);
135   }
136 }
137
138 // =======================================================================
139 // function : Bind
140 // purpose  :
141 // =======================================================================
142 void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
143                            const Graphic3d_TextureUnit   theTextureUnit) const
144 {
145   if (theCtx->core15fwd != NULL)
146   {
147     theCtx->core15fwd->glActiveTexture (GL_TEXTURE0 + theTextureUnit);
148   }
149   mySampler->Bind (theCtx, theTextureUnit);
150   glBindTexture (myTarget, myTextureId);
151 }
152
153 // =======================================================================
154 // function : Unbind
155 // purpose  :
156 // =======================================================================
157 void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
158                              const Graphic3d_TextureUnit   theTextureUnit) const
159 {
160   if (theCtx->core15fwd != NULL)
161   {
162     theCtx->core15fwd->glActiveTexture (GL_TEXTURE0 + theTextureUnit);
163   }
164   mySampler->Unbind (theCtx, theTextureUnit);
165   glBindTexture (myTarget, NO_TEXTURE);
166 }
167
168 //=======================================================================
169 //function : InitSamplerObject
170 //purpose  :
171 //=======================================================================
172 bool OpenGl_Texture::InitSamplerObject (const Handle(OpenGl_Context)& theCtx)
173 {
174   return myTextureId != NO_TEXTURE
175       && mySampler->Init (theCtx, *this);
176 }
177
178 //=======================================================================
179 //function : GetDataFormat
180 //purpose  :
181 //=======================================================================
182 bool OpenGl_Texture::GetDataFormat (const Handle(OpenGl_Context)& theCtx,
183                                     const Image_PixMap&           theData,
184                                     GLint&                        theTextFormat,
185                                     GLenum&                       thePixelFormat,
186                                     GLenum&                       theDataType)
187 {
188   theTextFormat  = GL_RGBA8;
189   thePixelFormat = 0;
190   theDataType    = 0;
191   switch (theData.Format())
192   {
193     case Image_Format_GrayF:
194     {
195       if (theCtx->core11 == NULL)
196       {
197         theTextFormat  = GL_R8;  // GL_R32F
198         thePixelFormat = GL_RED;
199       }
200       else
201       {
202       #if !defined(GL_ES_VERSION_2_0)
203         theTextFormat  = GL_LUMINANCE8;
204       #else
205         theTextFormat  = GL_LUMINANCE;
206       #endif
207         thePixelFormat = GL_LUMINANCE;
208       }
209       theDataType = GL_FLOAT;
210       return true;
211     }
212     case Image_Format_AlphaF:
213     {
214       if (theCtx->core11 == NULL)
215       {
216         theTextFormat  = GL_R8;  // GL_R32F
217         thePixelFormat = GL_RED;
218       }
219       else
220       {
221       #if !defined(GL_ES_VERSION_2_0)
222         theTextFormat  = GL_ALPHA8;
223       #else
224         theTextFormat  = GL_ALPHA;
225       #endif
226         thePixelFormat = GL_ALPHA;
227       }
228       theDataType = GL_FLOAT;
229       return true;
230     }
231     case Image_Format_RGBAF:
232     {
233       theTextFormat  = GL_RGBA8; // GL_RGBA32F
234       thePixelFormat = GL_RGBA;
235       theDataType    = GL_FLOAT;
236       return true;
237     }
238     case Image_Format_BGRAF:
239     {
240       if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
241       {
242         return false;
243       }
244       theTextFormat  = GL_RGBA8;    // GL_RGBA32F
245       thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA
246       theDataType    = GL_FLOAT;
247       return true;
248     }
249     case Image_Format_RGBF:
250     {
251       theTextFormat  = GL_RGB8; // GL_RGB32F
252       thePixelFormat = GL_RGB;
253       theDataType    = GL_FLOAT;
254       return true;
255     }
256     case Image_Format_BGRF:
257     {
258     #if !defined(GL_ES_VERSION_2_0)
259       theTextFormat  = GL_RGB8; // GL_RGB32F
260       thePixelFormat = GL_BGR;  // equals to GL_BGR_EXT
261       theDataType    = GL_FLOAT;
262       return true;
263     #else
264       return false;
265     #endif
266     }
267     case Image_Format_RGBA:
268     {
269       theTextFormat = GL_RGBA8;
270       thePixelFormat = GL_RGBA;
271       theDataType    = GL_UNSIGNED_BYTE;
272       return true;
273     }
274     case Image_Format_BGRA:
275     {
276     #if !defined(GL_ES_VERSION_2_0)
277       if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
278       {
279         return false;
280       }
281       theTextFormat  = GL_RGBA8;
282     #else
283       if (!theCtx->extBgra)
284       {
285         return false;
286       }
287       theTextFormat  = GL_BGRA_EXT;
288     #endif
289       thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA
290       theDataType    = GL_UNSIGNED_BYTE;
291       return true;
292     }
293     case Image_Format_RGB32:
294     {
295     #if !defined(GL_ES_VERSION_2_0)
296       // ask driver to convert data to RGB8 to save memory
297       theTextFormat  = GL_RGB8;
298     #else
299       // conversion is not supported
300       theTextFormat  = GL_RGBA8;
301     #endif
302       thePixelFormat = GL_RGBA;
303       theDataType    = GL_UNSIGNED_BYTE;
304       return true;
305     }
306     case Image_Format_BGR32:
307     {
308     #if !defined(GL_ES_VERSION_2_0)
309       if (!theCtx->IsGlGreaterEqual(1, 2) && !theCtx->extBgra)
310       {
311         return false;
312       }
313       theTextFormat  = GL_RGB8;
314     #else
315       if (!theCtx->extBgra)
316       {
317         return false;
318       }
319       theTextFormat  = GL_BGRA_EXT;
320     #endif
321       thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA
322       theDataType    = GL_UNSIGNED_BYTE;
323       return true;
324     }
325     case Image_Format_RGB:
326     {
327       theTextFormat = GL_RGB8;
328       thePixelFormat = GL_RGB;
329       theDataType    = GL_UNSIGNED_BYTE;
330       return true;
331     }
332     case Image_Format_BGR:
333     {
334     #if !defined(GL_ES_VERSION_2_0)
335       if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
336       {
337         return false;
338       }
339       theTextFormat = GL_RGB8;
340       thePixelFormat = GL_BGR; // equals to GL_BGR_EXT
341       theDataType    = GL_UNSIGNED_BYTE;
342       return true;
343     #else
344       return false;
345     #endif
346     }
347     case Image_Format_Gray:
348     {
349       if (theCtx->core11 == NULL)
350       {
351         theTextFormat  = GL_R8;
352         thePixelFormat = GL_RED;
353       }
354       else
355       {
356       #if !defined(GL_ES_VERSION_2_0)
357         theTextFormat  = GL_LUMINANCE8;
358       #else
359         theTextFormat  = GL_LUMINANCE;
360       #endif
361         thePixelFormat = GL_LUMINANCE;
362       }
363       theDataType = GL_UNSIGNED_BYTE;
364       return true;
365     }
366     case Image_Format_Alpha:
367     {
368       if (theCtx->core11 == NULL)
369       {
370         theTextFormat  = GL_R8;
371         thePixelFormat = GL_RED;
372       }
373       else
374       {
375       #if !defined(GL_ES_VERSION_2_0)
376         theTextFormat  = GL_ALPHA8;
377       #else
378         theTextFormat  = GL_ALPHA;
379       #endif
380         thePixelFormat = GL_ALPHA;
381       }
382       theDataType = GL_UNSIGNED_BYTE;
383       return true;
384     }
385     case Image_Format_UNKNOWN:
386     {
387       return false;
388     }
389   }
390   return false;
391 }
392
393 // =======================================================================
394 // function : Init
395 // purpose  :
396 // =======================================================================
397 bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
398                            const Standard_Integer        theTextFormat,
399                            const GLenum                  thePixelFormat,
400                            const GLenum                  theDataType,
401                            const Standard_Integer        theSizeX,
402                            const Standard_Integer        theSizeY,
403                            const Graphic3d_TypeOfTexture theType,
404                            const Image_PixMap*           theImage)
405 {
406 #if !defined(GL_ES_VERSION_2_0)
407   const GLenum aTarget = theType == Graphic3d_TOT_1D
408                        ? GL_TEXTURE_1D
409                        : GL_TEXTURE_2D;
410 #else
411   const GLenum aTarget = GL_TEXTURE_2D;
412 #endif
413   const Standard_Boolean toCreateMipMaps = (theType == Graphic3d_TOT_2D_MIPMAP);
414   const bool toPatchExisting = IsValid()
415                             && myTextFormat == thePixelFormat
416                             && myTarget == aTarget
417                             && myHasMipmaps == toCreateMipMaps
418                             && mySizeX  == theSizeX
419                             && (mySizeY == theSizeY || theType == Graphic3d_TOT_1D);
420   if (!Create (theCtx))
421   {
422     Release (theCtx.operator->());
423     return false;
424   }
425
426   if (theImage != NULL)
427   {
428     myIsAlpha = theImage->Format() == Image_Format_Alpha
429              || theImage->Format() == Image_Format_AlphaF;
430   }
431   else
432   {
433     myIsAlpha = thePixelFormat == GL_ALPHA;
434   }
435
436   myHasMipmaps             = toCreateMipMaps;
437   myTextFormat             = thePixelFormat;
438   mySizedFormat            = theTextFormat;
439   myNbSamples              = 1;
440 #if !defined(GL_ES_VERSION_2_0)
441   const GLint anIntFormat  = theTextFormat;
442 #else
443   // ES 2.0 does not support sized formats and format conversions - them detected from data type
444   const GLint anIntFormat  = theCtx->IsGlGreaterEqual (3, 0) ? theTextFormat : thePixelFormat;
445 #endif
446
447   if (theDataType == GL_FLOAT && !theCtx->arbTexFloat)
448   {
449     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
450                          "Error: floating-point textures are not supported by hardware.");
451     Release (theCtx.operator->());
452     return false;
453   }
454
455   const GLsizei aMaxSize = theCtx->MaxTextureSize();
456   if (theSizeX > aMaxSize
457    || theSizeY > aMaxSize)
458   {
459     TCollection_ExtendedString aWarnMessage = TCollection_ExtendedString ("Error: Texture dimension - ")
460       + theSizeX + "x" + theSizeY + " exceeds hardware limits (" + aMaxSize + "x" + aMaxSize + ")";
461
462     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage);
463     Release (theCtx.operator->());
464     return false;
465   }
466 #if !defined(GL_ES_VERSION_2_0)
467   else if (!theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW)
468   {
469     // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications
470     // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT!
471     // Trying to create NPOT textures on such hardware will not fail
472     // but driver will fall back into software rendering,
473     const GLsizei aWidthP2  = OpenGl_Context::GetPowerOfTwo (theSizeX, aMaxSize);
474     const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (theSizeY, aMaxSize);
475
476     if (theSizeX != aWidthP2
477      || (theType != Graphic3d_TOT_1D && theSizeY != aHeightP2))
478     {
479       TCollection_ExtendedString aWarnMessage =
480         TCollection_ExtendedString ("Error: NPOT Textures (") + theSizeX + "x" + theSizeY + ") are not supported by hardware.";
481
482       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage);
483
484       Release (theCtx.operator->());
485       return false;
486     }
487   }
488 #else
489   else if (!theCtx->IsGlGreaterEqual (3, 0) && theType == Graphic3d_TOT_2D_MIPMAP)
490   {
491     // Mipmap NPOT textures are not supported by OpenGL ES 2.0.
492     const GLsizei aWidthP2  = OpenGl_Context::GetPowerOfTwo (theSizeX, aMaxSize);
493     const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (theSizeY, aMaxSize);
494
495     if (theSizeX != aWidthP2
496      || theSizeY != aHeightP2)
497     {
498       TCollection_ExtendedString aWarnMessage =
499         TCollection_ExtendedString ("Error: Mipmap NPOT Textures (") + theSizeX + "x" + theSizeY + ") are not supported by OpenGL ES 2.0";
500
501       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage);
502
503       Release (theCtx.operator->());
504       return false;
505     }
506   }
507 #endif
508
509 #if !defined(GL_ES_VERSION_2_0)
510   GLint aTestWidth  = 0;
511   GLint aTestHeight = 0;
512 #endif
513   GLvoid* aDataPtr = (theImage != NULL) ? (GLvoid* )theImage->Data() : NULL;
514
515   // setup the alignment
516   OpenGl_UnpackAlignmentSentry anUnpackSentry;
517   (void)anUnpackSentry; // avoid compiler warning
518
519   if (aDataPtr != NULL)
520   {
521     const GLint anAligment = Min ((GLint )theImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
522     glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
523
524   #if !defined(GL_ES_VERSION_2_0)
525     // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension
526     const GLint anExtraBytes = GLint(theImage->RowExtraBytes());
527     const GLint aPixelsWidth = GLint(theImage->SizeRowBytes() / theImage->SizePixelBytes());
528     glPixelStorei (GL_UNPACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0);
529   #endif
530   }
531
532   myTarget = aTarget;
533   switch (theType)
534   {
535     case Graphic3d_TOT_1D:
536     {
537     #if !defined(GL_ES_VERSION_2_0)
538       Bind (theCtx);
539       applyDefaultSamplerParams (theCtx);
540       if (toPatchExisting)
541       {
542         glTexSubImage1D (GL_TEXTURE_1D, 0, 0,
543                          theSizeX, thePixelFormat, theDataType, aDataPtr);
544         Unbind (theCtx);
545         return true;
546       }
547
548       // use proxy to check texture could be created or not
549       glTexImage1D (GL_PROXY_TEXTURE_1D, 0, anIntFormat,
550                     theSizeX, 0,
551                     thePixelFormat, theDataType, NULL);
552       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
553       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
554       if (aTestWidth == 0)
555       {
556         // no memory or broken input parameters
557         Unbind (theCtx);
558         Release (theCtx.operator->());
559         return false;
560       }
561
562       glTexImage1D (GL_TEXTURE_1D, 0, anIntFormat,
563                     theSizeX, 0,
564                     thePixelFormat, theDataType, aDataPtr);
565       if (glGetError() != GL_NO_ERROR)
566       {
567         Unbind (theCtx);
568         Release (theCtx.operator->());
569         return false;
570       }
571
572       mySizeX = theSizeX;
573       mySizeY = 1;
574
575       Unbind (theCtx);
576       return true;
577     #else
578       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
579                            "Error: 1D textures are not supported by hardware.");
580       Release (theCtx.operator->());
581       return false;
582     #endif
583     }
584     case Graphic3d_TOT_2D:
585     {
586       Bind (theCtx);
587       applyDefaultSamplerParams (theCtx);
588       if (toPatchExisting)
589       {
590         glTexSubImage2D (GL_TEXTURE_2D, 0,
591                          0, 0,
592                          theSizeX, theSizeY,
593                          thePixelFormat, theDataType, aDataPtr);
594         Unbind (theCtx);
595         return true;
596       }
597
598     #if !defined(GL_ES_VERSION_2_0)
599       // use proxy to check texture could be created or not
600       glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat,
601                     theSizeX, theSizeY, 0,
602                     thePixelFormat, theDataType, NULL);
603       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH,  &aTestWidth);
604       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
605       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
606       if (aTestWidth == 0 || aTestHeight == 0)
607       {
608         // no memory or broken input parameters
609         Unbind (theCtx);
610         Release (theCtx.operator->());
611         return false;
612       }
613     #endif
614
615       glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
616                     theSizeX, theSizeY, 0,
617                     thePixelFormat, theDataType, aDataPtr);
618       const GLenum anErr = glGetError();
619       if (anErr != GL_NO_ERROR)
620       {
621         theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
622                              TCollection_AsciiString ("Error: 2D texture ") + theSizeX + "x" + theSizeY
623                                                    + " IF: " + int(anIntFormat) + " PF: " + int(thePixelFormat) + " DT: " + int(theDataType)
624                                                    + " can not be created with error " + int(anErr) + ".");
625         Unbind (theCtx);
626         Release (theCtx.operator->());
627         return false;
628       }
629
630       mySizeX = theSizeX;
631       mySizeY = theSizeY;
632
633       Unbind (theCtx);
634       return true;
635     }
636     case Graphic3d_TOT_2D_MIPMAP:
637     {
638       Bind (theCtx);
639       applyDefaultSamplerParams (theCtx);
640       if (toPatchExisting)
641       {
642         glTexSubImage2D (GL_TEXTURE_2D, 0,
643                          0, 0,
644                          theSizeX, theSizeY,
645                          thePixelFormat, theDataType, aDataPtr);
646         if (theCtx->arbFBO != NULL)
647         {
648           // generate mipmaps
649           theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
650           if (glGetError() != GL_NO_ERROR)
651           {
652             Unbind (theCtx);
653             Release (theCtx.operator->());
654             return false;
655           }
656         }
657
658         Unbind (theCtx);
659         return true;
660       }
661
662     #if !defined(GL_ES_VERSION_2_0)
663       // use proxy to check texture could be created or not
664       glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat,
665                     theSizeX, theSizeY, 0,
666                     thePixelFormat, theDataType, NULL);
667       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH,  &aTestWidth);
668       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
669       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
670       if (aTestWidth == 0 || aTestHeight == 0)
671       {
672         // no memory or broken input parameters
673         Unbind (theCtx);
674         Release (theCtx.operator->());
675         return false;
676       }
677     #endif
678
679       // upload main picture
680       glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
681                     theSizeX, theSizeY, 0,
682                     thePixelFormat, theDataType, theImage->Data());
683       const GLenum aTexImgErr = glGetError();
684       if (aTexImgErr != GL_NO_ERROR)
685       {
686         theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
687                              TCollection_AsciiString ("Error: 2D texture ") + theSizeX + "x" + theSizeY
688                                                     + " IF: " + int(anIntFormat) + " PF: " + int(thePixelFormat) + " DT: " + int(theDataType)
689                                                     + " can not be created with error " + int(aTexImgErr) + ".");
690         Unbind (theCtx);
691         Release (theCtx.operator->());
692         return false;
693       }
694
695       mySizeX = theSizeX;
696       mySizeY = theSizeY;
697
698       if (theCtx->arbFBO != NULL)
699       {
700         // generate mipmaps
701         //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
702         theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
703
704         if (glGetError() != GL_NO_ERROR)
705         {
706           Unbind (theCtx);
707           Release (theCtx.operator->());
708           return false;
709         }
710       }
711       else
712       {
713         const TCollection_ExtendedString aWarnMessage ("Warning: generating mipmaps requires GL_ARB_framebuffer_object extension which is missing.");
714
715         theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage);
716
717         Unbind (theCtx);
718         Release (theCtx.operator->());
719         return false;
720       }
721
722       Unbind (theCtx);
723       return true;
724     }
725   }
726
727   Release (theCtx.operator->());
728   return false;
729 }
730
731 // =======================================================================
732 // function : Init
733 // purpose  :
734 // =======================================================================
735 bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
736                            const Image_PixMap&           theImage,
737                            const Graphic3d_TypeOfTexture theType)
738 {
739   if (theImage.IsEmpty())
740   {
741     Release (theCtx.operator->());
742     return false;
743   }
744
745   GLenum aPixelFormat;
746   GLenum aDataType;
747   GLint aTextFormat;
748   if (!GetDataFormat (theCtx, theImage, aTextFormat, aPixelFormat, aDataType))
749   {
750     Release (theCtx.operator->());
751     return false;
752   }
753
754   return Init (theCtx,
755                aTextFormat, aPixelFormat, aDataType,
756                (Standard_Integer)theImage.SizeX(),
757                (Standard_Integer)theImage.SizeY(),
758                theType, &theImage);
759 }
760
761 // =======================================================================
762 // function : Init2DMultisample
763 // purpose  :
764 // =======================================================================
765 bool OpenGl_Texture::Init2DMultisample (const Handle(OpenGl_Context)& theCtx,
766                                         const GLsizei                 theNbSamples,
767                                         const GLint                   theTextFormat,
768                                         const GLsizei                 theSizeX,
769                                         const GLsizei                 theSizeY)
770 {
771   if (!Create (theCtx)
772     || theNbSamples > theCtx->MaxMsaaSamples()
773     || theNbSamples < 1)
774   {
775     return false;
776   }
777
778   myNbSamples = OpenGl_Context::GetPowerOfTwo (theNbSamples, theCtx->MaxMsaaSamples());
779   myTarget = GL_TEXTURE_2D_MULTISAMPLE;
780   myHasMipmaps = false;
781   if(theSizeX > theCtx->MaxTextureSize()
782   || theSizeY > theCtx->MaxTextureSize())
783   {
784     return false;
785   }
786
787   Bind (theCtx);
788   //myTextFormat = theTextFormat;
789   mySizedFormat = theTextFormat;
790 #if !defined(GL_ES_VERSION_2_0)
791   if (theCtx->Functions()->glTexStorage2DMultisample != NULL)
792   {
793     theCtx->Functions()->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
794   }
795   else
796   {
797     theCtx->Functions()->glTexImage2DMultisample   (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
798   }
799 #else
800   theCtx->Functions()  ->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
801 #endif
802   if (theCtx->core11fwd->glGetError() != GL_NO_ERROR)
803   {
804     Unbind (theCtx);
805     return false;
806   }
807
808   mySizeX = theSizeX;
809   mySizeY = theSizeY;
810
811   Unbind (theCtx);
812   return true;
813 }
814
815 // =======================================================================
816 // function : InitRectangle
817 // purpose  :
818 // =======================================================================
819 bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
820                                     const Standard_Integer        theSizeX,
821                                     const Standard_Integer        theSizeY,
822                                     const OpenGl_TextureFormat&   theFormat)
823 {
824   if (!Create (theCtx) || !theCtx->IsGlGreaterEqual (3, 0))
825   {
826     return false;
827   }
828
829 #if !defined(GL_ES_VERSION_2_0)
830   myTarget = GL_TEXTURE_RECTANGLE;
831   myNbSamples = 1;
832   myHasMipmaps = false;
833
834   const GLsizei aSizeX    = Min (theCtx->MaxTextureSize(), theSizeX);
835   const GLsizei aSizeY    = Min (theCtx->MaxTextureSize(), theSizeY);
836
837   Bind (theCtx);
838   applyDefaultSamplerParams (theCtx);
839
840   myTextFormat  = theFormat.Format();
841   mySizedFormat = theFormat.Internal();
842
843   glTexImage2D (GL_PROXY_TEXTURE_RECTANGLE, 0, mySizedFormat,
844                 aSizeX, aSizeY, 0,
845                 myTextFormat, GL_FLOAT, NULL);
846
847   GLint aTestSizeX = 0;
848   GLint aTestSizeY = 0;
849
850   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH,  &aTestSizeX);
851   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
852   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
853
854   if (aTestSizeX == 0 || aTestSizeY == 0)
855   {
856     Unbind (theCtx);
857     return false;
858   }
859
860   glTexImage2D (myTarget, 0, mySizedFormat,
861                 aSizeX, aSizeY, 0,
862                 myTextFormat, GL_FLOAT, NULL);
863
864   if (glGetError() != GL_NO_ERROR)
865   {
866     Unbind (theCtx);
867     return false;
868   }
869
870   mySizeX = aSizeX;
871   mySizeY = aSizeY;
872
873   Unbind (theCtx);
874   return true;
875 #else
876   (void )theSizeX;
877   (void )theSizeY;
878   (void )theFormat;
879   return false;
880 #endif
881 }
882
883 // =======================================================================
884 // function : Init3D
885 // purpose  :
886 // =======================================================================
887 bool OpenGl_Texture::Init3D (const Handle(OpenGl_Context)& theCtx,
888                              const GLint                   theTextFormat,
889                              const GLenum                  thePixelFormat,
890                              const GLenum                  theDataType,
891                              const Standard_Integer        theSizeX,
892                              const Standard_Integer        theSizeY,
893                              const Standard_Integer        theSizeZ,
894                              const void*                   thePixels)
895 {
896   if (theCtx->Functions()->glTexImage3D == NULL)
897   {
898     TCollection_ExtendedString aMsg ("Error: three-dimensional textures are not supported by hardware.");
899
900     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
901                          GL_DEBUG_TYPE_ERROR,
902                          0,
903                          GL_DEBUG_SEVERITY_HIGH,
904                          aMsg);
905
906     return false;
907   }
908
909   if (!Create(theCtx))
910   {
911     return false;
912   }
913
914   myTarget = GL_TEXTURE_3D;
915   myNbSamples = 1;
916   myHasMipmaps = false;
917
918   const GLsizei aSizeX = Min (theCtx->MaxTextureSize(), theSizeX);
919   const GLsizei aSizeY = Min (theCtx->MaxTextureSize(), theSizeY);
920   const GLsizei aSizeZ = Min (theCtx->MaxTextureSize(), theSizeZ);
921
922   Bind (theCtx);
923
924   if (theDataType == GL_FLOAT && !theCtx->arbTexFloat)
925   {
926     TCollection_ExtendedString aMsg ("Error: floating-point textures are not supported by hardware.");
927
928     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
929                          GL_DEBUG_TYPE_ERROR,
930                          0,
931                          GL_DEBUG_SEVERITY_HIGH,
932                          aMsg);
933
934     Release (theCtx.operator->());
935     Unbind (theCtx);
936     return false;
937   }
938
939   mySizedFormat = theTextFormat;
940
941 #if !defined (GL_ES_VERSION_2_0)
942   theCtx->core15fwd->glTexImage3D (GL_PROXY_TEXTURE_3D, 0, mySizedFormat,
943                                    aSizeX, aSizeY, aSizeZ, 0,
944                                    thePixelFormat, theDataType, NULL);
945
946   GLint aTestSizeX = 0;
947   GLint aTestSizeY = 0;
948   GLint aTestSizeZ = 0;
949
950   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &aTestSizeX);
951   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
952   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_DEPTH, &aTestSizeZ);
953   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
954
955   if (aTestSizeX == 0 || aTestSizeY == 0 || aTestSizeZ == 0)
956   {
957     Unbind (theCtx);
958     Release (theCtx.operator->());
959     return false;
960   }
961 #endif
962
963   applyDefaultSamplerParams (theCtx);
964   theCtx->Functions()->glTexImage3D (myTarget, 0, mySizedFormat,
965                                      aSizeX, aSizeY, aSizeZ, 0,
966                                      thePixelFormat, theDataType, thePixels);
967
968   if (glGetError() != GL_NO_ERROR)
969   {
970     Unbind (theCtx);
971     Release (theCtx.operator->());
972     return false;
973   }
974
975   mySizeX = aSizeX;
976   mySizeY = aSizeY;
977   mySizeZ = aSizeZ;
978
979   Unbind (theCtx);
980   return true;
981 }
982
983 // =======================================================================
984 // function : PixelSizeOfPixelFormat
985 // purpose  :
986 // =======================================================================
987 Standard_Size OpenGl_Texture::PixelSizeOfPixelFormat (Standard_Integer theInternalFormat)
988 {
989   switch(theInternalFormat)
990   {
991     // RED variations (GL_RED, OpenGL 3.0+)
992     case GL_RED:
993     case GL_R8:       return 1;
994     case GL_R16:      return 2;
995     case GL_R16F:     return 2;
996     case GL_R32F:     return 4;
997     // RGB variations
998     case GL_RGB:      return 3;
999     case GL_RGB8:     return 3;
1000     case GL_RGB16:    return 6;
1001     case GL_RGB16F:   return 6;
1002     case GL_RGB32F:   return 12;
1003     // RGBA variations
1004     case GL_RGBA:     return 4;
1005     case GL_RGBA8:    return 4;
1006     case GL_RGB10_A2: return 4;
1007     case GL_RGBA12:   return 6;
1008     case GL_RGBA16:   return 8;
1009     case GL_RGBA16F:  return 8;
1010     case GL_RGBA32F:  return 16;
1011     //
1012     case GL_BGRA_EXT:  return 4;
1013     // ALPHA variations (deprecated)
1014     case GL_ALPHA:
1015     case GL_ALPHA8:    return 1;
1016     case GL_ALPHA16:   return 2;
1017     case GL_LUMINANCE: return 1;
1018     case GL_LUMINANCE_ALPHA: return 2;
1019     // depth-stencil
1020     case GL_DEPTH24_STENCIL8:   return 4;
1021     case GL_DEPTH32F_STENCIL8:  return 8;
1022     case GL_DEPTH_COMPONENT16:  return 2;
1023     case GL_DEPTH_COMPONENT24:  return 3;
1024     case GL_DEPTH_COMPONENT32F: return 4;
1025   }
1026   return 0;
1027 }
1028
1029 // =======================================================================
1030 // function : EstimatedDataSize
1031 // purpose  :
1032 // =======================================================================
1033 Standard_Size OpenGl_Texture::EstimatedDataSize() const
1034 {
1035   if (!IsValid())
1036   {
1037     return 0;
1038   }
1039
1040   Standard_Size aSize = PixelSizeOfPixelFormat (mySizedFormat) * mySizeX * myNbSamples;
1041   if (mySizeY != 0)
1042   {
1043     aSize *= Standard_Size(mySizeY);
1044   }
1045   if (mySizeZ != 0)
1046   {
1047     aSize *= Standard_Size(mySizeZ);
1048   }
1049   if (myHasMipmaps)
1050   {
1051     aSize = aSize + aSize / 3;
1052   }
1053   return aSize;
1054 }