a87bb9f1427af078e3c831e0dd9414c1f1ea0b80
[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 (theSizeX < 1
409    || theSizeY < 1)
410   {
411     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
412                          "Error: texture of 0 size cannot be created.");
413     Release (theCtx.operator->());
414     return false;
415   }
416
417 #if !defined(GL_ES_VERSION_2_0)
418   const GLenum aTarget = theType == Graphic3d_TOT_1D
419                        ? GL_TEXTURE_1D
420                        : GL_TEXTURE_2D;
421 #else
422   const GLenum aTarget = GL_TEXTURE_2D;
423 #endif
424   const Standard_Boolean toCreateMipMaps = (theType == Graphic3d_TOT_2D_MIPMAP);
425   const bool toPatchExisting = IsValid()
426                             && myTextFormat == thePixelFormat
427                             && myTarget == aTarget
428                             && myHasMipmaps == toCreateMipMaps
429                             && mySizeX  == theSizeX
430                             && (mySizeY == theSizeY || theType == Graphic3d_TOT_1D);
431   if (!Create (theCtx))
432   {
433     Release (theCtx.operator->());
434     return false;
435   }
436
437   if (theImage != NULL)
438   {
439     myIsAlpha = theImage->Format() == Image_Format_Alpha
440              || theImage->Format() == Image_Format_AlphaF;
441   }
442   else
443   {
444     myIsAlpha = thePixelFormat == GL_ALPHA;
445   }
446
447   myHasMipmaps             = toCreateMipMaps;
448   myTextFormat             = thePixelFormat;
449   mySizedFormat            = theTextFormat;
450   myNbSamples              = 1;
451 #if !defined(GL_ES_VERSION_2_0)
452   const GLint anIntFormat  = theTextFormat;
453 #else
454   // ES 2.0 does not support sized formats and format conversions - them detected from data type
455   const GLint anIntFormat  = theCtx->IsGlGreaterEqual (3, 0) ? theTextFormat : thePixelFormat;
456 #endif
457
458   if (theDataType == GL_FLOAT && !theCtx->arbTexFloat)
459   {
460     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
461                          "Error: floating-point textures are not supported by hardware.");
462     Release (theCtx.operator->());
463     return false;
464   }
465
466   const GLsizei aMaxSize = theCtx->MaxTextureSize();
467   if (theSizeX > aMaxSize
468    || theSizeY > aMaxSize)
469   {
470     TCollection_ExtendedString aWarnMessage = TCollection_ExtendedString ("Error: Texture dimension - ")
471       + theSizeX + "x" + theSizeY + " exceeds hardware limits (" + aMaxSize + "x" + aMaxSize + ")";
472
473     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage);
474     Release (theCtx.operator->());
475     return false;
476   }
477 #if !defined(GL_ES_VERSION_2_0)
478   else if (!theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW)
479   {
480     // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications
481     // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT!
482     // Trying to create NPOT textures on such hardware will not fail
483     // but driver will fall back into software rendering,
484     const GLsizei aWidthP2  = OpenGl_Context::GetPowerOfTwo (theSizeX, aMaxSize);
485     const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (theSizeY, aMaxSize);
486
487     if (theSizeX != aWidthP2
488      || (theType != Graphic3d_TOT_1D && theSizeY != aHeightP2))
489     {
490       TCollection_ExtendedString aWarnMessage =
491         TCollection_ExtendedString ("Error: NPOT Textures (") + theSizeX + "x" + theSizeY + ") are not supported by hardware.";
492
493       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage);
494
495       Release (theCtx.operator->());
496       return false;
497     }
498   }
499 #else
500   else if (!theCtx->IsGlGreaterEqual (3, 0) && theType == Graphic3d_TOT_2D_MIPMAP)
501   {
502     // Mipmap NPOT textures are not supported by OpenGL ES 2.0.
503     const GLsizei aWidthP2  = OpenGl_Context::GetPowerOfTwo (theSizeX, aMaxSize);
504     const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (theSizeY, aMaxSize);
505
506     if (theSizeX != aWidthP2
507      || theSizeY != aHeightP2)
508     {
509       TCollection_ExtendedString aWarnMessage =
510         TCollection_ExtendedString ("Error: Mipmap NPOT Textures (") + theSizeX + "x" + theSizeY + ") are not supported by OpenGL ES 2.0";
511
512       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage);
513
514       Release (theCtx.operator->());
515       return false;
516     }
517   }
518 #endif
519
520 #if !defined(GL_ES_VERSION_2_0)
521   GLint aTestWidth  = 0;
522   GLint aTestHeight = 0;
523 #endif
524   GLvoid* aDataPtr = (theImage != NULL) ? (GLvoid* )theImage->Data() : NULL;
525
526   // setup the alignment
527   OpenGl_UnpackAlignmentSentry anUnpackSentry;
528   (void)anUnpackSentry; // avoid compiler warning
529
530   if (aDataPtr != NULL)
531   {
532     const GLint anAligment = Min ((GLint )theImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
533     glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
534
535   #if !defined(GL_ES_VERSION_2_0)
536     // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension
537     const GLint anExtraBytes = GLint(theImage->RowExtraBytes());
538     const GLint aPixelsWidth = GLint(theImage->SizeRowBytes() / theImage->SizePixelBytes());
539     glPixelStorei (GL_UNPACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0);
540   #endif
541   }
542
543   myTarget = aTarget;
544   switch (theType)
545   {
546     case Graphic3d_TOT_1D:
547     {
548     #if !defined(GL_ES_VERSION_2_0)
549       Bind (theCtx);
550       applyDefaultSamplerParams (theCtx);
551       if (toPatchExisting)
552       {
553         glTexSubImage1D (GL_TEXTURE_1D, 0, 0,
554                          theSizeX, thePixelFormat, theDataType, aDataPtr);
555         Unbind (theCtx);
556         return true;
557       }
558
559       // use proxy to check texture could be created or not
560       glTexImage1D (GL_PROXY_TEXTURE_1D, 0, anIntFormat,
561                     theSizeX, 0,
562                     thePixelFormat, theDataType, NULL);
563       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
564       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
565       if (aTestWidth == 0)
566       {
567         // no memory or broken input parameters
568         Unbind (theCtx);
569         Release (theCtx.operator->());
570         return false;
571       }
572
573       glTexImage1D (GL_TEXTURE_1D, 0, anIntFormat,
574                     theSizeX, 0,
575                     thePixelFormat, theDataType, aDataPtr);
576       if (glGetError() != GL_NO_ERROR)
577       {
578         Unbind (theCtx);
579         Release (theCtx.operator->());
580         return false;
581       }
582
583       mySizeX = theSizeX;
584       mySizeY = 1;
585
586       Unbind (theCtx);
587       return true;
588     #else
589       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
590                            "Error: 1D textures are not supported by hardware.");
591       Release (theCtx.operator->());
592       return false;
593     #endif
594     }
595     case Graphic3d_TOT_2D:
596     {
597       Bind (theCtx);
598       applyDefaultSamplerParams (theCtx);
599       if (toPatchExisting)
600       {
601         glTexSubImage2D (GL_TEXTURE_2D, 0,
602                          0, 0,
603                          theSizeX, theSizeY,
604                          thePixelFormat, theDataType, aDataPtr);
605         Unbind (theCtx);
606         return true;
607       }
608
609     #if !defined(GL_ES_VERSION_2_0)
610       // use proxy to check texture could be created or not
611       glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat,
612                     theSizeX, theSizeY, 0,
613                     thePixelFormat, theDataType, NULL);
614       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH,  &aTestWidth);
615       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
616       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
617       if (aTestWidth == 0 || aTestHeight == 0)
618       {
619         // no memory or broken input parameters
620         Unbind (theCtx);
621         Release (theCtx.operator->());
622         return false;
623       }
624     #endif
625
626       glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
627                     theSizeX, theSizeY, 0,
628                     thePixelFormat, theDataType, aDataPtr);
629       const GLenum anErr = glGetError();
630       if (anErr != GL_NO_ERROR)
631       {
632         theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
633                              TCollection_AsciiString ("Error: 2D texture ") + theSizeX + "x" + theSizeY
634                                                    + " IF: " + int(anIntFormat) + " PF: " + int(thePixelFormat) + " DT: " + int(theDataType)
635                                                    + " can not be created with error " + int(anErr) + ".");
636         Unbind (theCtx);
637         Release (theCtx.operator->());
638         return false;
639       }
640
641       mySizeX = theSizeX;
642       mySizeY = theSizeY;
643
644       Unbind (theCtx);
645       return true;
646     }
647     case Graphic3d_TOT_2D_MIPMAP:
648     {
649       Bind (theCtx);
650       applyDefaultSamplerParams (theCtx);
651       if (toPatchExisting)
652       {
653         glTexSubImage2D (GL_TEXTURE_2D, 0,
654                          0, 0,
655                          theSizeX, theSizeY,
656                          thePixelFormat, theDataType, aDataPtr);
657         if (theCtx->arbFBO != NULL)
658         {
659           // generate mipmaps
660           theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
661           if (glGetError() != GL_NO_ERROR)
662           {
663             Unbind (theCtx);
664             Release (theCtx.operator->());
665             return false;
666           }
667         }
668
669         Unbind (theCtx);
670         return true;
671       }
672
673     #if !defined(GL_ES_VERSION_2_0)
674       // use proxy to check texture could be created or not
675       glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat,
676                     theSizeX, theSizeY, 0,
677                     thePixelFormat, theDataType, NULL);
678       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH,  &aTestWidth);
679       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
680       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
681       if (aTestWidth == 0 || aTestHeight == 0)
682       {
683         // no memory or broken input parameters
684         Unbind (theCtx);
685         Release (theCtx.operator->());
686         return false;
687       }
688     #endif
689
690       // upload main picture
691       glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
692                     theSizeX, theSizeY, 0,
693                     thePixelFormat, theDataType, theImage->Data());
694       const GLenum aTexImgErr = glGetError();
695       if (aTexImgErr != GL_NO_ERROR)
696       {
697         theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
698                              TCollection_AsciiString ("Error: 2D texture ") + theSizeX + "x" + theSizeY
699                                                     + " IF: " + int(anIntFormat) + " PF: " + int(thePixelFormat) + " DT: " + int(theDataType)
700                                                     + " can not be created with error " + int(aTexImgErr) + ".");
701         Unbind (theCtx);
702         Release (theCtx.operator->());
703         return false;
704       }
705
706       mySizeX = theSizeX;
707       mySizeY = theSizeY;
708
709       if (theCtx->arbFBO != NULL)
710       {
711         // generate mipmaps
712         //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
713         theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
714
715         if (glGetError() != GL_NO_ERROR)
716         {
717           Unbind (theCtx);
718           Release (theCtx.operator->());
719           return false;
720         }
721       }
722       else
723       {
724         const TCollection_ExtendedString aWarnMessage ("Warning: generating mipmaps requires GL_ARB_framebuffer_object extension which is missing.");
725
726         theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage);
727
728         Unbind (theCtx);
729         Release (theCtx.operator->());
730         return false;
731       }
732
733       Unbind (theCtx);
734       return true;
735     }
736   }
737
738   Release (theCtx.operator->());
739   return false;
740 }
741
742 // =======================================================================
743 // function : Init
744 // purpose  :
745 // =======================================================================
746 bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
747                            const Image_PixMap&           theImage,
748                            const Graphic3d_TypeOfTexture theType)
749 {
750   if (theImage.IsEmpty())
751   {
752     Release (theCtx.operator->());
753     return false;
754   }
755
756   GLenum aPixelFormat;
757   GLenum aDataType;
758   GLint aTextFormat;
759   if (!GetDataFormat (theCtx, theImage, aTextFormat, aPixelFormat, aDataType))
760   {
761     Release (theCtx.operator->());
762     return false;
763   }
764
765   return Init (theCtx,
766                aTextFormat, aPixelFormat, aDataType,
767                (Standard_Integer)theImage.SizeX(),
768                (Standard_Integer)theImage.SizeY(),
769                theType, &theImage);
770 }
771
772 // =======================================================================
773 // function : Init2DMultisample
774 // purpose  :
775 // =======================================================================
776 bool OpenGl_Texture::Init2DMultisample (const Handle(OpenGl_Context)& theCtx,
777                                         const GLsizei                 theNbSamples,
778                                         const GLint                   theTextFormat,
779                                         const GLsizei                 theSizeX,
780                                         const GLsizei                 theSizeY)
781 {
782   if (!Create (theCtx)
783     || theNbSamples > theCtx->MaxMsaaSamples()
784     || theNbSamples < 1)
785   {
786     return false;
787   }
788
789   myNbSamples = OpenGl_Context::GetPowerOfTwo (theNbSamples, theCtx->MaxMsaaSamples());
790   myTarget = GL_TEXTURE_2D_MULTISAMPLE;
791   myHasMipmaps = false;
792   if(theSizeX > theCtx->MaxTextureSize()
793   || theSizeY > theCtx->MaxTextureSize())
794   {
795     return false;
796   }
797
798   Bind (theCtx);
799   //myTextFormat = theTextFormat;
800   mySizedFormat = theTextFormat;
801 #if !defined(GL_ES_VERSION_2_0)
802   if (theCtx->Functions()->glTexStorage2DMultisample != NULL)
803   {
804     theCtx->Functions()->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
805   }
806   else
807   {
808     theCtx->Functions()->glTexImage2DMultisample   (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
809   }
810 #else
811   theCtx->Functions()  ->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
812 #endif
813   if (theCtx->core11fwd->glGetError() != GL_NO_ERROR)
814   {
815     Unbind (theCtx);
816     return false;
817   }
818
819   mySizeX = theSizeX;
820   mySizeY = theSizeY;
821
822   Unbind (theCtx);
823   return true;
824 }
825
826 // =======================================================================
827 // function : InitRectangle
828 // purpose  :
829 // =======================================================================
830 bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
831                                     const Standard_Integer        theSizeX,
832                                     const Standard_Integer        theSizeY,
833                                     const OpenGl_TextureFormat&   theFormat)
834 {
835   if (!Create (theCtx) || !theCtx->IsGlGreaterEqual (3, 0))
836   {
837     return false;
838   }
839
840 #if !defined(GL_ES_VERSION_2_0)
841   myTarget = GL_TEXTURE_RECTANGLE;
842   myNbSamples = 1;
843   myHasMipmaps = false;
844
845   const GLsizei aSizeX    = Min (theCtx->MaxTextureSize(), theSizeX);
846   const GLsizei aSizeY    = Min (theCtx->MaxTextureSize(), theSizeY);
847
848   Bind (theCtx);
849   applyDefaultSamplerParams (theCtx);
850
851   myTextFormat  = theFormat.Format();
852   mySizedFormat = theFormat.Internal();
853
854   // setup the alignment
855   OpenGl_UnpackAlignmentSentry::Reset();
856
857   glTexImage2D (GL_PROXY_TEXTURE_RECTANGLE, 0, mySizedFormat,
858                 aSizeX, aSizeY, 0,
859                 myTextFormat, GL_FLOAT, NULL);
860
861   GLint aTestSizeX = 0;
862   GLint aTestSizeY = 0;
863
864   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH,  &aTestSizeX);
865   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
866   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
867
868   if (aTestSizeX == 0 || aTestSizeY == 0)
869   {
870     Unbind (theCtx);
871     return false;
872   }
873
874   glTexImage2D (myTarget, 0, mySizedFormat,
875                 aSizeX, aSizeY, 0,
876                 myTextFormat, GL_FLOAT, NULL);
877
878   if (glGetError() != GL_NO_ERROR)
879   {
880     Unbind (theCtx);
881     return false;
882   }
883
884   mySizeX = aSizeX;
885   mySizeY = aSizeY;
886
887   Unbind (theCtx);
888   return true;
889 #else
890   (void )theSizeX;
891   (void )theSizeY;
892   (void )theFormat;
893   return false;
894 #endif
895 }
896
897 // =======================================================================
898 // function : Init3D
899 // purpose  :
900 // =======================================================================
901 bool OpenGl_Texture::Init3D (const Handle(OpenGl_Context)& theCtx,
902                              const GLint                   theTextFormat,
903                              const GLenum                  thePixelFormat,
904                              const GLenum                  theDataType,
905                              const Standard_Integer        theSizeX,
906                              const Standard_Integer        theSizeY,
907                              const Standard_Integer        theSizeZ,
908                              const void*                   thePixels)
909 {
910   if (theCtx->Functions()->glTexImage3D == NULL)
911   {
912     TCollection_ExtendedString aMsg ("Error: three-dimensional textures are not supported by hardware.");
913
914     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
915                          GL_DEBUG_TYPE_ERROR,
916                          0,
917                          GL_DEBUG_SEVERITY_HIGH,
918                          aMsg);
919
920     return false;
921   }
922
923   if (!Create(theCtx))
924   {
925     return false;
926   }
927
928   myTarget = GL_TEXTURE_3D;
929   myNbSamples = 1;
930   myHasMipmaps = false;
931
932   const GLsizei aSizeX = Min (theCtx->MaxTextureSize(), theSizeX);
933   const GLsizei aSizeY = Min (theCtx->MaxTextureSize(), theSizeY);
934   const GLsizei aSizeZ = Min (theCtx->MaxTextureSize(), theSizeZ);
935
936   Bind (theCtx);
937
938   if (theDataType == GL_FLOAT && !theCtx->arbTexFloat)
939   {
940     TCollection_ExtendedString aMsg ("Error: floating-point textures are not supported by hardware.");
941
942     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
943                          GL_DEBUG_TYPE_ERROR,
944                          0,
945                          GL_DEBUG_SEVERITY_HIGH,
946                          aMsg);
947
948     Release (theCtx.operator->());
949     Unbind (theCtx);
950     return false;
951   }
952
953   mySizedFormat = theTextFormat;
954
955   // setup the alignment
956   OpenGl_UnpackAlignmentSentry::Reset();
957
958 #if !defined (GL_ES_VERSION_2_0)
959   theCtx->core15fwd->glTexImage3D (GL_PROXY_TEXTURE_3D, 0, mySizedFormat,
960                                    aSizeX, aSizeY, aSizeZ, 0,
961                                    thePixelFormat, theDataType, NULL);
962
963   GLint aTestSizeX = 0;
964   GLint aTestSizeY = 0;
965   GLint aTestSizeZ = 0;
966
967   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &aTestSizeX);
968   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
969   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_DEPTH, &aTestSizeZ);
970   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
971
972   if (aTestSizeX == 0 || aTestSizeY == 0 || aTestSizeZ == 0)
973   {
974     Unbind (theCtx);
975     Release (theCtx.operator->());
976     return false;
977   }
978 #endif
979
980   applyDefaultSamplerParams (theCtx);
981   theCtx->Functions()->glTexImage3D (myTarget, 0, mySizedFormat,
982                                      aSizeX, aSizeY, aSizeZ, 0,
983                                      thePixelFormat, theDataType, thePixels);
984
985   if (glGetError() != GL_NO_ERROR)
986   {
987     Unbind (theCtx);
988     Release (theCtx.operator->());
989     return false;
990   }
991
992   mySizeX = aSizeX;
993   mySizeY = aSizeY;
994   mySizeZ = aSizeZ;
995
996   Unbind (theCtx);
997   return true;
998 }
999
1000 // =======================================================================
1001 // function : PixelSizeOfPixelFormat
1002 // purpose  :
1003 // =======================================================================
1004 Standard_Size OpenGl_Texture::PixelSizeOfPixelFormat (Standard_Integer theInternalFormat)
1005 {
1006   switch(theInternalFormat)
1007   {
1008     // RED variations (GL_RED, OpenGL 3.0+)
1009     case GL_RED:
1010     case GL_R8:       return 1;
1011     case GL_R16:      return 2;
1012     case GL_R16F:     return 2;
1013     case GL_R32F:     return 4;
1014     // RGB variations
1015     case GL_RGB:      return 3;
1016     case GL_RGB8:     return 3;
1017     case GL_RGB16:    return 6;
1018     case GL_RGB16F:   return 6;
1019     case GL_RGB32F:   return 12;
1020     // RGBA variations
1021     case GL_RGBA:     return 4;
1022     case GL_RGBA8:    return 4;
1023     case GL_RGB10_A2: return 4;
1024     case GL_RGBA12:   return 6;
1025     case GL_RGBA16:   return 8;
1026     case GL_RGBA16F:  return 8;
1027     case GL_RGBA32F:  return 16;
1028     //
1029     case GL_BGRA_EXT:  return 4;
1030     // ALPHA variations (deprecated)
1031     case GL_ALPHA:
1032     case GL_ALPHA8:    return 1;
1033     case GL_ALPHA16:   return 2;
1034     case GL_LUMINANCE: return 1;
1035     case GL_LUMINANCE_ALPHA: return 2;
1036     // depth-stencil
1037     case GL_DEPTH24_STENCIL8:   return 4;
1038     case GL_DEPTH32F_STENCIL8:  return 8;
1039     case GL_DEPTH_COMPONENT16:  return 2;
1040     case GL_DEPTH_COMPONENT24:  return 3;
1041     case GL_DEPTH_COMPONENT32F: return 4;
1042   }
1043   return 0;
1044 }
1045
1046 // =======================================================================
1047 // function : EstimatedDataSize
1048 // purpose  :
1049 // =======================================================================
1050 Standard_Size OpenGl_Texture::EstimatedDataSize() const
1051 {
1052   if (!IsValid())
1053   {
1054     return 0;
1055   }
1056
1057   Standard_Size aSize = PixelSizeOfPixelFormat (mySizedFormat) * mySizeX * myNbSamples;
1058   if (mySizeY != 0)
1059   {
1060     aSize *= Standard_Size(mySizeY);
1061   }
1062   if (mySizeZ != 0)
1063   {
1064     aSize *= Standard_Size(mySizeZ);
1065   }
1066   if (myHasMipmaps)
1067   {
1068     aSize = aSize + aSize / 3;
1069   }
1070   return aSize;
1071 }