0032089: Visualization, TKOpenGl - support GL_EXT_sRGB extension to OpenGL ES 2.0
[occt.git] / src / OpenGl / OpenGl_Context.cxx
1 // Created on: 2012-01-26
2 // Created by: Kirill GAVRILOV
3 // Copyright (c) 2012-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #if defined(_WIN32)
17   #include <windows.h>
18 #endif
19
20 #include <OpenGl_Context.hxx>
21
22 #include <OpenGl_ArbTBO.hxx>
23 #include <OpenGl_ArbIns.hxx>
24 #include <OpenGl_ArbDbg.hxx>
25 #include <OpenGl_ArbFBO.hxx>
26 #include <OpenGl_ExtGS.hxx>
27 #include <OpenGl_ArbSamplerObject.hxx>
28 #include <OpenGl_ArbTexBindless.hxx>
29 #include <OpenGl_GlCore46.hxx>
30 #include <OpenGl_FrameBuffer.hxx>
31 #include <OpenGl_FrameStats.hxx>
32 #include <OpenGl_Sampler.hxx>
33 #include <OpenGl_ShaderManager.hxx>
34 #include <OpenGl_TextureSetPairIterator.hxx>
35 #include <OpenGl_Workspace.hxx>
36 #include <OpenGl_Aspects.hxx>
37
38 #include <Graphic3d_TransformUtils.hxx>
39 #include <Graphic3d_RenderingParams.hxx>
40 #include <Image_SupportedFormats.hxx>
41 #include <Message_Messenger.hxx>
42 #include <NCollection_Vector.hxx>
43 #include <Standard_ProgramError.hxx>
44 #include <Standard_WarningDisableFunctionCast.hxx>
45
46 #if defined(_WIN32) && defined(max)
47   #undef max
48 #endif
49 #include <limits>
50
51 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Context,Standard_Transient)
52
53 #if defined(HAVE_EGL)
54   #include <EGL/egl.h>
55   #ifdef _MSC_VER
56     #pragma comment(lib, "libEGL.lib")
57   #endif
58 #elif defined(_WIN32)
59   //
60 #elif defined(HAVE_XLIB)
61   #include <GL/glx.h> // glXGetProcAddress()
62 #elif defined(__APPLE__)
63   #include <dlfcn.h>
64   #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
65     //
66   #else
67     #include <OpenGL/OpenGL.h>
68     #include <CoreGraphics/CoreGraphics.h>
69   #endif
70 #else
71   //
72 #endif
73
74 #ifdef __EMSCRIPTEN__
75   #include <emscripten.h>
76   #include <emscripten/html5.h>
77 #endif
78
79 namespace
80 {
81   static const Handle(OpenGl_Resource) NULL_GL_RESOURCE;
82   static const OpenGl_Mat4 THE_IDENTITY_MATRIX;
83
84   //! Add key-value pair to the dictionary.
85   static void addInfo (TColStd_IndexedDataMapOfStringString& theDict,
86                        const TCollection_AsciiString& theKey,
87                        const TCollection_AsciiString& theValue)
88   {
89     theDict.ChangeFromIndex (theDict.Add (theKey, theValue)) = theValue;
90   }
91
92   //! Add key-value pair to the dictionary.
93   static void addInfo (TColStd_IndexedDataMapOfStringString& theDict,
94                        const TCollection_AsciiString& theKey,
95                        const char* theValue)
96   {
97     TCollection_AsciiString aValue (theValue != NULL ? theValue : "");
98     theDict.ChangeFromIndex (theDict.Add (theKey, aValue)) = aValue;
99   }
100 }
101
102 // =======================================================================
103 // function : OpenGl_Context
104 // purpose  :
105 // =======================================================================
106 OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
107 : core11ffp  (NULL),
108   core11fwd  (NULL),
109   core15     (NULL),
110   core20     (NULL),
111   core30     (NULL),
112   core32     (NULL),
113   core33     (NULL),
114   core41     (NULL),
115   core42     (NULL),
116   core43     (NULL),
117   core44     (NULL),
118   core45     (NULL),
119   core46     (NULL),
120   core15fwd  (NULL),
121   core20fwd  (NULL),
122   caps   (!theCaps.IsNull() ? theCaps : new OpenGl_Caps()),
123   hasGetBufferData (Standard_False),
124 #if defined(GL_ES_VERSION_2_0)
125   hasPackRowLength (Standard_False),
126   hasUnpackRowLength (Standard_False),
127   hasHighp   (Standard_False),
128   hasUintIndex(Standard_False),
129   hasTexRGBA8(Standard_False),
130 #else
131   hasPackRowLength (Standard_True),
132   hasUnpackRowLength (Standard_True),
133   hasHighp   (Standard_True),
134   hasUintIndex(Standard_True),
135   hasTexRGBA8(Standard_True),
136 #endif
137   hasTexFloatLinear (Standard_False),
138   hasTexSRGB (Standard_False),
139   hasFboSRGB (Standard_False),
140   hasSRGBControl (Standard_False),
141   hasFboRenderMipmap (Standard_False),
142 #if defined(GL_ES_VERSION_2_0)
143   hasFlatShading (OpenGl_FeatureNotAvailable),
144 #else
145   hasFlatShading (OpenGl_FeatureInCore),
146 #endif
147   hasGlslBitwiseOps  (OpenGl_FeatureNotAvailable),
148   hasDrawBuffers     (OpenGl_FeatureNotAvailable),
149   hasFloatBuffer     (OpenGl_FeatureNotAvailable),
150   hasHalfFloatBuffer (OpenGl_FeatureNotAvailable),
151   hasSampleVariables (OpenGl_FeatureNotAvailable),
152   hasGeometryStage   (OpenGl_FeatureNotAvailable),
153   arbDrawBuffers (Standard_False),
154   arbNPTW  (Standard_False),
155   arbTexRG (Standard_False),
156   arbTexFloat (Standard_False),
157   arbSamplerObject (NULL),
158   arbTexBindless (NULL),
159   arbTBO (NULL),
160   arbTboRGB32 (Standard_False),
161   arbClipControl (Standard_False),
162   arbIns (NULL),
163   arbDbg (NULL),
164   arbFBO (NULL),
165   arbFBOBlit (NULL),
166   arbSampleShading (Standard_False),
167   arbDepthClamp (Standard_False),
168   extFragDepth (Standard_False),
169   extDrawBuffers (Standard_False),
170   extGS  (NULL),
171   extBgra(Standard_False),
172   extAnis(Standard_False),
173   extPDS (Standard_False),
174   atiMem (Standard_False),
175   nvxMem (Standard_False),
176   oesSampleVariables (Standard_False),
177   oesStdDerivatives (Standard_False),
178   myWindow  (0),
179   myDisplay (0),
180   myGContext(0),
181   mySharedResources (new OpenGl_ResourcesMap()),
182   myDelayed         (new OpenGl_DelayReleaseMap()),
183   myUnusedResources (new OpenGl_ResourcesStack()),
184   myClippingState (),
185   myGlLibHandle (NULL),
186   myFuncs (new OpenGl_GlFunctions()),
187   mySupportedFormats (new Image_SupportedFormats()),
188   myAnisoMax   (1),
189   myTexClamp   (GL_CLAMP_TO_EDGE),
190   myMaxTexDim  (1024),
191   myMaxTexCombined (1),
192   myMaxTexUnitsFFP (1),
193   myMaxDumpSizeX (1024),
194   myMaxDumpSizeY (1024),
195   myMaxClipPlanes (6),
196   myMaxMsaaSamples(0),
197   myMaxDrawBuffers (1),
198   myMaxColorAttachments (1),
199   myGlVerMajor (0),
200   myGlVerMinor (0),
201   myIsInitialized (Standard_False),
202   myIsStereoBuffers (Standard_False),
203   myIsGlNormalizeEnabled (Standard_False),
204   mySpriteTexUnit (Graphic3d_TextureUnit_PointSprite),
205   myHasRayTracing (Standard_False),
206   myHasRayTracingTextures (Standard_False),
207   myHasRayTracingAdaptiveSampling (Standard_False),
208   myHasRayTracingAdaptiveSamplingAtomic (Standard_False),
209   myHasPBR (Standard_False),
210   myPBREnvLUTTexUnit       (Graphic3d_TextureUnit_PbrEnvironmentLUT),
211   myPBRDiffIBLMapSHTexUnit (Graphic3d_TextureUnit_PbrIblDiffuseSH),
212   myPBRSpecIBLMapTexUnit   (Graphic3d_TextureUnit_PbrIblSpecular),
213   myShadowMapTexUnit       (Graphic3d_TextureUnit_ShadowMap),
214   myDepthPeelingDepthTexUnit (Graphic3d_TextureUnit_DepthPeelingDepth),
215   myDepthPeelingFrontColorTexUnit (Graphic3d_TextureUnit_DepthPeelingFrontColor),
216   myFrameStats (new OpenGl_FrameStats()),
217   myActiveMockTextures (0),
218   myActiveHatchType (Aspect_HS_SOLID),
219   myHatchIsEnabled (false),
220 #if !defined(GL_ES_VERSION_2_0)
221   myPointSpriteOrig (GL_UPPER_LEFT),
222   myRenderMode (GL_RENDER),
223   myShadeModel (GL_SMOOTH),
224   myPolygonMode (GL_FILL),
225 #else
226   myPointSpriteOrig (0),
227   myRenderMode (0),
228   myShadeModel (0),
229   myPolygonMode (0),
230 #endif
231   myToCullBackFaces (false),
232   myReadBuffer (0),
233   myDrawBuffers (0, 7),
234   myDefaultVao (0),
235   myColorMask (true),
236   myAlphaToCoverage (false),
237   myIsGlDebugCtx (false),
238   myIsSRgbWindow (false),
239   myResolution (Graphic3d_RenderingParams::THE_DEFAULT_RESOLUTION),
240   myResolutionRatio (1.0f),
241   myLineWidthScale (1.0f),
242   myLineFeather (1.0f),
243   myRenderScale (1.0f),
244   myRenderScaleInv (1.0f)
245 {
246   myViewport[0] = 0;
247   myViewport[1] = 0;
248   myViewport[2] = 0;
249   myViewport[3] = 0;
250   myViewportVirt[0] = 0;
251   myViewportVirt[1] = 0;
252   myViewportVirt[2] = 0;
253   myViewportVirt[3] = 0;
254
255   myPolygonOffset.Mode   = Aspect_POM_Off;
256   myPolygonOffset.Factor = 0.0f;
257   myPolygonOffset.Units  = 0.0f;
258
259   // system-dependent fields
260 #if defined(HAVE_EGL)
261   myDisplay  = (Aspect_Display          )EGL_NO_DISPLAY;
262   myWindow   = (Aspect_Drawable         )EGL_NO_SURFACE;
263   myGContext = (Aspect_RenderingContext )EGL_NO_CONTEXT;
264 #elif defined(__APPLE__) && !defined(HAVE_XLIB)
265   // Vendors can not extend functionality on this system
266   // and developers are limited to OpenGL support provided by Mac OS X SDK.
267   // We retrieve function pointers from system library
268   // to generalize extensions support on all platforms.
269   // In this way we also reach binary compatibility benefit between OS releases
270   // if some newest functionality is optionally used.
271   // Notice that GL version / extension availability checks are required
272   // because function pointers may be available but not functionality itself
273   // (depends on renderer).
274 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
275   myGlLibHandle = dlopen ("/System/Library/Frameworks/OpenGLES.framework/OpenGLES", RTLD_LAZY);
276 #else
277   myGlLibHandle = dlopen ("/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL", RTLD_LAZY);
278 #endif
279 #endif
280
281   memset (myFuncs.operator->(), 0, sizeof(OpenGl_GlFunctions));
282   myShaderManager = new OpenGl_ShaderManager (this);
283 }
284
285 // =======================================================================
286 // function : ~OpenGl_Context
287 // purpose  :
288 // =======================================================================
289 OpenGl_Context::~OpenGl_Context()
290 {
291   // release clean up queue
292   ReleaseDelayed();
293
294 #if !defined(GL_ES_VERSION_2_0)
295   // release default VAO
296   if (myDefaultVao != 0
297    && IsValid()
298    && core32 != NULL)
299   {
300     core32->glDeleteVertexArrays (1, &myDefaultVao);
301   }
302   myDefaultVao = 0;
303 #endif
304
305   // release mock textures
306   if (!myTextureRgbaBlack.IsNull())
307   {
308     myTextureRgbaBlack->Release (this);
309     myTextureRgbaBlack.Nullify();
310   }
311   if (!myTextureRgbaWhite.IsNull())
312   {
313     myTextureRgbaWhite->Release (this);
314     myTextureRgbaWhite.Nullify();
315   }
316
317   // release default FBO
318   if (!myDefaultFbo.IsNull())
319   {
320     myDefaultFbo->Release (this);
321     myDefaultFbo.Nullify();
322   }
323
324   // release shared resources if any
325   if (mySharedResources->GetRefCount() <= 1)
326   {
327     myShaderManager.Nullify();
328     for (NCollection_DataMap<TCollection_AsciiString, Handle(OpenGl_Resource)>::Iterator anIter (*mySharedResources);
329          anIter.More(); anIter.Next())
330     {
331       anIter.Value()->Release (this);
332     }
333
334     // release delayed resources added during deletion of shared resources
335     while (!myUnusedResources->IsEmpty())
336     {
337       myUnusedResources->First()->Release (this);
338       myUnusedResources->RemoveFirst();
339     }
340   }
341   else if (myShaderManager->IsSameContext (this))
342   {
343     myShaderManager->SetContext (NULL);
344   }
345   mySharedResources.Nullify();
346   myDelayed.Nullify();
347
348   if (arbDbg != NULL
349    && myIsGlDebugCtx
350    && IsValid())
351   {
352     // reset callback
353   #if !defined(GL_ES_VERSION_2_0)
354     void* aPtr = NULL;
355     glGetPointerv (GL_DEBUG_CALLBACK_USER_PARAM, &aPtr);
356     if (aPtr == this)
357   #endif
358     {
359       arbDbg->glDebugMessageCallback (NULL, NULL);
360     }
361     myIsGlDebugCtx = Standard_False;
362   }
363 }
364
365 // =======================================================================
366 // function : forcedRelease
367 // purpose  :
368 // =======================================================================
369 void OpenGl_Context::forcedRelease()
370 {
371   ReleaseDelayed();
372   for (NCollection_DataMap<TCollection_AsciiString, Handle(OpenGl_Resource)>::Iterator anIter (*mySharedResources);
373        anIter.More(); anIter.Next())
374   {
375     anIter.Value()->Release (this);
376   }
377   mySharedResources->Clear();
378   myShaderManager->clear();
379   myShaderManager->SetContext (NULL);
380
381   // release delayed resources added during deletion of shared resources
382   while (!myUnusedResources->IsEmpty())
383   {
384     myUnusedResources->First()->Release (this);
385     myUnusedResources->RemoveFirst();
386   }
387 }
388
389 // =======================================================================
390 // function : ResizeViewport
391 // purpose  :
392 // =======================================================================
393 void OpenGl_Context::ResizeViewport (const Standard_Integer* theRect)
394 {
395   core11fwd->glViewport (theRect[0], theRect[1], theRect[2], theRect[3]);
396   myViewport[0] = theRect[0];
397   myViewport[1] = theRect[1];
398   myViewport[2] = theRect[2];
399   myViewport[3] = theRect[3];
400   if (HasRenderScale())
401   {
402     myViewportVirt[0] = Standard_Integer(theRect[0] * myRenderScaleInv);
403     myViewportVirt[1] = Standard_Integer(theRect[1] * myRenderScaleInv);
404     myViewportVirt[2] = Standard_Integer(theRect[2] * myRenderScaleInv);
405     myViewportVirt[3] = Standard_Integer(theRect[3] * myRenderScaleInv);
406   }
407   else
408   {
409     myViewportVirt[0] = theRect[0];
410     myViewportVirt[1] = theRect[1];
411     myViewportVirt[2] = theRect[2];
412     myViewportVirt[3] = theRect[3];
413   }
414 }
415
416 #if !defined(GL_ES_VERSION_2_0)
417 inline Standard_Integer stereoToMonoBuffer (const Standard_Integer theBuffer)
418 {
419   switch (theBuffer)
420   {
421     case GL_BACK_LEFT:
422     case GL_BACK_RIGHT:
423       return GL_BACK;
424     case GL_FRONT_LEFT:
425     case GL_FRONT_RIGHT:
426       return GL_FRONT;
427     default:
428       return theBuffer;
429   }
430 }
431 #endif
432
433 // =======================================================================
434 // function : SetReadBuffer
435 // purpose  :
436 // =======================================================================
437 void OpenGl_Context::SetReadBuffer (const Standard_Integer theReadBuffer)
438 {
439 #if !defined(GL_ES_VERSION_2_0)
440   myReadBuffer = !myIsStereoBuffers ? stereoToMonoBuffer (theReadBuffer) : theReadBuffer;
441   if (myReadBuffer < GL_COLOR_ATTACHMENT0
442    && arbFBO != NULL)
443   {
444     arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
445   }
446   ::glReadBuffer (myReadBuffer);
447 #else
448   (void )theReadBuffer;
449 #endif
450 }
451
452 // =======================================================================
453 // function : SetDrawBuffer
454 // purpose  :
455 // =======================================================================
456 void OpenGl_Context::SetDrawBuffer (const Standard_Integer theDrawBuffer)
457 {
458 #if !defined(GL_ES_VERSION_2_0)
459   const Standard_Integer aDrawBuffer = !myIsStereoBuffers ? stereoToMonoBuffer (theDrawBuffer) : theDrawBuffer;
460   if (aDrawBuffer < GL_COLOR_ATTACHMENT0
461    && arbFBO != NULL)
462   {
463     arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
464   }
465   ::glDrawBuffer (aDrawBuffer);
466
467   myDrawBuffers.Init (GL_NONE);
468   myDrawBuffers.SetValue (0, aDrawBuffer);
469 #else
470   (void )theDrawBuffer;
471 #endif
472 }
473
474 // =======================================================================
475 // function : SetDrawBuffers
476 // purpose  :
477 // =======================================================================
478 void OpenGl_Context::SetDrawBuffers (const Standard_Integer theNb, const Standard_Integer* theDrawBuffers)
479 {
480   Standard_ASSERT_RETURN (hasDrawBuffers, "Multiple draw buffers feature is not supported by the context", Standard_ASSERT_DO_NOTHING());
481
482   if (myDrawBuffers.Length() < theNb)
483   {
484     // should actually never happen here
485     myDrawBuffers.Resize (0, theNb - 1, false);
486   }
487   myDrawBuffers.Init (GL_NONE);
488
489   Standard_Boolean useDefaultFbo = Standard_False;
490   for (Standard_Integer anI = 0; anI < theNb; ++anI)
491   {
492     if (theDrawBuffers[anI] < GL_COLOR_ATTACHMENT0 && theDrawBuffers[anI] != GL_NONE)
493     {
494       useDefaultFbo = Standard_True;
495     }
496     else
497     {
498       myDrawBuffers.SetValue (anI, theDrawBuffers[anI]);
499     }
500   }
501   if (arbFBO != NULL && useDefaultFbo)
502   {
503     arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
504   }
505
506   myFuncs->glDrawBuffers (theNb, (const GLenum*)theDrawBuffers);
507 }
508
509 // =======================================================================
510 // function : SetFrameBufferSRGB
511 // purpose  :
512 // =======================================================================
513 void OpenGl_Context::SetFrameBufferSRGB (bool theIsFbo, bool theIsFboSRgb)
514 {
515   if (!hasFboSRGB)
516   {
517     myIsSRgbActive = false;
518     return;
519   }
520   myIsSRgbActive = ToRenderSRGB()
521                && (theIsFbo || myIsSRgbWindow)
522                && theIsFboSRgb;
523   if (!hasSRGBControl)
524   {
525     return;
526   }
527
528   if (myIsSRgbActive)
529   {
530     core11fwd->glEnable (GL_FRAMEBUFFER_SRGB);
531   }
532   else
533   {
534     core11fwd->glDisable (GL_FRAMEBUFFER_SRGB);
535   }
536 }
537
538 // =======================================================================
539 // function : SetCullBackFaces
540 // purpose  :
541 // =======================================================================
542 void OpenGl_Context::SetCullBackFaces (bool theToEnable)
543 {
544   if (myToCullBackFaces == theToEnable)
545   {
546     return;
547   }
548
549   myToCullBackFaces = theToEnable;
550   if (theToEnable)
551   {
552     //glCullFace (GL_BACK); GL_BACK by default
553     core11fwd->glEnable (GL_CULL_FACE);
554   }
555   else
556   {
557     core11fwd->glDisable (GL_CULL_FACE);
558   }
559 }
560
561 // =======================================================================
562 // function : FetchState
563 // purpose  :
564 // =======================================================================
565 void OpenGl_Context::FetchState()
566 {
567 #if !defined(GL_ES_VERSION_2_0)
568   // cache feedback mode state
569   if (core11ffp != NULL)
570   {
571     ::glGetIntegerv (GL_RENDER_MODE, &myRenderMode);
572     ::glGetIntegerv (GL_SHADE_MODEL, &myShadeModel);
573   }
574
575   // cache read buffers state
576   ::glGetIntegerv (GL_READ_BUFFER, &myReadBuffer);
577
578   // cache draw buffers state
579   if (myDrawBuffers.Length() < myMaxDrawBuffers)
580   {
581     myDrawBuffers.Resize (0, myMaxDrawBuffers - 1, false);
582   }
583   myDrawBuffers.Init (GL_NONE);
584
585   Standard_Integer aDrawBuffer = GL_NONE;
586   if (myMaxDrawBuffers == 1)
587   {
588     ::glGetIntegerv (GL_DRAW_BUFFER, &aDrawBuffer);
589     myDrawBuffers.SetValue (0, aDrawBuffer);
590   }
591   else
592   {
593     for (Standard_Integer anI = 0; anI < myMaxDrawBuffers; ++anI)
594     {
595       ::glGetIntegerv (GL_DRAW_BUFFER0 + anI, &aDrawBuffer);
596       myDrawBuffers.SetValue (anI, aDrawBuffer);
597     }
598   }
599 #endif
600 }
601
602 // =======================================================================
603 // function : Share
604 // purpose  :
605 // =======================================================================
606 void OpenGl_Context::Share (const Handle(OpenGl_Context)& theShareCtx)
607 {
608   if (!theShareCtx.IsNull())
609   {
610     mySharedResources = theShareCtx->mySharedResources;
611     myDelayed         = theShareCtx->myDelayed;
612     myUnusedResources = theShareCtx->myUnusedResources;
613     myShaderManager   = theShareCtx->myShaderManager;
614   }
615 }
616
617 #if !defined(__APPLE__) || defined(HAVE_XLIB)
618
619 // =======================================================================
620 // function : IsCurrent
621 // purpose  :
622 // =======================================================================
623 Standard_Boolean OpenGl_Context::IsCurrent() const
624 {
625 #if defined(HAVE_EGL)
626   if ((EGLDisplay )myDisplay  == EGL_NO_DISPLAY
627    || (EGLContext )myGContext == EGL_NO_CONTEXT)
628   {
629     return Standard_False;
630   }
631
632   return (((EGLDisplay )myDisplay  == eglGetCurrentDisplay())
633        && ((EGLContext )myGContext == eglGetCurrentContext())
634        && ((EGLSurface )myWindow   == eglGetCurrentSurface (EGL_DRAW)));
635 #elif defined(_WIN32)
636   if (myDisplay == NULL || myGContext == NULL)
637   {
638     return Standard_False;
639   }
640   return (( (HDC )myDisplay  == wglGetCurrentDC())
641       && ((HGLRC )myGContext == wglGetCurrentContext()));
642 #elif defined(HAVE_XLIB)
643   if (myDisplay == NULL || myWindow == 0 || myGContext == 0)
644   {
645     return Standard_False;
646   }
647
648   return (   ((Display* )myDisplay  == glXGetCurrentDisplay())
649        &&  ((GLXContext )myGContext == glXGetCurrentContext())
650        && ((GLXDrawable )myWindow   == glXGetCurrentDrawable()));
651 #else
652   return Standard_False;
653 #endif
654 }
655
656 // =======================================================================
657 // function : MakeCurrent
658 // purpose  :
659 // =======================================================================
660 Standard_Boolean OpenGl_Context::MakeCurrent()
661 {
662 #if defined(HAVE_EGL)
663   if ((EGLDisplay )myDisplay  == EGL_NO_DISPLAY
664    || (EGLContext )myGContext == EGL_NO_CONTEXT)
665   {
666     Standard_ProgramError_Raise_if (myIsInitialized, "OpenGl_Context::Init() should be called before!");
667     return Standard_False;
668   }
669
670   if (eglMakeCurrent ((EGLDisplay )myDisplay, (EGLSurface )myWindow, (EGLSurface )myWindow, (EGLContext )myGContext) != EGL_TRUE)
671   {
672     // if there is no current context it might be impossible to use glGetError() correctly
673     PushMessage (GL_DEBUG_SOURCE_WINDOW_SYSTEM, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
674                  "eglMakeCurrent() has failed!");
675     myIsInitialized = Standard_False;
676     return Standard_False;
677   }
678 #elif defined(_WIN32)
679   if (myDisplay == NULL || myGContext == NULL)
680   {
681     Standard_ProgramError_Raise_if (myIsInitialized, "OpenGl_Context::Init() should be called before!");
682     return Standard_False;
683   }
684
685   // technically it should be safe to activate already bound GL context
686   // however some drivers (Intel etc.) may FAIL doing this for unknown reason
687   if (IsCurrent())
688   {
689     myShaderManager->SetContext (this);
690     return Standard_True;
691   }
692   else if (wglMakeCurrent ((HDC )myDisplay, (HGLRC )myGContext) != TRUE)
693   {
694     // notice that glGetError() couldn't be used here!
695     wchar_t* aMsgBuff = NULL;
696     DWORD anErrorCode = GetLastError();
697     FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
698                     NULL, anErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (wchar_t* )&aMsgBuff, 0, NULL);
699     TCollection_ExtendedString aMsg ("wglMakeCurrent() has failed. ");
700     if (aMsgBuff != NULL)
701     {
702       aMsg += (Standard_ExtString )aMsgBuff;
703       LocalFree (aMsgBuff);
704     }
705     PushMessage (GL_DEBUG_SOURCE_WINDOW_SYSTEM, GL_DEBUG_TYPE_ERROR, (unsigned int )anErrorCode, GL_DEBUG_SEVERITY_HIGH, aMsg);
706     myIsInitialized = Standard_False;
707     return Standard_False;
708   }
709 #elif defined(HAVE_XLIB)
710   if (myDisplay == NULL || myWindow == 0 || myGContext == 0)
711   {
712     Standard_ProgramError_Raise_if (myIsInitialized, "OpenGl_Context::Init() should be called before!");
713     return Standard_False;
714   }
715
716   if (!glXMakeCurrent ((Display* )myDisplay, (GLXDrawable )myWindow, (GLXContext )myGContext))
717   {
718     // if there is no current context it might be impossible to use glGetError() correctly
719     PushMessage (GL_DEBUG_SOURCE_WINDOW_SYSTEM, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
720                  "glXMakeCurrent() has failed!");
721     myIsInitialized = Standard_False;
722     return Standard_False;
723   }
724 #else
725   // not implemented
726   if (!myIsInitialized)
727   {
728     throw Standard_ProgramError ("OpenGl_Context::Init() should be called before!");
729   }
730 #endif
731   myShaderManager->SetContext (this);
732   return Standard_True;
733 }
734
735 // =======================================================================
736 // function : SwapBuffers
737 // purpose  :
738 // =======================================================================
739 void OpenGl_Context::SwapBuffers()
740 {
741 #if defined(HAVE_EGL)
742   if ((EGLSurface )myWindow != EGL_NO_SURFACE)
743   {
744     eglSwapBuffers ((EGLDisplay )myDisplay, (EGLSurface )myWindow);
745   }
746 #elif defined(_WIN32)
747   if ((HDC )myDisplay != NULL)
748   {
749     ::SwapBuffers ((HDC )myDisplay);
750     glFlush();
751   }
752 #elif defined(HAVE_XLIB)
753   if ((Display* )myDisplay != NULL)
754   {
755     glXSwapBuffers ((Display* )myDisplay, (GLXDrawable )myWindow);
756   }
757 #else
758   //
759 #endif
760 }
761
762 #endif // __APPLE__
763
764 // =======================================================================
765 // function : SetSwapInterval
766 // purpose  :
767 // =======================================================================
768 Standard_Boolean OpenGl_Context::SetSwapInterval (const Standard_Integer theInterval)
769 {
770 #if defined(HAVE_EGL)
771   if (::eglSwapInterval ((EGLDisplay )myDisplay, theInterval) == EGL_TRUE)
772   {
773     return Standard_True;
774   }
775 #elif defined(_WIN32)
776   if (myFuncs->wglSwapIntervalEXT != NULL)
777   {
778     myFuncs->wglSwapIntervalEXT (theInterval);
779     return Standard_True;
780   }
781 #elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
782   (void )theInterval; // vsync cannot be turned OFF on iOS
783 #elif defined(__APPLE__)
784   if (::CGLSetParameter (CGLGetCurrentContext(), kCGLCPSwapInterval, &theInterval) == kCGLNoError)
785   {
786     return Standard_True;
787   }
788 #elif defined(HAVE_XLIB)
789   if (theInterval == -1
790    && myFuncs->glXSwapIntervalEXT != NULL)
791   {
792     typedef int (*glXSwapIntervalEXT_t_x)(Display* theDisplay, GLXDrawable theDrawable, int theInterval);
793     glXSwapIntervalEXT_t_x aFuncPtr = (glXSwapIntervalEXT_t_x )myFuncs->glXSwapIntervalEXT;
794     aFuncPtr ((Display* )myDisplay, (GLXDrawable )myWindow, theInterval);
795     return Standard_True;
796   }
797   else if (myFuncs->glXSwapIntervalSGI != NULL)
798   {
799     myFuncs->glXSwapIntervalSGI (theInterval);
800     return Standard_True;
801   }
802 #else
803   //
804 #endif
805   return Standard_False;
806 }
807
808 // =======================================================================
809 // function : findProc
810 // purpose  :
811 // =======================================================================
812 void* OpenGl_Context::findProc (const char* theFuncName)
813 {
814 #if defined(HAVE_EGL)
815   return (void* )eglGetProcAddress (theFuncName);
816 #elif defined(_WIN32)
817   return (void* )wglGetProcAddress (theFuncName);
818 #elif defined(HAVE_XLIB)
819   return (void* )glXGetProcAddress ((const GLubyte* )theFuncName);
820 #elif defined(__APPLE__)
821   return (myGlLibHandle != NULL) ? dlsym (myGlLibHandle, theFuncName) : NULL;
822 #else
823   (void )theFuncName;
824   return NULL;
825 #endif
826 }
827
828 // =======================================================================
829 // function : CheckExtension
830 // purpose  :
831 // =======================================================================
832 Standard_Boolean OpenGl_Context::CheckExtension (const char* theExtName) const
833 {
834   if (theExtName  == NULL)
835   {
836 #ifdef OCCT_DEBUG
837     std::cerr << "CheckExtension called with NULL string!\n";
838 #endif
839     return Standard_False;
840   }
841   else if (caps->contextNoExtensions)
842   {
843     return Standard_False;
844   }
845
846 #if !defined(GL_ES_VERSION_2_0)
847   // available since OpenGL 3.0
848   // and the ONLY way to check extensions with OpenGL 3.1+ core profile
849   if (IsGlGreaterEqual (3, 0)
850    && myFuncs->glGetStringi != NULL)
851   {
852     GLint anExtNb = 0;
853     ::glGetIntegerv (GL_NUM_EXTENSIONS, &anExtNb);
854     const size_t anExtNameLen = strlen (theExtName);
855     for (GLint anIter = 0; anIter < anExtNb; ++anIter)
856     {
857       const char* anExtension = (const char* )myFuncs->glGetStringi (GL_EXTENSIONS, (GLuint )anIter);
858       const size_t aTestExtNameLen = strlen (anExtension);
859       if (aTestExtNameLen == anExtNameLen
860        && strncmp (anExtension, theExtName, anExtNameLen) == 0)
861       {
862         return Standard_True;
863       }
864     }
865     return Standard_False;
866   }
867 #endif
868
869   // use old way with huge string for all extensions
870   const char* anExtString = (const char* )glGetString (GL_EXTENSIONS);
871   if (anExtString == NULL)
872   {
873     Messenger()->Send ("TKOpenGL: glGetString (GL_EXTENSIONS) has returned NULL! No GL context?", Message_Warning);
874     return Standard_False;
875   }
876   if (!CheckExtension (anExtString, theExtName))
877   {
878     return Standard_False;
879   }
880
881 #ifdef __EMSCRIPTEN__
882   //! Check if WebGL extension is available and activate it
883   //! (usage of extension without activation will generate errors).
884   if (EMSCRIPTEN_WEBGL_CONTEXT_HANDLE aWebGlCtx = emscripten_webgl_get_current_context())
885   {
886     if (emscripten_webgl_enable_extension (aWebGlCtx, theExtName))
887     {
888       return Standard_True;
889     }
890   }
891   return Standard_False;
892 #else
893   return Standard_True;
894 #endif
895 }
896
897 // =======================================================================
898 // function : CheckExtension
899 // purpose  :
900 // =======================================================================
901 Standard_Boolean OpenGl_Context::CheckExtension (const char* theExtString,
902                                                  const char* theExtName)
903 {
904   if (theExtString == NULL)
905   {
906     return Standard_False;
907   }
908
909   // Search for theExtName in the extensions string.
910   // Use of strstr() is not sufficient because extension names can be prefixes of other extension names.
911   char* aPtrIter = (char* )theExtString;
912   const char*  aPtrEnd      = aPtrIter + strlen (theExtString);
913   const size_t anExtNameLen = strlen (theExtName);
914   while (aPtrIter < aPtrEnd)
915   {
916     const size_t n = strcspn (aPtrIter, " ");
917     if ((n == anExtNameLen) && (strncmp (aPtrIter, theExtName, anExtNameLen) == 0))
918     {
919       return Standard_True;
920     }
921     aPtrIter += (n + 1);
922   }
923   return Standard_False;
924 }
925
926 #if !defined(__APPLE__) || defined(HAVE_XLIB)
927
928 // =======================================================================
929 // function : Init
930 // purpose  :
931 // =======================================================================
932 Standard_Boolean OpenGl_Context::Init (const Standard_Boolean theIsCoreProfile)
933 {
934   if (myIsInitialized)
935   {
936     return Standard_True;
937   }
938
939 #if defined(HAVE_EGL)
940   myDisplay  = (Aspect_Display )eglGetCurrentDisplay();
941   myGContext = (Aspect_RenderingContext )eglGetCurrentContext();
942   myWindow   = (Aspect_Drawable )eglGetCurrentSurface(EGL_DRAW);
943 #elif defined(_WIN32)
944   myDisplay  = (Aspect_Handle )wglGetCurrentDC();
945   myGContext = (Aspect_RenderingContext )wglGetCurrentContext();
946 #elif defined(HAVE_XLIB)
947   myDisplay  = (Aspect_Display )glXGetCurrentDisplay();
948   myGContext = (Aspect_RenderingContext )glXGetCurrentContext();
949   myWindow   = (Aspect_Drawable )glXGetCurrentDrawable();
950 #else
951   //
952 #endif
953   if (myGContext == NULL)
954   {
955     return Standard_False;
956   }
957
958   init (theIsCoreProfile);
959   myIsInitialized = Standard_True;
960   return Standard_True;
961 }
962
963 #endif // __APPLE__
964
965 // =======================================================================
966 // function : Init
967 // purpose  :
968 // =======================================================================
969 Standard_Boolean OpenGl_Context::Init (const Aspect_Drawable         theSurface,
970                                        const Aspect_Display          theDisplay,
971                                        const Aspect_RenderingContext theContext,
972                                        const Standard_Boolean        theIsCoreProfile)
973 {
974   Standard_ProgramError_Raise_if (myIsInitialized, "OpenGl_Context::Init() should be called only once!");
975   myWindow   = theSurface;
976   myDisplay  = theDisplay;
977   myGContext = theContext;
978   if (myGContext == NULL || !MakeCurrent())
979   {
980     return Standard_False;
981   }
982
983   init (theIsCoreProfile);
984   myIsInitialized = Standard_True;
985   return Standard_True;
986 }
987
988 // =======================================================================
989 // function : FormatGlEnumHex
990 // purpose  :
991 // =======================================================================
992 TCollection_AsciiString OpenGl_Context::FormatGlEnumHex (int theGlEnum)
993 {
994   char aBuff[16];
995   Sprintf (aBuff, theGlEnum < (int )std::numeric_limits<uint16_t>::max()
996                 ? "0x%04X"
997                 : "0x%08X", theGlEnum);
998   return aBuff;
999 }
1000
1001 // =======================================================================
1002 // function : FormatSize
1003 // purpose  :
1004 // =======================================================================
1005 TCollection_AsciiString OpenGl_Context::FormatSize (Standard_Size theSize)
1006 {
1007   char aBuff[32];
1008   Sprintf (aBuff, "%" PRIu64, (uint64_t )theSize);
1009   return aBuff;
1010 }
1011
1012 // =======================================================================
1013 // function : FormatPointer
1014 // purpose  :
1015 // =======================================================================
1016 TCollection_AsciiString OpenGl_Context::FormatPointer (const void* thePtr)
1017 {
1018   char aBuff[32];
1019   Sprintf (aBuff, "0x%" PRIXPTR, (uintptr_t )thePtr);
1020   return aBuff;
1021 }
1022
1023 // =======================================================================
1024 // function : FormatGlError
1025 // purpose  :
1026 // =======================================================================
1027 TCollection_AsciiString OpenGl_Context::FormatGlError (int theGlError)
1028 {
1029   switch (theGlError)
1030   {
1031     case GL_INVALID_ENUM:      return "GL_INVALID_ENUM";
1032     case GL_INVALID_VALUE:     return "GL_INVALID_VALUE";
1033     case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION";
1034   #ifdef GL_STACK_OVERFLOW
1035     case GL_STACK_OVERFLOW:    return "GL_STACK_OVERFLOW";
1036     case GL_STACK_UNDERFLOW:   return "GL_STACK_UNDERFLOW";
1037   #endif
1038     case GL_OUT_OF_MEMORY:     return "GL_OUT_OF_MEMORY";
1039     case GL_INVALID_FRAMEBUFFER_OPERATION: return "GL_INVALID_FRAMEBUFFER_OPERATION";
1040   }
1041   return FormatGlEnumHex (theGlError);
1042 }
1043
1044 // =======================================================================
1045 // function : ResetErrors
1046 // purpose  :
1047 // =======================================================================
1048 bool OpenGl_Context::ResetErrors (const bool theToPrintErrors)
1049 {
1050   int aPrevErr = 0;
1051   int anErr    = ::glGetError();
1052   const bool hasError = anErr != GL_NO_ERROR;
1053   if (!theToPrintErrors)
1054   {
1055     for (; anErr != GL_NO_ERROR && aPrevErr != anErr; aPrevErr = anErr, anErr = ::glGetError())
1056     {
1057       //
1058     }
1059     return hasError;
1060   }
1061
1062   for (; anErr != GL_NO_ERROR && aPrevErr != anErr; aPrevErr = anErr, anErr = ::glGetError())
1063   {
1064     const TCollection_ExtendedString aMsg = TCollection_ExtendedString ("Unhandled GL error: ") + FormatGlError (anErr);
1065     PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_OTHER, 0, GL_DEBUG_SEVERITY_LOW, aMsg);
1066   }
1067   return hasError;
1068 }
1069
1070 // =======================================================================
1071 // function : debugPrintError
1072 // purpose  :
1073 // =======================================================================
1074 bool OpenGl_GlFunctions::debugPrintError (const char* theName) const
1075 {
1076   const int anErr = ::glGetError();
1077   if (anErr != GL_NO_ERROR)
1078   {
1079     Message::SendFail() << theName << "(), unhandled GL error: " << OpenGl_Context::FormatGlError (anErr);
1080     // there is no glSetError(), just emulate non-clear state
1081     switch (anErr)
1082     {
1083       case GL_INVALID_VALUE:
1084       {
1085         ::glLineWidth(-1.0f);
1086         ::glLineWidth( 1.0f);
1087         break;
1088       }
1089       default:
1090       case GL_INVALID_ENUM:
1091       {
1092         ::glEnable (0xFFFF);
1093         break;
1094       }
1095     }
1096   }
1097   return anErr != GL_NO_ERROR;
1098 }
1099
1100 // =======================================================================
1101 // function : ReadGlVersion
1102 // purpose  :
1103 // =======================================================================
1104 void OpenGl_Context::ReadGlVersion (Standard_Integer& theGlVerMajor,
1105                                     Standard_Integer& theGlVerMinor)
1106 {
1107   // reset values
1108   theGlVerMajor = 0;
1109   theGlVerMinor = 0;
1110
1111   bool toCheckVer3 = true;
1112 #if defined(__EMSCRIPTEN__)
1113   // WebGL 1.0 prints annoying invalid enumeration warnings to console.
1114   toCheckVer3 = false;
1115   if (EMSCRIPTEN_WEBGL_CONTEXT_HANDLE aWebGlCtx = emscripten_webgl_get_current_context())
1116   {
1117     EmscriptenWebGLContextAttributes anAttribs = {};
1118     if (emscripten_webgl_get_context_attributes (aWebGlCtx, &anAttribs) == EMSCRIPTEN_RESULT_SUCCESS)
1119     {
1120       toCheckVer3 = anAttribs.majorVersion >= 2;
1121     }
1122   }
1123 #endif
1124
1125   // Available since OpenGL 3.0 and OpenGL ES 3.0.
1126   if (toCheckVer3)
1127   {
1128     GLint aMajor = 0, aMinor = 0;
1129     glGetIntegerv (GL_MAJOR_VERSION, &aMajor);
1130     glGetIntegerv (GL_MINOR_VERSION, &aMinor);
1131     // glGetError() sometimes does not report an error here even if
1132     // GL does not know GL_MAJOR_VERSION and GL_MINOR_VERSION constants.
1133     // This happens on some renderers like e.g. Cygwin MESA.
1134     // Thus checking additionally if GL has put anything to
1135     // the output variables.
1136     if (::glGetError() == GL_NO_ERROR && aMajor != 0 && aMinor != 0)
1137     {
1138       theGlVerMajor = aMajor;
1139       theGlVerMinor = aMinor;
1140       return;
1141     }
1142     for (GLenum anErr = ::glGetError(), aPrevErr = GL_NO_ERROR;; aPrevErr = anErr, anErr = ::glGetError())
1143     {
1144       if (anErr == GL_NO_ERROR
1145        || anErr == aPrevErr)
1146       {
1147         break;
1148       }
1149     }
1150   }
1151
1152   // Read version string.
1153   // Notice that only first two numbers split by point '2.1 XXXXX' are significant.
1154   // Following trash (after space) is vendor-specific.
1155   // New drivers also returns micro version of GL like '3.3.0' which has no meaning
1156   // and should be considered as vendor-specific too.
1157   const char* aVerStr = (const char* )glGetString (GL_VERSION);
1158   if (aVerStr == NULL || *aVerStr == '\0')
1159   {
1160     // invalid GL context
1161     return;
1162   }
1163
1164 //#if defined(GL_ES_VERSION_2_0)
1165   // skip "OpenGL ES-** " section
1166   for (; *aVerStr != '\0'; ++aVerStr)
1167   {
1168     if (*aVerStr >= '0' && *aVerStr <= '9')
1169     {
1170       break;
1171     }
1172   }
1173 //#endif
1174
1175   // parse string for major number
1176   char aMajorStr[32];
1177   char aMinorStr[32];
1178   size_t aMajIter = 0;
1179   while (aVerStr[aMajIter] >= '0' && aVerStr[aMajIter] <= '9')
1180   {
1181     ++aMajIter;
1182   }
1183   if (aMajIter == 0 || aMajIter >= sizeof(aMajorStr))
1184   {
1185     return;
1186   }
1187   memcpy (aMajorStr, aVerStr, aMajIter);
1188   aMajorStr[aMajIter] = '\0';
1189
1190   // parse string for minor number
1191   aVerStr += aMajIter + 1;
1192   size_t aMinIter = 0;
1193   while (aVerStr[aMinIter] >= '0' && aVerStr[aMinIter] <= '9')
1194   {
1195     ++aMinIter;
1196   }
1197   if (aMinIter == 0 || aMinIter >= sizeof(aMinorStr))
1198   {
1199     return;
1200   }
1201   memcpy (aMinorStr, aVerStr, aMinIter);
1202   aMinorStr[aMinIter] = '\0';
1203
1204   // read numbers
1205   theGlVerMajor = atoi (aMajorStr);
1206   theGlVerMinor = atoi (aMinorStr);
1207 #if defined(__EMSCRIPTEN__)
1208   if (theGlVerMajor >= 3)
1209   {
1210     if (!toCheckVer3
1211      || ::strstr (aVerStr, "WebGL 1.0") != NULL)
1212     {
1213       Message::SendWarning() << "Warning! OpenGL context reports version " << theGlVerMajor << "." << theGlVerMinor
1214                              << " but WebGL 2.0 was unavailable\n"
1215                              << "Fallback to OpenGL ES 2.0 will be used instead of reported version";
1216       theGlVerMajor = 2;
1217       theGlVerMinor = 0;
1218     }
1219   }
1220 #endif
1221
1222   if (theGlVerMajor <= 0)
1223   {
1224     theGlVerMajor = 0;
1225     theGlVerMinor = 0;
1226   }
1227 }
1228
1229 static Standard_CString THE_DBGMSG_UNKNOWN = "UNKNOWN";
1230 static Standard_CString THE_DBGMSG_SOURCES[] =
1231 {
1232   ".OpenGL",    // GL_DEBUG_SOURCE_API
1233   ".WinSystem", // GL_DEBUG_SOURCE_WINDOW_SYSTEM
1234   ".GLSL",      // GL_DEBUG_SOURCE_SHADER_COMPILER
1235   ".3rdParty",  // GL_DEBUG_SOURCE_THIRD_PARTY
1236   "",           // GL_DEBUG_SOURCE_APPLICATION
1237   ".Other"      // GL_DEBUG_SOURCE_OTHER
1238 };
1239
1240 static Standard_CString THE_DBGMSG_TYPES[] =
1241 {
1242   "Error",           // GL_DEBUG_TYPE_ERROR
1243   "Deprecated",      // GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR
1244   "Undef. behavior", // GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR
1245   "Portability",     // GL_DEBUG_TYPE_PORTABILITY
1246   "Performance",     // GL_DEBUG_TYPE_PERFORMANCE
1247   "Other"            // GL_DEBUG_TYPE_OTHER
1248 };
1249
1250 static Standard_CString THE_DBGMSG_SEV_HIGH   = "High";   // GL_DEBUG_SEVERITY_HIGH
1251 static Standard_CString THE_DBGMSG_SEV_MEDIUM = "Medium"; // GL_DEBUG_SEVERITY_MEDIUM
1252 static Standard_CString THE_DBGMSG_SEV_LOW    = "Low";    // GL_DEBUG_SEVERITY_LOW
1253
1254 //! Callback for GL_ARB_debug_output extension
1255 static void APIENTRY debugCallbackWrap(unsigned int theSource,
1256                                        unsigned int theType,
1257                                        unsigned int theId,
1258                                        unsigned int theSeverity,
1259                                        int          /*theLength*/,
1260                                        const char*  theMessage,
1261                                        const void*  theUserParam)
1262 {
1263   OpenGl_Context* aCtx = (OpenGl_Context* )theUserParam;
1264   aCtx->PushMessage (theSource, theType, theId, theSeverity, theMessage);
1265 }
1266
1267 // =======================================================================
1268 // function : PushMessage
1269 // purpose  :
1270 // =======================================================================
1271 void OpenGl_Context::PushMessage (const unsigned int theSource,
1272                                   const unsigned int theType,
1273                                   const unsigned int theId,
1274                                   const unsigned int theSeverity,
1275                                   const TCollection_ExtendedString& theMessage)
1276 {
1277   if (caps->suppressExtraMsg
1278    && theSource >= GL_DEBUG_SOURCE_API
1279    && theSource <= GL_DEBUG_SOURCE_OTHER
1280    && myFilters[theSource - GL_DEBUG_SOURCE_API].Contains (theId))
1281   {
1282     return;
1283   }
1284
1285   Standard_CString& aSrc = (theSource >= GL_DEBUG_SOURCE_API
1286                         && theSource <= GL_DEBUG_SOURCE_OTHER)
1287                          ? THE_DBGMSG_SOURCES[theSource - GL_DEBUG_SOURCE_API]
1288                          : THE_DBGMSG_UNKNOWN;
1289   Standard_CString& aType = (theType >= GL_DEBUG_TYPE_ERROR
1290                          && theType <= GL_DEBUG_TYPE_OTHER)
1291                           ? THE_DBGMSG_TYPES[theType - GL_DEBUG_TYPE_ERROR]
1292                           : THE_DBGMSG_UNKNOWN;
1293   Standard_CString& aSev = theSeverity == GL_DEBUG_SEVERITY_HIGH
1294                          ? THE_DBGMSG_SEV_HIGH
1295                          : (theSeverity == GL_DEBUG_SEVERITY_MEDIUM
1296                           ? THE_DBGMSG_SEV_MEDIUM
1297                           : THE_DBGMSG_SEV_LOW);
1298   Message_Gravity aGrav = theSeverity == GL_DEBUG_SEVERITY_HIGH
1299                         ? Message_Alarm
1300                         : (theSeverity == GL_DEBUG_SEVERITY_MEDIUM
1301                          ? Message_Warning
1302                          : Message_Info);
1303
1304   TCollection_ExtendedString aMsg;
1305   aMsg += "TKOpenGl"; aMsg += aSrc;
1306   aMsg += " | Type: ";        aMsg += aType;
1307   aMsg += " | ID: ";          aMsg += (Standard_Integer )theId;
1308   aMsg += " | Severity: ";    aMsg += aSev;
1309   aMsg += " | Message:\n  ";
1310   aMsg += theMessage;
1311   Messenger()->Send (aMsg, aGrav);
1312 }
1313
1314 // =======================================================================
1315 // function : ExcludeMessage
1316 // purpose  :
1317 // ======================================================================
1318 Standard_Boolean OpenGl_Context::ExcludeMessage (const unsigned int theSource,
1319                                                  const unsigned int theId)
1320 {
1321   return theSource >= GL_DEBUG_SOURCE_API
1322       && theSource <= GL_DEBUG_SOURCE_OTHER
1323       && myFilters[theSource - GL_DEBUG_SOURCE_API].Add (theId);
1324 }
1325
1326 // =======================================================================
1327 // function : IncludeMessage
1328 // purpose  :
1329 // ======================================================================
1330 Standard_Boolean OpenGl_Context::IncludeMessage (const unsigned int theSource,
1331                                                  const unsigned int theId)
1332 {
1333   return theSource >= GL_DEBUG_SOURCE_API
1334       && theSource <= GL_DEBUG_SOURCE_OTHER
1335       && myFilters[theSource - GL_DEBUG_SOURCE_API].Remove (theId);
1336 }
1337
1338 // =======================================================================
1339 // function : checkWrongVersion
1340 // purpose  :
1341 // ======================================================================
1342 void OpenGl_Context::checkWrongVersion (Standard_Integer theGlVerMajor, Standard_Integer theGlVerMinor,
1343                                         const char* theLastFailedProc)
1344 {
1345   if (!IsGlGreaterEqual (theGlVerMajor, theGlVerMinor))
1346   {
1347     return;
1348   }
1349
1350   PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
1351                TCollection_AsciiString()
1352                + "Error! OpenGL context reports version "
1353                + myGlVerMajor  + "." + myGlVerMinor
1354                + " but does not export required functions for " + theGlVerMajor + "." + theGlVerMinor
1355                + " (" + (theLastFailedProc != NULL ? theLastFailedProc : "") + ")\n"
1356                + "Please report this issue to OpenGL driver vendor '" + myVendor + "'");
1357
1358   // lower internal version
1359   if (theGlVerMinor > 0)
1360   {
1361     myGlVerMajor = theGlVerMajor;
1362     myGlVerMinor = theGlVerMinor - 1;
1363     return;
1364   }
1365 #if defined(GL_ES_VERSION_2_0)
1366   switch (theGlVerMajor)
1367   {
1368     case 3: myGlVerMajor = 2; myGlVerMinor = 0; return;
1369   }
1370 #else
1371   switch (theGlVerMajor)
1372   {
1373     case 2: myGlVerMajor = 1; myGlVerMinor = 5; return;
1374     case 3: myGlVerMajor = 2; myGlVerMinor = 1; return;
1375     case 4: myGlVerMajor = 3; myGlVerMinor = 3; return;
1376   }
1377 #endif
1378 }
1379
1380 // =======================================================================
1381 // function : init
1382 // purpose  :
1383 // =======================================================================
1384 void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
1385 {
1386   // read version
1387   myGlVerMajor = 0;
1388   myGlVerMinor = 0;
1389   myMaxMsaaSamples = 0;
1390   myMaxDrawBuffers = 1;
1391   myMaxColorAttachments = 1;
1392   myDefaultVao = 0;
1393   ReadGlVersion (myGlVerMajor, myGlVerMinor);
1394   myVendor = (const char* )::glGetString (GL_VENDOR);
1395   myVendor.LowerCase();
1396   mySupportedFormats->Clear();
1397
1398   if (caps->contextMajorVersionUpper != -1)
1399   {
1400     // synthetically restrict OpenGL version for testing
1401     Standard_Integer aCtxVer[2] = { myGlVerMajor, myGlVerMinor };
1402     bool isLowered = false;
1403     if (myGlVerMajor > caps->contextMajorVersionUpper)
1404     {
1405       isLowered = true;
1406       myGlVerMajor = caps->contextMajorVersionUpper;
1407     #if defined(GL_ES_VERSION_2_0)
1408       switch (myGlVerMajor)
1409       {
1410         case 2: myGlVerMinor = 0; break;
1411       }
1412     #else
1413       switch (myGlVerMajor)
1414       {
1415         case 1: myGlVerMinor = 5; break;
1416         case 2: myGlVerMinor = 1; break;
1417         case 3: myGlVerMinor = 3; break;
1418       }
1419     #endif
1420     }
1421     if (caps->contextMinorVersionUpper != -1
1422      && myGlVerMinor > caps->contextMinorVersionUpper)
1423     {
1424       isLowered = true;
1425       myGlVerMinor = caps->contextMinorVersionUpper;
1426     }
1427     if (isLowered)
1428     {
1429       PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
1430                    TCollection_AsciiString ("OpenGL version ") + aCtxVer[0] + "." + aCtxVer[1]
1431                    + " has been lowered to " + myGlVerMajor + "." + myGlVerMinor);
1432     }
1433   }
1434
1435   if (!caps->ffpEnable
1436    && !IsGlGreaterEqual (2, 0))
1437   {
1438     caps->ffpEnable = true;
1439     TCollection_ExtendedString aMsg =
1440       TCollection_ExtendedString("OpenGL driver is too old! Context info:\n")
1441                                + "    Vendor:   " + (const char* )::glGetString (GL_VENDOR)   + "\n"
1442                                + "    Renderer: " + (const char* )::glGetString (GL_RENDERER) + "\n"
1443                                + "    Version:  " + (const char* )::glGetString (GL_VERSION)  + "\n"
1444                                + "  Fallback using deprecated fixed-function pipeline.\n"
1445                                + "  Visualization might work incorrectly.\n"
1446                                  "  Consider upgrading the graphics driver.";
1447     PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, aMsg);
1448   }
1449
1450 #if defined(GL_ES_VERSION_2_0)
1451   (void )theIsCoreProfile;
1452   const bool isCoreProfile = false;
1453 #else
1454
1455   if (myVendor.Search ("nvidia") != -1)
1456   {
1457     // Buffer detailed info: Buffer object 1 (bound to GL_ARRAY_BUFFER_ARB, usage hint is GL_STATIC_DRAW)
1458     // will use VIDEO memory as the source for buffer object operations.
1459     ExcludeMessage (GL_DEBUG_SOURCE_API, 131185);
1460   }
1461   if (IsGlGreaterEqual (3, 0))
1462   {
1463     // retrieve auxiliary function in advance
1464     FindProc ("glGetStringi", myFuncs->glGetStringi);
1465   }
1466
1467   bool isCoreProfile = false;
1468   if (IsGlGreaterEqual (3, 2))
1469   {
1470     isCoreProfile = (theIsCoreProfile == Standard_True);
1471
1472     // detect Core profile
1473     if (!isCoreProfile)
1474     {
1475       GLint aProfile = 0;
1476       ::glGetIntegerv (GL_CONTEXT_PROFILE_MASK, &aProfile);
1477       isCoreProfile = (aProfile & GL_CONTEXT_CORE_PROFILE_BIT) != 0;
1478     }
1479   }
1480 #endif
1481
1482   myFuncs->load (*this, isCoreProfile);
1483
1484   // setup shader generator
1485   myShaderManager->SetGapiVersion (myGlVerMajor, myGlVerMinor);
1486   myShaderManager->SetEmulateDepthClamp (!arbDepthClamp);
1487
1488   bool toReverseDFdxSign = false;
1489 #if defined(GL_ES_VERSION_2_0)
1490   // workaround Adreno driver bug computing reversed normal using dFdx/dFdy
1491   toReverseDFdxSign = myVendor.Search("qualcomm") != -1;
1492 #endif
1493   myShaderManager->SetFlatShading (hasFlatShading != OpenGl_FeatureNotAvailable, toReverseDFdxSign);
1494 #if defined(GL_ES_VERSION_2_0)
1495   myShaderManager->SetUseRedAlpha (false);
1496 #else
1497   myShaderManager->SetUseRedAlpha (core11ffp == NULL);
1498 #endif
1499   #define checkGlslExtensionShort(theName) myShaderManager->EnableGlslExtension (Graphic3d_GlslExtension_ ## theName, CheckExtension (#theName))
1500 #if defined(GL_ES_VERSION_2_0)
1501   checkGlslExtensionShort(GL_OES_standard_derivatives);
1502   checkGlslExtensionShort(GL_EXT_shader_texture_lod);
1503   checkGlslExtensionShort(GL_EXT_frag_depth);
1504 #else
1505   checkGlslExtensionShort(GL_EXT_gpu_shader4);
1506 #endif
1507
1508   // initialize debug context extension
1509   if (arbDbg != NULL
1510    && caps->contextDebug)
1511   {
1512     // setup default callback
1513     myIsGlDebugCtx = Standard_True;
1514     arbDbg->glDebugMessageCallback (debugCallbackWrap, this);
1515   #if defined(GL_ES_VERSION_2_0)
1516     ::glEnable (GL_DEBUG_OUTPUT);
1517   #else
1518     if (core43 != NULL)
1519     {
1520       ::glEnable (GL_DEBUG_OUTPUT);
1521     }
1522   #endif
1523     if (caps->contextSyncDebug)
1524     {
1525       // note that some broken implementations (e.g. simulators) might generate error message on this call
1526       ::glEnable (GL_DEBUG_OUTPUT_SYNCHRONOUS);
1527     }
1528   }
1529
1530   if (hasDrawBuffers)
1531   {
1532     glGetIntegerv (GL_MAX_DRAW_BUFFERS,      &myMaxDrawBuffers);
1533     glGetIntegerv (GL_MAX_COLOR_ATTACHMENTS, &myMaxColorAttachments);
1534     if (myDrawBuffers.Length() < myMaxDrawBuffers)
1535     {
1536       myDrawBuffers.Resize (0, myMaxDrawBuffers - 1, false);
1537     }
1538   }
1539
1540   glGetIntegerv (GL_MAX_TEXTURE_SIZE, &myMaxTexDim);
1541 #if !defined(GL_ES_VERSION_2_0)
1542   if (IsGlGreaterEqual (1, 3) && core11ffp != NULL)
1543   {
1544     // this is a maximum of texture units for FFP functionality,
1545     // usually smaller than combined texture units available for GLSL
1546     glGetIntegerv (GL_MAX_TEXTURE_UNITS, &myMaxTexUnitsFFP);
1547     myMaxTexCombined = myMaxTexUnitsFFP;
1548   }
1549 #endif
1550   if (IsGlGreaterEqual (2, 0))
1551   {
1552     glGetIntegerv (GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &myMaxTexCombined);
1553   }
1554   mySpriteTexUnit = myMaxTexCombined >= 2
1555                   ? Graphic3d_TextureUnit_PointSprite
1556                   : Graphic3d_TextureUnit_0;
1557
1558   GLint aMaxVPortSize[2] = {0, 0};
1559   glGetIntegerv (GL_MAX_VIEWPORT_DIMS, aMaxVPortSize);
1560   myMaxDumpSizeX = Min (aMaxVPortSize[0], myMaxTexDim);
1561   myMaxDumpSizeY = Min (aMaxVPortSize[1], myMaxTexDim);
1562   if (myVendor == "intel")
1563   {
1564     // Intel drivers have known bug with empty dump for images with width>=5462
1565     myMaxDumpSizeX = Min (myMaxDumpSizeX, 4096);
1566   }
1567
1568   if (extAnis)
1569   {
1570     glGetIntegerv (GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &myAnisoMax);
1571   }
1572
1573   myClippingState.Init();
1574
1575 #if defined(GL_ES_VERSION_2_0)
1576   if (IsGlGreaterEqual (3, 1)
1577    && myFuncs->glTexStorage2DMultisample != NULL)
1578   {
1579     // MSAA RenderBuffers have been defined in OpenGL ES 3.0,
1580     // but MSAA Textures - only in OpenGL ES 3.1+
1581     ::glGetIntegerv (GL_MAX_SAMPLES, &myMaxMsaaSamples);
1582   }
1583 #else
1584   if (core30 != NULL)
1585   {
1586     // MSAA RenderBuffers have been defined in OpenGL 3.0,
1587     // but MSAA Textures - only in OpenGL 3.2+
1588     if (core32 != NULL)
1589     {
1590       ::glGetIntegerv (GL_MAX_SAMPLES, &myMaxMsaaSamples);
1591     }
1592     else if (CheckExtension ("GL_ARB_texture_multisample")
1593           && myFuncs->glTexImage2DMultisample != NULL)
1594     {
1595       GLint aNbColorSamples = 0, aNbDepthSamples = 0;
1596       ::glGetIntegerv (GL_MAX_COLOR_TEXTURE_SAMPLES, &aNbColorSamples);
1597       ::glGetIntegerv (GL_MAX_DEPTH_TEXTURE_SAMPLES, &aNbDepthSamples);
1598       myMaxMsaaSamples = Min (aNbColorSamples, aNbDepthSamples);
1599     }
1600   }
1601 #endif
1602
1603 #if !defined(GL_ES_VERSION_2_0)
1604   if (core32 != NULL && isCoreProfile)
1605   {
1606     core32->glGenVertexArrays (1, &myDefaultVao);
1607   }
1608
1609   myTexClamp = IsGlGreaterEqual (1, 2) ? GL_CLAMP_TO_EDGE : GL_CLAMP;
1610
1611   GLint aStereo = GL_FALSE;
1612   glGetIntegerv (GL_STEREO, &aStereo);
1613   myIsStereoBuffers = aStereo == 1;
1614
1615   // get number of maximum clipping planes
1616   glGetIntegerv (GL_MAX_CLIP_PLANES, &myMaxClipPlanes);
1617 #endif
1618
1619 #if defined(GL_ES_VERSION_2_0)
1620   // check whether ray tracing mode is supported
1621   myHasRayTracing = IsGlGreaterEqual (3, 2);
1622   myHasRayTracingTextures = myHasRayTracingAdaptiveSampling = myHasRayTracingAdaptiveSamplingAtomic = false;
1623 #else
1624   // check whether ray tracing mode is supported
1625   myHasRayTracing = IsGlGreaterEqual (3, 1)
1626                  && arbTboRGB32
1627                  && arbFBOBlit  != NULL;
1628
1629   // check whether textures in ray tracing mode are supported
1630   myHasRayTracingTextures = myHasRayTracing
1631                          && arbTexBindless != NULL;
1632
1633   // check whether adaptive screen sampling in ray tracing mode is supported
1634   myHasRayTracingAdaptiveSampling = myHasRayTracing
1635                                  && core44 != NULL;
1636   myHasRayTracingAdaptiveSamplingAtomic = myHasRayTracingAdaptiveSampling
1637                                        && CheckExtension ("GL_NV_shader_atomic_float");
1638 #endif
1639
1640   if (arbFBO != NULL
1641    && hasFboSRGB)
1642   {
1643     // Detect if window buffer is considered by OpenGL as sRGB-ready
1644     // (linear RGB color written by shader is automatically converted into sRGB)
1645     // or not (offscreen FBO should be blit into window buffer with gamma correction).
1646     const GLenum aDefWinBuffer =
1647     #if !defined(GL_ES_VERSION_2_0)
1648       GL_BACK_LEFT;
1649     #else
1650       GL_BACK;
1651     #endif
1652     GLint aWinColorEncoding = 0; // GL_LINEAR
1653     bool toSkipCheck = false;
1654   #if defined(GL_ES_VERSION_2_0)
1655     toSkipCheck = !IsGlGreaterEqual (3, 0);
1656   #endif
1657     if (!toSkipCheck)
1658     {
1659       arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, aDefWinBuffer, GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING, &aWinColorEncoding);
1660       ResetErrors (true);
1661     }
1662     myIsSRgbWindow = aWinColorEncoding == GL_SRGB;
1663
1664     // On desktop OpenGL, pixel formats are almost always sRGB-ready, even when not requested;
1665     // it is safe behavior on desktop where GL_FRAMEBUFFER_SRGB is disabled by default
1666     // (contrary to OpenGL ES, where it is enabled by default).
1667     // NVIDIA drivers, however, always return GL_LINEAR even for sRGB-ready pixel formats on Windows platform,
1668     // while AMD and Intel report GL_SRGB as expected.
1669     // macOS drivers seems to be also report GL_LINEAR even for [NSColorSpace sRGBColorSpace].
1670   #if !defined(GL_ES_VERSION_2_0)
1671   #ifdef __APPLE__
1672     myIsSRgbWindow = true;
1673   #else
1674     if (!myIsSRgbWindow
1675       && myVendor.Search ("nvidia") != -1)
1676     {
1677       myIsSRgbWindow = true;
1678     }
1679   #endif
1680   #endif
1681     if (!myIsSRgbWindow)
1682     {
1683       Message::SendTrace ("OpenGl_Context, warning: window buffer is not sRGB-ready.\n"
1684                           "Check OpenGL window creation parameters for optimal performance.");
1685     }
1686   }
1687
1688   // standard formats
1689   mySupportedFormats->Add (Image_Format_Gray);
1690   mySupportedFormats->Add (Image_Format_Alpha);
1691   mySupportedFormats->Add (Image_Format_RGB);
1692   mySupportedFormats->Add (Image_Format_RGB32);
1693   mySupportedFormats->Add (Image_Format_RGBA);
1694   if (extBgra)
1695   {
1696   #if !defined(GL_ES_VERSION_2_0)
1697     // no BGR on OpenGL ES - only BGRA as extension
1698     mySupportedFormats->Add (Image_Format_BGR);
1699   #endif
1700     mySupportedFormats->Add (Image_Format_BGR32);
1701     mySupportedFormats->Add (Image_Format_BGRA);
1702   }
1703   if (arbTexFloat)
1704   {
1705     mySupportedFormats->Add (Image_Format_GrayF);
1706     mySupportedFormats->Add (Image_Format_AlphaF);
1707     mySupportedFormats->Add (Image_Format_RGBF);
1708     mySupportedFormats->Add (Image_Format_RGBAF);
1709     if (hasHalfFloatBuffer != OpenGl_FeatureNotAvailable)
1710     {
1711       mySupportedFormats->Add (Image_Format_RGBAF_half);
1712     }
1713     if (arbTexRG)
1714     {
1715       mySupportedFormats->Add (Image_Format_RGF);
1716       if (hasHalfFloatBuffer != OpenGl_FeatureNotAvailable)
1717       {
1718         mySupportedFormats->Add (Image_Format_RGF_half);
1719       }
1720     }
1721     if (extBgra)
1722     {
1723     #if !defined(GL_ES_VERSION_2_0)
1724       mySupportedFormats->Add (Image_Format_BGRF);
1725     #endif
1726       mySupportedFormats->Add (Image_Format_BGRAF);
1727     }
1728   }
1729
1730 #ifdef __EMSCRIPTEN__
1731   if (CheckExtension ("GL_WEBGL_compressed_texture_s3tc")) // GL_WEBGL_compressed_texture_s3tc_srgb for sRGB formats
1732   {
1733     mySupportedFormats->Add (Image_CompressedFormat_RGB_S3TC_DXT1);
1734     mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT1);
1735     mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT3);
1736     mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT5);
1737   }
1738   if (!extPDS
1739     && CheckExtension ("GL_WEBGL_depth_texture"))
1740   {
1741     extPDS = true; // WebGL 1.0 extension (in WebGL 2.0 core)
1742   }
1743 #else
1744   if (CheckExtension ("GL_EXT_texture_compression_s3tc")) // GL_EXT_texture_sRGB for sRGB formats
1745   {
1746     mySupportedFormats->Add (Image_CompressedFormat_RGB_S3TC_DXT1);
1747     mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT1);
1748     mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT3);
1749     mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT5);
1750   }
1751   else
1752   {
1753     if (CheckExtension ("GL_EXT_texture_compression_dxt1"))
1754     {
1755       mySupportedFormats->Add (Image_CompressedFormat_RGB_S3TC_DXT1);
1756       mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT1);
1757     }
1758     if (CheckExtension ("GL_ANGLE_texture_compression_dxt3"))
1759     {
1760       mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT3);
1761     }
1762     if (CheckExtension ("GL_ANGLE_texture_compression_dxt5"))
1763     {
1764       mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT5);
1765     }
1766   }
1767 #endif
1768
1769   // check whether PBR shading model is supported
1770   myHasPBR = arbFBO != NULL
1771           && myMaxTexCombined >= 4
1772           && arbTexFloat
1773           && (IsGlGreaterEqual (3, 0)
1774         #if defined(GL_ES_VERSION_2_0)
1775            || hasHighp
1776         // || CheckExtension ("GL_EXT_shader_texture_lod") fallback is used when extension is unavailable
1777         #else
1778           || (IsGlGreaterEqual (2, 1) && CheckExtension ("GL_EXT_gpu_shader4"))
1779         #endif
1780              );
1781
1782   myDepthPeelingDepthTexUnit      = static_cast<Graphic3d_TextureUnit>(myMaxTexCombined + Graphic3d_TextureUnit_DepthPeelingDepth);      // -6
1783   myDepthPeelingFrontColorTexUnit = static_cast<Graphic3d_TextureUnit>(myMaxTexCombined + Graphic3d_TextureUnit_DepthPeelingFrontColor); // -5
1784   myShadowMapTexUnit              = static_cast<Graphic3d_TextureUnit>(myMaxTexCombined + Graphic3d_TextureUnit_ShadowMap);              // -4
1785   myPBREnvLUTTexUnit              = static_cast<Graphic3d_TextureUnit>(myMaxTexCombined + Graphic3d_TextureUnit_PbrEnvironmentLUT);      // -3
1786   myPBRDiffIBLMapSHTexUnit        = static_cast<Graphic3d_TextureUnit>(myMaxTexCombined + Graphic3d_TextureUnit_PbrIblDiffuseSH);        // -2
1787   myPBRSpecIBLMapTexUnit          = static_cast<Graphic3d_TextureUnit>(myMaxTexCombined + Graphic3d_TextureUnit_PbrIblSpecular);         // -1
1788   if (!myHasPBR)
1789   {
1790     myDepthPeelingDepthTexUnit      = static_cast<Graphic3d_TextureUnit>(myDepthPeelingDepthTexUnit + 3);
1791     myDepthPeelingFrontColorTexUnit = static_cast<Graphic3d_TextureUnit>(myDepthPeelingFrontColorTexUnit + 3);
1792     myShadowMapTexUnit              = static_cast<Graphic3d_TextureUnit>(myShadowMapTexUnit + 3);
1793   }
1794 }
1795
1796 // =======================================================================
1797 // function : MemoryInfo
1798 // purpose  :
1799 // =======================================================================
1800 Standard_Size OpenGl_Context::AvailableMemory() const
1801 {
1802 #if !defined(GL_ES_VERSION_2_0)
1803   if (atiMem)
1804   {
1805     // this is actually information for VBO pool
1806     // however because pools are mostly shared
1807     // it can be used for total GPU memory estimations
1808     GLint aMemInfo[4];
1809     aMemInfo[0] = 0;
1810     glGetIntegerv (GL_VBO_FREE_MEMORY_ATI, aMemInfo);
1811     // returned value is in KiB, however this maybe changed in future
1812     return Standard_Size(aMemInfo[0]) * 1024;
1813   }
1814   else if (nvxMem)
1815   {
1816     // current available dedicated video memory (in KiB), currently unused GPU memory
1817     GLint aMemInfo = 0;
1818     glGetIntegerv (GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &aMemInfo);
1819     return Standard_Size(aMemInfo) * 1024;
1820   }
1821 #endif
1822   return 0;
1823 }
1824
1825 // =======================================================================
1826 // function : MemoryInfo
1827 // purpose  :
1828 // =======================================================================
1829 TCollection_AsciiString OpenGl_Context::MemoryInfo() const
1830 {
1831   TColStd_IndexedDataMapOfStringString aDict;
1832   MemoryInfo (aDict);
1833
1834   TCollection_AsciiString aText;
1835   for (TColStd_IndexedDataMapOfStringString::Iterator anIter (aDict); anIter.More(); anIter.Next())
1836   {
1837     if (!aText.IsEmpty())
1838     {
1839       aText += "\n";
1840     }
1841     aText += TCollection_AsciiString("  ") + anIter.Key() + ": " + anIter.Value();
1842   }
1843   return aText;
1844 }
1845
1846 // =======================================================================
1847 // function : MemoryInfo
1848 // purpose  :
1849 // =======================================================================
1850 void OpenGl_Context::MemoryInfo (TColStd_IndexedDataMapOfStringString& theDict) const
1851 {
1852 #if defined(GL_ES_VERSION_2_0)
1853   (void )theDict;
1854 #elif defined(__APPLE__) && !defined(HAVE_XLIB)
1855   GLint aGlRendId = 0;
1856   CGLGetParameter (CGLGetCurrentContext(), kCGLCPCurrentRendererID, &aGlRendId);
1857
1858   CGLRendererInfoObj  aRendObj = NULL;
1859   CGOpenGLDisplayMask aDispMask = CGDisplayIDToOpenGLDisplayMask (kCGDirectMainDisplay);
1860   GLint aRendNb = 0;
1861   CGLQueryRendererInfo (aDispMask, &aRendObj, &aRendNb);
1862   for (GLint aRendIter = 0; aRendIter < aRendNb; ++aRendIter)
1863   {
1864     GLint aRendId = 0;
1865     if (CGLDescribeRenderer (aRendObj, aRendIter, kCGLRPRendererID, &aRendId) != kCGLNoError
1866      || aRendId != aGlRendId)
1867     {
1868       continue;
1869     }
1870
1871     //kCGLRPVideoMemoryMegabytes   = 131;
1872     //kCGLRPTextureMemoryMegabytes = 132;
1873     GLint aVMem = 0;
1874   #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
1875     if (CGLDescribeRenderer(aRendObj, aRendIter, kCGLRPVideoMemoryMegabytes, &aVMem) == kCGLNoError)
1876     {
1877       addInfo (theDict, "GPU memory",         TCollection_AsciiString() + aVMem + " MiB");
1878     }
1879     if (CGLDescribeRenderer(aRendObj, aRendIter, kCGLRPTextureMemoryMegabytes, &aVMem) == kCGLNoError)
1880     {
1881       addInfo (theDict, "GPU Texture memory", TCollection_AsciiString() + aVMem + " MiB");
1882     }
1883   #else
1884     if (CGLDescribeRenderer(aRendObj, aRendIter, kCGLRPVideoMemory, &aVMem) == kCGLNoError)
1885     {
1886       addInfo (theDict, "GPU memory",         TCollection_AsciiString() + (aVMem / (1024 * 1024)) + " MiB");
1887     }
1888     if (CGLDescribeRenderer(aRendObj, aRendIter, kCGLRPTextureMemory, &aVMem) == kCGLNoError)
1889     {
1890       addInfo (theDict, "GPU Texture memory", TCollection_AsciiString() + (aVMem / (1024 * 1024)) + " MiB");
1891     }
1892   #endif
1893   }
1894 #endif
1895
1896 #if !defined(GL_ES_VERSION_2_0)
1897   if (atiMem)
1898   {
1899     GLint aValues[4];
1900     memset (aValues, 0, sizeof(aValues));
1901     glGetIntegerv (GL_VBO_FREE_MEMORY_ATI, aValues);
1902
1903     // total memory free in the pool
1904     addInfo (theDict, "GPU free memory",    TCollection_AsciiString() + (aValues[0] / 1024) + " MiB");
1905
1906     if (aValues[1] != aValues[0])
1907     {
1908       // largest available free block in the pool
1909       addInfo (theDict, "Largest free block", TCollection_AsciiString() + (aValues[1] / 1024) + " MiB");
1910     }
1911     if (aValues[2] != aValues[0])
1912     {
1913       // total auxiliary memory free
1914       addInfo (theDict, "Free auxiliary memory", TCollection_AsciiString() + (aValues[2] / 1024) + " MiB");
1915     }
1916   }
1917   else if (nvxMem)
1918   {
1919     //current available dedicated video memory (in KiB), currently unused GPU memory
1920     GLint aValue = 0;
1921     glGetIntegerv (GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &aValue);
1922     addInfo (theDict, "GPU free memory", TCollection_AsciiString() + (aValue / 1024) + " MiB");
1923
1924     // dedicated video memory, total size (in KiB) of the GPU memory
1925     GLint aDedicated = 0;
1926     glGetIntegerv (GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &aDedicated);
1927     addInfo (theDict, "GPU memory", TCollection_AsciiString() + (aDedicated / 1024) + " MiB");
1928
1929     // total available memory, total size (in KiB) of the memory available for allocations
1930     glGetIntegerv (GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &aValue);
1931     if (aValue != aDedicated)
1932     {
1933       // different only for special configurations
1934       addInfo (theDict, "Total memory", TCollection_AsciiString() + (aValue / 1024) + " MiB");
1935     }
1936   }
1937 #if defined(_WIN32)
1938   else if (myFuncs->wglGetGPUInfoAMD != NULL
1939         && myFuncs->wglGetContextGPUIDAMD != NULL)
1940   {
1941     GLuint aTotalMemMiB = 0;
1942     UINT anAmdId = myFuncs->wglGetContextGPUIDAMD ((HGLRC )myGContext);
1943     if (anAmdId != 0)
1944     {
1945       if (myFuncs->wglGetGPUInfoAMD (anAmdId, WGL_GPU_RAM_AMD, GL_UNSIGNED_INT, sizeof(aTotalMemMiB), &aTotalMemMiB) > 0)
1946       {
1947         addInfo (theDict, "GPU memory", TCollection_AsciiString() + (int )aTotalMemMiB + " MiB");
1948       }
1949     }
1950   }
1951 #endif
1952 #endif
1953
1954 #if !defined(GL_ES_VERSION_2_0) && !defined(__APPLE__) && !defined(_WIN32)
1955   // GLX_RENDERER_VENDOR_ID_MESA
1956   if (myFuncs->glXQueryCurrentRendererIntegerMESA != NULL)
1957   {
1958     unsigned int aVMemMiB = 0;
1959     if (myFuncs->glXQueryCurrentRendererIntegerMESA (GLX_RENDERER_VIDEO_MEMORY_MESA, &aVMemMiB) != False)
1960     {
1961       addInfo (theDict, "GPU memory", TCollection_AsciiString() + int(aVMemMiB) + " MiB");
1962     }
1963   }
1964 #endif
1965 }
1966
1967 // =======================================================================
1968 // function : DiagnosticInfo
1969 // purpose  :
1970 // =======================================================================
1971 void OpenGl_Context::DiagnosticInformation (TColStd_IndexedDataMapOfStringString& theDict,
1972                                             Graphic3d_DiagnosticInfo theFlags) const
1973 {
1974   if ((theFlags & Graphic3d_DiagnosticInfo_NativePlatform) != 0)
1975   {
1976   #if defined(HAVE_EGL)
1977     addInfo (theDict, "EGLVersion",    ::eglQueryString ((EGLDisplay )myDisplay, EGL_VERSION));
1978     addInfo (theDict, "EGLVendor",     ::eglQueryString ((EGLDisplay )myDisplay, EGL_VENDOR));
1979     addInfo (theDict, "EGLClientAPIs", ::eglQueryString ((EGLDisplay )myDisplay, EGL_CLIENT_APIS));
1980     if ((theFlags & Graphic3d_DiagnosticInfo_Extensions) != 0)
1981     {
1982       addInfo (theDict, "EGLExtensions", ::eglQueryString ((EGLDisplay )myDisplay, EGL_EXTENSIONS));
1983     }
1984   #elif defined(_WIN32)
1985     if ((theFlags & Graphic3d_DiagnosticInfo_Extensions) != 0
1986      && myFuncs->wglGetExtensionsStringARB != NULL)
1987     {
1988       const char* aWglExts = myFuncs->wglGetExtensionsStringARB ((HDC )myDisplay);
1989       addInfo (theDict, "WGLExtensions", aWglExts);
1990     }
1991   #elif defined(HAVE_XLIB)
1992     Display* aDisplay = (Display*)myDisplay;
1993     const int aScreen = DefaultScreen(aDisplay);
1994     addInfo (theDict, "GLXDirectRendering", ::glXIsDirect (aDisplay, (GLXContext )myGContext) ? "Yes" : "No");
1995     addInfo (theDict, "GLXVendor",  ::glXQueryServerString (aDisplay, aScreen, GLX_VENDOR));
1996     addInfo (theDict, "GLXVersion", ::glXQueryServerString (aDisplay, aScreen, GLX_VERSION));
1997     if ((theFlags & Graphic3d_DiagnosticInfo_Extensions) != 0)
1998     {
1999       const char* aGlxExts = ::glXQueryExtensionsString (aDisplay, aScreen);
2000       addInfo(theDict, "GLXExtensions", aGlxExts);
2001     }
2002
2003     addInfo (theDict, "GLXClientVendor",  ::glXGetClientString (aDisplay, GLX_VENDOR));
2004     addInfo (theDict, "GLXClientVersion", ::glXGetClientString (aDisplay, GLX_VERSION));
2005     if ((theFlags & Graphic3d_DiagnosticInfo_Extensions) != 0)
2006     {
2007       addInfo (theDict, "GLXClientExtensions", ::glXGetClientString (aDisplay, GLX_EXTENSIONS));
2008     }
2009   #else
2010     //
2011   #endif
2012   }
2013
2014   if ((theFlags & Graphic3d_DiagnosticInfo_Device) != 0)
2015   {
2016     Standard_Integer aDriverVer[2] = {};
2017     ReadGlVersion (aDriverVer[0], aDriverVer[1]);
2018     addInfo (theDict, "GLvendor",    (const char*)::glGetString (GL_VENDOR));
2019     addInfo (theDict, "GLdevice",    (const char*)::glGetString (GL_RENDERER));
2020   #ifdef __EMSCRIPTEN__
2021     if (CheckExtension ("GL_WEBGL_debug_renderer_info"))
2022     {
2023       if (const char* aVendor = (const char*)::glGetString (0x9245))
2024       {
2025         addInfo (theDict, "GLunmaskedVendor", aVendor);
2026       }
2027       if (const char* aDevice = (const char*)::glGetString (0x9246))
2028       {
2029         addInfo (theDict, "GLunmaskedDevice", aDevice);
2030       }
2031     }
2032   #endif
2033
2034     addInfo (theDict, "GLversion",   (const char*)::glGetString (GL_VERSION));
2035     if (myGlVerMajor != aDriverVer[0]
2036      || myGlVerMinor != aDriverVer[1])
2037     {
2038       addInfo (theDict, "GLversionOcct", TCollection_AsciiString (myGlVerMajor) + "." + TCollection_AsciiString (myGlVerMinor));
2039     }
2040     if (IsGlGreaterEqual (2, 0))
2041     {
2042       addInfo (theDict, "GLSLversion", (const char*)::glGetString (GL_SHADING_LANGUAGE_VERSION));
2043     }
2044     if (myIsGlDebugCtx)
2045     {
2046       addInfo (theDict, "GLdebug", "ON");
2047     }
2048   }
2049
2050   if ((theFlags & Graphic3d_DiagnosticInfo_Limits) != 0)
2051   {
2052     addInfo (theDict, "Max texture size", TCollection_AsciiString(myMaxTexDim));
2053     addInfo (theDict, "Max FBO dump size", TCollection_AsciiString() + myMaxDumpSizeX + "x" + myMaxDumpSizeY);
2054     addInfo (theDict, "Max combined texture units", TCollection_AsciiString(myMaxTexCombined));
2055     addInfo (theDict, "Max MSAA samples", TCollection_AsciiString(myMaxMsaaSamples));
2056   }
2057
2058   if ((theFlags & Graphic3d_DiagnosticInfo_FrameBuffer) != 0)
2059   {
2060     GLint aViewport[4] = {};
2061     ::glGetIntegerv (GL_VIEWPORT, aViewport);
2062     addInfo (theDict, "Viewport", TCollection_AsciiString() + aViewport[2] + "x" + aViewport[3]);
2063   }
2064
2065   if ((theFlags & Graphic3d_DiagnosticInfo_Memory) != 0)
2066   {
2067     MemoryInfo (theDict);
2068   }
2069
2070   if ((theFlags & Graphic3d_DiagnosticInfo_Extensions) != 0)
2071   {
2072   #if !defined(GL_ES_VERSION_2_0)
2073     if (IsGlGreaterEqual (3, 0)
2074      && myFuncs->glGetStringi != NULL)
2075     {
2076       TCollection_AsciiString anExtList;
2077       GLint anExtNb = 0;
2078       ::glGetIntegerv (GL_NUM_EXTENSIONS, &anExtNb);
2079       for (GLint anIter = 0; anIter < anExtNb; ++anIter)
2080       {
2081         const char* anExtension = (const char*)myFuncs->glGetStringi (GL_EXTENSIONS, (GLuint)anIter);
2082         if (!anExtList.IsEmpty())
2083         {
2084           anExtList += " ";
2085         }
2086         anExtList += anExtension;
2087       }
2088       addInfo(theDict, "GLextensions", anExtList);
2089     }
2090     else
2091   #endif
2092     {
2093       addInfo (theDict, "GLextensions", (const char*)::glGetString (GL_EXTENSIONS));
2094     }
2095   }
2096 }
2097
2098 // =======================================================================
2099 // function : GetResource
2100 // purpose  :
2101 // =======================================================================
2102 const Handle(OpenGl_Resource)& OpenGl_Context::GetResource (const TCollection_AsciiString& theKey) const
2103 {
2104   return mySharedResources->IsBound (theKey) ? mySharedResources->Find (theKey) : NULL_GL_RESOURCE;
2105 }
2106
2107 // =======================================================================
2108 // function : ShareResource
2109 // purpose  :
2110 // =======================================================================
2111 Standard_Boolean OpenGl_Context::ShareResource (const TCollection_AsciiString& theKey,
2112                                                 const Handle(OpenGl_Resource)& theResource)
2113 {
2114   if (theKey.IsEmpty() || theResource.IsNull())
2115   {
2116     return Standard_False;
2117   }
2118   return mySharedResources->Bind (theKey, theResource);
2119 }
2120
2121 // =======================================================================
2122 // function : ReleaseResource
2123 // purpose  :
2124 // =======================================================================
2125 void OpenGl_Context::ReleaseResource (const TCollection_AsciiString& theKey,
2126                                       const Standard_Boolean         theToDelay)
2127 {
2128   if (!mySharedResources->IsBound (theKey))
2129   {
2130     return;
2131   }
2132   const Handle(OpenGl_Resource)& aRes = mySharedResources->Find (theKey);
2133   if (aRes->GetRefCount() > 1)
2134   {
2135     return;
2136   }
2137
2138   if (theToDelay)
2139   {
2140     myDelayed->Bind (theKey, 1);
2141   }
2142   else
2143   {
2144     aRes->Release (this);
2145     mySharedResources->UnBind (theKey);
2146   }
2147 }
2148
2149 // =======================================================================
2150 // function : ReleaseDelayed
2151 // purpose  :
2152 // =======================================================================
2153 void OpenGl_Context::ReleaseDelayed()
2154 {
2155   // release queued elements
2156   while (!myUnusedResources->IsEmpty())
2157   {
2158     myUnusedResources->First()->Release (this);
2159     myUnusedResources->RemoveFirst();
2160   }
2161
2162   // release delayed shared resources
2163   NCollection_Vector<TCollection_AsciiString> aDeadList;
2164   for (NCollection_DataMap<TCollection_AsciiString, Standard_Integer>::Iterator anIter (*myDelayed);
2165        anIter.More(); anIter.Next())
2166   {
2167     if (++anIter.ChangeValue() <= 2)
2168     {
2169       continue; // postpone release one more frame to ensure no one uses it periodically
2170     }
2171
2172     const TCollection_AsciiString& aKey = anIter.Key();
2173     if (!mySharedResources->IsBound (aKey))
2174     {
2175       // mixed unshared strategy delayed/undelayed was used!
2176       aDeadList.Append (aKey);
2177       continue;
2178     }
2179
2180     const Handle(OpenGl_Resource)& aRes = mySharedResources->ChangeFind (aKey);
2181     if (aRes->GetRefCount() > 1)
2182     {
2183       // should be only 1 instance in mySharedResources
2184       // if not - resource was reused again
2185       aDeadList.Append (aKey);
2186       continue;
2187     }
2188
2189     // release resource if no one requested it more than 2 redraw calls
2190     aRes->Release (this);
2191     mySharedResources->UnBind (aKey);
2192     aDeadList.Append (aKey);
2193   }
2194
2195   for (Standard_Integer anIter = 0; anIter < aDeadList.Length(); ++anIter)
2196   {
2197     myDelayed->UnBind (aDeadList.Value (anIter));
2198   }
2199 }
2200
2201 // =======================================================================
2202 // function : BindTextures
2203 // purpose  :
2204 // =======================================================================
2205 Handle(OpenGl_TextureSet) OpenGl_Context::BindTextures (const Handle(OpenGl_TextureSet)& theTextures,
2206                                                         const Handle(OpenGl_ShaderProgram)& theProgram)
2207 {
2208   const Standard_Integer aTextureSetBits = !theTextures.IsNull() ? theTextures->TextureSetBits() : 0;
2209   const Standard_Integer aProgramBits    = !theProgram.IsNull() ? theProgram->TextureSetBits() : 0;
2210   Standard_Integer aMissingBits = aProgramBits & ~aTextureSetBits;
2211   if (aMissingBits != 0
2212    && myTextureRgbaBlack.IsNull())
2213   {
2214     // allocate mock textures
2215     myTextureRgbaBlack = new OpenGl_Texture();
2216     myTextureRgbaWhite = new OpenGl_Texture();
2217     Image_PixMap anImage;
2218     anImage.InitZero (Image_Format_RGBA, 2, 2, 0, (Standard_Byte )0);
2219     if (!myTextureRgbaBlack->Init (this, OpenGl_TextureFormat::Create<GLubyte, 4>(), Graphic3d_Vec2i (2, 2), Graphic3d_TOT_2D, &anImage))
2220     {
2221       PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
2222                     "Error: unable to create unit mock PBR texture map.");
2223     }
2224     anImage.InitZero (Image_Format_RGBA, 2, 2, 0, (Standard_Byte )255);
2225     if (!myTextureRgbaWhite->Init (this, OpenGl_TextureFormat::Create<GLubyte, 4>(), Graphic3d_Vec2i (2, 2), Graphic3d_TOT_2D, &anImage))
2226     {
2227       PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
2228                     "Error: unable to create normal mock PBR texture map.");
2229     }
2230   }
2231
2232   Handle(OpenGl_TextureSet) anOldTextures = myActiveTextures;
2233   if (myActiveTextures != theTextures)
2234   {
2235     Handle(OpenGl_Context) aThisCtx (this);
2236     for (OpenGl_TextureSetPairIterator aSlotIter (myActiveTextures, theTextures); aSlotIter.More(); aSlotIter.Next())
2237     {
2238       const Graphic3d_TextureUnit aTexUnit = aSlotIter.Unit();
2239       const OpenGl_Texture* aTextureOld = aSlotIter.Texture1();
2240       const OpenGl_Texture* aTextureNew = aSlotIter.Texture2();
2241       if (aTextureNew == aTextureOld)
2242       {
2243         continue;
2244       }
2245
2246       if (aTextureNew != NULL
2247        && aTextureNew->IsValid())
2248       {
2249         if (aTexUnit >= myMaxTexCombined)
2250         {
2251           PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
2252                        TCollection_AsciiString("Texture unit ") + aTexUnit + " for " + aTextureNew->ResourceId() + " exceeds hardware limit " + myMaxTexCombined);
2253           continue;
2254         }
2255
2256         aTextureNew->Bind (aThisCtx, aTexUnit);
2257         if (aTextureNew->Sampler()->ToUpdateParameters())
2258         {
2259           if (aTextureNew->Sampler()->IsImmutable())
2260           {
2261             aTextureNew->Sampler()->Init (aThisCtx, *aTextureNew);
2262           }
2263           else
2264           {
2265             OpenGl_Sampler::applySamplerParams (aThisCtx, aTextureNew->Sampler()->Parameters(), aTextureNew->Sampler().get(), aTextureNew->GetTarget(), aTextureNew->MaxMipmapLevel());
2266           }
2267         }
2268       #if !defined(GL_ES_VERSION_2_0)
2269         if (core11ffp != NULL)
2270         {
2271           OpenGl_Sampler::applyGlobalTextureParams (aThisCtx, *aTextureNew, aTextureNew->Sampler()->Parameters());
2272         }
2273       #endif
2274       }
2275       else if (aTextureOld != NULL
2276             && aTextureOld->IsValid())
2277       {
2278         aTextureOld->Unbind (aThisCtx, aTexUnit);
2279       #if !defined(GL_ES_VERSION_2_0)
2280         if (core11ffp != NULL)
2281         {
2282           OpenGl_Sampler::resetGlobalTextureParams (aThisCtx, *aTextureOld, aTextureOld->Sampler()->Parameters());
2283         }
2284       #endif
2285       }
2286     }
2287     myActiveTextures = theTextures;
2288   }
2289
2290   if (myActiveMockTextures != aMissingBits)
2291   {
2292     myActiveMockTextures = aMissingBits;
2293     for (Standard_Integer aBitIter = 0; aMissingBits != 0; ++aBitIter)
2294     {
2295       Standard_Integer aUnitMask = 1 << aBitIter;
2296       if ((aUnitMask & aMissingBits) != 0)
2297       {
2298         aMissingBits = aMissingBits & ~aUnitMask;
2299         if (aBitIter == Graphic3d_TextureUnit_Normal)
2300         {
2301           myTextureRgbaBlack->Bind (this, static_cast<Graphic3d_TextureUnit>(aBitIter));
2302         }
2303         else
2304         {
2305           myTextureRgbaWhite->Bind (this, static_cast<Graphic3d_TextureUnit>(aBitIter));
2306         }
2307       }
2308     }
2309   }
2310
2311   return anOldTextures;
2312 }
2313
2314 // =======================================================================
2315 // function : BindProgram
2316 // purpose  :
2317 // =======================================================================
2318 Standard_Boolean OpenGl_Context::BindProgram (const Handle(OpenGl_ShaderProgram)& theProgram)
2319 {
2320   if (core20fwd == NULL)
2321   {
2322     return Standard_False;
2323   }
2324   else if (myActiveProgram == theProgram)
2325   {
2326     return Standard_True;
2327   }
2328
2329   if (theProgram.IsNull()
2330   || !theProgram->IsValid())
2331   {
2332     if (!myActiveProgram.IsNull())
2333     {
2334       core20fwd->glUseProgram (OpenGl_ShaderProgram::NO_PROGRAM);
2335       myActiveProgram.Nullify();
2336     }
2337     return Standard_False;
2338   }
2339
2340   myActiveProgram = theProgram;
2341   core20fwd->glUseProgram (theProgram->ProgramId());
2342   return Standard_True;
2343 }
2344
2345 // =======================================================================
2346 // function : BindDefaultVao
2347 // purpose  :
2348 // =======================================================================
2349 void OpenGl_Context::BindDefaultVao()
2350 {
2351 #if !defined(GL_ES_VERSION_2_0)
2352   if (myDefaultVao == 0
2353    || core32 == NULL)
2354   {
2355     return;
2356   }
2357
2358   core32->glBindVertexArray (myDefaultVao);
2359 #endif
2360 }
2361
2362 // =======================================================================
2363 // function : SetDefaultFrameBuffer
2364 // purpose  :
2365 // =======================================================================
2366 Handle(OpenGl_FrameBuffer) OpenGl_Context::SetDefaultFrameBuffer (const Handle(OpenGl_FrameBuffer)& theFbo)
2367 {
2368   Handle(OpenGl_FrameBuffer) aFbo = myDefaultFbo;
2369   myDefaultFbo = theFbo;
2370   return aFbo;
2371 }
2372
2373 // =======================================================================
2374 // function : SetShadingMaterial
2375 // purpose  :
2376 // =======================================================================
2377 void OpenGl_Context::SetShadingMaterial (const OpenGl_Aspects* theAspect,
2378                                          const Handle(Graphic3d_PresentationAttributes)& theHighlight)
2379 {
2380   const Handle(Graphic3d_Aspects)& anAspect = (!theHighlight.IsNull() && !theHighlight->BasicFillAreaAspect().IsNull())
2381                                             ?  (const Handle(Graphic3d_Aspects)& )theHighlight->BasicFillAreaAspect()
2382                                             :  theAspect->Aspect();
2383
2384   const bool toDistinguish = anAspect->Distinguish();
2385   const bool toMapTexture  = anAspect->ToMapTexture();
2386   const Graphic3d_MaterialAspect& aMatFrontSrc = anAspect->FrontMaterial();
2387   const Graphic3d_MaterialAspect& aMatBackSrc  = toDistinguish
2388                                                ? anAspect->BackMaterial()
2389                                                : aMatFrontSrc;
2390   const Quantity_Color& aFrontIntColor = anAspect->InteriorColor();
2391   const Quantity_Color& aBackIntColor  = toDistinguish
2392                                        ? anAspect->BackInteriorColor()
2393                                        : aFrontIntColor;
2394
2395   myMaterial.Init (*this, aMatFrontSrc, aFrontIntColor, aMatBackSrc, aBackIntColor);
2396   if (!theHighlight.IsNull()
2397     && theHighlight->BasicFillAreaAspect().IsNull())
2398   {
2399     myMaterial.SetColor (theHighlight->ColorRGBA().GetRGB());
2400     myMaterial.SetColor (theHighlight->ColorRGBA().GetRGB());
2401   }
2402
2403   float anAlphaFront = 1.0f, anAlphaBack = 1.0f;
2404   if (CheckIsTransparent (theAspect, theHighlight, anAlphaFront, anAlphaBack))
2405   {
2406     myMaterial.Common[0].Diffuse.a() = anAlphaFront;
2407     myMaterial.Common[1].Diffuse.a() = anAlphaBack;
2408
2409     myMaterial.Pbr[0].BaseColor.a() = anAlphaFront;
2410     myMaterial.Pbr[1].BaseColor.a() = anAlphaBack;
2411   }
2412
2413   // do not update material properties in case of zero reflection mode,
2414   // because GL lighting will be disabled by OpenGl_PrimitiveArray::DrawArray() anyway.
2415   const OpenGl_MaterialState& aMatState = myShaderManager->MaterialState();
2416   float anAlphaCutoff = (anAspect->AlphaMode() == Graphic3d_AlphaMode_Mask
2417                       || anAspect->AlphaMode() == Graphic3d_AlphaMode_MaskBlend)
2418                       ? anAspect->AlphaCutoff()
2419                       : ShortRealLast();
2420   if (anAspect->ToDrawEdges())
2421   {
2422     if (anAspect->InteriorStyle() == Aspect_IS_EMPTY
2423      || (anAspect->InteriorStyle() == Aspect_IS_SOLID
2424       && anAspect->EdgeColorRGBA().Alpha() < 1.0f))
2425     {
2426       anAlphaCutoff = 0.285f;
2427     }
2428   }
2429   if (theAspect->ShadingModel() == Graphic3d_TypeOfShadingModel_Unlit)
2430   {
2431     if (anAlphaCutoff == aMatState.AlphaCutoff())
2432     {
2433       return;
2434     }
2435   }
2436   else if (myMaterial.IsEqual (aMatState.Material())
2437         && toDistinguish == aMatState.ToDistinguish()
2438         && toMapTexture  == aMatState.ToMapTexture()
2439         && anAlphaCutoff == aMatState.AlphaCutoff())
2440   {
2441     return;
2442   }
2443
2444   myShaderManager->UpdateMaterialStateTo (myMaterial, anAlphaCutoff, toDistinguish, toMapTexture);
2445 }
2446
2447 // =======================================================================
2448 // function : CheckIsTransparent
2449 // purpose  :
2450 // =======================================================================
2451 Standard_Boolean OpenGl_Context::CheckIsTransparent (const OpenGl_Aspects* theAspect,
2452                                                      const Handle(Graphic3d_PresentationAttributes)& theHighlight,
2453                                                      Standard_ShortReal& theAlphaFront,
2454                                                      Standard_ShortReal& theAlphaBack)
2455 {
2456   const Handle(Graphic3d_Aspects)& anAspect = (!theHighlight.IsNull() && !theHighlight->BasicFillAreaAspect().IsNull())
2457                                             ?  (const Handle(Graphic3d_Aspects)& )theHighlight->BasicFillAreaAspect()
2458                                             :  theAspect->Aspect();
2459
2460   const bool toDistinguish = anAspect->Distinguish();
2461   const Graphic3d_MaterialAspect& aMatFrontSrc = anAspect->FrontMaterial();
2462   const Graphic3d_MaterialAspect& aMatBackSrc  = toDistinguish
2463                                                ? anAspect->BackMaterial()
2464                                                : aMatFrontSrc;
2465
2466   // handling transparency
2467   if (!theHighlight.IsNull()
2468     && theHighlight->BasicFillAreaAspect().IsNull())
2469   {
2470     theAlphaFront = theHighlight->ColorRGBA().Alpha();
2471     theAlphaBack  = theHighlight->ColorRGBA().Alpha();
2472   }
2473   else
2474   {
2475     theAlphaFront = aMatFrontSrc.Alpha();
2476     theAlphaBack  = aMatBackSrc .Alpha();
2477   }
2478
2479   if (anAspect->AlphaMode() == Graphic3d_AlphaMode_BlendAuto)
2480   {
2481     return theAlphaFront < 1.0f
2482         || theAlphaBack  < 1.0f;
2483   }
2484   // Graphic3d_AlphaMode_Mask and Graphic3d_AlphaMode_MaskBlend are not considered transparent here
2485   return anAspect->AlphaMode() == Graphic3d_AlphaMode_Blend;
2486 }
2487
2488 // =======================================================================
2489 // function : SetColor4fv
2490 // purpose  :
2491 // =======================================================================
2492 void OpenGl_Context::SetColor4fv (const OpenGl_Vec4& theColor)
2493 {
2494   if (!myActiveProgram.IsNull())
2495   {
2496     if (const OpenGl_ShaderUniformLocation& aLoc = myActiveProgram->GetStateLocation (OpenGl_OCCT_COLOR))
2497     {
2498       myActiveProgram->SetUniform (this, aLoc, Vec4FromQuantityColor (theColor));
2499     }
2500   }
2501 #if !defined(GL_ES_VERSION_2_0)
2502   else if (core11ffp != NULL)
2503   {
2504     core11ffp->glColor4fv (theColor.GetData());
2505   }
2506 #endif
2507 }
2508
2509 // =======================================================================
2510 // function : SetTypeOfLine
2511 // purpose  :
2512 // =======================================================================
2513 void OpenGl_Context::SetTypeOfLine (const Aspect_TypeOfLine  theType,
2514                                     const Standard_ShortReal theFactor)
2515 {
2516   SetLineStipple (theFactor, Graphic3d_Aspects::DefaultLinePatternForType (theType));
2517 }
2518
2519 // =======================================================================
2520 // function : SetLineStipple
2521 // purpose  :
2522 // =======================================================================
2523 void OpenGl_Context::SetLineStipple (const Standard_ShortReal theFactor,
2524                                      const uint16_t thePattern)
2525 {
2526   if (!myActiveProgram.IsNull())
2527   {
2528     if (const OpenGl_ShaderUniformLocation aPatternLoc = myActiveProgram->GetStateLocation (OpenGl_OCCT_LINE_STIPPLE_PATTERN))
2529     {
2530       if (hasGlslBitwiseOps != OpenGl_FeatureNotAvailable)
2531       {
2532         myActiveProgram->SetUniform (this, aPatternLoc, (Standard_Integer )thePattern);
2533       }
2534       else
2535       {
2536         Standard_Integer aPatArr[16] = {};
2537         for (unsigned int aBit = 0; aBit < 16; ++aBit)
2538         {
2539           aPatArr[aBit] = ((unsigned int)(thePattern) & (1U << aBit)) != 0 ? 1 : 0;
2540         }
2541         myActiveProgram->SetUniform (this, aPatternLoc, 16, aPatArr);
2542       }
2543       myActiveProgram->SetUniform (this, myActiveProgram->GetStateLocation (OpenGl_OCCT_LINE_STIPPLE_FACTOR), theFactor);
2544     }
2545     return;
2546   }
2547
2548 #if !defined(GL_ES_VERSION_2_0)
2549   if (thePattern != 0xFFFF)
2550   {
2551     if (core11ffp != NULL)
2552     {
2553       core11fwd->glEnable (GL_LINE_STIPPLE);
2554
2555       core11ffp->glLineStipple (static_cast<GLint>    (theFactor),
2556                                 static_cast<GLushort> (thePattern));
2557     }
2558   }
2559   else
2560   {
2561     if (core11ffp != NULL)
2562     {
2563       core11fwd->glDisable (GL_LINE_STIPPLE);
2564     }
2565   }
2566 #endif
2567 }
2568
2569 // =======================================================================
2570 // function : SetLineWidth
2571 // purpose  :
2572 // =======================================================================
2573 void OpenGl_Context::SetLineWidth (const Standard_ShortReal theWidth)
2574 {
2575 #if !defined(GL_ES_VERSION_2_0)
2576   if (core11ffp != NULL)
2577 #endif
2578   {
2579     // glLineWidth() is still defined within Core Profile, but has no effect with values != 1.0f
2580     core11fwd->glLineWidth (theWidth * myLineWidthScale);
2581   }
2582 }
2583
2584 // =======================================================================
2585 // function : SetTextureMatrix
2586 // purpose  :
2587 // =======================================================================
2588 void OpenGl_Context::SetTextureMatrix (const Handle(Graphic3d_TextureParams)& theParams,
2589                                        const Standard_Boolean theIsTopDown)
2590 {
2591   if (theParams.IsNull())
2592   {
2593     return;
2594   }
2595
2596   const Graphic3d_Vec2& aScale = theParams->Scale();
2597   const Graphic3d_Vec2& aTrans = theParams->Translation();
2598   if (!myActiveProgram.IsNull())
2599   {
2600     const GLint aUniLoc = myActiveProgram->GetStateLocation (OpenGl_OCCT_TEXTURE_TRSF2D);
2601     if (aUniLoc == OpenGl_ShaderProgram::INVALID_LOCATION)
2602     {
2603       return;
2604     }
2605
2606     // pack transformation parameters
2607     OpenGl_Vec4 aTrsf[2] =
2608     {
2609       OpenGl_Vec4 (-aTrans.x(), -aTrans.y(), aScale.x(), aScale.y()),
2610       OpenGl_Vec4 (static_cast<float> (std::sin (-theParams->Rotation() * M_PI / 180.0)),
2611                    static_cast<float> (std::cos (-theParams->Rotation() * M_PI / 180.0)),
2612                    0.0f, 0.0f)
2613     };
2614     if (caps->isTopDownTextureUV != theIsTopDown)
2615     {
2616       // flip V
2617       aTrsf[0].y() = -aTrans.y() + 1.0f / aScale.y();
2618       aTrsf[0].w() = -aScale.y();
2619     }
2620     myActiveProgram->SetUniform (this, aUniLoc, 2, aTrsf);
2621     return;
2622   }
2623
2624 #if !defined(GL_ES_VERSION_2_0)
2625   if (core11ffp != NULL)
2626   {
2627     GLint aMatrixMode = GL_TEXTURE;
2628     ::glGetIntegerv (GL_MATRIX_MODE, &aMatrixMode);
2629
2630     core11ffp->glMatrixMode (GL_TEXTURE);
2631     OpenGl_Mat4 aTextureMat;
2632     if (caps->isTopDownTextureUV != theIsTopDown)
2633     {
2634       // flip V
2635       Graphic3d_TransformUtils::Scale     (aTextureMat,  aScale.x(), -aScale.y(), 1.0f);
2636       Graphic3d_TransformUtils::Translate (aTextureMat, -aTrans.x(), -aTrans.y() + 1.0f / aScale.y(), 0.0f);
2637     }
2638     else
2639     {
2640       Graphic3d_TransformUtils::Scale     (aTextureMat,  aScale.x(),  aScale.y(), 1.0f);
2641       Graphic3d_TransformUtils::Translate (aTextureMat, -aTrans.x(), -aTrans.y(), 0.0f);
2642     }
2643     Graphic3d_TransformUtils::Rotate (aTextureMat, -theParams->Rotation(), 0.0f, 0.0f, 1.0f);
2644     core11ffp->glLoadMatrixf (aTextureMat.GetData());
2645     core11ffp->glMatrixMode (aMatrixMode);
2646   }
2647 #endif
2648 }
2649
2650 // =======================================================================
2651 // function : SetPointSize
2652 // purpose  :
2653 // =======================================================================
2654 void OpenGl_Context::SetPointSize (const Standard_ShortReal theSize)
2655 {
2656   if (!myActiveProgram.IsNull())
2657   {
2658     myActiveProgram->SetUniform (this, myActiveProgram->GetStateLocation (OpenGl_OCCT_POINT_SIZE), theSize);
2659   #if !defined(GL_ES_VERSION_2_0)
2660     //myContext->core11fwd->glEnable (GL_VERTEX_PROGRAM_POINT_SIZE);
2661   #endif
2662   }
2663 #if !defined(GL_ES_VERSION_2_0)
2664   //else
2665   {
2666     core11fwd->glPointSize (theSize);
2667     if (core20fwd != NULL)
2668     {
2669       //myContext->core11fwd->glDisable (GL_VERTEX_PROGRAM_POINT_SIZE);
2670     }
2671   }
2672 #endif
2673 }
2674
2675 // =======================================================================
2676 // function : SetPointSpriteOrigin
2677 // purpose  :
2678 // =======================================================================
2679 void OpenGl_Context::SetPointSpriteOrigin()
2680 {
2681 #if !defined(GL_ES_VERSION_2_0)
2682   if (core15fwd == NULL)
2683   {
2684     return;
2685   }
2686
2687   const int aNewState = !myActiveProgram.IsNull() ? GL_UPPER_LEFT : GL_LOWER_LEFT;
2688   if (myPointSpriteOrig != aNewState)
2689   {
2690     myPointSpriteOrig = aNewState;
2691     core15fwd->glPointParameteri (GL_POINT_SPRITE_COORD_ORIGIN, aNewState);
2692   }
2693 #endif
2694 }
2695
2696 // =======================================================================
2697 // function : SetGlNormalizeEnabled
2698 // purpose  :
2699 // =======================================================================
2700 Standard_Boolean OpenGl_Context::SetGlNormalizeEnabled (Standard_Boolean isEnabled)
2701 {
2702   if (isEnabled == myIsGlNormalizeEnabled)
2703   {
2704     return myIsGlNormalizeEnabled;
2705   }
2706
2707   Standard_Boolean anOldGlNormalize = myIsGlNormalizeEnabled;
2708   myIsGlNormalizeEnabled = isEnabled;
2709 #if !defined(GL_ES_VERSION_2_0)
2710   if (core11ffp != NULL)
2711   {
2712     if (isEnabled)
2713     {
2714       core11fwd->glEnable  (GL_NORMALIZE);
2715     }
2716     else
2717     {
2718       core11fwd->glDisable (GL_NORMALIZE);
2719     }
2720   }
2721 #endif
2722
2723   return anOldGlNormalize;
2724 }
2725
2726 // =======================================================================
2727 // function : SetShadeModel
2728 // purpose  :
2729 // =======================================================================
2730 void OpenGl_Context::SetShadeModel (Graphic3d_TypeOfShadingModel theModel)
2731 {
2732 #if !defined(GL_ES_VERSION_2_0)
2733   if (core11ffp != NULL)
2734   {
2735     const Standard_Integer aModel = theModel == Graphic3d_TypeOfShadingModel_PhongFacet
2736                                  || theModel == Graphic3d_TypeOfShadingModel_PbrFacet ? GL_FLAT : GL_SMOOTH;
2737     if (myShadeModel == aModel)
2738     {
2739       return;
2740     }
2741     myShadeModel = aModel;
2742     core11ffp->glShadeModel (aModel);
2743   }
2744 #else
2745   (void )theModel;
2746 #endif
2747 }
2748
2749 // =======================================================================
2750 // function : SetPolygonMode
2751 // purpose  :
2752 // =======================================================================
2753 Standard_Integer OpenGl_Context::SetPolygonMode (const Standard_Integer theMode)
2754 {
2755   if (myPolygonMode == theMode)
2756   {
2757     return myPolygonMode;
2758   }
2759
2760   const Standard_Integer anOldPolygonMode = myPolygonMode;
2761
2762   myPolygonMode = theMode;
2763
2764 #if !defined(GL_ES_VERSION_2_0)
2765   ::glPolygonMode (GL_FRONT_AND_BACK, (GLenum)theMode);
2766 #endif
2767
2768   return anOldPolygonMode;
2769 }
2770
2771 // =======================================================================
2772 // function : SetPolygonHatchEnabled
2773 // purpose  :
2774 // =======================================================================
2775 bool OpenGl_Context::SetPolygonHatchEnabled (const bool theIsEnabled)
2776 {
2777   if (core11ffp == NULL)
2778   {
2779     return false;
2780   }
2781   else if (myHatchIsEnabled == theIsEnabled)
2782   {
2783     return theIsEnabled;
2784   }
2785
2786   const bool anOldIsEnabled = myHatchIsEnabled;
2787 #if !defined(GL_ES_VERSION_2_0)
2788   if (theIsEnabled
2789    && myActiveHatchType != Aspect_HS_SOLID)
2790   {
2791     core11fwd->glEnable (GL_POLYGON_STIPPLE);
2792   }
2793   else
2794   {
2795     core11fwd->glDisable (GL_POLYGON_STIPPLE);
2796   }
2797 #endif
2798   myHatchIsEnabled = theIsEnabled;
2799   return anOldIsEnabled;
2800 }
2801
2802 // =======================================================================
2803 // function : SetPolygonHatchStyle
2804 // purpose  :
2805 // =======================================================================
2806 Standard_Integer OpenGl_Context::SetPolygonHatchStyle (const Handle(Graphic3d_HatchStyle)& theStyle)
2807 {
2808   const Standard_Integer aNewStyle = !theStyle.IsNull() ? theStyle->HatchType() : Aspect_HS_SOLID;
2809   if (myActiveHatchType == aNewStyle
2810    || core11ffp == NULL)
2811   {
2812     return myActiveHatchType;
2813   }
2814
2815 #if !defined(GL_ES_VERSION_2_0)
2816   if (aNewStyle == Aspect_HS_SOLID)
2817   {
2818     if (myHatchIsEnabled)
2819     {
2820       core11fwd->glDisable (GL_POLYGON_STIPPLE);
2821     }
2822     return myActiveHatchType;
2823   }
2824
2825   if (myHatchStyles.IsNull()
2826   && !GetResource ("OpenGl_LineAttributes", myHatchStyles))
2827   {
2828     // share and register for release once the resource is no longer used
2829     myHatchStyles = new OpenGl_LineAttributes();
2830     ShareResource ("OpenGl_LineAttributes", myHatchStyles);
2831   }
2832
2833   const Standard_Integer anOldType = myActiveHatchType;
2834   myActiveHatchType = aNewStyle;
2835   myHatchStyles->SetTypeOfHatch (this, theStyle);
2836   if (myHatchIsEnabled
2837    && anOldType == Aspect_HS_SOLID)
2838   {
2839     core11fwd->glEnable (GL_POLYGON_STIPPLE);
2840   }
2841   return anOldType;
2842 #else
2843   return myActiveHatchType;
2844 #endif
2845 }
2846
2847 // =======================================================================
2848 // function : SetPolygonOffset
2849 // purpose  :
2850 // =======================================================================
2851 void OpenGl_Context::SetPolygonOffset (const Graphic3d_PolygonOffset& theOffset)
2852 {
2853   const bool toFillOld = (myPolygonOffset.Mode & Aspect_POM_Fill) == Aspect_POM_Fill;
2854   const bool toFillNew = (theOffset.Mode       & Aspect_POM_Fill) == Aspect_POM_Fill;
2855   if (toFillNew != toFillOld)
2856   {
2857     if (toFillNew)
2858     {
2859       core11fwd->glEnable (GL_POLYGON_OFFSET_FILL);
2860     }
2861     else
2862     {
2863       core11fwd->glDisable (GL_POLYGON_OFFSET_FILL);
2864     }
2865   }
2866
2867 #if !defined(GL_ES_VERSION_2_0)
2868   const bool toLineOld = (myPolygonOffset.Mode & Aspect_POM_Line) == Aspect_POM_Line;
2869   const bool toLineNew = (theOffset.Mode       & Aspect_POM_Line) == Aspect_POM_Line;
2870   if (toLineNew != toLineOld)
2871   {
2872     if (toLineNew)
2873     {
2874       core11fwd->glEnable (GL_POLYGON_OFFSET_LINE);
2875     }
2876     else
2877     {
2878       core11fwd->glDisable (GL_POLYGON_OFFSET_LINE);
2879     }
2880   }
2881
2882   const bool toPointOld = (myPolygonOffset.Mode & Aspect_POM_Point) == Aspect_POM_Point;
2883   const bool toPointNew = (theOffset.Mode       & Aspect_POM_Point) == Aspect_POM_Point;
2884   if (toPointNew != toPointOld)
2885   {
2886     if (toPointNew)
2887     {
2888       core11fwd->glEnable (GL_POLYGON_OFFSET_POINT);
2889     }
2890     else
2891     {
2892       core11fwd->glDisable (GL_POLYGON_OFFSET_POINT);
2893     }
2894   }
2895 #endif
2896
2897   if (myPolygonOffset.Factor != theOffset.Factor
2898    || myPolygonOffset.Units  != theOffset.Units)
2899   {
2900     core11fwd->glPolygonOffset (theOffset.Factor, theOffset.Units);
2901   }
2902   myPolygonOffset = theOffset;
2903 }
2904
2905 // =======================================================================
2906 // function : SetCamera
2907 // purpose  :
2908 // =======================================================================
2909 void OpenGl_Context::SetCamera (const Handle(Graphic3d_Camera)& theCamera)
2910 {
2911   myCamera = theCamera;
2912   if (!theCamera.IsNull())
2913   {
2914     ProjectionState.SetCurrent (theCamera->ProjectionMatrixF());
2915     WorldViewState .SetCurrent (theCamera->OrientationMatrixF());
2916     ApplyProjectionMatrix();
2917     ApplyWorldViewMatrix();
2918   }
2919 }
2920
2921 // =======================================================================
2922 // function : ApplyModelWorldMatrix
2923 // purpose  :
2924 // =======================================================================
2925 void OpenGl_Context::ApplyModelWorldMatrix()
2926 {
2927   if (myShaderManager->ModelWorldState().ModelWorldMatrix() != ModelWorldState.Current())
2928   {
2929     myShaderManager->UpdateModelWorldStateTo (ModelWorldState.Current());
2930   }
2931 }
2932
2933 // =======================================================================
2934 // function : ApplyWorldViewMatrix
2935 // purpose  :
2936 // =======================================================================
2937 void OpenGl_Context::ApplyWorldViewMatrix()
2938 {
2939   if (myShaderManager->ModelWorldState().ModelWorldMatrix() != THE_IDENTITY_MATRIX)
2940   {
2941     myShaderManager->UpdateModelWorldStateTo (THE_IDENTITY_MATRIX);
2942   }
2943   if (myShaderManager->WorldViewState().WorldViewMatrix() != WorldViewState.Current())
2944   {
2945     myShaderManager->UpdateWorldViewStateTo (WorldViewState.Current());
2946   }
2947 }
2948
2949 // =======================================================================
2950 // function : ApplyModelViewMatrix
2951 // purpose  :
2952 // =======================================================================
2953 void OpenGl_Context::ApplyModelViewMatrix()
2954 {
2955   if (myShaderManager->ModelWorldState().ModelWorldMatrix() != ModelWorldState.Current())
2956   {
2957     myShaderManager->UpdateModelWorldStateTo (ModelWorldState.Current());
2958   }
2959   if (myShaderManager->WorldViewState().WorldViewMatrix() != WorldViewState.Current())
2960   {
2961     myShaderManager->UpdateWorldViewStateTo  (WorldViewState.Current());
2962   }
2963 }
2964
2965 // =======================================================================
2966 // function : ApplyProjectionMatrix
2967 // purpose  :
2968 // =======================================================================
2969 void OpenGl_Context::ApplyProjectionMatrix()
2970 {
2971   if (myShaderManager->ProjectionState().ProjectionMatrix() != ProjectionState.Current())
2972   {
2973     myShaderManager->UpdateProjectionStateTo (ProjectionState.Current());
2974   }
2975 }
2976
2977 // =======================================================================
2978 // function : EnableFeatures
2979 // purpose  :
2980 // =======================================================================
2981 void OpenGl_Context::EnableFeatures() const
2982 {
2983   //
2984 }
2985
2986 // =======================================================================
2987 // function : DisableFeatures
2988 // purpose  :
2989 // =======================================================================
2990 void OpenGl_Context::DisableFeatures() const
2991 {
2992   // Disable stuff that's likely to slow down glDrawPixels.
2993   core11fwd->glDisable(GL_DITHER);
2994   core11fwd->glDisable(GL_BLEND);
2995   core11fwd->glDisable(GL_DEPTH_TEST);
2996   core11fwd->glDisable(GL_STENCIL_TEST);
2997
2998 #if !defined(GL_ES_VERSION_2_0)
2999   if (core11ffp == NULL)
3000   {
3001     return;
3002   }
3003
3004   core11fwd->glDisable(GL_TEXTURE_1D);
3005   core11fwd->glDisable(GL_TEXTURE_2D);
3006
3007   core11fwd->glDisable(GL_LIGHTING);
3008   core11fwd->glDisable(GL_ALPHA_TEST);
3009   core11fwd->glDisable(GL_FOG);
3010   core11fwd->glDisable(GL_LOGIC_OP);
3011
3012   glPixelTransferi(GL_MAP_COLOR, GL_FALSE);
3013   glPixelTransferi(GL_RED_SCALE, 1);
3014   glPixelTransferi(GL_RED_BIAS, 0);
3015   glPixelTransferi(GL_GREEN_SCALE, 1);
3016   glPixelTransferi(GL_GREEN_BIAS, 0);
3017   glPixelTransferi(GL_BLUE_SCALE, 1);
3018   glPixelTransferi(GL_BLUE_BIAS, 0);
3019   glPixelTransferi(GL_ALPHA_SCALE, 1);
3020   glPixelTransferi(GL_ALPHA_BIAS, 0);
3021
3022   if ((myGlVerMajor >= 1) && (myGlVerMinor >= 2))
3023   {
3024     if (CheckExtension ("GL_CONVOLUTION_1D_EXT"))
3025       core11fwd->glDisable(GL_CONVOLUTION_1D_EXT);
3026
3027     if (CheckExtension ("GL_CONVOLUTION_2D_EXT"))
3028       core11fwd->glDisable(GL_CONVOLUTION_2D_EXT);
3029
3030     if (CheckExtension ("GL_SEPARABLE_2D_EXT"))
3031       core11fwd->glDisable(GL_SEPARABLE_2D_EXT);
3032
3033     if (CheckExtension ("GL_SEPARABLE_2D_EXT"))
3034       core11fwd->glDisable(GL_HISTOGRAM_EXT);
3035
3036     if (CheckExtension ("GL_MINMAX_EXT"))
3037       core11fwd->glDisable(GL_MINMAX_EXT);
3038
3039     if (CheckExtension ("GL_TEXTURE_3D_EXT"))
3040       core11fwd->glDisable(GL_TEXTURE_3D_EXT);
3041   }
3042 #endif
3043 }
3044
3045 // =======================================================================
3046 // function : SetColorMaskRGBA
3047 // purpose  :
3048 // =======================================================================
3049 void OpenGl_Context::SetColorMaskRGBA (const NCollection_Vec4<bool>& theVal)
3050 {
3051   core11fwd->glColorMask (theVal.r() ? GL_TRUE : GL_FALSE,
3052                theVal.g() ? GL_TRUE : GL_FALSE,
3053                theVal.b() ? GL_TRUE : GL_FALSE,
3054                theVal.a() ? GL_TRUE : GL_FALSE);
3055   myColorMask = theVal;
3056 }
3057
3058 // =======================================================================
3059 // function : SetColorMask
3060 // purpose  :
3061 // =======================================================================
3062 bool OpenGl_Context::SetColorMask (bool theToWriteColor)
3063 {
3064   const bool anOldValue = myColorMask.r();
3065   myColorMask.SetValues (theToWriteColor, theToWriteColor, theToWriteColor, caps->buffersOpaqueAlpha ? false : theToWriteColor);
3066   const GLboolean toWrite = theToWriteColor ? GL_TRUE : GL_FALSE;
3067   core11fwd->glColorMask (toWrite, toWrite, toWrite, myColorMask.a() ? GL_TRUE : GL_FALSE);
3068   return anOldValue;
3069 }
3070
3071 // =======================================================================
3072 // function : SetSampleAlphaToCoverage
3073 // purpose  :
3074 // =======================================================================
3075 bool OpenGl_Context::SetSampleAlphaToCoverage (bool theToEnable)
3076 {
3077   bool toEnable = myAllowAlphaToCov && theToEnable;
3078   if (myAlphaToCoverage == toEnable)
3079   {
3080     return myAlphaToCoverage;
3081   }
3082
3083   if (core15fwd != NULL)
3084   {
3085     if (toEnable)
3086     {
3087       //core15fwd->core15fwd->glSampleCoverage (1.0f, GL_FALSE);
3088       core15fwd->glEnable (GL_SAMPLE_ALPHA_TO_COVERAGE);
3089     }
3090     else
3091     {
3092       core15fwd->glDisable (GL_SAMPLE_ALPHA_TO_COVERAGE);
3093     }
3094   }
3095
3096   const bool anOldValue = myAlphaToCoverage;
3097   myAlphaToCoverage = toEnable;
3098   return anOldValue;
3099 }
3100
3101 // =======================================================================
3102 // function : GetBufferSubData
3103 // purpose  :
3104 // =======================================================================
3105 bool OpenGl_Context::GetBufferSubData (GLenum theTarget, GLintptr theOffset, GLsizeiptr theSize, void* theData)
3106 {
3107   if (!hasGetBufferData)
3108   {
3109     return false;
3110   }
3111 #ifdef __EMSCRIPTEN__
3112   EM_ASM_(
3113   {
3114     Module.ctx.getBufferSubData($0, $1, HEAPU8.subarray($2, $2 + $3));
3115   }, theTarget, theOffset, theData, theSize);
3116   return true;
3117 #elif defined(GL_ES_VERSION_2_0)
3118   if (void* aData = core30->glMapBufferRange (theTarget, theOffset, theSize, GL_MAP_READ_BIT))
3119   {
3120     memcpy (theData, aData, theSize);
3121     core30->glUnmapBuffer (theTarget);
3122     return true;
3123   }
3124   return false;
3125 #else
3126   core15fwd->glGetBufferSubData (theTarget, theOffset, theSize, theData);
3127   return true;
3128 #endif
3129 }
3130
3131 // =======================================================================
3132 // function : DumpJson
3133 // purpose  :
3134 // =======================================================================
3135 void OpenGl_Context::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
3136 {
3137   OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
3138
3139   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myAnisoMax)
3140   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myTexClamp)
3141   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMaxTexDim)
3142   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMaxTexCombined)
3143   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMaxDumpSizeX)
3144   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMaxDumpSizeY)
3145   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMaxClipPlanes)
3146   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMaxMsaaSamples)
3147   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMaxDrawBuffers)
3148   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMaxColorAttachments)
3149   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myGlVerMajor)
3150   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myGlVerMinor)
3151   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsInitialized)
3152   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsStereoBuffers)
3153   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsGlNormalizeEnabled)
3154
3155   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myHasRayTracing)
3156   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myHasRayTracingTextures)
3157   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myHasRayTracingAdaptiveSampling)
3158   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myHasRayTracingAdaptiveSamplingAtomic)
3159
3160   for (int i = 0; i < 4; i++)
3161   {
3162     OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myViewport[i])
3163   }
3164
3165   for (int i = 0; i < 4; i++)
3166   {
3167     OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myViewportVirt[i])
3168   }
3169
3170   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myPointSpriteOrig)
3171   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myRenderMode)
3172   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myPolygonMode)
3173   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myPolygonOffset)
3174   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myToCullBackFaces)
3175   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myReadBuffer)
3176
3177   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myDefaultVao)
3178   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myColorMask)
3179   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myAllowAlphaToCov)
3180   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myAlphaToCoverage)
3181   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsGlDebugCtx)
3182
3183   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myResolution)
3184   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myResolutionRatio)
3185
3186   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myLineWidthScale)
3187   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myLineFeather)
3188   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myRenderScale)
3189   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myRenderScaleInv)
3190   
3191   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &ModelWorldState)
3192   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &WorldViewState)
3193   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &ProjectionState)
3194 }
3195
3196 // =======================================================================
3197 // function : DumpJsonOpenGlState
3198 // purpose  :
3199 // =======================================================================
3200 void OpenGl_Context::DumpJsonOpenGlState (Standard_OStream& theOStream, Standard_Integer)
3201 {
3202   GLboolean isEnableBlend = glIsEnabled (GL_BLEND);
3203   GLboolean isEnableCullFace = glIsEnabled (GL_CULL_FACE);
3204   GLboolean isEnableDepthTest = glIsEnabled (GL_DEPTH_TEST);
3205   
3206   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, isEnableBlend)
3207   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, isEnableCullFace)
3208   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, isEnableDepthTest)
3209 }
3210