0030483: Visualization, Path Tracing - make Tile Size configurable
[occt.git] / src / OpenGl / OpenGl_Texture.cxx
CommitLineData
bf75be98 1// Created by: Kirill GAVRILOV
d5f74e42 2// Copyright (c) 2013-2014 OPEN CASCADE SAS
bf75be98 3//
973c2be1 4// This file is part of Open CASCADE Technology software library.
bf75be98 5//
d5f74e42 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
973c2be1 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.
bf75be98 11//
973c2be1 12// Alternatively, this file may be used under the terms of Open CASCADE
13// commercial license or contractual agreement.
bf75be98 14
15#include <OpenGl_Texture.hxx>
16
01ca42b2 17#include <OpenGl_ArbFBO.hxx>
bf75be98 18#include <OpenGl_Context.hxx>
3c4b62a4 19#include <OpenGl_GlCore32.hxx>
cc8cbabe 20#include <OpenGl_Sampler.hxx>
bf75be98 21#include <Graphic3d_TextureParams.hxx>
fa4dcbe0 22#include <TCollection_ExtendedString.hxx>
bf75be98 23#include <Standard_Assert.hxx>
24#include <Image_PixMap.hxx>
25
cc8cbabe 26IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture, OpenGl_NamedResource)
92efcf78 27
74706083 28//! Simple class to reset unpack alignment settings
29struct OpenGl_UnpackAlignmentSentry
30{
31
32 //! Reset unpack alignment settings to safe values
90fd6145 33 static void Reset()
74706083 34 {
35 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
ca3c13d1 36 #if !defined(GL_ES_VERSION_2_0)
74706083 37 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
ca3c13d1 38 #endif
74706083 39 }
40
90fd6145 41 OpenGl_UnpackAlignmentSentry() {}
42
74706083 43 ~OpenGl_UnpackAlignmentSentry()
44 {
45 Reset();
46 }
47
48};
49
bf75be98 50// =======================================================================
51// function : OpenGl_Texture
52// purpose :
53// =======================================================================
cc8cbabe 54OpenGl_Texture::OpenGl_Texture (const TCollection_AsciiString& theResourceId,
55 const Handle(Graphic3d_TextureParams)& theParams)
56: OpenGl_NamedResource (theResourceId),
57 mySampler (new OpenGl_Sampler (theParams)),
d2edda76 58 myRevision (0),
bf75be98 59 myTextureId (NO_TEXTURE),
60 myTarget (GL_TEXTURE_2D),
61 mySizeX (0),
62 mySizeY (0),
74fb257d 63 mySizeZ (0),
8625ef7e 64 myTextFormat (GL_RGBA),
15669413 65 mySizedFormat(GL_RGBA8),
66 myNbSamples (1),
bf75be98 67 myHasMipmaps (Standard_False),
cc8cbabe 68 myIsAlpha (false)
bf75be98 69{
cc8cbabe 70 //
bf75be98 71}
72
73// =======================================================================
74// function : ~OpenGl_Texture
75// purpose :
76// =======================================================================
77OpenGl_Texture::~OpenGl_Texture()
78{
79 Release (NULL);
80}
81
82// =======================================================================
bf75be98 83// function : Create
84// purpose :
85// =======================================================================
cc8cbabe 86bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& theCtx)
bf75be98 87{
cc8cbabe 88 if (myTextureId != NO_TEXTURE)
89 {
90 return true;
91 }
92
93 theCtx->core11fwd->glGenTextures (1, &myTextureId);
bf75be98 94 if (myTextureId == NO_TEXTURE)
95 {
cc8cbabe 96 return false;
bf75be98 97 }
cc8cbabe 98
99 //mySampler->Create (theCtx); // do not create sampler object by default
100 return true;
bf75be98 101}
102
103// =======================================================================
104// function : Release
105// purpose :
106// =======================================================================
10b9c7df 107void OpenGl_Texture::Release (OpenGl_Context* theGlCtx)
bf75be98 108{
cc8cbabe 109 mySampler->Release (theGlCtx);
bf75be98 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
ec2eeb2d 119 if (theGlCtx->IsValid())
120 {
121 glDeleteTextures (1, &myTextureId);
122 }
bf75be98 123 myTextureId = NO_TEXTURE;
d2edda76 124 mySizeX = mySizeY = mySizeZ = 0;
bf75be98 125}
126
127// =======================================================================
cc8cbabe 128// function : applyDefaultSamplerParams
129// purpose :
130// =======================================================================
131void 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// =======================================================================
bf75be98 141// function : Bind
142// purpose :
143// =======================================================================
144void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
cc8cbabe 145 const Graphic3d_TextureUnit theTextureUnit) const
bf75be98 146{
4e1523ef 147 if (theCtx->core15fwd != NULL)
bf75be98 148 {
cc8cbabe 149 theCtx->core15fwd->glActiveTexture (GL_TEXTURE0 + theTextureUnit);
bf75be98 150 }
cc8cbabe 151 mySampler->Bind (theCtx, theTextureUnit);
bf75be98 152 glBindTexture (myTarget, myTextureId);
153}
154
155// =======================================================================
156// function : Unbind
157// purpose :
158// =======================================================================
159void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
cc8cbabe 160 const Graphic3d_TextureUnit theTextureUnit) const
bf75be98 161{
4e1523ef 162 if (theCtx->core15fwd != NULL)
bf75be98 163 {
cc8cbabe 164 theCtx->core15fwd->glActiveTexture (GL_TEXTURE0 + theTextureUnit);
bf75be98 165 }
cc8cbabe 166 mySampler->Unbind (theCtx, theTextureUnit);
bf75be98 167 glBindTexture (myTarget, NO_TEXTURE);
168}
169
18f4e8e2 170//=======================================================================
cc8cbabe 171//function : InitSamplerObject
172//purpose :
173//=======================================================================
174bool OpenGl_Texture::InitSamplerObject (const Handle(OpenGl_Context)& theCtx)
175{
176 return myTextureId != NO_TEXTURE
177 && mySampler->Init (theCtx, *this);
178}
179
180//=======================================================================
18f4e8e2 181//function : GetDataFormat
182//purpose :
183//=======================================================================
184bool OpenGl_Texture::GetDataFormat (const Handle(OpenGl_Context)& theCtx,
185 const Image_PixMap& theData,
186 GLint& theTextFormat,
187 GLenum& thePixelFormat,
188 GLenum& theDataType)
bf75be98 189{
18f4e8e2 190 theTextFormat = GL_RGBA8;
191 thePixelFormat = 0;
192 theDataType = 0;
193 switch (theData.Format())
bf75be98 194 {
dc858f4c 195 case Image_Format_GrayF:
bf75be98 196 {
076ca35c 197 if (theCtx->core11 == NULL)
198 {
199 theTextFormat = GL_R8; // GL_R32F
200 thePixelFormat = GL_RED;
201 }
202 else
203 {
a1073ae2 204 #if !defined(GL_ES_VERSION_2_0)
076ca35c 205 theTextFormat = GL_LUMINANCE8;
a1073ae2 206 #else
207 theTextFormat = GL_LUMINANCE;
208 #endif
076ca35c 209 thePixelFormat = GL_LUMINANCE;
210 }
211 theDataType = GL_FLOAT;
212 return true;
213 }
dc858f4c 214 case Image_Format_AlphaF:
076ca35c 215 {
216 if (theCtx->core11 == NULL)
217 {
218 theTextFormat = GL_R8; // GL_R32F
219 thePixelFormat = GL_RED;
220 }
221 else
222 {
a1073ae2 223 #if !defined(GL_ES_VERSION_2_0)
076ca35c 224 theTextFormat = GL_ALPHA8;
a1073ae2 225 #else
226 theTextFormat = GL_ALPHA;
227 #endif
076ca35c 228 thePixelFormat = GL_ALPHA;
229 }
230 theDataType = GL_FLOAT;
18f4e8e2 231 return true;
bf75be98 232 }
dc858f4c 233 case Image_Format_RGBAF:
bf75be98 234 {
076ca35c 235 theTextFormat = GL_RGBA8; // GL_RGBA32F
18f4e8e2 236 thePixelFormat = GL_RGBA;
237 theDataType = GL_FLOAT;
238 return true;
bf75be98 239 }
dc858f4c 240 case Image_Format_BGRAF:
bf75be98 241 {
242 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
243 {
244 return false;
245 }
ca3c13d1 246 theTextFormat = GL_RGBA8; // GL_RGBA32F
247 thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA
18f4e8e2 248 theDataType = GL_FLOAT;
249 return true;
bf75be98 250 }
dc858f4c 251 case Image_Format_RGBF:
bf75be98 252 {
076ca35c 253 theTextFormat = GL_RGB8; // GL_RGB32F
18f4e8e2 254 thePixelFormat = GL_RGB;
255 theDataType = GL_FLOAT;
256 return true;
bf75be98 257 }
dc858f4c 258 case Image_Format_BGRF:
bf75be98 259 {
ca3c13d1 260 #if !defined(GL_ES_VERSION_2_0)
261 theTextFormat = GL_RGB8; // GL_RGB32F
18f4e8e2 262 thePixelFormat = GL_BGR; // equals to GL_BGR_EXT
263 theDataType = GL_FLOAT;
264 return true;
ca3c13d1 265 #else
266 return false;
267 #endif
bf75be98 268 }
dc858f4c 269 case Image_Format_RGBA:
bf75be98 270 {
18f4e8e2 271 theTextFormat = GL_RGBA8;
272 thePixelFormat = GL_RGBA;
273 theDataType = GL_UNSIGNED_BYTE;
274 return true;
bf75be98 275 }
dc858f4c 276 case Image_Format_BGRA:
bf75be98 277 {
177781da 278 #if !defined(GL_ES_VERSION_2_0)
bf75be98 279 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
280 {
281 return false;
282 }
ca3c13d1 283 theTextFormat = GL_RGBA8;
177781da 284 #else
285 if (!theCtx->extBgra)
286 {
287 return false;
288 }
289 theTextFormat = GL_BGRA_EXT;
290 #endif
ca3c13d1 291 thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA
18f4e8e2 292 theDataType = GL_UNSIGNED_BYTE;
293 return true;
bf75be98 294 }
dc858f4c 295 case Image_Format_RGB32:
bf75be98 296 {
177781da 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
18f4e8e2 304 thePixelFormat = GL_RGBA;
305 theDataType = GL_UNSIGNED_BYTE;
306 return true;
bf75be98 307 }
dc858f4c 308 case Image_Format_BGR32:
bf75be98 309 {
177781da 310 #if !defined(GL_ES_VERSION_2_0)
311 if (!theCtx->IsGlGreaterEqual(1, 2) && !theCtx->extBgra)
bf75be98 312 {
313 return false;
314 }
ca3c13d1 315 theTextFormat = GL_RGB8;
177781da 316 #else
317 if (!theCtx->extBgra)
318 {
319 return false;
320 }
321 theTextFormat = GL_BGRA_EXT;
322 #endif
ca3c13d1 323 thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA
18f4e8e2 324 theDataType = GL_UNSIGNED_BYTE;
325 return true;
bf75be98 326 }
dc858f4c 327 case Image_Format_RGB:
bf75be98 328 {
18f4e8e2 329 theTextFormat = GL_RGB8;
330 thePixelFormat = GL_RGB;
331 theDataType = GL_UNSIGNED_BYTE;
332 return true;
bf75be98 333 }
dc858f4c 334 case Image_Format_BGR:
bf75be98 335 {
ca3c13d1 336 #if !defined(GL_ES_VERSION_2_0)
bf75be98 337 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
338 {
339 return false;
340 }
18f4e8e2 341 theTextFormat = GL_RGB8;
342 thePixelFormat = GL_BGR; // equals to GL_BGR_EXT
343 theDataType = GL_UNSIGNED_BYTE;
344 return true;
ca3c13d1 345 #else
346 return false;
347 #endif
bf75be98 348 }
dc858f4c 349 case Image_Format_Gray:
bf75be98 350 {
076ca35c 351 if (theCtx->core11 == NULL)
352 {
353 theTextFormat = GL_R8;
354 thePixelFormat = GL_RED;
355 }
356 else
357 {
a1073ae2 358 #if !defined(GL_ES_VERSION_2_0)
076ca35c 359 theTextFormat = GL_LUMINANCE8;
a1073ae2 360 #else
361 theTextFormat = GL_LUMINANCE;
362 #endif
076ca35c 363 thePixelFormat = GL_LUMINANCE;
364 }
365 theDataType = GL_UNSIGNED_BYTE;
366 return true;
367 }
dc858f4c 368 case Image_Format_Alpha:
076ca35c 369 {
370 if (theCtx->core11 == NULL)
371 {
372 theTextFormat = GL_R8;
373 thePixelFormat = GL_RED;
374 }
375 else
376 {
a1073ae2 377 #if !defined(GL_ES_VERSION_2_0)
076ca35c 378 theTextFormat = GL_ALPHA8;
a1073ae2 379 #else
380 theTextFormat = GL_ALPHA;
381 #endif
076ca35c 382 thePixelFormat = GL_ALPHA;
383 }
384 theDataType = GL_UNSIGNED_BYTE;
18f4e8e2 385 return true;
bf75be98 386 }
dc858f4c 387 case Image_Format_UNKNOWN:
bf75be98 388 {
389 return false;
390 }
391 }
076ca35c 392 return false;
18f4e8e2 393}
bf75be98 394
18f4e8e2 395// =======================================================================
396// function : Init
397// purpose :
398// =======================================================================
399bool 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{
66d1cdc6 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
d2edda76 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);
18f4e8e2 431 if (!Create (theCtx))
432 {
433 Release (theCtx.operator->());
434 return false;
435 }
4e1523ef 436
437 if (theImage != NULL)
438 {
dc858f4c 439 myIsAlpha = theImage->Format() == Image_Format_Alpha
440 || theImage->Format() == Image_Format_AlphaF;
4e1523ef 441 }
442 else
443 {
444 myIsAlpha = thePixelFormat == GL_ALPHA;
445 }
446
d2edda76 447 myHasMipmaps = toCreateMipMaps;
8625ef7e 448 myTextFormat = thePixelFormat;
15669413 449 mySizedFormat = theTextFormat;
450 myNbSamples = 1;
8625ef7e 451#if !defined(GL_ES_VERSION_2_0)
452 const GLint anIntFormat = theTextFormat;
453#else
a1073ae2 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;
8625ef7e 456#endif
bf75be98 457
ff6665dc 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
d2edda76 466 const GLsizei aMaxSize = theCtx->MaxTextureSize();
467 if (theSizeX > aMaxSize
468 || theSizeY > aMaxSize)
fa4dcbe0 469 {
470 TCollection_ExtendedString aWarnMessage = TCollection_ExtendedString ("Error: Texture dimension - ")
d2edda76 471 + theSizeX + "x" + theSizeY + " exceeds hardware limits (" + aMaxSize + "x" + aMaxSize + ")";
fa4dcbe0 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,
d2edda76 484 const GLsizei aWidthP2 = OpenGl_Context::GetPowerOfTwo (theSizeX, aMaxSize);
485 const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (theSizeY, aMaxSize);
fa4dcbe0 486
d2edda76 487 if (theSizeX != aWidthP2
488 || (theType != Graphic3d_TOT_1D && theSizeY != aHeightP2))
fa4dcbe0 489 {
490 TCollection_ExtendedString aWarnMessage =
d2edda76 491 TCollection_ExtendedString ("Error: NPOT Textures (") + theSizeX + "x" + theSizeY + ") are not supported by hardware.";
fa4dcbe0 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.
d2edda76 503 const GLsizei aWidthP2 = OpenGl_Context::GetPowerOfTwo (theSizeX, aMaxSize);
504 const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (theSizeY, aMaxSize);
fa4dcbe0 505
d2edda76 506 if (theSizeX != aWidthP2
507 || theSizeY != aHeightP2)
fa4dcbe0 508 {
509 TCollection_ExtendedString aWarnMessage =
d2edda76 510 TCollection_ExtendedString ("Error: Mipmap NPOT Textures (") + theSizeX + "x" + theSizeY + ") are not supported by OpenGL ES 2.0";
fa4dcbe0 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
ca3c13d1 520#if !defined(GL_ES_VERSION_2_0)
bf75be98 521 GLint aTestWidth = 0;
522 GLint aTestHeight = 0;
ca3c13d1 523#endif
18f4e8e2 524 GLvoid* aDataPtr = (theImage != NULL) ? (GLvoid* )theImage->Data() : NULL;
bf75be98 525
74706083 526 // setup the alignment
527 OpenGl_UnpackAlignmentSentry anUnpackSentry;
fa4dcbe0 528 (void)anUnpackSentry; // avoid compiler warning
529
18f4e8e2 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);
74706083 534
ca3c13d1 535 #if !defined(GL_ES_VERSION_2_0)
18f4e8e2 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);
ca3c13d1 540 #endif
18f4e8e2 541 }
74706083 542
d2edda76 543 myTarget = aTarget;
bf75be98 544 switch (theType)
545 {
546 case Graphic3d_TOT_1D:
547 {
ca3c13d1 548 #if !defined(GL_ES_VERSION_2_0)
bf75be98 549 Bind (theCtx);
cc8cbabe 550 applyDefaultSamplerParams (theCtx);
d2edda76 551 if (toPatchExisting)
552 {
553 glTexSubImage1D (GL_TEXTURE_1D, 0, 0,
554 theSizeX, thePixelFormat, theDataType, aDataPtr);
555 Unbind (theCtx);
556 return true;
557 }
bf75be98 558
bf75be98 559 // use proxy to check texture could be created or not
8625ef7e 560 glTexImage1D (GL_PROXY_TEXTURE_1D, 0, anIntFormat,
d2edda76 561 theSizeX, 0,
18f4e8e2 562 thePixelFormat, theDataType, NULL);
ff6665dc 563 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
15669413 564 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
bf75be98 565 if (aTestWidth == 0)
566 {
567 // no memory or broken input parameters
568 Unbind (theCtx);
18f4e8e2 569 Release (theCtx.operator->());
bf75be98 570 return false;
571 }
572
8625ef7e 573 glTexImage1D (GL_TEXTURE_1D, 0, anIntFormat,
d2edda76 574 theSizeX, 0,
18f4e8e2 575 thePixelFormat, theDataType, aDataPtr);
a174a3c5 576 if (glGetError() != GL_NO_ERROR)
577 {
578 Unbind (theCtx);
18f4e8e2 579 Release (theCtx.operator->());
a174a3c5 580 return false;
581 }
582
d2edda76 583 mySizeX = theSizeX;
a174a3c5 584 mySizeY = 1;
bf75be98 585
586 Unbind (theCtx);
587 return true;
ca3c13d1 588 #else
ff6665dc 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.");
fa4dcbe0 591 Release (theCtx.operator->());
ca3c13d1 592 return false;
593 #endif
bf75be98 594 }
595 case Graphic3d_TOT_2D:
596 {
bf75be98 597 Bind (theCtx);
cc8cbabe 598 applyDefaultSamplerParams (theCtx);
d2edda76 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 }
bf75be98 608
ca3c13d1 609 #if !defined(GL_ES_VERSION_2_0)
bf75be98 610 // use proxy to check texture could be created or not
8625ef7e 611 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat,
d2edda76 612 theSizeX, theSizeY, 0,
18f4e8e2 613 thePixelFormat, theDataType, NULL);
bf75be98 614 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
615 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
15669413 616 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
bf75be98 617 if (aTestWidth == 0 || aTestHeight == 0)
618 {
619 // no memory or broken input parameters
620 Unbind (theCtx);
18f4e8e2 621 Release (theCtx.operator->());
bf75be98 622 return false;
623 }
ca3c13d1 624 #endif
bf75be98 625
8625ef7e 626 glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
d2edda76 627 theSizeX, theSizeY, 0,
18f4e8e2 628 thePixelFormat, theDataType, aDataPtr);
177781da 629 const GLenum anErr = glGetError();
630 if (anErr != GL_NO_ERROR)
a174a3c5 631 {
177781da 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) + ".");
a174a3c5 636 Unbind (theCtx);
18f4e8e2 637 Release (theCtx.operator->());
a174a3c5 638 return false;
639 }
640
d2edda76 641 mySizeX = theSizeX;
642 mySizeY = theSizeY;
bf75be98 643
644 Unbind (theCtx);
645 return true;
646 }
647 case Graphic3d_TOT_2D_MIPMAP:
648 {
bf75be98 649 Bind (theCtx);
cc8cbabe 650 applyDefaultSamplerParams (theCtx);
d2edda76 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 }
bf75be98 672
fa4dcbe0 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,
d2edda76 676 theSizeX, theSizeY, 0,
fa4dcbe0 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);
15669413 680 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
fa4dcbe0 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,
d2edda76 692 theSizeX, theSizeY, 0,
fa4dcbe0 693 thePixelFormat, theDataType, theImage->Data());
177781da 694 const GLenum aTexImgErr = glGetError();
695 if (aTexImgErr != GL_NO_ERROR)
1a7dfdb7 696 {
177781da 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) + ".");
fa4dcbe0 701 Unbind (theCtx);
702 Release (theCtx.operator->());
703 return false;
704 }
705
d2edda76 706 mySizeX = theSizeX;
707 mySizeY = theSizeY;
fa4dcbe0 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);
1a7dfdb7 714
a174a3c5 715 if (glGetError() != GL_NO_ERROR)
716 {
717 Unbind (theCtx);
18f4e8e2 718 Release (theCtx.operator->());
a174a3c5 719 return false;
720 }
1a7dfdb7 721 }
722 else
723 {
fa4dcbe0 724 const TCollection_ExtendedString aWarnMessage ("Warning: generating mipmaps requires GL_ARB_framebuffer_object extension which is missing.");
725
3b523c4c 726 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage);
a174a3c5 727
1a7dfdb7 728 Unbind (theCtx);
fa4dcbe0 729 Release (theCtx.operator->());
ca3c13d1 730 return false;
1a7dfdb7 731 }
fa4dcbe0 732
733 Unbind (theCtx);
734 return true;
bf75be98 735 }
bf75be98 736 }
d2edda76 737
738 Release (theCtx.operator->());
739 return false;
bf75be98 740}
68333c8f 741
742// =======================================================================
18f4e8e2 743// function : Init
744// purpose :
745// =======================================================================
746bool 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// =======================================================================
3c4b62a4 773// function : Init2DMultisample
774// purpose :
775// =======================================================================
776bool 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
15669413 789 myNbSamples = OpenGl_Context::GetPowerOfTwo (theNbSamples, theCtx->MaxMsaaSamples());
3c4b62a4 790 myTarget = GL_TEXTURE_2D_MULTISAMPLE;
15669413 791 myHasMipmaps = false;
3c4b62a4 792 if(theSizeX > theCtx->MaxTextureSize()
793 || theSizeY > theCtx->MaxTextureSize())
794 {
795 return false;
796 }
797
798 Bind (theCtx);
799 //myTextFormat = theTextFormat;
15669413 800 mySizedFormat = theTextFormat;
3c4b62a4 801#if !defined(GL_ES_VERSION_2_0)
802 if (theCtx->Functions()->glTexStorage2DMultisample != NULL)
803 {
15669413 804 theCtx->Functions()->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
3c4b62a4 805 }
806 else
807 {
15669413 808 theCtx->Functions()->glTexImage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
3c4b62a4 809 }
810#else
15669413 811 theCtx->Functions() ->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
3c4b62a4 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// =======================================================================
68333c8f 827// function : InitRectangle
828// purpose :
829// =======================================================================
830bool 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 }
ca3c13d1 839
840#if !defined(GL_ES_VERSION_2_0)
68333c8f 841 myTarget = GL_TEXTURE_RECTANGLE;
15669413 842 myNbSamples = 1;
843 myHasMipmaps = false;
68333c8f 844
fe3a29bc 845 const GLsizei aSizeX = Min (theCtx->MaxTextureSize(), theSizeX);
846 const GLsizei aSizeY = Min (theCtx->MaxTextureSize(), theSizeY);
ca3c13d1 847
68333c8f 848 Bind (theCtx);
cc8cbabe 849 applyDefaultSamplerParams (theCtx);
68333c8f 850
15669413 851 myTextFormat = theFormat.Format();
852 mySizedFormat = theFormat.Internal();
68333c8f 853
90fd6145 854 // setup the alignment
855 OpenGl_UnpackAlignmentSentry::Reset();
856
15669413 857 glTexImage2D (GL_PROXY_TEXTURE_RECTANGLE, 0, mySizedFormat,
858 aSizeX, aSizeY, 0,
859 myTextFormat, GL_FLOAT, NULL);
68333c8f 860
861 GLint aTestSizeX = 0;
862 GLint aTestSizeY = 0;
863
15669413 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);
68333c8f 867
868 if (aTestSizeX == 0 || aTestSizeY == 0)
869 {
870 Unbind (theCtx);
871 return false;
872 }
873
15669413 874 glTexImage2D (myTarget, 0, mySizedFormat,
875 aSizeX, aSizeY, 0,
876 myTextFormat, GL_FLOAT, NULL);
68333c8f 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;
ca3c13d1 889#else
20aeeb7b 890 (void )theSizeX;
891 (void )theSizeY;
892 (void )theFormat;
ca3c13d1 893 return false;
894#endif
68333c8f 895}
74fb257d 896
897// =======================================================================
898// function : Init3D
899// purpose :
900// =======================================================================
901bool 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;
15669413 929 myNbSamples = 1;
930 myHasMipmaps = false;
74fb257d 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
15669413 953 mySizedFormat = theTextFormat;
74fb257d 954
90fd6145 955 // setup the alignment
956 OpenGl_UnpackAlignmentSentry::Reset();
957
74fb257d 958#if !defined (GL_ES_VERSION_2_0)
15669413 959 theCtx->core15fwd->glTexImage3D (GL_PROXY_TEXTURE_3D, 0, mySizedFormat,
960 aSizeX, aSizeY, aSizeZ, 0,
961 thePixelFormat, theDataType, NULL);
74fb257d 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);
15669413 970 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
74fb257d 971
972 if (aTestSizeX == 0 || aTestSizeY == 0 || aTestSizeZ == 0)
973 {
974 Unbind (theCtx);
975 Release (theCtx.operator->());
976 return false;
977 }
978#endif
979
cc8cbabe 980 applyDefaultSamplerParams (theCtx);
15669413 981 theCtx->Functions()->glTexImage3D (myTarget, 0, mySizedFormat,
982 aSizeX, aSizeY, aSizeZ, 0,
983 thePixelFormat, theDataType, thePixels);
74fb257d 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}
15669413 999
1000// =======================================================================
1001// function : PixelSizeOfPixelFormat
1002// purpose :
1003// =======================================================================
1004Standard_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// =======================================================================
1050Standard_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}