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