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