0024739: TKOpenGl - port ray-tracing from OpenCL to GLSL for better integration and...
[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>
01ca42b2 19#include <OpenGl_GlCore15.hxx>
bf75be98 20#include <Graphic3d_TextureParams.hxx>
21#include <Standard_Assert.hxx>
22#include <Image_PixMap.hxx>
23
24IMPLEMENT_STANDARD_HANDLE (OpenGl_Texture, OpenGl_Resource)
25IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture, OpenGl_Resource)
26
74706083 27//! Simple class to reset unpack alignment settings
28struct OpenGl_UnpackAlignmentSentry
29{
30
31 //! Reset unpack alignment settings to safe values
32 void Reset()
33 {
34 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
35 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
36 }
37
38 ~OpenGl_UnpackAlignmentSentry()
39 {
40 Reset();
41 }
42
43};
44
bf75be98 45// =======================================================================
46// function : OpenGl_Texture
47// purpose :
48// =======================================================================
49OpenGl_Texture::OpenGl_Texture (const Handle(Graphic3d_TextureParams)& theParams)
50: OpenGl_Resource(),
51 myTextureId (NO_TEXTURE),
52 myTarget (GL_TEXTURE_2D),
53 mySizeX (0),
54 mySizeY (0),
55 myTextFormat (GL_FLOAT),
56 myHasMipmaps (Standard_False),
57 myParams (theParams)
58{
59 if (myParams.IsNull())
60 {
61 myParams = new Graphic3d_TextureParams();
62 }
63}
64
65// =======================================================================
66// function : ~OpenGl_Texture
67// purpose :
68// =======================================================================
69OpenGl_Texture::~OpenGl_Texture()
70{
71 Release (NULL);
72}
73
74// =======================================================================
75// function : HasMipmaps
76// purpose :
77// =======================================================================
78const Standard_Boolean OpenGl_Texture::HasMipmaps() const
79{
80 return myHasMipmaps;
81}
82
83// =======================================================================
84// function : GetParams
85// purpose :
86// =======================================================================
87const Handle(Graphic3d_TextureParams)& OpenGl_Texture::GetParams() const
88{
89 return myParams;
90}
91
92// =======================================================================
93// function : SetParams
94// purpose :
95// =======================================================================
96void OpenGl_Texture::SetParams (const Handle(Graphic3d_TextureParams)& theParams)
97{
98 myParams = theParams;
99}
100
101// =======================================================================
102// function : Create
103// purpose :
104// =======================================================================
105bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& )
106{
107 if (myTextureId == NO_TEXTURE)
108 {
109 glGenTextures (1, &myTextureId);
110 }
111 return myTextureId != NO_TEXTURE;
112}
113
114// =======================================================================
115// function : Release
116// purpose :
117// =======================================================================
118void OpenGl_Texture::Release (const OpenGl_Context* theGlCtx)
119{
120 if (myTextureId == NO_TEXTURE)
121 {
122 return;
123 }
124
125 // application can not handle this case by exception - this is bug in code
126 Standard_ASSERT_RETURN (theGlCtx != NULL,
127 "OpenGl_Texture destroyed without GL context! Possible GPU memory leakage...",);
128
ec2eeb2d 129 if (theGlCtx->IsValid())
130 {
131 glDeleteTextures (1, &myTextureId);
132 }
bf75be98 133 myTextureId = NO_TEXTURE;
134 mySizeX = mySizeY = 0;
135}
136
137// =======================================================================
138// function : Bind
139// purpose :
140// =======================================================================
141void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
142 const GLenum theTextureUnit) const
143{
01ca42b2 144 if (theCtx->IsGlGreaterEqual (1, 5))
bf75be98 145 {
01ca42b2 146 theCtx->core15fwd->glActiveTexture (theTextureUnit);
bf75be98 147 }
148 glBindTexture (myTarget, myTextureId);
149}
150
151// =======================================================================
152// function : Unbind
153// purpose :
154// =======================================================================
155void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
156 const GLenum theTextureUnit) const
157{
01ca42b2 158 if (theCtx->IsGlGreaterEqual (1, 5))
bf75be98 159 {
01ca42b2 160 theCtx->core15fwd->glActiveTexture (theTextureUnit);
bf75be98 161 }
162 glBindTexture (myTarget, NO_TEXTURE);
163}
164
165// =======================================================================
166// function : Init
167// purpose :
168// =======================================================================
169bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
170 const Image_PixMap& theImage,
171 const Graphic3d_TypeOfTexture theType)
172{
173 myHasMipmaps = Standard_False;
174 if (theImage.IsEmpty() || !Create (theCtx))
175 {
176 return false;
177 }
178
a577aaab 179 myTextFormat = GL_RGBA8;
180 GLenum aPixelFormat = 0;
181 GLenum aDataType = 0;
bf75be98 182 switch (theImage.Format())
183 {
184 case Image_PixMap::ImgGrayF:
185 {
a577aaab 186 myTextFormat = GL_ALPHA8; // GL_R8, GL_R32F
187 aPixelFormat = GL_ALPHA; // GL_RED
188 aDataType = GL_FLOAT;
bf75be98 189 break;
190 }
191 case Image_PixMap::ImgRGBAF:
192 {
a577aaab 193 myTextFormat = GL_RGBA8; // GL_RGBA32F
194 aPixelFormat = GL_RGBA;
195 aDataType = GL_FLOAT;
bf75be98 196 break;
197 }
198 case Image_PixMap::ImgBGRAF:
199 {
200 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
201 {
202 return false;
203 }
a577aaab 204 myTextFormat = GL_RGBA8; // GL_RGBA32F
205 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
206 aDataType = GL_FLOAT;
bf75be98 207 break;
208 }
209 case Image_PixMap::ImgRGBF:
210 {
a577aaab 211 myTextFormat = GL_RGB8; // GL_RGB32F
212 aPixelFormat = GL_RGB;
213 aDataType = GL_FLOAT;
bf75be98 214 break;
215 }
216 case Image_PixMap::ImgBGRF:
217 {
a577aaab 218 myTextFormat = GL_RGB8; // GL_RGB32F
219 aPixelFormat = GL_BGR; // equals to GL_BGR_EXT
220 aDataType = GL_FLOAT;
bf75be98 221 break;
222 }
223 case Image_PixMap::ImgRGBA:
224 {
a577aaab 225 myTextFormat = GL_RGBA8;
226 aPixelFormat = GL_RGBA;
227 aDataType = GL_UNSIGNED_BYTE;
bf75be98 228 break;
229 }
230 case Image_PixMap::ImgBGRA:
231 {
232 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
233 {
234 return false;
235 }
a577aaab 236 myTextFormat = GL_RGBA8;
237 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
238 aDataType = GL_UNSIGNED_BYTE;
bf75be98 239 break;
240 }
241 case Image_PixMap::ImgRGB32:
242 {
a577aaab 243 myTextFormat = GL_RGB8;
244 aPixelFormat = GL_RGBA;
245 aDataType = GL_UNSIGNED_BYTE;
bf75be98 246 break;
247 }
248 case Image_PixMap::ImgBGR32:
249 {
250 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
251 {
252 return false;
253 }
a577aaab 254 myTextFormat = GL_RGB8;
255 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
256 aDataType = GL_UNSIGNED_BYTE;
bf75be98 257 break;
258 }
259 case Image_PixMap::ImgRGB:
260 {
a577aaab 261 myTextFormat = GL_RGB8;
262 aPixelFormat = GL_RGB;
263 aDataType = GL_UNSIGNED_BYTE;
bf75be98 264 break;
265 }
266 case Image_PixMap::ImgBGR:
267 {
268 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
269 {
270 return false;
271 }
a577aaab 272 myTextFormat = GL_RGB8;
273 aPixelFormat = GL_BGR; // equals to GL_BGR_EXT
274 aDataType = GL_UNSIGNED_BYTE;
bf75be98 275 break;
276 }
277 case Image_PixMap::ImgGray:
278 {
a577aaab 279 myTextFormat = GL_ALPHA8; // GL_R8
280 aPixelFormat = GL_ALPHA; // GL_RED
281 aDataType = GL_UNSIGNED_BYTE;
bf75be98 282 break;
283 }
284 default:
285 {
286 return false;
287 }
288 }
289
290 const GLsizei aMaxSize = theCtx->MaxTextureSize();
291 const GLsizei aWidth = (GLsizei )theImage.SizeX();
292 const GLsizei aHeight = (GLsizei )theImage.SizeY();
293
294 // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications
295 // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT!
68333c8f 296 // Trying to create NPOT textures on such hardware will not fail
bf75be98 297 // but driver will fall back into software rendering,
298 const bool toForceP2 = !theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW;
a174a3c5 299 const GLsizei aWidthOut = toForceP2 ? OpenGl_Context::GetPowerOfTwo (aWidth, aMaxSize) : Min (aWidth, aMaxSize);
300 const GLsizei aHeightOut = toForceP2 ? OpenGl_Context::GetPowerOfTwo (aHeight, aMaxSize) : Min (aHeight, aMaxSize);
bf75be98 301
302 GLint aTestWidth = 0;
303 GLint aTestHeight = 0;
304
74706083 305 // setup the alignment
306 OpenGl_UnpackAlignmentSentry anUnpackSentry;
307 const GLint anAligment = Min ((GLint )theImage.MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
308 glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
309
310 // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension
311 const GLint anExtraBytes = GLint(theImage.RowExtraBytes());
312 const GLint aPixelsWidth = GLint(theImage.SizeRowBytes() / theImage.SizePixelBytes());
313 glPixelStorei (GL_UNPACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0);
314
bf75be98 315 switch (theType)
316 {
317 case Graphic3d_TOT_1D:
318 {
319 myTarget = GL_TEXTURE_1D;
320 Bind (theCtx);
321 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
322 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
323
324 Image_PixMap aCopy;
325 GLvoid* aDataPtr = (GLvoid* )theImage.Data();
326 if (aWidth != aWidthOut)
327 {
74706083 328 glPixelStorei (GL_PACK_ALIGNMENT, 1);
329 glPixelStorei (GL_PACK_ROW_LENGTH, 0);
bf75be98 330 if (!aCopy.InitTrash (theImage.Format(), Standard_Size(aWidthOut), 1)
331 || gluScaleImage (aPixelFormat,
332 aWidth, 1, aDataType, theImage.Data(),
333 aWidthOut, 1, aDataType, aCopy.ChangeData()) != 0)
334 {
335 Unbind (theCtx);
336 return false;
337 }
338
339 aDataPtr = (GLvoid* )aCopy.Data();
74706083 340 anUnpackSentry.Reset();
bf75be98 341 }
342
343 // use proxy to check texture could be created or not
a577aaab 344 glTexImage1D (GL_PROXY_TEXTURE_1D, 0, myTextFormat,
bf75be98 345 aWidthOut, 0,
346 aPixelFormat, aDataType, NULL);
347 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
348 if (aTestWidth == 0)
349 {
350 // no memory or broken input parameters
351 Unbind (theCtx);
352 return false;
353 }
354
a577aaab 355 glTexImage1D (GL_TEXTURE_1D, 0, myTextFormat,
bf75be98 356 aWidthOut, 0,
357 aPixelFormat, aDataType, aDataPtr);
a174a3c5 358 if (glGetError() != GL_NO_ERROR)
359 {
360 Unbind (theCtx);
361 return false;
362 }
363
364 mySizeX = aWidthOut;
365 mySizeY = 1;
bf75be98 366
367 Unbind (theCtx);
368 return true;
369 }
370 case Graphic3d_TOT_2D:
371 {
372 myTarget = GL_TEXTURE_2D;
373 Bind (theCtx);
374 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
375 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
376
377 Image_PixMap aCopy;
378 GLvoid* aDataPtr = (GLvoid* )theImage.Data();
379 if (aWidth != aWidthOut || aHeight != aHeightOut)
380 {
381 // scale texture
74706083 382 glPixelStorei (GL_PACK_ALIGNMENT, 1);
383 glPixelStorei (GL_PACK_ROW_LENGTH, 0);
bf75be98 384 if (!aCopy.InitTrash (theImage.Format(), Standard_Size(aWidthOut), Standard_Size(aHeightOut))
385 || gluScaleImage (aPixelFormat,
386 aWidth, aHeight, aDataType, theImage.Data(),
387 aWidthOut, aHeightOut, aDataType, aCopy.ChangeData()) != 0)
388 {
389 Unbind (theCtx);
390 return false;
391 }
392
393 aDataPtr = (GLvoid* )aCopy.Data();
74706083 394 anUnpackSentry.Reset();
bf75be98 395 }
396
397 // use proxy to check texture could be created or not
a577aaab 398 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, myTextFormat,
bf75be98 399 aWidthOut, aHeightOut, 0,
400 aPixelFormat, aDataType, NULL);
401 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
402 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
403 if (aTestWidth == 0 || aTestHeight == 0)
404 {
405 // no memory or broken input parameters
406 Unbind (theCtx);
407 return false;
408 }
409
a577aaab 410 glTexImage2D (GL_TEXTURE_2D, 0, myTextFormat,
bf75be98 411 aWidthOut, aHeightOut, 0,
412 aPixelFormat, aDataType, aDataPtr);
a174a3c5 413 if (glGetError() != GL_NO_ERROR)
414 {
415 Unbind (theCtx);
416 return false;
417 }
418
419 mySizeX = aWidthOut;
420 mySizeY = aHeightOut;
bf75be98 421
422 Unbind (theCtx);
423 return true;
424 }
425 case Graphic3d_TOT_2D_MIPMAP:
426 {
427 myTarget = GL_TEXTURE_2D;
428 myHasMipmaps = Standard_True;
429 Bind (theCtx);
430 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
431 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
432
01ca42b2 433 if (theCtx->arbFBO != NULL
1a7dfdb7 434 && aWidth == aWidthOut && aHeight == aHeightOut)
435 {
436 // use proxy to check texture could be created or not
a577aaab 437 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, myTextFormat,
1a7dfdb7 438 aWidthOut, aHeightOut, 0,
439 aPixelFormat, aDataType, NULL);
440 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
441 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
442 if (aTestWidth == 0 || aTestHeight == 0)
443 {
444 // no memory or broken input parameters
445 Unbind (theCtx);
446 return false;
447 }
448
449 // upload main picture
a577aaab 450 glTexImage2D (GL_TEXTURE_2D, 0, myTextFormat,
1a7dfdb7 451 aWidthOut, aHeightOut, 0,
452 aPixelFormat, aDataType, theImage.Data());
a174a3c5 453 if (glGetError() != GL_NO_ERROR)
454 {
455 Unbind (theCtx);
456 return false;
457 }
458
459 mySizeX = aWidthOut;
460 mySizeY = aHeightOut;
1a7dfdb7 461
462 // generate mipmaps
463 //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
01ca42b2 464 theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
1a7dfdb7 465
466 Unbind (theCtx);
467 return true;
468 }
469 else
470 {
a577aaab 471 bool isCreated = gluBuild2DMipmaps (GL_TEXTURE_2D, myTextFormat,
1a7dfdb7 472 aWidth, aHeight,
473 aPixelFormat, aDataType, theImage.Data()) == 0;
a174a3c5 474 if (isCreated)
475 {
476 glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &mySizeX);
477 glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &mySizeY);
478 }
479
1a7dfdb7 480 Unbind (theCtx);
481 return isCreated;
482 }
bf75be98 483 }
484 default:
485 {
486 return false;
487 }
488 }
489}
68333c8f 490
491// =======================================================================
492// function : InitRectangle
493// purpose :
494// =======================================================================
495bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
496 const Standard_Integer theSizeX,
497 const Standard_Integer theSizeY,
498 const OpenGl_TextureFormat& theFormat)
499{
500 if (!Create (theCtx) || !theCtx->IsGlGreaterEqual (3, 0))
501 {
502 return false;
503 }
504
505 myTarget = GL_TEXTURE_RECTANGLE;
506
507 const GLsizei aSizeX = Min (theCtx->MaxTextureSize(), theSizeX);
508 const GLsizei aSizeY = Min (theCtx->MaxTextureSize(), theSizeY);
509
510 Bind (theCtx);
511
512 if (myParams->Filter() == Graphic3d_TOTF_NEAREST)
513 {
514 glTexParameteri (myTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
515 glTexParameteri (myTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
516 }
517 else
518 {
519 glTexParameteri (myTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
520 glTexParameteri (myTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
521 }
522
523 myTextFormat = theFormat.Internal();
524
525 glTexImage2D (GL_PROXY_TEXTURE_RECTANGLE,
526 0,
527 myTextFormat,
528 aSizeX,
529 aSizeY,
530 0,
531 theFormat.Format(),
532 GL_FLOAT,
533 NULL);
534
535 GLint aTestSizeX = 0;
536 GLint aTestSizeY = 0;
537
538 glGetTexLevelParameteriv (
539 GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH, &aTestSizeX);
540 glGetTexLevelParameteriv (
541 GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
542
543 if (aTestSizeX == 0 || aTestSizeY == 0)
544 {
545 Unbind (theCtx);
546 return false;
547 }
548
549 glTexImage2D (myTarget,
550 0,
551 myTextFormat,
552 aSizeX,
553 aSizeY,
554 0,
555 theFormat.Format(),
556 GL_FLOAT,
557 NULL);
558
559 if (glGetError() != GL_NO_ERROR)
560 {
561 Unbind (theCtx);
562 return false;
563 }
564
565 mySizeX = aSizeX;
566 mySizeY = aSizeY;
567
568 Unbind (theCtx);
569 return true;
570}