0024250: TKOpenGl - per-pixel lighting using GLSL program (Phong shading)
[occt.git] / src / OpenGl / OpenGl_Context.cxx
1 // Created on: 2012-01-26
2 // Created by: Kirill GAVRILOV
3 // Copyright (c) 2012 OPEN CASCADE SAS
4 //
5 // The content of this file is subject to the Open CASCADE Technology Public
6 // License Version 6.5 (the "License"). You may not use the content of this file
7 // except in compliance with the License. Please obtain a copy of the License
8 // at http://www.opencascade.org and read it completely before using this file.
9 //
10 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
11 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
12 //
13 // The Original Code and all software distributed under the License is
14 // distributed on an "AS IS" basis, without warranty of any kind, and the
15 // Initial Developer hereby disclaims all such warranties, including without
16 // limitation, any warranties of merchantability, fitness for a particular
17 // purpose or non-infringement. Please see the License for the specific terms
18 // and conditions governing the rights and limitations under the License.
19
20 #if defined(_WIN32)
21   #include <windows.h>
22 #endif
23
24 #include <OpenGl_Context.hxx>
25
26 #include <OpenGl_ArbVBO.hxx>
27 #include <OpenGl_ArbTBO.hxx>
28 #include <OpenGl_ArbIns.hxx>
29 #include <OpenGl_ArbDbg.hxx>
30 #include <OpenGl_ExtFBO.hxx>
31 #include <OpenGl_ExtGS.hxx>
32 #include <OpenGl_GlCore20.hxx>
33 #include <OpenGl_ShaderManager.hxx>
34
35 #include <Message_Messenger.hxx>
36
37 #include <NCollection_Vector.hxx>
38
39 #include <Standard_ProgramError.hxx>
40
41 #if defined(_WIN32)
42   //
43 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
44   #include <dlfcn.h>
45 #else
46   #include <GL/glx.h> // glXGetProcAddress()
47 #endif
48
49 // GL_NVX_gpu_memory_info
50 #ifndef GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX
51   enum
52   {
53     GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX         = 0x9047,
54     GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX   = 0x9048,
55     GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX = 0x9049,
56     GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX           = 0x904A,
57     GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX           = 0x904B
58   };
59 #endif
60
61 IMPLEMENT_STANDARD_HANDLE (OpenGl_Context, Standard_Transient)
62 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Context, Standard_Transient)
63
64 //! Make record shorter to retrieve function pointer using variable with same name
65 #define FindProcShort(theStruct, theFunc) FindProc(#theFunc, theStruct->theFunc)
66
67 namespace
68 {
69   static const Handle(OpenGl_Resource) NULL_GL_RESOURCE;
70   static const GLdouble OpenGl_DefaultPlaneEq[] = {0.0, 0.0, 0.0, 0.0};
71 };
72
73 // =======================================================================
74 // function : OpenGl_Context
75 // purpose  :
76 // =======================================================================
77 OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
78 : core12 (NULL),
79   core13 (NULL),
80   core14 (NULL),
81   core15 (NULL),
82   core20 (NULL),
83   caps   (!theCaps.IsNull() ? theCaps : new OpenGl_Caps()),
84   arbNPTW(Standard_False),
85   arbVBO (NULL),
86   arbTBO (NULL),
87   arbIns (NULL),
88   arbDbg (NULL),
89   extFBO (NULL),
90   extGS  (NULL),
91   extBgra(Standard_False),
92   extAnis(Standard_False),
93   extPDS (Standard_False),
94   atiMem (Standard_False),
95   nvxMem (Standard_False),
96   mySharedResources (new OpenGl_ResourcesMap()),
97   myDelayed         (new OpenGl_DelayReleaseMap()),
98   myReleaseQueue    (new OpenGl_ResourcesQueue()),
99   myClippingState (),
100   myGlLibHandle (NULL),
101   myGlCore20 (NULL),
102   myAnisoMax   (1),
103   myMaxTexDim  (1024),
104   myMaxClipPlanes (6),
105   myGlVerMajor (0),
106   myGlVerMinor (0),
107   myIsFeedback (Standard_False),
108   myIsInitialized (Standard_False)
109 {
110 #if defined(MAC_OS_X_VERSION_10_3) && !defined(MACOSX_USE_GLX)
111   // Vendors can not extend functionality on this system
112   // and developers are limited to OpenGL support provided by Mac OS X SDK.
113   // We retrieve function pointers from system library
114   // to generalize extensions support on all platforms.
115   // In this way we also reach binary compatibility benefit between OS releases
116   // if some newest functionality is optionally used.
117   // Notice that GL version / extension availability checks are required
118   // because function pointers may be available but not functionality itself
119   // (depends on renderer).
120   myGlLibHandle = dlopen ("/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL", RTLD_LAZY);
121 #endif
122
123   myShaderManager = new OpenGl_ShaderManager (this);
124 }
125
126 // =======================================================================
127 // function : ~OpenGl_Context
128 // purpose  :
129 // =======================================================================
130 OpenGl_Context::~OpenGl_Context()
131 {
132   // release clean up queue
133   ReleaseDelayed();
134
135   // release shared resources if any
136   if (((const Handle(Standard_Transient)& )mySharedResources)->GetRefCount() <= 1)
137   {
138     myShaderManager.Nullify();
139     for (NCollection_DataMap<TCollection_AsciiString, Handle(OpenGl_Resource)>::Iterator anIter (*mySharedResources);
140          anIter.More(); anIter.Next())
141     {
142       anIter.Value()->Release (this);
143     }
144   }
145   else
146   {
147     myShaderManager->SetContext (NULL);
148   }
149   mySharedResources.Nullify();
150   myDelayed.Nullify();
151
152   if (arbDbg != NULL
153    && caps->contextDebug)
154   {
155     // reset callback
156     void* aPtr = NULL;
157     glGetPointerv (GL_DEBUG_CALLBACK_USER_PARAM_ARB, &aPtr);
158     if (aPtr == this)
159     {
160       arbDbg->glDebugMessageCallbackARB (NULL, NULL);
161     }
162   }
163
164   delete myGlCore20;
165   delete arbVBO;
166   delete arbTBO;
167   delete arbIns;
168   delete arbDbg;
169   delete extFBO;
170   delete extGS;
171 }
172
173 // =======================================================================
174 // function : MaxDegreeOfAnisotropy
175 // purpose  :
176 // =======================================================================
177 Standard_Integer OpenGl_Context::MaxDegreeOfAnisotropy() const
178 {
179   return myAnisoMax;
180 }
181
182 // =======================================================================
183 // function : MaxTextureSize
184 // purpose  :
185 // =======================================================================
186 Standard_Integer OpenGl_Context::MaxTextureSize() const
187 {
188   return myMaxTexDim;
189 }
190
191 // =======================================================================
192 // function : MaxClipPlanes
193 // purpose  :
194 // =======================================================================
195 Standard_Integer OpenGl_Context::MaxClipPlanes() const
196 {
197   return myMaxClipPlanes;
198 }
199
200 // =======================================================================
201 // function : Share
202 // purpose  :
203 // =======================================================================
204 void OpenGl_Context::Share (const Handle(OpenGl_Context)& theShareCtx)
205 {
206   if (!theShareCtx.IsNull())
207   {
208     mySharedResources = theShareCtx->mySharedResources;
209     myDelayed         = theShareCtx->myDelayed;
210     myReleaseQueue    = theShareCtx->myReleaseQueue;
211     myShaderManager   = theShareCtx->myShaderManager;
212   }
213 }
214
215 #if !defined(__APPLE__) || defined(MACOSX_USE_GLX)
216
217 // =======================================================================
218 // function : IsCurrent
219 // purpose  :
220 // =======================================================================
221 Standard_Boolean OpenGl_Context::IsCurrent() const
222 {
223 #if defined(_WIN32)
224   if (myWindowDC == NULL || myGContext == NULL)
225   {
226     return Standard_False;
227   }
228   return (( (HDC )myWindowDC == wglGetCurrentDC())
229       && ((HGLRC )myGContext == wglGetCurrentContext()));
230 #else
231   if (myDisplay == NULL || myWindow == 0 || myGContext == 0)
232   {
233     return Standard_False;
234   }
235
236   return (   ((Display* )myDisplay  == glXGetCurrentDisplay())
237        &&  ((GLXContext )myGContext == glXGetCurrentContext())
238        && ((GLXDrawable )myWindow   == glXGetCurrentDrawable()));
239 #endif
240 }
241
242 // =======================================================================
243 // function : MakeCurrent
244 // purpose  :
245 // =======================================================================
246 Standard_Boolean OpenGl_Context::MakeCurrent()
247 {
248 #if defined(_WIN32)
249   if (myWindowDC == NULL || myGContext == NULL)
250   {
251     Standard_ProgramError_Raise_if (myIsInitialized, "OpenGl_Context::Init() should be called before!");
252     return Standard_False;
253   }
254
255   // technically it should be safe to activate already bound GL context
256   // however some drivers (Intel etc.) may FAIL doing this for unknown reason
257   if (IsCurrent())
258   {
259     myShaderManager->SetContext (this);
260     return Standard_True;
261   }
262   else if (wglMakeCurrent ((HDC )myWindowDC, (HGLRC )myGContext) != TRUE)
263   {
264     // notice that glGetError() couldn't be used here!
265     wchar_t* aMsgBuff = NULL;
266     DWORD anErrorCode = GetLastError();
267     FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
268                     NULL, anErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (wchar_t* )&aMsgBuff, 0, NULL);
269     TCollection_ExtendedString aMsg ("wglMakeCurrent() has failed. ");
270     if (aMsgBuff != NULL)
271     {
272       aMsg += (Standard_ExtString )aMsgBuff;
273       LocalFree (aMsgBuff);
274     }
275     PushMessage (GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB, GL_DEBUG_TYPE_ERROR_ARB, (unsigned int )anErrorCode, GL_DEBUG_SEVERITY_HIGH_ARB, aMsg);
276     myIsInitialized = Standard_False;
277     return Standard_False;
278   }
279 #else
280   if (myDisplay == NULL || myWindow == 0 || myGContext == 0)
281   {
282     Standard_ProgramError_Raise_if (myIsInitialized, "OpenGl_Context::Init() should be called before!");
283     return Standard_False;
284   }
285
286   if (!glXMakeCurrent ((Display* )myDisplay, (GLXDrawable )myWindow, (GLXContext )myGContext))
287   {
288     // if there is no current context it might be impossible to use glGetError() correctly
289     PushMessage (GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB, GL_DEBUG_TYPE_ERROR_ARB, 0, GL_DEBUG_SEVERITY_HIGH_ARB,
290                  "glXMakeCurrent() has failed!");
291     myIsInitialized = Standard_False;
292     return Standard_False;
293   }
294 #endif
295   myShaderManager->SetContext (this);
296   return Standard_True;
297 }
298
299 // =======================================================================
300 // function : SwapBuffers
301 // purpose  :
302 // =======================================================================
303 void OpenGl_Context::SwapBuffers()
304 {
305 #if defined(_WIN32)
306   if ((HDC )myWindowDC != NULL)
307   {
308     ::SwapBuffers ((HDC )myWindowDC);
309     glFlush();
310   }
311 #else
312   if ((Display* )myDisplay != NULL)
313   {
314     glXSwapBuffers ((Display* )myDisplay, (GLXDrawable )myWindow);
315   }
316 #endif
317 }
318
319 #endif // __APPLE__
320
321 // =======================================================================
322 // function : findProc
323 // purpose  :
324 // =======================================================================
325 void* OpenGl_Context::findProc (const char* theFuncName)
326 {
327 #if defined(_WIN32)
328   return wglGetProcAddress (theFuncName);
329 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
330   return (myGlLibHandle != NULL) ? dlsym (myGlLibHandle, theFuncName) : NULL;
331 #else
332   return (void* )glXGetProcAddress ((const GLubyte* )theFuncName);
333 #endif
334 }
335
336 // =======================================================================
337 // function : CheckExtension
338 // purpose  :
339 // =======================================================================
340 Standard_Boolean OpenGl_Context::CheckExtension (const char* theExtName) const
341 {
342   if (theExtName  == NULL)
343   {
344     std::cerr << "CheckExtension called with NULL string!\n";
345     return Standard_False;
346   }
347
348   // available since OpenGL 3.0
349   // and the ONLY way to check extensions with OpenGL 3.1+ core profile
350   /**if (IsGlGreaterEqual (3, 0))
351   {
352     GLint anExtNb = 0;
353     glGetIntegerv (GL_NUM_EXTENSIONS, &anExtNb);
354     for (GLint anIter = 0; anIter < anExtNb; ++anIter)
355     {
356       const char* anExtension = (const char* )core30->glGetStringi (GL_EXTENSIONS, (GLuint )anIter);
357       if (anExtension[anExtNameLen] == '\0' &&
358           strncmp (anExtension, theExtName, anExtNameLen) == 0)
359       {
360         return Standard_True;
361       }
362     }
363     return Standard_False;
364   }*/
365
366   // use old way with huge string for all extensions
367   const char* anExtString = (const char* )glGetString (GL_EXTENSIONS);
368   if (anExtString == NULL)
369   {
370     Messanger()->Send ("TKOpenGL: glGetString (GL_EXTENSIONS) has returned NULL! No GL context?", Message_Warning);
371     return Standard_False;
372   }
373   return CheckExtension (anExtString, theExtName);
374 }
375
376 // =======================================================================
377 // function : CheckExtension
378 // purpose  :
379 // =======================================================================
380 Standard_Boolean OpenGl_Context::CheckExtension (const char* theExtString,
381                                                  const char* theExtName)
382 {
383   if (theExtString == NULL)
384   {
385     return Standard_False;
386   }
387
388   // Search for theExtName in the extensions string.
389   // Use of strstr() is not sufficient because extension names can be prefixes of other extension names.
390   char* aPtrIter = (char* )theExtString;
391   const char*  aPtrEnd      = aPtrIter + strlen (theExtString);
392   const size_t anExtNameLen = strlen (theExtName);
393   while (aPtrIter < aPtrEnd)
394   {
395     const size_t n = strcspn (aPtrIter, " ");
396     if ((n == anExtNameLen) && (strncmp (aPtrIter, theExtName, anExtNameLen) == 0))
397     {
398       return Standard_True;
399     }
400     aPtrIter += (n + 1);
401   }
402   return Standard_False;
403 }
404
405 #if !defined(__APPLE__) || defined(MACOSX_USE_GLX)
406
407 // =======================================================================
408 // function : Init
409 // purpose  :
410 // =======================================================================
411 Standard_Boolean OpenGl_Context::Init()
412 {
413   if (myIsInitialized)
414   {
415     return Standard_True;
416   }
417
418 #if defined(_WIN32)
419   myWindowDC = (Aspect_Handle )wglGetCurrentDC();
420   myGContext = (Aspect_RenderingContext )wglGetCurrentContext();
421 #else
422   myDisplay  = (Aspect_Display )glXGetCurrentDisplay();
423   myGContext = (Aspect_RenderingContext )glXGetCurrentContext();
424   myWindow   = (Aspect_Drawable )glXGetCurrentDrawable();
425 #endif
426   if (myGContext == NULL)
427   {
428     return Standard_False;
429   }
430
431   init();
432   myIsInitialized = Standard_True;
433   return Standard_True;
434 }
435
436 #endif // __APPLE__
437
438 // =======================================================================
439 // function : Init
440 // purpose  :
441 // =======================================================================
442 #if defined(_WIN32)
443 Standard_Boolean OpenGl_Context::Init (const Aspect_Handle           theWindow,
444                                        const Aspect_Handle           theWindowDC,
445                                        const Aspect_RenderingContext theGContext)
446 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
447 Standard_Boolean OpenGl_Context::Init (const void*                   theGContext)
448 #else
449 Standard_Boolean OpenGl_Context::Init (const Aspect_Drawable         theWindow,
450                                        const Aspect_Display          theDisplay,
451                                        const Aspect_RenderingContext theGContext)
452 #endif
453 {
454   Standard_ProgramError_Raise_if (myIsInitialized, "OpenGl_Context::Init() should be called only once!");
455 #if defined(_WIN32)
456   myWindow   = theWindow;
457   myGContext = theGContext;
458   myWindowDC = theWindowDC;
459 #elif defined(__APPLE__) && !defined(MACOSX_USE_GLX)
460   myGContext = (void* )theGContext;
461 #else
462   myWindow   = theWindow;
463   myGContext = theGContext;
464   myDisplay  = theDisplay;
465 #endif
466   if (myGContext == NULL || !MakeCurrent())
467   {
468     return Standard_False;
469   }
470
471   init();
472   myIsInitialized = Standard_True;
473   return Standard_True;
474 }
475
476 // =======================================================================
477 // function : ResetErrors
478 // purpose  :
479 // =======================================================================
480 void OpenGl_Context::ResetErrors()
481 {
482   while (glGetError() != GL_NO_ERROR)
483   {
484     //
485   }
486 }
487
488 // =======================================================================
489 // function : readGlVersion
490 // purpose  :
491 // =======================================================================
492 void OpenGl_Context::readGlVersion()
493 {
494   // reset values
495   myGlVerMajor = 0;
496   myGlVerMinor = 0;
497
498   // available since OpenGL 3.0
499   GLint aMajor = 0, aMinor = 0;
500   glGetIntegerv (GL_MAJOR_VERSION, &aMajor);
501   glGetIntegerv (GL_MINOR_VERSION, &aMinor);
502   // glGetError() sometimes does not report an error here even if
503   // GL does not know GL_MAJOR_VERSION and GL_MINOR_VERSION constants.
504   // This happens on some rendereres like e.g. Cygwin MESA.
505   // Thus checking additionally if GL has put anything to
506   // the output variables.
507   if (glGetError() == GL_NO_ERROR && aMajor != 0 && aMinor != 0)
508   {
509     myGlVerMajor = aMajor;
510     myGlVerMinor = aMinor;
511     return;
512   }
513   ResetErrors();
514
515   // Read version string.
516   // Notice that only first two numbers splitted by point '2.1 XXXXX' are significant.
517   // Following trash (after space) is vendor-specific.
518   // New drivers also returns micro version of GL like '3.3.0' which has no meaning
519   // and should be considered as vendor-specific too.
520   const char* aVerStr = (const char* )glGetString (GL_VERSION);
521   if (aVerStr == NULL || *aVerStr == '\0')
522   {
523     // invalid GL context
524     return;
525   }
526
527   // parse string for major number
528   char aMajorStr[32];
529   char aMinorStr[32];
530   size_t aMajIter = 0;
531   while (aVerStr[aMajIter] >= '0' && aVerStr[aMajIter] <= '9')
532   {
533     ++aMajIter;
534   }
535   if (aMajIter == 0 || aMajIter >= sizeof(aMajorStr))
536   {
537     return;
538   }
539   memcpy (aMajorStr, aVerStr, aMajIter);
540   aMajorStr[aMajIter] = '\0';
541
542   // parse string for minor number
543   aVerStr += aMajIter + 1;
544   size_t aMinIter = 0;
545   while (aVerStr[aMinIter] >= '0' && aVerStr[aMinIter] <= '9')
546   {
547     ++aMinIter;
548   }
549   if (aMinIter == 0 || aMinIter >= sizeof(aMinorStr))
550   {
551     return;
552   }
553   memcpy (aMinorStr, aVerStr, aMinIter);
554   aMinorStr[aMinIter] = '\0';
555
556   // read numbers
557   myGlVerMajor = atoi (aMajorStr);
558   myGlVerMinor = atoi (aMinorStr);
559
560   if (myGlVerMajor <= 0)
561   {
562     myGlVerMajor = 0;
563     myGlVerMinor = 0;
564   }
565 }
566
567 static Standard_CString THE_DBGMSG_UNKNOWN = "UNKNOWN";
568 static Standard_CString THE_DBGMSG_SOURCES[] =
569 {
570   ".OpenGL",    // GL_DEBUG_SOURCE_API_ARB
571   ".WinSystem", // GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB
572   ".GLSL",      // GL_DEBUG_SOURCE_SHADER_COMPILER_ARB
573   ".3rdParty",  // GL_DEBUG_SOURCE_THIRD_PARTY_ARB
574   "",           // GL_DEBUG_SOURCE_APPLICATION_ARB
575   ".Other"      // GL_DEBUG_SOURCE_OTHER_ARB
576 };
577
578 static Standard_CString THE_DBGMSG_TYPES[] =
579 {
580   "Error",           // GL_DEBUG_TYPE_ERROR_ARB
581   "Deprecated",      // GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB
582   "Undef. behavior", // GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB
583   "Portability",     // GL_DEBUG_TYPE_PORTABILITY_ARB
584   "Performance",     // GL_DEBUG_TYPE_PERFORMANCE_ARB
585   "Other"            // GL_DEBUG_TYPE_OTHER_ARB
586 };
587
588 static Standard_CString THE_DBGMSG_SEV_HIGH   = "High";   // GL_DEBUG_SEVERITY_HIGH_ARB
589 static Standard_CString THE_DBGMSG_SEV_MEDIUM = "Medium"; // GL_DEBUG_SEVERITY_MEDIUM_ARB
590 static Standard_CString THE_DBGMSG_SEV_LOW    = "Low";    // GL_DEBUG_SEVERITY_LOW_ARB
591
592 //! Callback for GL_ARB_debug_output extension
593 static void APIENTRY debugCallbackWrap(unsigned int theSource,
594                                        unsigned int theType,
595                                        unsigned int theId,
596                                        unsigned int theSeverity,
597                                        int          /*theLength*/,
598                                        const char*  theMessage,
599                                        void*        theUserParam)
600 {
601   OpenGl_Context* aCtx = (OpenGl_Context* )theUserParam;
602   aCtx->PushMessage (theSource, theType, theId, theSeverity, theMessage);
603 }
604
605 // =======================================================================
606 // function : PushMessage
607 // purpose  :
608 // =======================================================================
609 void OpenGl_Context::PushMessage (const unsigned int theSource,
610                                   const unsigned int theType,
611                                   const unsigned int theId,
612                                   const unsigned int theSeverity,
613                                   const TCollection_ExtendedString& theMessage)
614 {
615   //OpenGl_Context* aCtx = (OpenGl_Context* )theUserParam;
616   Standard_CString& aSrc = (theSource >= GL_DEBUG_SOURCE_API_ARB
617                          && theSource <= GL_DEBUG_SOURCE_OTHER_ARB)
618                          ? THE_DBGMSG_SOURCES[theSource - GL_DEBUG_SOURCE_API_ARB]
619                          : THE_DBGMSG_UNKNOWN;
620   Standard_CString& aType = (theType >= GL_DEBUG_TYPE_ERROR_ARB
621                           && theType <= GL_DEBUG_TYPE_OTHER_ARB)
622                           ? THE_DBGMSG_TYPES[theType - GL_DEBUG_TYPE_ERROR_ARB]
623                           : THE_DBGMSG_UNKNOWN;
624   Standard_CString& aSev = theSeverity == GL_DEBUG_SEVERITY_HIGH_ARB
625                          ? THE_DBGMSG_SEV_HIGH
626                          : (theSeverity == GL_DEBUG_SEVERITY_MEDIUM_ARB
627                           ? THE_DBGMSG_SEV_MEDIUM
628                           : THE_DBGMSG_SEV_LOW);
629   Message_Gravity aGrav = theSeverity == GL_DEBUG_SEVERITY_HIGH_ARB
630                         ? Message_Alarm
631                         : (theSeverity == GL_DEBUG_SEVERITY_MEDIUM_ARB
632                          ? Message_Warning
633                          : Message_Info);
634
635   TCollection_ExtendedString aMsg;
636   aMsg += "TKOpenGl"; aMsg += aSrc;
637   aMsg += " | Type: ";        aMsg += aType;
638   aMsg += " | ID: ";          aMsg += (Standard_Integer )theId;
639   aMsg += " | Severity: ";    aMsg += aSev;
640   aMsg += " | Message:\n  ";
641   aMsg += theMessage;
642
643   Messanger()->Send (aMsg, aGrav);
644 }
645
646 // =======================================================================
647 // function : init
648 // purpose  :
649 // =======================================================================
650 void OpenGl_Context::init()
651 {
652   // read version
653   readGlVersion();
654
655   arbNPTW = CheckExtension ("GL_ARB_texture_non_power_of_two");
656   extBgra = CheckExtension ("GL_EXT_bgra");
657   extAnis = CheckExtension ("GL_EXT_texture_filter_anisotropic");
658   extPDS  = CheckExtension ("GL_EXT_packed_depth_stencil");
659   atiMem  = CheckExtension ("GL_ATI_meminfo");
660   nvxMem  = CheckExtension ("GL_NVX_gpu_memory_info");
661
662   // get number of maximum clipping planes
663   glGetIntegerv (GL_MAX_CLIP_PLANES, &myMaxClipPlanes);
664   glGetIntegerv (GL_MAX_TEXTURE_SIZE, &myMaxTexDim);
665   if (extAnis)
666   {
667     glGetIntegerv (GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &myAnisoMax);
668   }
669
670   myClippingState.Init (myMaxClipPlanes);
671
672   // initialize debug context extension
673   if (CheckExtension ("GL_ARB_debug_output"))
674   {
675     arbDbg = new OpenGl_ArbDbg();
676     memset (arbDbg, 0, sizeof(OpenGl_ArbDbg)); // nullify whole structure
677     if (!FindProcShort (arbDbg, glDebugMessageControlARB)
678      || !FindProcShort (arbDbg, glDebugMessageInsertARB)
679      || !FindProcShort (arbDbg, glDebugMessageCallbackARB)
680      || !FindProcShort (arbDbg, glGetDebugMessageLogARB))
681     {
682       delete arbDbg;
683       arbDbg = NULL;
684     }
685     if (arbDbg != NULL
686      && caps->contextDebug)
687     {
688       // setup default callback
689       arbDbg->glDebugMessageCallbackARB (debugCallbackWrap, this);
690     #ifdef DEB
691       glEnable (GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
692     #endif
693     }
694   }
695
696   // initialize VBO extension (ARB)
697   if (CheckExtension ("GL_ARB_vertex_buffer_object"))
698   {
699     arbVBO = new OpenGl_ArbVBO();
700     memset (arbVBO, 0, sizeof(OpenGl_ArbVBO)); // nullify whole structure
701     if (!FindProcShort (arbVBO, glGenBuffersARB)
702      || !FindProcShort (arbVBO, glBindBufferARB)
703      || !FindProcShort (arbVBO, glBufferDataARB)
704      || !FindProcShort (arbVBO, glDeleteBuffersARB))
705     {
706       delete arbVBO;
707       arbVBO = NULL;
708     }
709   }
710
711   // initialize TBO extension (ARB)
712   if (CheckExtension ("GL_ARB_texture_buffer_object"))
713   {
714     arbTBO = new OpenGl_ArbTBO();
715     memset (arbTBO, 0, sizeof(OpenGl_ArbTBO)); // nullify whole structure
716     if (!FindProcShort (arbTBO, glTexBufferARB))
717     {
718       delete arbTBO;
719       arbTBO = NULL;
720     }
721   }
722
723   // initialize hardware instancing extension (ARB)
724   if (CheckExtension ("GL_ARB_draw_instanced"))
725   {
726     arbIns = new OpenGl_ArbIns();
727     memset (arbIns, 0, sizeof(OpenGl_ArbIns)); // nullify whole structure
728     if (!FindProcShort (arbIns, glDrawArraysInstancedARB)
729      || !FindProcShort (arbIns, glDrawElementsInstancedARB))
730     {
731       delete arbIns;
732       arbIns = NULL;
733     }
734   }
735
736   // initialize FBO extension (EXT)
737   if (CheckExtension ("GL_EXT_framebuffer_object"))
738   {
739     extFBO = new OpenGl_ExtFBO();
740     memset (extFBO, 0, sizeof(OpenGl_ExtFBO)); // nullify whole structure
741     if (!FindProcShort (extFBO, glGenFramebuffersEXT)
742      || !FindProcShort (extFBO, glDeleteFramebuffersEXT)
743      || !FindProcShort (extFBO, glBindFramebufferEXT)
744      || !FindProcShort (extFBO, glFramebufferTexture2DEXT)
745      || !FindProcShort (extFBO, glCheckFramebufferStatusEXT)
746      || !FindProcShort (extFBO, glGenRenderbuffersEXT)
747      || !FindProcShort (extFBO, glDeleteRenderbuffersEXT)
748      || !FindProcShort (extFBO, glBindRenderbufferEXT)
749      || !FindProcShort (extFBO, glRenderbufferStorageEXT)
750      || !FindProcShort (extFBO, glFramebufferRenderbufferEXT)
751      || !FindProcShort (extFBO, glGenerateMipmapEXT))
752     {
753       delete extFBO;
754       extFBO = NULL;
755     }
756   }
757
758   // initialize GS extension (EXT)
759   if (CheckExtension ("GL_EXT_geometry_shader4"))
760   {
761     extGS = new OpenGl_ExtGS();
762     memset (extGS, 0, sizeof(OpenGl_ExtGS)); // nullify whole structure
763     if (!FindProcShort (extGS, glProgramParameteriEXT))
764     {
765       delete extGS;
766       extGS = NULL;
767     }
768   }
769
770   myGlCore20 = new OpenGl_GlCore20();
771   memset (myGlCore20, 0, sizeof(OpenGl_GlCore20)); // nullify whole structure
772
773   // Check if OpenGL 1.2 core functionality is actually present
774   Standard_Boolean hasGlCore12 = IsGlGreaterEqual (1, 2)
775     && FindProcShort (myGlCore20, glBlendColor)
776     && FindProcShort (myGlCore20, glBlendEquation)
777     && FindProcShort (myGlCore20, glDrawRangeElements)
778     && FindProcShort (myGlCore20, glTexImage3D)
779     && FindProcShort (myGlCore20, glTexSubImage3D)
780     && FindProcShort (myGlCore20, glCopyTexSubImage3D);
781
782   // Check if OpenGL 1.3 core functionality is actually present
783   Standard_Boolean hasGlCore13 = IsGlGreaterEqual (1, 3)
784     && FindProcShort (myGlCore20, glActiveTexture)
785     && FindProcShort (myGlCore20, glSampleCoverage)
786     && FindProcShort (myGlCore20, glCompressedTexImage3D)
787     && FindProcShort (myGlCore20, glCompressedTexImage2D)
788     && FindProcShort (myGlCore20, glCompressedTexImage1D)
789     && FindProcShort (myGlCore20, glCompressedTexSubImage3D)
790     && FindProcShort (myGlCore20, glCompressedTexSubImage2D)
791     && FindProcShort (myGlCore20, glCompressedTexSubImage1D)
792     && FindProcShort (myGlCore20, glGetCompressedTexImage)
793      // deprecated
794     && FindProcShort (myGlCore20, glClientActiveTexture)
795     && FindProcShort (myGlCore20, glMultiTexCoord1d)
796     && FindProcShort (myGlCore20, glMultiTexCoord1dv)
797     && FindProcShort (myGlCore20, glMultiTexCoord1f)
798     && FindProcShort (myGlCore20, glMultiTexCoord1fv)
799     && FindProcShort (myGlCore20, glMultiTexCoord1i)
800     && FindProcShort (myGlCore20, glMultiTexCoord1iv)
801     && FindProcShort (myGlCore20, glMultiTexCoord1s)
802     && FindProcShort (myGlCore20, glMultiTexCoord1sv)
803     && FindProcShort (myGlCore20, glMultiTexCoord2d)
804     && FindProcShort (myGlCore20, glMultiTexCoord2dv)
805     && FindProcShort (myGlCore20, glMultiTexCoord2f)
806     && FindProcShort (myGlCore20, glMultiTexCoord2fv)
807     && FindProcShort (myGlCore20, glMultiTexCoord2i)
808     && FindProcShort (myGlCore20, glMultiTexCoord2iv)
809     && FindProcShort (myGlCore20, glMultiTexCoord2s)
810     && FindProcShort (myGlCore20, glMultiTexCoord2sv)
811     && FindProcShort (myGlCore20, glMultiTexCoord3d)
812     && FindProcShort (myGlCore20, glMultiTexCoord3dv)
813     && FindProcShort (myGlCore20, glMultiTexCoord3f)
814     && FindProcShort (myGlCore20, glMultiTexCoord3fv)
815     && FindProcShort (myGlCore20, glMultiTexCoord3i)
816     && FindProcShort (myGlCore20, glMultiTexCoord3iv)
817     && FindProcShort (myGlCore20, glMultiTexCoord3s)
818     && FindProcShort (myGlCore20, glMultiTexCoord3sv)
819     && FindProcShort (myGlCore20, glMultiTexCoord4d)
820     && FindProcShort (myGlCore20, glMultiTexCoord4dv)
821     && FindProcShort (myGlCore20, glMultiTexCoord4f)
822     && FindProcShort (myGlCore20, glMultiTexCoord4fv)
823     && FindProcShort (myGlCore20, glMultiTexCoord4i)
824     && FindProcShort (myGlCore20, glMultiTexCoord4iv)
825     && FindProcShort (myGlCore20, glMultiTexCoord4s)
826     && FindProcShort (myGlCore20, glMultiTexCoord4sv)
827     && FindProcShort (myGlCore20, glLoadTransposeMatrixf)
828     && FindProcShort (myGlCore20, glLoadTransposeMatrixd)
829     && FindProcShort (myGlCore20, glMultTransposeMatrixf)
830     && FindProcShort (myGlCore20, glMultTransposeMatrixd);
831
832   // Check if OpenGL 1.4 core functionality is actually present
833   Standard_Boolean hasGlCore14 = IsGlGreaterEqual (1, 4)
834     && FindProcShort (myGlCore20, glBlendFuncSeparate)
835     && FindProcShort (myGlCore20, glMultiDrawArrays)
836     && FindProcShort (myGlCore20, glMultiDrawElements)
837     && FindProcShort (myGlCore20, glPointParameterf)
838     && FindProcShort (myGlCore20, glPointParameterfv)
839     && FindProcShort (myGlCore20, glPointParameteri)
840     && FindProcShort (myGlCore20, glPointParameteriv);
841
842   // Check if OpenGL 1.5 core functionality is actually present
843   Standard_Boolean hasGlCore15 = IsGlGreaterEqual (1, 5)
844     && FindProcShort (myGlCore20, glGenQueries)
845     && FindProcShort (myGlCore20, glDeleteQueries)
846     && FindProcShort (myGlCore20, glIsQuery)
847     && FindProcShort (myGlCore20, glBeginQuery)
848     && FindProcShort (myGlCore20, glEndQuery)
849     && FindProcShort (myGlCore20, glGetQueryiv)
850     && FindProcShort (myGlCore20, glGetQueryObjectiv)
851     && FindProcShort (myGlCore20, glGetQueryObjectuiv)
852     && FindProcShort (myGlCore20, glBindBuffer)
853     && FindProcShort (myGlCore20, glDeleteBuffers)
854     && FindProcShort (myGlCore20, glGenBuffers)
855     && FindProcShort (myGlCore20, glIsBuffer)
856     && FindProcShort (myGlCore20, glBufferData)
857     && FindProcShort (myGlCore20, glBufferSubData)
858     && FindProcShort (myGlCore20, glGetBufferSubData)
859     && FindProcShort (myGlCore20, glMapBuffer)
860     && FindProcShort (myGlCore20, glUnmapBuffer)
861     && FindProcShort (myGlCore20, glGetBufferParameteriv)
862     && FindProcShort (myGlCore20, glGetBufferPointerv);
863
864   // Check if OpenGL 2.0 core functionality is actually present
865   Standard_Boolean hasGlCore20 = IsGlGreaterEqual (2, 0)
866     && FindProcShort (myGlCore20, glBlendEquationSeparate)
867     && FindProcShort (myGlCore20, glDrawBuffers)
868     && FindProcShort (myGlCore20, glStencilOpSeparate)
869     && FindProcShort (myGlCore20, glStencilFuncSeparate)
870     && FindProcShort (myGlCore20, glStencilMaskSeparate)
871     && FindProcShort (myGlCore20, glAttachShader)
872     && FindProcShort (myGlCore20, glBindAttribLocation)
873     && FindProcShort (myGlCore20, glCompileShader)
874     && FindProcShort (myGlCore20, glCreateProgram)
875     && FindProcShort (myGlCore20, glCreateShader)
876     && FindProcShort (myGlCore20, glDeleteProgram)
877     && FindProcShort (myGlCore20, glDeleteShader)
878     && FindProcShort (myGlCore20, glDetachShader)
879     && FindProcShort (myGlCore20, glDisableVertexAttribArray)
880     && FindProcShort (myGlCore20, glEnableVertexAttribArray)
881     && FindProcShort (myGlCore20, glGetActiveAttrib)
882     && FindProcShort (myGlCore20, glGetActiveUniform)
883     && FindProcShort (myGlCore20, glGetAttachedShaders)
884     && FindProcShort (myGlCore20, glGetAttribLocation)
885     && FindProcShort (myGlCore20, glGetProgramiv)
886     && FindProcShort (myGlCore20, glGetProgramInfoLog)
887     && FindProcShort (myGlCore20, glGetShaderiv)
888     && FindProcShort (myGlCore20, glGetShaderInfoLog)
889     && FindProcShort (myGlCore20, glGetShaderSource)
890     && FindProcShort (myGlCore20, glGetUniformLocation)
891     && FindProcShort (myGlCore20, glGetUniformfv)
892     && FindProcShort (myGlCore20, glGetUniformiv)
893     && FindProcShort (myGlCore20, glGetVertexAttribdv)
894     && FindProcShort (myGlCore20, glGetVertexAttribfv)
895     && FindProcShort (myGlCore20, glGetVertexAttribiv)
896     && FindProcShort (myGlCore20, glGetVertexAttribPointerv)
897     && FindProcShort (myGlCore20, glIsProgram)
898     && FindProcShort (myGlCore20, glIsShader)
899     && FindProcShort (myGlCore20, glLinkProgram)
900     && FindProcShort (myGlCore20, glShaderSource)
901     && FindProcShort (myGlCore20, glUseProgram)
902     && FindProcShort (myGlCore20, glUniform1f)
903     && FindProcShort (myGlCore20, glUniform2f)
904     && FindProcShort (myGlCore20, glUniform3f)
905     && FindProcShort (myGlCore20, glUniform4f)
906     && FindProcShort (myGlCore20, glUniform1i)
907     && FindProcShort (myGlCore20, glUniform2i)
908     && FindProcShort (myGlCore20, glUniform3i)
909     && FindProcShort (myGlCore20, glUniform4i)
910     && FindProcShort (myGlCore20, glUniform1fv)
911     && FindProcShort (myGlCore20, glUniform2fv)
912     && FindProcShort (myGlCore20, glUniform3fv)
913     && FindProcShort (myGlCore20, glUniform4fv)
914     && FindProcShort (myGlCore20, glUniform1iv)
915     && FindProcShort (myGlCore20, glUniform2iv)
916     && FindProcShort (myGlCore20, glUniform3iv)
917     && FindProcShort (myGlCore20, glUniform4iv)
918     && FindProcShort (myGlCore20, glUniformMatrix2fv)
919     && FindProcShort (myGlCore20, glUniformMatrix3fv)
920     && FindProcShort (myGlCore20, glUniformMatrix4fv)
921     && FindProcShort (myGlCore20, glValidateProgram)
922     && FindProcShort (myGlCore20, glVertexAttrib1d)
923     && FindProcShort (myGlCore20, glVertexAttrib1dv)
924     && FindProcShort (myGlCore20, glVertexAttrib1f)
925     && FindProcShort (myGlCore20, glVertexAttrib1fv)
926     && FindProcShort (myGlCore20, glVertexAttrib1s)
927     && FindProcShort (myGlCore20, glVertexAttrib1sv)
928     && FindProcShort (myGlCore20, glVertexAttrib2d)
929     && FindProcShort (myGlCore20, glVertexAttrib2dv)
930     && FindProcShort (myGlCore20, glVertexAttrib2f)
931     && FindProcShort (myGlCore20, glVertexAttrib2fv)
932     && FindProcShort (myGlCore20, glVertexAttrib2s)
933     && FindProcShort (myGlCore20, glVertexAttrib2sv)
934     && FindProcShort (myGlCore20, glVertexAttrib3d)
935     && FindProcShort (myGlCore20, glVertexAttrib3dv)
936     && FindProcShort (myGlCore20, glVertexAttrib3f)
937     && FindProcShort (myGlCore20, glVertexAttrib3fv)
938     && FindProcShort (myGlCore20, glVertexAttrib3s)
939     && FindProcShort (myGlCore20, glVertexAttrib3sv)
940     && FindProcShort (myGlCore20, glVertexAttrib4Nbv)
941     && FindProcShort (myGlCore20, glVertexAttrib4Niv)
942     && FindProcShort (myGlCore20, glVertexAttrib4Nsv)
943     && FindProcShort (myGlCore20, glVertexAttrib4Nub)
944     && FindProcShort (myGlCore20, glVertexAttrib4Nubv)
945     && FindProcShort (myGlCore20, glVertexAttrib4Nuiv)
946     && FindProcShort (myGlCore20, glVertexAttrib4Nusv)
947     && FindProcShort (myGlCore20, glVertexAttrib4bv)
948     && FindProcShort (myGlCore20, glVertexAttrib4d)
949     && FindProcShort (myGlCore20, glVertexAttrib4dv)
950     && FindProcShort (myGlCore20, glVertexAttrib4f)
951     && FindProcShort (myGlCore20, glVertexAttrib4fv)
952     && FindProcShort (myGlCore20, glVertexAttrib4iv)
953     && FindProcShort (myGlCore20, glVertexAttrib4s)
954     && FindProcShort (myGlCore20, glVertexAttrib4sv)
955     && FindProcShort (myGlCore20, glVertexAttrib4ubv)
956     && FindProcShort (myGlCore20, glVertexAttrib4uiv)
957     && FindProcShort (myGlCore20, glVertexAttrib4usv)
958     && FindProcShort (myGlCore20, glVertexAttribPointer);
959
960   if (!hasGlCore12)
961   {
962     myGlVerMajor = 1;
963     myGlVerMinor = 1;
964     return;
965   }
966   else
967   {
968     core12 = myGlCore20;
969   }
970   if (!hasGlCore13)
971   {
972     myGlVerMajor = 1;
973     myGlVerMinor = 2;
974     return;
975   }
976   else
977   {
978     core13 = myGlCore20;
979   }
980   if(!hasGlCore14)
981   {
982     myGlVerMajor = 1;
983     myGlVerMinor = 3;
984     return;
985   }
986   else
987   {
988     core14 = myGlCore20;
989   }
990   if(!hasGlCore15)
991   {
992     myGlVerMajor = 1;
993     myGlVerMinor = 4;
994     return;
995   }
996   else
997   {
998     core15 = myGlCore20;
999   }
1000   if(!hasGlCore20)
1001   {
1002     myGlVerMajor = 1;
1003     myGlVerMinor = 5;
1004   }
1005   else
1006   {
1007     core20 = myGlCore20;
1008   }
1009 }
1010 // =======================================================================
1011 // function : IsFeedback
1012 // purpose  :
1013 // =======================================================================
1014 Standard_Boolean OpenGl_Context::IsFeedback() const
1015 {
1016   return myIsFeedback;
1017 }
1018
1019 // =======================================================================
1020 // function : SetFeedback
1021 // purpose  :
1022 // =======================================================================
1023 void OpenGl_Context::SetFeedback (const Standard_Boolean theFeedbackOn)
1024 {
1025   myIsFeedback = theFeedbackOn;
1026 }
1027
1028 // =======================================================================
1029 // function : MemoryInfo
1030 // purpose  :
1031 // =======================================================================
1032 Standard_Size OpenGl_Context::AvailableMemory() const
1033 {
1034   if (atiMem)
1035   {
1036     // this is actually information for VBO pool
1037     // however because pools are mostly shared
1038     // it can be used for total GPU memory estimations
1039     GLint aMemInfo[4];
1040     aMemInfo[0] = 0;
1041     glGetIntegerv (GL_VBO_FREE_MEMORY_ATI, aMemInfo);
1042     // returned value is in KiB, however this maybe changed in future
1043     return Standard_Size(aMemInfo[0]) * 1024;
1044   }
1045   else if (nvxMem)
1046   {
1047     // current available dedicated video memory (in KiB), currently unused GPU memory
1048     GLint aMemInfo = 0;
1049     glGetIntegerv (GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &aMemInfo);
1050     return Standard_Size(aMemInfo) * 1024;
1051   }
1052   return 0;
1053 }
1054
1055 // =======================================================================
1056 // function : MemoryInfo
1057 // purpose  :
1058 // =======================================================================
1059 TCollection_AsciiString OpenGl_Context::MemoryInfo() const
1060 {
1061   TCollection_AsciiString anInfo;
1062   if (atiMem)
1063   {
1064     GLint aValues[4];
1065     memset (aValues, 0, sizeof(aValues));
1066     glGetIntegerv (GL_VBO_FREE_MEMORY_ATI, aValues);
1067
1068     // total memory free in the pool
1069     anInfo += TCollection_AsciiString ("  GPU free memory:    ") + (aValues[0] / 1024) + " MiB\n";
1070
1071     // largest available free block in the pool
1072     anInfo += TCollection_AsciiString ("  Largest free block: ") + (aValues[1] / 1024) + " MiB\n";
1073     if (aValues[2] != aValues[0])
1074     {
1075       // total auxiliary memory free
1076       anInfo += TCollection_AsciiString ("  Free memory:        ") + (aValues[2] / 1024) + " MiB\n";
1077     }
1078   }
1079   else if (nvxMem)
1080   {
1081     //current available dedicated video memory (in KiB), currently unused GPU memory
1082     GLint aValue = 0;
1083     glGetIntegerv (GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &aValue);
1084     anInfo += TCollection_AsciiString ("  GPU free memory:    ") + (aValue / 1024) + " MiB\n";
1085
1086     // dedicated video memory, total size (in KiB) of the GPU memory
1087     GLint aDedicated = 0;
1088     glGetIntegerv (GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &aDedicated);
1089     anInfo += TCollection_AsciiString ("  GPU memory:         ") + (aDedicated / 1024) + " MiB\n";
1090
1091     // total available memory, total size (in KiB) of the memory available for allocations
1092     glGetIntegerv (GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &aValue);
1093     if (aValue != aDedicated)
1094     {
1095       // different only for special configurations
1096       anInfo += TCollection_AsciiString ("  Total memory:       ") + (aValue / 1024) + " MiB\n";
1097     }
1098   }
1099   return anInfo;
1100 }
1101
1102
1103 // =======================================================================
1104 // function : GetResource
1105 // purpose  :
1106 // =======================================================================
1107 const Handle(OpenGl_Resource)& OpenGl_Context::GetResource (const TCollection_AsciiString& theKey) const
1108 {
1109   return mySharedResources->IsBound (theKey) ? mySharedResources->Find (theKey) : NULL_GL_RESOURCE;
1110 }
1111
1112 // =======================================================================
1113 // function : ShareResource
1114 // purpose  :
1115 // =======================================================================
1116 Standard_Boolean OpenGl_Context::ShareResource (const TCollection_AsciiString& theKey,
1117                                                 const Handle(OpenGl_Resource)& theResource)
1118 {
1119   if (theKey.IsEmpty() || theResource.IsNull())
1120   {
1121     return Standard_False;
1122   }
1123   return mySharedResources->Bind (theKey, theResource);
1124 }
1125
1126 // =======================================================================
1127 // function : ReleaseResource
1128 // purpose  :
1129 // =======================================================================
1130 void OpenGl_Context::ReleaseResource (const TCollection_AsciiString& theKey,
1131                                       const Standard_Boolean         theToDelay)
1132 {
1133   if (!mySharedResources->IsBound (theKey))
1134   {
1135     return;
1136   }
1137   const Handle(OpenGl_Resource)& aRes = mySharedResources->Find (theKey);
1138   if (aRes->GetRefCount() > 1)
1139   {
1140     return;
1141   }
1142
1143   if (theToDelay)
1144   {
1145     myDelayed->Bind (theKey, 1);
1146   }
1147   else
1148   {
1149     aRes->Release (this);
1150     mySharedResources->UnBind (theKey);
1151   }
1152 }
1153
1154 // =======================================================================
1155 // function : DelayedRelease
1156 // purpose  :
1157 // =======================================================================
1158 void OpenGl_Context::DelayedRelease (Handle(OpenGl_Resource)& theResource)
1159 {
1160   myReleaseQueue->Push (theResource);
1161   theResource.Nullify();
1162 }
1163
1164 // =======================================================================
1165 // function : ReleaseDelayed
1166 // purpose  :
1167 // =======================================================================
1168 void OpenGl_Context::ReleaseDelayed()
1169 {
1170   // release queued elements
1171   while (!myReleaseQueue->IsEmpty())
1172   {
1173     myReleaseQueue->Front()->Release (this);
1174     myReleaseQueue->Pop();
1175   }
1176
1177   // release delayed shared resoruces
1178   NCollection_Vector<TCollection_AsciiString> aDeadList;
1179   for (NCollection_DataMap<TCollection_AsciiString, Standard_Integer>::Iterator anIter (*myDelayed);
1180        anIter.More(); anIter.Next())
1181   {
1182     if (++anIter.ChangeValue() <= 2)
1183     {
1184       continue; // postpone release one more frame to ensure noone use it periodically
1185     }
1186
1187     const TCollection_AsciiString& aKey = anIter.Key();
1188     if (!mySharedResources->IsBound (aKey))
1189     {
1190       // mixed unshared strategy delayed/undelayed was used!
1191       aDeadList.Append (aKey);
1192       continue;
1193     }
1194
1195     Handle(OpenGl_Resource)& aRes = mySharedResources->ChangeFind (aKey);
1196     if (aRes->GetRefCount() > 1)
1197     {
1198       // should be only 1 instance in mySharedResources
1199       // if not - resource was reused again
1200       aDeadList.Append (aKey);
1201       continue;
1202     }
1203
1204     // release resource if no one requiested it more than 2 redraw calls
1205     aRes->Release (this);
1206     mySharedResources->UnBind (aKey);
1207     aDeadList.Append (aKey);
1208   }
1209
1210   for (Standard_Integer anIter = 0; anIter < aDeadList.Length(); ++anIter)
1211   {
1212     myDelayed->UnBind (aDeadList.Value (anIter));
1213   }
1214 }