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