0032465: Visualization, TKOpenGles - invalid enum on GL_RGBA16F initialization in...
[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>
8f8fe4a9 19#include <OpenGl_GlCore45.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>
faff3767 24#include <Image_CompressedPixMap.hxx>
bf75be98 25#include <Image_PixMap.hxx>
faff3767 26#include <Image_SupportedFormats.hxx>
bf75be98 27
e1d17ceb 28#include <algorithm>
29
cc8cbabe 30IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture, OpenGl_NamedResource)
92efcf78 31
faff3767 32namespace
33{
34
74706083 35//! Simple class to reset unpack alignment settings
36struct OpenGl_UnpackAlignmentSentry
37{
74706083 38 //! Reset unpack alignment settings to safe values
e1d17ceb 39 static void Reset (const OpenGl_Context& theCtx)
74706083 40 {
e1d17ceb 41 theCtx.core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
42 if (theCtx.hasUnpackRowLength)
43 {
44 theCtx.core11fwd->glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
45 }
74706083 46 }
47
e1d17ceb 48 OpenGl_UnpackAlignmentSentry (const Handle(OpenGl_Context)& theCtx)
49 : myCtx (theCtx.get()) {}
90fd6145 50
74706083 51 ~OpenGl_UnpackAlignmentSentry()
52 {
e1d17ceb 53 Reset (*myCtx);
74706083 54 }
55
e1d17ceb 56private:
57 OpenGl_Context* myCtx;
74706083 58};
59
faff3767 60//! Compute the upper mipmap level for complete mipmap set (e.g. till the 1x1 level).
61static Standard_Integer computeUpperMipMapLevel (Standard_Integer theSize)
62{
63 for (Standard_Integer aMipIter = 0;; ++aMipIter, theSize /= 2)
64 {
65 if (theSize <= 1)
66 {
67 return aMipIter;
68 }
69 }
70}
71
72//! Compute the upper mipmap level for complete mipmap set (e.g. till the 1x1 level).
73static Standard_Integer computeUpperMipMapLevel (Standard_Integer theSizeX, Standard_Integer theSizeY)
74{
75 return computeUpperMipMapLevel (Max (theSizeX, theSizeY));
76}
77
78//! Compute size of the smallest defined mipmap level (for verbose messages).
79static Graphic3d_Vec2i computeSmallestMipMapSize (const Graphic3d_Vec2i& theBaseSize, Standard_Integer theMaxLevel)
80{
81 Graphic3d_Vec2i aMipSizeXY = theBaseSize;
82 for (Standard_Integer aMipIter = 0;; ++aMipIter)
83 {
84 if (aMipIter > theMaxLevel)
85 {
86 return aMipSizeXY;
87 }
88
89 aMipSizeXY /= 2;
90 if (aMipSizeXY.x() == 0) { aMipSizeXY.x() = 1; }
91 if (aMipSizeXY.y() == 0) { aMipSizeXY.y() = 1; }
92 }
93}
94
95}
96
bf75be98 97// =======================================================================
98// function : OpenGl_Texture
99// purpose :
100// =======================================================================
cc8cbabe 101OpenGl_Texture::OpenGl_Texture (const TCollection_AsciiString& theResourceId,
102 const Handle(Graphic3d_TextureParams)& theParams)
103: OpenGl_NamedResource (theResourceId),
104 mySampler (new OpenGl_Sampler (theParams)),
d2edda76 105 myRevision (0),
bf75be98 106 myTextureId (NO_TEXTURE),
107 myTarget (GL_TEXTURE_2D),
108 mySizeX (0),
109 mySizeY (0),
74fb257d 110 mySizeZ (0),
8625ef7e 111 myTextFormat (GL_RGBA),
15669413 112 mySizedFormat(GL_RGBA8),
113 myNbSamples (1),
faff3767 114 myMaxMipLevel(0),
115 myIsAlpha (false),
116 myIsTopDown (true)
bf75be98 117{
cc8cbabe 118 //
bf75be98 119}
120
121// =======================================================================
122// function : ~OpenGl_Texture
123// purpose :
124// =======================================================================
125OpenGl_Texture::~OpenGl_Texture()
126{
127 Release (NULL);
128}
129
bf75be98 130// =======================================================================
131// function : Create
132// purpose :
133// =======================================================================
cc8cbabe 134bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& theCtx)
bf75be98 135{
cc8cbabe 136 if (myTextureId != NO_TEXTURE)
137 {
138 return true;
139 }
140
141 theCtx->core11fwd->glGenTextures (1, &myTextureId);
bf75be98 142 if (myTextureId == NO_TEXTURE)
143 {
cc8cbabe 144 return false;
bf75be98 145 }
cc8cbabe 146
147 //mySampler->Create (theCtx); // do not create sampler object by default
148 return true;
bf75be98 149}
150
151// =======================================================================
152// function : Release
153// purpose :
154// =======================================================================
10b9c7df 155void OpenGl_Texture::Release (OpenGl_Context* theGlCtx)
bf75be98 156{
cc8cbabe 157 mySampler->Release (theGlCtx);
bf75be98 158 if (myTextureId == NO_TEXTURE)
159 {
160 return;
161 }
162
163 // application can not handle this case by exception - this is bug in code
164 Standard_ASSERT_RETURN (theGlCtx != NULL,
165 "OpenGl_Texture destroyed without GL context! Possible GPU memory leakage...",);
166
ec2eeb2d 167 if (theGlCtx->IsValid())
168 {
e1d17ceb 169 theGlCtx->core11fwd->glDeleteTextures (1, &myTextureId);
ec2eeb2d 170 }
bf75be98 171 myTextureId = NO_TEXTURE;
d2edda76 172 mySizeX = mySizeY = mySizeZ = 0;
bf75be98 173}
174
cc8cbabe 175// =======================================================================
176// function : applyDefaultSamplerParams
177// purpose :
178// =======================================================================
179void OpenGl_Texture::applyDefaultSamplerParams (const Handle(OpenGl_Context)& theCtx)
180{
faff3767 181 OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), NULL, myTarget, myMaxMipLevel);
cc8cbabe 182 if (mySampler->IsValid() && !mySampler->IsImmutable())
183 {
faff3767 184 OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), mySampler.get(), myTarget, myMaxMipLevel);
cc8cbabe 185 }
186}
187
bf75be98 188// =======================================================================
189// function : Bind
190// purpose :
191// =======================================================================
192void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
cc8cbabe 193 const Graphic3d_TextureUnit theTextureUnit) const
bf75be98 194{
4e1523ef 195 if (theCtx->core15fwd != NULL)
bf75be98 196 {
cc8cbabe 197 theCtx->core15fwd->glActiveTexture (GL_TEXTURE0 + theTextureUnit);
bf75be98 198 }
cc8cbabe 199 mySampler->Bind (theCtx, theTextureUnit);
e1d17ceb 200 theCtx->core11fwd->glBindTexture (myTarget, myTextureId);
bf75be98 201}
202
203// =======================================================================
204// function : Unbind
205// purpose :
206// =======================================================================
207void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
cc8cbabe 208 const Graphic3d_TextureUnit theTextureUnit) const
bf75be98 209{
4e1523ef 210 if (theCtx->core15fwd != NULL)
bf75be98 211 {
cc8cbabe 212 theCtx->core15fwd->glActiveTexture (GL_TEXTURE0 + theTextureUnit);
bf75be98 213 }
cc8cbabe 214 mySampler->Unbind (theCtx, theTextureUnit);
e1d17ceb 215 theCtx->core11fwd->glBindTexture (myTarget, NO_TEXTURE);
bf75be98 216}
217
cc8cbabe 218//=======================================================================
219//function : InitSamplerObject
220//purpose :
221//=======================================================================
222bool OpenGl_Texture::InitSamplerObject (const Handle(OpenGl_Context)& theCtx)
223{
224 return myTextureId != NO_TEXTURE
225 && mySampler->Init (theCtx, *this);
226}
227
18f4e8e2 228// =======================================================================
229// function : Init
230// purpose :
231// =======================================================================
232bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
ba00aab7 233 const OpenGl_TextureFormat& theFormat,
234 const Graphic3d_Vec2i& theSizeXY,
18f4e8e2 235 const Graphic3d_TypeOfTexture theType,
236 const Image_PixMap* theImage)
237{
ba00aab7 238 if (theSizeXY.x() < 1
239 || theSizeXY.y() < 1)
66d1cdc6 240 {
241 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
776302d4 242 TCollection_AsciiString ("Error: texture of 0 size cannot be created [") + myResourceId +"]");
ba00aab7 243 Release (theCtx.get());
66d1cdc6 244 return false;
245 }
246
d2edda76 247#if !defined(GL_ES_VERSION_2_0)
248 const GLenum aTarget = theType == Graphic3d_TOT_1D
249 ? GL_TEXTURE_1D
250 : GL_TEXTURE_2D;
251#else
252 const GLenum aTarget = GL_TEXTURE_2D;
253#endif
d2edda76 254 const bool toPatchExisting = IsValid()
ba00aab7 255 && myTextFormat == theFormat.PixelFormat()
d2edda76 256 && myTarget == aTarget
faff3767 257 && HasMipmaps() == (theType == Graphic3d_TOT_2D_MIPMAP)
ba00aab7 258 && mySizeX == theSizeXY.x()
259 && (mySizeY == theSizeXY.y() || theType == Graphic3d_TOT_1D);
18f4e8e2 260 if (!Create (theCtx))
261 {
ba00aab7 262 Release (theCtx.get());
18f4e8e2 263 return false;
264 }
4e1523ef 265
266 if (theImage != NULL)
267 {
dc858f4c 268 myIsAlpha = theImage->Format() == Image_Format_Alpha
269 || theImage->Format() == Image_Format_AlphaF;
faff3767 270 myIsTopDown = theImage->IsTopDown();
4e1523ef 271 }
272 else
273 {
ba00aab7 274 myIsAlpha = theFormat.PixelFormat() == GL_ALPHA;
4e1523ef 275 }
276
faff3767 277 myMaxMipLevel = theType == Graphic3d_TOT_2D_MIPMAP && theCtx->arbFBO != NULL
278 ? computeUpperMipMapLevel (theSizeXY.x(), theSizeXY.y())
279 : 0;
280 myTextFormat = theFormat.PixelFormat();
281 mySizedFormat = theFormat.InternalFormat();
282 myNbSamples = 1;
8625ef7e 283#if !defined(GL_ES_VERSION_2_0)
ba00aab7 284 const GLint anIntFormat = theFormat.InternalFormat();
8625ef7e 285#else
a1073ae2 286 // ES 2.0 does not support sized formats and format conversions - them detected from data type
ba00aab7 287 const GLint anIntFormat = theCtx->IsGlGreaterEqual (3, 0) ? theFormat.InternalFormat() : theFormat.PixelFormat();
8625ef7e 288#endif
bf75be98 289
ba00aab7 290 if (theFormat.DataType() == GL_FLOAT
291 && !theCtx->arbTexFloat)
ff6665dc 292 {
293 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
776302d4 294 TCollection_AsciiString ("Error: floating-point textures are not supported by hardware [") + myResourceId +"]");
ba00aab7 295 Release (theCtx.get());
ff6665dc 296 return false;
297 }
298
d2edda76 299 const GLsizei aMaxSize = theCtx->MaxTextureSize();
ba00aab7 300 if (theSizeXY.x() > aMaxSize
301 || theSizeXY.y() > aMaxSize)
fa4dcbe0 302 {
ba00aab7 303 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
304 TCollection_AsciiString ("Error: Texture dimension - ") + theSizeXY.x() + "x" + theSizeXY.y()
776302d4 305 + " exceeds hardware limits (" + aMaxSize + "x" + aMaxSize + ")"
306 + " [" + myResourceId +"]");
ba00aab7 307 Release (theCtx.get());
fa4dcbe0 308 return false;
309 }
310#if !defined(GL_ES_VERSION_2_0)
311 else if (!theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW)
312 {
313 // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications
314 // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT!
315 // Trying to create NPOT textures on such hardware will not fail
316 // but driver will fall back into software rendering,
ba00aab7 317 const GLsizei aWidthP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.x(), aMaxSize);
318 const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.y(), aMaxSize);
319 if (theSizeXY.x() != aWidthP2
320 || (theType != Graphic3d_TOT_1D && theSizeXY.y() != aHeightP2))
fa4dcbe0 321 {
ba00aab7 322 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
323 TCollection_AsciiString ("Error: NPOT Textures (") + theSizeXY.x() + "x" + theSizeXY.y() + ")"
776302d4 324 " are not supported by hardware [" + myResourceId +"]");
ba00aab7 325 Release (theCtx.get());
fa4dcbe0 326 return false;
327 }
328 }
329#else
330 else if (!theCtx->IsGlGreaterEqual (3, 0) && theType == Graphic3d_TOT_2D_MIPMAP)
331 {
332 // Mipmap NPOT textures are not supported by OpenGL ES 2.0.
ba00aab7 333 const GLsizei aWidthP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.x(), aMaxSize);
334 const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.y(), aMaxSize);
335 if (theSizeXY.x() != aWidthP2
336 || theSizeXY.y() != aHeightP2)
fa4dcbe0 337 {
ba00aab7 338 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
339 TCollection_AsciiString ("Error: Mipmap NPOT Textures (") + theSizeXY.x() + "x" + theSizeXY.y() + ")"
776302d4 340 " are not supported by OpenGL ES 2.0 [" + myResourceId +"]");
ba00aab7 341 Release (theCtx.get());
fa4dcbe0 342 return false;
343 }
344 }
345#endif
346
ca3c13d1 347#if !defined(GL_ES_VERSION_2_0)
e1d17ceb 348 GLint aTestWidth = 0, aTestHeight = 0;
ca3c13d1 349#endif
18f4e8e2 350 GLvoid* aDataPtr = (theImage != NULL) ? (GLvoid* )theImage->Data() : NULL;
bf75be98 351
74706083 352 // setup the alignment
e1d17ceb 353 OpenGl_UnpackAlignmentSentry anUnpackSentry (theCtx);
fa4dcbe0 354 (void)anUnpackSentry; // avoid compiler warning
355
18f4e8e2 356 if (aDataPtr != NULL)
357 {
358 const GLint anAligment = Min ((GLint )theImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
a46ab511 359 theCtx->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
18f4e8e2 360 const GLint anExtraBytes = GLint(theImage->RowExtraBytes());
361 const GLint aPixelsWidth = GLint(theImage->SizeRowBytes() / theImage->SizePixelBytes());
e1d17ceb 362 if (theCtx->hasUnpackRowLength)
363 {
364 theCtx->core11fwd->glPixelStorei (GL_UNPACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0);
365 }
366 else if (anExtraBytes >= anAligment)
367 {
368 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
369 TCollection_AsciiString ("Error: unsupported image stride within OpenGL ES 2.0 [") + myResourceId +"]");
370 Release (theCtx.get());
371 return false;
372 }
18f4e8e2 373 }
74706083 374
d2edda76 375 myTarget = aTarget;
bf75be98 376 switch (theType)
377 {
378 case Graphic3d_TOT_1D:
379 {
ca3c13d1 380 #if !defined(GL_ES_VERSION_2_0)
bf75be98 381 Bind (theCtx);
cc8cbabe 382 applyDefaultSamplerParams (theCtx);
d2edda76 383 if (toPatchExisting)
384 {
a46ab511 385 theCtx->core11fwd->glTexSubImage1D (GL_TEXTURE_1D, 0, 0,
386 theSizeXY.x(), theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
d2edda76 387 Unbind (theCtx);
388 return true;
389 }
bf75be98 390
bf75be98 391 // use proxy to check texture could be created or not
a46ab511 392 theCtx->core11fwd->glTexImage1D (GL_PROXY_TEXTURE_1D, 0, anIntFormat,
393 theSizeXY.x(), 0,
394 theFormat.PixelFormat(), theFormat.DataType(), NULL);
ff6665dc 395 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
15669413 396 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
bf75be98 397 if (aTestWidth == 0)
398 {
399 // no memory or broken input parameters
400 Unbind (theCtx);
18f4e8e2 401 Release (theCtx.operator->());
bf75be98 402 return false;
403 }
404
a46ab511 405 theCtx->core11fwd->glTexImage1D (GL_TEXTURE_1D, 0, anIntFormat,
406 theSizeXY.x(), 0,
407 theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
408 if (theCtx->core11fwd->glGetError() != GL_NO_ERROR)
a174a3c5 409 {
410 Unbind (theCtx);
ba00aab7 411 Release (theCtx.get());
a174a3c5 412 return false;
413 }
414
ba00aab7 415 mySizeX = theSizeXY.x();
a174a3c5 416 mySizeY = 1;
bf75be98 417
418 Unbind (theCtx);
419 return true;
ca3c13d1 420 #else
ff6665dc 421 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
776302d4 422 TCollection_AsciiString ( "Error: 1D textures are not supported by hardware [") + myResourceId +"]");
ba00aab7 423 Release (theCtx.get());
ca3c13d1 424 return false;
425 #endif
bf75be98 426 }
427 case Graphic3d_TOT_2D:
bf75be98 428 case Graphic3d_TOT_2D_MIPMAP:
429 {
bf75be98 430 Bind (theCtx);
cc8cbabe 431 applyDefaultSamplerParams (theCtx);
d2edda76 432 if (toPatchExisting)
433 {
a46ab511 434 theCtx->core11fwd->glTexSubImage2D (GL_TEXTURE_2D, 0,
435 0, 0,
436 theSizeXY.x(), theSizeXY.y(),
437 theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
faff3767 438
439 if (myMaxMipLevel > 0)
d2edda76 440 {
441 // generate mipmaps
442 theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
a46ab511 443 if (theCtx->core11fwd->glGetError() != GL_NO_ERROR)
d2edda76 444 {
faff3767 445 myMaxMipLevel = 0;
d2edda76 446 }
447 }
448
449 Unbind (theCtx);
450 return true;
451 }
bf75be98 452
fa4dcbe0 453 #if !defined(GL_ES_VERSION_2_0)
454 // use proxy to check texture could be created or not
a46ab511 455 theCtx->core11fwd->glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat,
456 theSizeXY.x(), theSizeXY.y(), 0,
457 theFormat.PixelFormat(), theFormat.DataType(), NULL);
fa4dcbe0 458 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
459 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
15669413 460 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
fa4dcbe0 461 if (aTestWidth == 0 || aTestHeight == 0)
462 {
463 // no memory or broken input parameters
464 Unbind (theCtx);
ba00aab7 465 Release (theCtx.get());
fa4dcbe0 466 return false;
467 }
468 #endif
469
a46ab511 470 theCtx->core11fwd->glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
471 theSizeXY.x(), theSizeXY.y(), 0,
472 theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
473 GLenum anErr = theCtx->core11fwd->glGetError();
faff3767 474 if (anErr != GL_NO_ERROR)
1a7dfdb7 475 {
177781da 476 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
ba00aab7 477 TCollection_AsciiString ("Error: 2D texture ") + theSizeXY.x() + "x" + theSizeXY.y()
a46ab511 478 + " IF: " + OpenGl_TextureFormat::FormatFormat (anIntFormat)
479 + " PF: " + OpenGl_TextureFormat::FormatFormat (theFormat.PixelFormat())
480 + " DT: " + OpenGl_TextureFormat::FormatDataType (theFormat.DataType())
776302d4 481 + " can not be created with error " + OpenGl_Context::FormatGlError (anErr)
482 + " [" + myResourceId +"]");
fa4dcbe0 483 Unbind (theCtx);
ba00aab7 484 Release (theCtx.get());
fa4dcbe0 485 return false;
486 }
487
ba00aab7 488 mySizeX = theSizeXY.x();
489 mySizeY = theSizeXY.y();
fa4dcbe0 490
faff3767 491 if (myMaxMipLevel > 0)
fa4dcbe0 492 {
493 // generate mipmaps
494 //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
495 theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
a46ab511 496 anErr = theCtx->core11fwd->glGetError();
faff3767 497 if (anErr != GL_NO_ERROR)
a174a3c5 498 {
faff3767 499 myMaxMipLevel = 0;
776302d4 500 #if defined(GL_ES_VERSION_2_0)
501 if (theFormat.InternalFormat() == GL_RGB8
502 || theFormat.InternalFormat() == GL_SRGB8)
503 {
504 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
505 TCollection_AsciiString ("Warning: generating mipmaps requires color-renderable format, while giving ")
506 + OpenGl_TextureFormat::FormatFormat (anIntFormat) + " [" + myResourceId +"]");
507 }
508 else
509 #endif
510 {
511 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
512 TCollection_AsciiString ("Warning: generating mipmaps has failed [") + myResourceId +"]");
513 }
a174a3c5 514 }
1a7dfdb7 515 }
fa4dcbe0 516
517 Unbind (theCtx);
518 return true;
bf75be98 519 }
077a220c 520 case Graphic3d_TOT_CUBEMAP:
521 {
522 Unbind (theCtx);
523 Release (theCtx.get());
524 return false;
525 }
bf75be98 526 }
d2edda76 527
ba00aab7 528 Release (theCtx.get());
d2edda76 529 return false;
bf75be98 530}
68333c8f 531
18f4e8e2 532// =======================================================================
533// function : Init
534// purpose :
535// =======================================================================
536bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
537 const Image_PixMap& theImage,
ba00aab7 538 const Graphic3d_TypeOfTexture theType,
539 const Standard_Boolean theIsColorMap)
18f4e8e2 540{
541 if (theImage.IsEmpty())
542 {
ba00aab7 543 Release (theCtx.get());
18f4e8e2 544 return false;
545 }
546
ba00aab7 547 const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindFormat (theCtx, theImage.Format(), theIsColorMap);
548 if (!aFormat.IsValid())
18f4e8e2 549 {
776302d4 550 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
551 TCollection_AsciiString ("Error: No suitable texture format for ") + Image_PixMap::ImageFormatToString (theImage.Format()) + " image format"
552 + " [" + myResourceId +"]");
ba00aab7 553 Release (theCtx.get());
18f4e8e2 554 return false;
555 }
556
ba00aab7 557 return Init (theCtx, aFormat, Graphic3d_Vec2i ((Standard_Integer)theImage.SizeX(), (Standard_Integer)theImage.SizeY()),
18f4e8e2 558 theType, &theImage);
559}
560
077a220c 561// =======================================================================
562// function : Init
563// purpose :
564// =======================================================================
565bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
566 const Handle(Graphic3d_TextureMap)& theTextureMap)
567{
568 if (theTextureMap.IsNull())
569 {
570 return false;
571 }
572
573 switch (theTextureMap->Type())
574 {
575 case Graphic3d_TOT_CUBEMAP:
576 {
67312b79 577 return InitCubeMap (theCtx, Handle(Graphic3d_CubeMap)::DownCast(theTextureMap),
ba00aab7 578 0, Image_Format_RGB, false, theTextureMap->IsColorMap());
077a220c 579 }
580 default:
581 {
faff3767 582 if (theCtx->SupportedTextureFormats()->HasCompressed()
583 && !theCtx->caps->compressedTexturesDisable)
584 {
585 if (Handle(Image_CompressedPixMap) aCompressed = theTextureMap->GetCompressedImage (theCtx->SupportedTextureFormats()))
586 {
587 return InitCompressed (theCtx, *aCompressed, theTextureMap->IsColorMap());
588 }
589 }
590
591 Handle(Image_PixMap) anImage = theTextureMap->GetImage (theCtx->SupportedTextureFormats());
077a220c 592 if (anImage.IsNull())
593 {
594 return false;
595 }
ba00aab7 596 return Init (theCtx, *anImage, theTextureMap->Type(), theTextureMap->IsColorMap());
077a220c 597 }
598 }
599}
600
faff3767 601// =======================================================================
602// function : InitCompressed
603// purpose :
604// =======================================================================
605bool OpenGl_Texture::InitCompressed (const Handle(OpenGl_Context)& theCtx,
606 const Image_CompressedPixMap& theImage,
607 const Standard_Boolean theIsColorMap)
608{
609 if (theImage.SizeX() < 1
610 || theImage.SizeY() < 1
611 || theImage.FaceData().IsNull())
612 {
613 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
614 "Error: texture of 0 size cannot be created.");
615 Release (theCtx.get());
616 return false;
617 }
618 if (theImage.SizeX() > theCtx->MaxTextureSize()
619 || theImage.SizeY() > theCtx->MaxTextureSize())
620 {
621 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
622 TCollection_AsciiString ("Error: Texture dimension - ") + theImage.SizeX() + "x" + theImage.SizeY()
623 + " exceeds hardware limits (" + theCtx->MaxTextureSize() + "x" + theCtx->MaxTextureSize() + ")");
624 Release (theCtx.get());
625 return false;
626 }
627
628 const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindCompressedFormat (theCtx, theImage.CompressedFormat(), theIsColorMap);
629 if (!aFormat.IsValid())
630 {
776302d4 631 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
632 TCollection_AsciiString ("Error: No suitable texture format for ") + Image_PixMap::ImageFormatToString (theImage.CompressedFormat()) + " image format "
633 + " [" + myResourceId +"]");
faff3767 634 Release (theCtx.get());
635 return false;
636 }
637
638 if (!Create (theCtx))
639 {
640 return false;
641 }
642
643 myTarget = GL_TEXTURE_2D;
644 myNbSamples = 1;
645 myTextFormat = aFormat.Format();
646 mySizedFormat = aFormat.Internal();
647 myIsTopDown = theImage.IsTopDown();
648 mySizeX = theImage.SizeX();
649 mySizeY = theImage.SizeY();
650 myMaxMipLevel = Max (theImage.MipMaps().Size() - 1, 0);
651 if (myMaxMipLevel > 0
652 && !theImage.IsCompleteMipMapSet())
653 {
654 const Graphic3d_Vec2i aMipSize = computeSmallestMipMapSize (Graphic3d_Vec2i (mySizeX, mySizeY), myMaxMipLevel);
655 if (!theCtx->HasTextureBaseLevel())
656 {
657 myMaxMipLevel = 0;
658 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0, GL_DEBUG_SEVERITY_MEDIUM,
659 TCollection_AsciiString ("Warning: compressed 2D texture ") + myResourceId + " " + mySizeX + "x" + mySizeY
660 + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y() + "; mipmaps will be ignored");
661 }
662 else
663 {
664 Message::SendTrace (TCollection_AsciiString ("Warning: compressed 2D texture ") + myResourceId + " " + mySizeX + "x" + mySizeY
665 + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y());
666 }
667 }
668
669 Bind (theCtx);
670 applyDefaultSamplerParams (theCtx);
671
672 // setup the alignment
e1d17ceb 673 OpenGl_UnpackAlignmentSentry::Reset (*theCtx);
faff3767 674
675 Graphic3d_Vec2i aMipSizeXY (theImage.SizeX(), theImage.SizeY());
676 const Standard_Byte* aData = theImage.FaceData()->Data();
677 for (Standard_Integer aMipIter = 0; aMipIter <= myMaxMipLevel; ++aMipIter)
678 {
679 const Standard_Integer aMipLength = theImage.MipMaps().Value (aMipIter);
680 theCtx->Functions()->glCompressedTexImage2D (GL_TEXTURE_2D, aMipIter, mySizedFormat, aMipSizeXY.x(), aMipSizeXY.y(), 0, aMipLength, aData);
e1d17ceb 681 const GLenum aTexImgErr = theCtx->core11fwd->glGetError();
faff3767 682 if (aTexImgErr != GL_NO_ERROR)
683 {
684 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
685 TCollection_AsciiString ("Error: 2D compressed texture ") + aMipSizeXY.x() + "x" + aMipSizeXY.y()
a46ab511 686 + " IF: " + OpenGl_TextureFormat::FormatFormat (aFormat.Internal())
687 + " PF: " + OpenGl_TextureFormat::FormatFormat (aFormat.PixelFormat())
688 + " DT: " + OpenGl_TextureFormat::FormatDataType (aFormat.DataType())
689 + " can not be created with error " + OpenGl_Context::FormatGlError (aTexImgErr) + ".");
faff3767 690 Unbind (theCtx);
691 Release (theCtx.get());
692 return false;
693 }
694
695 aData += aMipLength;
696 aMipSizeXY /= 2;
697 if (aMipSizeXY.x() == 0) { aMipSizeXY.x() = 1; }
698 if (aMipSizeXY.y() == 0) { aMipSizeXY.y() = 1; }
699 }
700
701 Unbind (theCtx);
702 return true;
703}
704
3c4b62a4 705// =======================================================================
706// function : Init2DMultisample
707// purpose :
708// =======================================================================
709bool OpenGl_Texture::Init2DMultisample (const Handle(OpenGl_Context)& theCtx,
1220d98e 710 const Standard_Integer theNbSamples,
711 const Standard_Integer theTextFormat,
712 const Standard_Integer theSizeX,
713 const Standard_Integer theSizeY)
3c4b62a4 714{
715 if (!Create (theCtx)
716 || theNbSamples > theCtx->MaxMsaaSamples()
717 || theNbSamples < 1)
718 {
719 return false;
720 }
721
15669413 722 myNbSamples = OpenGl_Context::GetPowerOfTwo (theNbSamples, theCtx->MaxMsaaSamples());
3c4b62a4 723 myTarget = GL_TEXTURE_2D_MULTISAMPLE;
faff3767 724 myMaxMipLevel = 0;
3c4b62a4 725 if(theSizeX > theCtx->MaxTextureSize()
726 || theSizeY > theCtx->MaxTextureSize())
727 {
728 return false;
729 }
730
731 Bind (theCtx);
732 //myTextFormat = theTextFormat;
15669413 733 mySizedFormat = theTextFormat;
3c4b62a4 734#if !defined(GL_ES_VERSION_2_0)
735 if (theCtx->Functions()->glTexStorage2DMultisample != NULL)
736 {
15669413 737 theCtx->Functions()->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
3c4b62a4 738 }
739 else
740 {
15669413 741 theCtx->Functions()->glTexImage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
3c4b62a4 742 }
743#else
15669413 744 theCtx->Functions() ->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
3c4b62a4 745#endif
746 if (theCtx->core11fwd->glGetError() != GL_NO_ERROR)
747 {
748 Unbind (theCtx);
749 return false;
750 }
751
752 mySizeX = theSizeX;
753 mySizeY = theSizeY;
754
755 Unbind (theCtx);
756 return true;
757}
758
68333c8f 759// =======================================================================
760// function : InitRectangle
761// purpose :
762// =======================================================================
763bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
764 const Standard_Integer theSizeX,
765 const Standard_Integer theSizeY,
766 const OpenGl_TextureFormat& theFormat)
767{
768 if (!Create (theCtx) || !theCtx->IsGlGreaterEqual (3, 0))
769 {
770 return false;
771 }
ca3c13d1 772
773#if !defined(GL_ES_VERSION_2_0)
68333c8f 774 myTarget = GL_TEXTURE_RECTANGLE;
15669413 775 myNbSamples = 1;
faff3767 776 myMaxMipLevel = 0;
68333c8f 777
e1d17ceb 778 const GLsizei aSizeX = Min (theCtx->MaxTextureSize(), theSizeX);
779 const GLsizei aSizeY = Min (theCtx->MaxTextureSize(), theSizeY);
ca3c13d1 780
68333c8f 781 Bind (theCtx);
cc8cbabe 782 applyDefaultSamplerParams (theCtx);
68333c8f 783
15669413 784 myTextFormat = theFormat.Format();
785 mySizedFormat = theFormat.Internal();
68333c8f 786
90fd6145 787 // setup the alignment
e1d17ceb 788 OpenGl_UnpackAlignmentSentry::Reset (*theCtx);
90fd6145 789
a46ab511 790 theCtx->core11fwd->glTexImage2D (GL_PROXY_TEXTURE_RECTANGLE, 0, mySizedFormat,
791 aSizeX, aSizeY, 0,
792 myTextFormat, GL_FLOAT, NULL);
68333c8f 793
e1d17ceb 794 GLint aTestSizeX = 0, aTestSizeY = 0;
15669413 795 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH, &aTestSizeX);
796 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
797 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
68333c8f 798 if (aTestSizeX == 0 || aTestSizeY == 0)
799 {
800 Unbind (theCtx);
801 return false;
802 }
803
a46ab511 804 theCtx->core11fwd->glTexImage2D (myTarget, 0, mySizedFormat,
805 aSizeX, aSizeY, 0,
806 myTextFormat, GL_FLOAT, NULL);
a46ab511 807 if (theCtx->core11fwd->glGetError() != GL_NO_ERROR)
68333c8f 808 {
809 Unbind (theCtx);
810 return false;
811 }
812
813 mySizeX = aSizeX;
814 mySizeY = aSizeY;
68333c8f 815 Unbind (theCtx);
816 return true;
ca3c13d1 817#else
20aeeb7b 818 (void )theSizeX;
819 (void )theSizeY;
820 (void )theFormat;
ca3c13d1 821 return false;
822#endif
68333c8f 823}
74fb257d 824
825// =======================================================================
826// function : Init3D
827// purpose :
828// =======================================================================
829bool OpenGl_Texture::Init3D (const Handle(OpenGl_Context)& theCtx,
ba00aab7 830 const OpenGl_TextureFormat& theFormat,
831 const Graphic3d_Vec3i& theSizeXYZ,
74fb257d 832 const void* thePixels)
833{
834 if (theCtx->Functions()->glTexImage3D == NULL)
835 {
ba00aab7 836 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
837 "Error: three-dimensional textures are not supported by hardware.");
74fb257d 838 return false;
839 }
840
841 if (!Create(theCtx))
842 {
843 return false;
844 }
845
846 myTarget = GL_TEXTURE_3D;
15669413 847 myNbSamples = 1;
faff3767 848 myMaxMipLevel = 0;
74fb257d 849
ba00aab7 850 const Graphic3d_Vec3i aSizeXYZ = theSizeXYZ.cwiseMin (Graphic3d_Vec3i (theCtx->MaxTextureSize()));
851 if (aSizeXYZ != theSizeXYZ)
852 {
853 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
854 "Error: 3D texture dimensions exceed hardware limits.");
855 Release (theCtx.get());
856 Unbind (theCtx);
857 return false;
858 }
74fb257d 859 Bind (theCtx);
860
ba00aab7 861 if (theFormat.DataType() == GL_FLOAT
862 && !theCtx->arbTexFloat)
74fb257d 863 {
ba00aab7 864 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
865 "Error: floating-point textures are not supported by hardware.");
866 Release (theCtx.get());
74fb257d 867 Unbind (theCtx);
868 return false;
869 }
870
ba00aab7 871 mySizedFormat = theFormat.InternalFormat();
74fb257d 872
90fd6145 873 // setup the alignment
e1d17ceb 874 OpenGl_UnpackAlignmentSentry::Reset (*theCtx);
90fd6145 875
74fb257d 876#if !defined (GL_ES_VERSION_2_0)
15669413 877 theCtx->core15fwd->glTexImage3D (GL_PROXY_TEXTURE_3D, 0, mySizedFormat,
ba00aab7 878 aSizeXYZ.x(), aSizeXYZ.y(), aSizeXYZ.z(), 0,
879 theFormat.PixelFormat(), theFormat.DataType(), NULL);
74fb257d 880
ba00aab7 881 NCollection_Vec3<GLint> aTestSizeXYZ;
882 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &aTestSizeXYZ.x());
883 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_HEIGHT, &aTestSizeXYZ.y());
884 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_DEPTH, &aTestSizeXYZ.z());
15669413 885 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
ba00aab7 886 if (aTestSizeXYZ.x() == 0 || aTestSizeXYZ.y() == 0 || aTestSizeXYZ.z() == 0)
74fb257d 887 {
888 Unbind (theCtx);
ba00aab7 889 Release (theCtx.get());
74fb257d 890 return false;
891 }
892#endif
893
cc8cbabe 894 applyDefaultSamplerParams (theCtx);
15669413 895 theCtx->Functions()->glTexImage3D (myTarget, 0, mySizedFormat,
ba00aab7 896 aSizeXYZ.x(), aSizeXYZ.y(), aSizeXYZ.z(), 0,
897 theFormat.PixelFormat(), theFormat.DataType(), thePixels);
74fb257d 898
a46ab511 899 if (theCtx->core11fwd->glGetError() != GL_NO_ERROR)
74fb257d 900 {
901 Unbind (theCtx);
ba00aab7 902 Release (theCtx.get());
74fb257d 903 return false;
904 }
905
ba00aab7 906 mySizeX = aSizeXYZ.x();
907 mySizeY = aSizeXYZ.y();
908 mySizeZ = aSizeXYZ.z();
74fb257d 909
910 Unbind (theCtx);
911 return true;
912}
15669413 913
077a220c 914// =======================================================================
67312b79 915// function : InitCubeMap
077a220c 916// purpose :
917// =======================================================================
67312b79 918bool OpenGl_Texture::InitCubeMap (const Handle(OpenGl_Context)& theCtx,
077a220c 919 const Handle(Graphic3d_CubeMap)& theCubeMap,
ba00aab7 920 Standard_Size theSize,
921 Image_Format theFormat,
922 Standard_Boolean theToGenMipmap,
923 Standard_Boolean theIsColorMap)
077a220c 924{
925 if (!Create (theCtx))
926 {
927 Release (theCtx.get());
928 return false;
929 }
930
faff3767 931 Handle(Image_PixMap) anImage;
932 Handle(Image_CompressedPixMap) aCompImage;
933 OpenGl_TextureFormat aFormat;
077a220c 934 if (!theCubeMap.IsNull())
935 {
faff3767 936 theCubeMap->Reset();
937 if (theCtx->SupportedTextureFormats()->HasCompressed()
938 && !theCtx->caps->compressedTexturesDisable)
077a220c 939 {
faff3767 940 aCompImage = theCubeMap->CompressedValue (theCtx->SupportedTextureFormats());
077a220c 941 }
faff3767 942 if (!aCompImage.IsNull())
077a220c 943 {
faff3767 944 aFormat = OpenGl_TextureFormat::FindCompressedFormat (theCtx, aCompImage->CompressedFormat(), theIsColorMap);
945 if (aFormat.IsValid())
946 {
947 theToGenMipmap = false;
948 theSize = aCompImage->SizeX();
949 theFormat = aCompImage->BaseFormat();
950 myMaxMipLevel = Max (aCompImage->MipMaps().Size() - 1, 0);
951 if (myMaxMipLevel > 0
952 && !aCompImage->IsCompleteMipMapSet())
953 {
954 const Graphic3d_Vec2i aMipSize = computeSmallestMipMapSize (Graphic3d_Vec2i (aCompImage->SizeX(), aCompImage->SizeY()), myMaxMipLevel);
955 if (!theCtx->HasTextureBaseLevel())
956 {
957 myMaxMipLevel = 0;
958 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0, GL_DEBUG_SEVERITY_MEDIUM,
959 TCollection_AsciiString ("Warning: Cubemap compressed texture ") + theCubeMap->GetId() + " " + aCompImage->SizeX() + "x" + aCompImage->SizeX()
960 + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y() + "; mipmaps will be ignored");
961 }
962 else
963 {
964 Message::SendTrace (TCollection_AsciiString ("Warning: Cubemap compressed texture ") + theCubeMap->GetId() + " " + aCompImage->SizeX() + "x" + aCompImage->SizeX()
965 + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y());
966 }
967 }
968
e1d17ceb 969 OpenGl_UnpackAlignmentSentry::Reset (*theCtx);
faff3767 970 }
971 else
972 {
973 aCompImage.Nullify();
974 }
975 }
976
977 if (!aFormat.IsValid())
978 {
979 anImage = theCubeMap->Reset().Value (theCtx->SupportedTextureFormats());
980 if (anImage.IsNull())
981 {
982 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
983 "Unable to get the first side of cubemap");
984 Release(theCtx.get());
985 return false;
986 }
987
988 theSize = anImage->SizeX();
989 theFormat = anImage->Format();
990 theToGenMipmap = theCubeMap->HasMipmaps();
991 myMaxMipLevel = theToGenMipmap ? computeUpperMipMapLevel ((Standard_Integer )theSize) : 0;
077a220c 992 }
faff3767 993
994 myIsTopDown = theCubeMap->IsTopDown();
995 }
996 else
997 {
998 myMaxMipLevel = theToGenMipmap ? computeUpperMipMapLevel ((Standard_Integer )theSize) : 0;
077a220c 999 }
1000
faff3767 1001 if (!aFormat.IsValid())
1002 {
1003 aFormat = OpenGl_TextureFormat::FindFormat (theCtx, theFormat, theIsColorMap);
1004 }
ba00aab7 1005 if (!aFormat.IsValid())
077a220c 1006 {
776302d4 1007 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
1008 TCollection_AsciiString ("Error: No suitable texture format for ") + Image_PixMap::ImageFormatToString (theFormat) + " image format"
1009 + " [" + myResourceId +"]");
077a220c 1010 Unbind(theCtx);
1011 Release(theCtx.get());
1012 return false;
1013 }
1014
1015 myTarget = GL_TEXTURE_CUBE_MAP;
077a220c 1016 myNbSamples = 1;
67312b79 1017 mySizeX = (GLsizei )theSize;
1018 mySizeY = (GLsizei )theSize;
faff3767 1019 myTextFormat = aFormat.Format();
1020 mySizedFormat = aFormat.Internal();
e4e3254a 1021#if !defined(GL_ES_VERSION_2_0)
1022 const GLint anIntFormat = aFormat.InternalFormat();
1023#else
1024 // ES 2.0 does not support sized formats and format conversions - them detected from data type
1025 const GLint anIntFormat = theCtx->IsGlGreaterEqual (3, 0) ? aFormat.InternalFormat() : aFormat.PixelFormat();
1026#endif
1027
077a220c 1028 Bind (theCtx);
1029 applyDefaultSamplerParams (theCtx);
1030
1031 for (Standard_Integer i = 0; i < 6; ++i)
1032 {
faff3767 1033 const Standard_Byte* aData = NULL;
077a220c 1034
1035 if (!theCubeMap.IsNull())
1036 {
faff3767 1037 if (i != 0)
1038 {
1039 if (!aCompImage.IsNull())
1040 {
1041 aCompImage = theCubeMap->CompressedValue (theCtx->SupportedTextureFormats());
1042 }
1043 else
1044 {
1045 anImage = theCubeMap->Value (theCtx->SupportedTextureFormats());
1046 }
1047 }
1048 if (!aCompImage.IsNull())
1049 {
1050 Graphic3d_Vec2i aMipSizeXY (mySizeX, mySizeY);
1051 aData = aCompImage->FaceData()->Data();
1052 for (Standard_Integer aMipIter = 0; aMipIter <= myMaxMipLevel; ++aMipIter)
1053 {
1054 const Standard_Integer aMipLength = aCompImage->MipMaps().Value (aMipIter);
1055 theCtx->Functions()->glCompressedTexImage2D (GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, aMipIter, mySizedFormat, aMipSizeXY.x(), aMipSizeXY.y(), 0, aMipLength, aData);
e1d17ceb 1056 const GLenum aTexImgErr = theCtx->core11fwd->glGetError();
faff3767 1057 if (aTexImgErr != GL_NO_ERROR)
1058 {
1059 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
1060 TCollection_AsciiString ("Error: cubemap compressed texture ") + aMipSizeXY.x() + "x" + aMipSizeXY.y()
a46ab511 1061 + " IF: " + OpenGl_TextureFormat::FormatFormat (aFormat.Internal())
1062 + " PF: " + OpenGl_TextureFormat::FormatFormat (aFormat.PixelFormat())
1063 + " DT: " + OpenGl_TextureFormat::FormatDataType (aFormat.DataType())
1064 + " can not be created with error " + OpenGl_Context::FormatGlError (aTexImgErr) + ".");
faff3767 1065 Unbind (theCtx);
1066 Release (theCtx.get());
1067 return false;
1068 }
1069
1070 aData += aMipLength;
1071 aMipSizeXY /= 2;
1072 if (aMipSizeXY.x() == 0) { aMipSizeXY.x() = 1; }
1073 if (aMipSizeXY.y() == 0) { aMipSizeXY.y() = 1; }
1074 }
1075
1076 theCubeMap->Next();
1077 continue;
1078 }
1079
077a220c 1080 if (!anImage.IsNull())
1081 {
077a220c 1082 const GLint anAligment = Min ((GLint)anImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
077a220c 1083 const GLint anExtraBytes = GLint(anImage->RowExtraBytes());
1084 const GLint aPixelsWidth = GLint(anImage->SizeRowBytes() / anImage->SizePixelBytes());
1085 const GLint aRowLength = (anExtraBytes >= anAligment) ? aPixelsWidth : 0;
e1d17ceb 1086 if (theCtx->hasUnpackRowLength)
1087 {
1088 theCtx->core11fwd->glPixelStorei (GL_UNPACK_ROW_LENGTH, aRowLength);
1089 }
1090
1091 if (aRowLength > 0
1092 && !theCtx->hasUnpackRowLength)
077a220c 1093 {
e1d17ceb 1094 Handle(Image_PixMap) aCopyImage = new Image_PixMap();
1095 aCopyImage->InitTrash (theFormat, theSize, theSize);
1096 const Standard_Size aRowBytesPacked = std::min (aCopyImage->SizeRowBytes(), anImage->SizeRowBytes());
1097 for (unsigned int y = 0; y < theSize; ++y)
077a220c 1098 {
e1d17ceb 1099 memcpy (aCopyImage->ChangeRow (y), anImage->ChangeRow (y), aRowBytesPacked);
077a220c 1100 }
e1d17ceb 1101 anImage = aCopyImage;
1102 const GLint anAligment2 = Min((GLint)anImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
1103 theCtx->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment2);
077a220c 1104 }
e1d17ceb 1105 else
1106 {
1107 theCtx->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
1108 }
1109
077a220c 1110 aData = anImage->Data();
1111 }
1112 else
1113 {
ba00aab7 1114 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
1115 TCollection_AsciiString() + "Unable to get [" + i + "] side of cubemap");
077a220c 1116 Unbind (theCtx);
1117 Release (theCtx.get());
1118 return false;
1119 }
1120 theCubeMap->Next();
1121 }
1122
a46ab511 1123 theCtx->core11fwd->glTexImage2D (GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0,
1124 anIntFormat,
1125 GLsizei(theSize), GLsizei(theSize),
1126 0, aFormat.PixelFormat(), aFormat.DataType(),
1127 aData);
077a220c 1128
e1d17ceb 1129 OpenGl_UnpackAlignmentSentry::Reset (*theCtx);
077a220c 1130
a46ab511 1131 const GLenum anErr = theCtx->core11fwd->glGetError();
ba00aab7 1132 if (anErr != GL_NO_ERROR)
077a220c 1133 {
1134 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
a46ab511 1135 TCollection_AsciiString ("Unable to initialize side of cubemap. Error ") + OpenGl_Context::FormatGlError (anErr));
077a220c 1136 Unbind (theCtx);
1137 Release (theCtx.get());
1138 return false;
1139 }
1140 }
1141
1142 if (theToGenMipmap && theCtx->arbFBO != NULL)
1143 {
ba00aab7 1144 theCtx->arbFBO->glGenerateMipmap (myTarget);
a46ab511 1145 const GLenum anErr = theCtx->core11fwd->glGetError();
ba00aab7 1146 if (anErr != GL_NO_ERROR)
1147 {
1148 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
776302d4 1149 TCollection_AsciiString ("Unable to generate mipmap of cubemap with format ")
1150 + OpenGl_TextureFormat::FormatFormat (anIntFormat)
1151 + ", error " + OpenGl_Context::FormatGlError (anErr));
1152 myMaxMipLevel = 0;
ba00aab7 1153 }
077a220c 1154 }
1155
1156 Unbind (theCtx.get());
1157 return true;
1158}
1159
15669413 1160// =======================================================================
1161// function : PixelSizeOfPixelFormat
1162// purpose :
1163// =======================================================================
1164Standard_Size OpenGl_Texture::PixelSizeOfPixelFormat (Standard_Integer theInternalFormat)
1165{
1166 switch(theInternalFormat)
1167 {
1168 // RED variations (GL_RED, OpenGL 3.0+)
1169 case GL_RED:
1170 case GL_R8: return 1;
1171 case GL_R16: return 2;
1172 case GL_R16F: return 2;
1173 case GL_R32F: return 4;
1174 // RGB variations
1175 case GL_RGB: return 3;
1176 case GL_RGB8: return 3;
1177 case GL_RGB16: return 6;
1178 case GL_RGB16F: return 6;
1179 case GL_RGB32F: return 12;
1180 // RGBA variations
1181 case GL_RGBA: return 4;
1182 case GL_RGBA8: return 4;
1183 case GL_RGB10_A2: return 4;
1184 case GL_RGBA12: return 6;
1185 case GL_RGBA16: return 8;
1186 case GL_RGBA16F: return 8;
1187 case GL_RGBA32F: return 16;
1188 //
1189 case GL_BGRA_EXT: return 4;
1190 // ALPHA variations (deprecated)
1191 case GL_ALPHA:
1192 case GL_ALPHA8: return 1;
1193 case GL_ALPHA16: return 2;
1194 case GL_LUMINANCE: return 1;
1195 case GL_LUMINANCE_ALPHA: return 2;
1196 // depth-stencil
1197 case GL_DEPTH24_STENCIL8: return 4;
1198 case GL_DEPTH32F_STENCIL8: return 8;
1199 case GL_DEPTH_COMPONENT16: return 2;
1200 case GL_DEPTH_COMPONENT24: return 3;
1201 case GL_DEPTH_COMPONENT32F: return 4;
faff3767 1202 // compressed
1203 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: // DXT1 uses circa half a byte per pixel (64 bits per 4x4 block)
1204 case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
1205 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1206 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
1207 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: // DXT3/5 uses circa 1 byte per pixel (128 bits per 4x4 block)
1208 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
1209 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
1210 case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
1211 return 1;
15669413 1212 }
faff3767 1213 return 1;
15669413 1214}
1215
1216// =======================================================================
1217// function : EstimatedDataSize
1218// purpose :
1219// =======================================================================
1220Standard_Size OpenGl_Texture::EstimatedDataSize() const
1221{
1222 if (!IsValid())
1223 {
1224 return 0;
1225 }
1226
1227 Standard_Size aSize = PixelSizeOfPixelFormat (mySizedFormat) * mySizeX * myNbSamples;
1228 if (mySizeY != 0)
1229 {
1230 aSize *= Standard_Size(mySizeY);
1231 }
1232 if (mySizeZ != 0)
1233 {
1234 aSize *= Standard_Size(mySizeZ);
1235 }
67312b79 1236 if (myTarget == GL_TEXTURE_CUBE_MAP)
1237 {
1238 aSize *= 6; // cube sides
1239 }
faff3767 1240 if (myMaxMipLevel > 0)
15669413 1241 {
1242 aSize = aSize + aSize / 3;
1243 }
1244 return aSize;
1245}
8f8fe4a9 1246
1247// =======================================================================
1248// function : ImageDump
1249// purpose :
1250// =======================================================================
1251bool OpenGl_Texture::ImageDump (Image_PixMap& theImage,
1252 const Handle(OpenGl_Context)& theCtx,
1253 Graphic3d_TextureUnit theTexUnit,
1254 Standard_Integer theLevel,
1255 Standard_Integer theCubeSide) const
1256{
1257#if !defined(GL_ES_VERSION_2_0)
1258 const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindSizedFormat (theCtx, mySizedFormat);
1259 if (theCtx.IsNull()
1260 || !IsValid()
1261 || theLevel < 0
1262 || !aFormat.IsValid()
1263 || aFormat.ImageFormat() == Image_Format_UNKNOWN
1264 || (myTarget == GL_TEXTURE_CUBE_MAP
1265 && (theCubeSide < 0 || theCubeSide > 5)))
1266 {
1267 return false;
1268 }
1269
1270 GLenum aTarget = myTarget;
1271 Graphic3d_Vec2i aSize (mySizeX, mySizeY);
1272 if (myTarget == GL_TEXTURE_CUBE_MAP)
1273 {
1274 aTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + theCubeSide;
1275 }
1276 for (Standard_Integer aMipIter = 0; aMipIter < theLevel; ++aMipIter)
1277 {
1278 aSize /= 2;
1279 if (aSize.x() == 0) { aSize.x() = 1; }
1280 if (aSize.y() == 0) { aSize.y() = 1; }
1281 }
1282 if (!theImage.InitTrash (aFormat.ImageFormat(), aSize.x(), aSize.y()))
1283 {
1284 return false;
1285 }
1286
1287 const GLint anAligment = Min (GLint(theImage.MaxRowAligmentBytes()), 8); // limit to 8 bytes for OpenGL
1288 theCtx->core11fwd->glPixelStorei (GL_PACK_ALIGNMENT, anAligment);
e1d17ceb 1289 if (theCtx->hasPackRowLength)
1290 {
1291 theCtx->core11fwd->glPixelStorei (GL_PACK_ROW_LENGTH, 0);
1292 }
8f8fe4a9 1293 // glGetTextureImage() allows avoiding to binding texture id, but apparently requires clean FBO binding state...
1294 //if (theCtx->core45 != NULL) { theCtx->core45->glGetTextureImage (myTextureId, theLevel, aFormat.PixelFormat(), aFormat.DataType(), (GLsizei )theImage.SizeBytes(), theImage.ChangeData()); } else
1295 {
1296 Bind (theCtx, theTexUnit);
1297 theCtx->core11fwd->glGetTexImage (aTarget, theLevel, aFormat.PixelFormat(), aFormat.DataType(), theImage.ChangeData());
1298 Unbind (theCtx, theTexUnit);
1299 }
1300 if (theImage.Format() != aFormat.ImageFormat())
1301 {
1302 Image_PixMap::SwapRgbaBgra (theImage);
1303 }
1304
1305 const bool hasErrors = theCtx->ResetErrors (true);
1306 theCtx->core11fwd->glPixelStorei (GL_PACK_ALIGNMENT, 1);
1307 return !hasErrors;
1308#else
1309 // glGetTexImage() is unavailable in OpenGL ES
1310 (void )theImage;
1311 (void )theCtx;
1312 (void )theTexUnit;
1313 (void )theLevel;
1314 (void )theCubeSide;
1315 return false;
1316#endif
1317}