0031596: Visualization, OpenGl_Context - take GL_OES_texture_float extension into...
[occt.git] / src / OpenGl / OpenGl_Context.cxx
index 0a7d396..36933dd 100644 (file)
 #include <OpenGl_ArbDbg.hxx>
 #include <OpenGl_ArbFBO.hxx>
 #include <OpenGl_ExtGS.hxx>
+#include <OpenGl_ArbSamplerObject.hxx>
 #include <OpenGl_ArbTexBindless.hxx>
-#include <OpenGl_GlCore44.hxx>
+#include <OpenGl_GlCore45.hxx>
 #include <OpenGl_FrameBuffer.hxx>
+#include <OpenGl_FrameStats.hxx>
 #include <OpenGl_Sampler.hxx>
 #include <OpenGl_ShaderManager.hxx>
+#include <OpenGl_TextureSetPairIterator.hxx>
 #include <OpenGl_Workspace.hxx>
-#include <OpenGl_AspectFace.hxx>
+#include <OpenGl_Aspects.hxx>
+
 #include <Graphic3d_TransformUtils.hxx>
 #include <Graphic3d_RenderingParams.hxx>
-
+#include <Image_SupportedFormats.hxx>
 #include <Message_Messenger.hxx>
-
 #include <NCollection_Vector.hxx>
-
 #include <Standard_ProgramError.hxx>
+#include <Standard_WarningDisableFunctionCast.hxx>
 
 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Context,Standard_Transient)
 
@@ -61,13 +64,29 @@ IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Context,Standard_Transient)
   #include <GL/glx.h> // glXGetProcAddress()
 #endif
 
-#ifdef HAVE_GL2PS
-  #include <gl2ps.h>
-  #ifdef _MSC_VER
-    #pragma comment (lib, "gl2ps.lib")
-  #endif
-#endif
+#ifdef __EMSCRIPTEN__
+  #include <emscripten.h>
+  #include <emscripten/html5.h>
 
+  //! Check if WebGL extension is available and activate it
+  //! (usage of extension without activation will generate errors).
+  static bool checkEnableWebGlExtension (const OpenGl_Context& theCtx,
+                                         const char* theExtName)
+  {
+    if (!theCtx.CheckExtension (theExtName))
+    {
+      return false;
+    }
+    if (EMSCRIPTEN_WEBGL_CONTEXT_HANDLE aWebGlCtx = emscripten_webgl_get_current_context())
+    {
+      if (emscripten_webgl_enable_extension (aWebGlCtx, theExtName))
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+#endif
 
 namespace
 {
@@ -103,6 +122,8 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
   core15fwd  (NULL),
   core20     (NULL),
   core20fwd  (NULL),
+  core30     (NULL),
+  core30fwd  (NULL),
   core32     (NULL),
   core32back (NULL),
   core33     (NULL),
@@ -115,7 +136,10 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
   core43back (NULL),
   core44     (NULL),
   core44back (NULL),
+  core45     (NULL),
+  core45back (NULL),
   caps   (!theCaps.IsNull() ? theCaps : new OpenGl_Caps()),
+  hasGetBufferData (Standard_False),
 #if defined(GL_ES_VERSION_2_0)
   hasHighp   (Standard_False),
   hasUintIndex(Standard_False),
@@ -125,14 +149,26 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
   hasUintIndex(Standard_True),
   hasTexRGBA8(Standard_True),
 #endif
+  hasTexFloatLinear (Standard_False),
+  hasTexSRGB (Standard_False),
+  hasFboSRGB (Standard_False),
+  hasSRGBControl (Standard_False),
+#if defined(GL_ES_VERSION_2_0)
+  hasFlatShading (OpenGl_FeatureNotAvailable),
+#else
+  hasFlatShading (OpenGl_FeatureInCore),
+#endif
+  hasGlslBitwiseOps  (OpenGl_FeatureNotAvailable),
   hasDrawBuffers     (OpenGl_FeatureNotAvailable),
   hasFloatBuffer     (OpenGl_FeatureNotAvailable),
   hasHalfFloatBuffer (OpenGl_FeatureNotAvailable),
   hasSampleVariables (OpenGl_FeatureNotAvailable),
+  hasGeometryStage   (OpenGl_FeatureNotAvailable),
   arbDrawBuffers (Standard_False),
   arbNPTW  (Standard_False),
   arbTexRG (Standard_False),
   arbTexFloat (Standard_False),
+  arbSamplerObject (NULL),
   arbTexBindless (NULL),
   arbTBO (NULL),
   arbTboRGB32 (Standard_False),
@@ -150,15 +186,21 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
   atiMem (Standard_False),
   nvxMem (Standard_False),
   oesSampleVariables (Standard_False),
+  oesStdDerivatives (Standard_False),
   mySharedResources (new OpenGl_ResourcesMap()),
   myDelayed         (new OpenGl_DelayReleaseMap()),
   myUnusedResources (new OpenGl_ResourcesStack()),
   myClippingState (),
   myGlLibHandle (NULL),
   myFuncs (new OpenGl_GlFunctions()),
+  mySupportedFormats (new Image_SupportedFormats()),
   myAnisoMax   (1),
   myTexClamp   (GL_CLAMP_TO_EDGE),
   myMaxTexDim  (1024),
+  myMaxTexCombined (1),
+  myMaxTexUnitsFFP (1),
+  myMaxDumpSizeX (1024),
+  myMaxDumpSizeY (1024),
   myMaxClipPlanes (6),
   myMaxMsaaSamples(0),
   myMaxDrawBuffers (1),
@@ -168,26 +210,40 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
   myIsInitialized (Standard_False),
   myIsStereoBuffers (Standard_False),
   myIsGlNormalizeEnabled (Standard_False),
+  mySpriteTexUnit (Graphic3d_TextureUnit_PointSprite),
   myHasRayTracing (Standard_False),
   myHasRayTracingTextures (Standard_False),
   myHasRayTracingAdaptiveSampling (Standard_False),
+  myHasRayTracingAdaptiveSamplingAtomic (Standard_False),
+  myHasPBR (Standard_False),
+  myPBREnvLUTTexUnit       (Graphic3d_TextureUnit_PbrEnvironmentLUT),
+  myPBRDiffIBLMapSHTexUnit (Graphic3d_TextureUnit_PbrIblDiffuseSH),
+  myPBRSpecIBLMapTexUnit   (Graphic3d_TextureUnit_PbrIblSpecular),
+  myFrameStats (new OpenGl_FrameStats()),
+  myActiveMockTextures (0),
 #if !defined(GL_ES_VERSION_2_0)
   myPointSpriteOrig (GL_UPPER_LEFT),
   myRenderMode (GL_RENDER),
+  myShadeModel (GL_SMOOTH),
   myPolygonMode (GL_FILL),
 #else
   myPointSpriteOrig (0),
   myRenderMode (0),
+  myShadeModel (0),
   myPolygonMode (0),
 #endif
   myToCullBackFaces (false),
   myReadBuffer (0),
-  myDrawBuffers (1),
+  myDrawBuffers (0, 7),
   myDefaultVao (0),
-  myIsGlDebugCtx (Standard_False),
+  myColorMask (true),
+  myAlphaToCoverage (false),
+  myIsGlDebugCtx (false),
+  myIsSRgbWindow (false),
   myResolution (Graphic3d_RenderingParams::THE_DEFAULT_RESOLUTION),
   myResolutionRatio (1.0f),
   myLineWidthScale (1.0f),
+  myLineFeather (1.0f),
   myRenderScale (1.0f),
   myRenderScaleInv (1.0f)
 {
@@ -200,6 +256,10 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
   myViewportVirt[2] = 0;
   myViewportVirt[3] = 0;
 
+  myPolygonOffset.Mode   = Aspect_POM_Off;
+  myPolygonOffset.Factor = 0.0f;
+  myPolygonOffset.Units  = 0.0f;
+
   // system-dependent fields
 #if defined(HAVE_EGL)
   myDisplay  = (Aspect_Display          )EGL_NO_DISPLAY;
@@ -256,6 +316,18 @@ OpenGl_Context::~OpenGl_Context()
   myDefaultVao = 0;
 #endif
 
+  // release mock textures
+  if (!myTextureRgbaBlack.IsNull())
+  {
+    myTextureRgbaBlack->Release (this);
+    myTextureRgbaBlack.Nullify();
+  }
+  if (!myTextureRgbaWhite.IsNull())
+  {
+    myTextureRgbaWhite->Release (this);
+    myTextureRgbaWhite.Nullify();
+  }
+
   // release default FBO
   if (!myDefaultFbo.IsNull())
   {
@@ -287,12 +359,6 @@ OpenGl_Context::~OpenGl_Context()
   mySharedResources.Nullify();
   myDelayed.Nullify();
 
-  // release sampler object
-  if (!myTexSampler.IsNull())
-  {
-    myTexSampler->Release (this);
-  }
-
   if (arbDbg != NULL
    && myIsGlDebugCtx
    && IsValid())
@@ -412,12 +478,8 @@ void OpenGl_Context::SetDrawBuffer (const Standard_Integer theDrawBuffer)
   }
   ::glDrawBuffer (aDrawBuffer);
 
-  myDrawBuffers.Clear();
-
-  if (aDrawBuffer != GL_NONE)
-  {
-    myDrawBuffers.SetValue (0, aDrawBuffer);
-  }
+  myDrawBuffers.Init (GL_NONE);
+  myDrawBuffers.SetValue (0, aDrawBuffer);
 #else
   (void )theDrawBuffer;
 #endif
@@ -431,23 +493,23 @@ void OpenGl_Context::SetDrawBuffers (const Standard_Integer theNb, const Standar
 {
   Standard_ASSERT_RETURN (hasDrawBuffers, "Multiple draw buffers feature is not supported by the context", Standard_ASSERT_DO_NOTHING());
 
-  myDrawBuffers.Clear();
+  if (myDrawBuffers.Length() < theNb)
+  {
+    // should actually never happen here
+    myDrawBuffers.Resize (0, theNb - 1, false);
+  }
+  myDrawBuffers.Init (GL_NONE);
 
   Standard_Boolean useDefaultFbo = Standard_False;
   for (Standard_Integer anI = 0; anI < theNb; ++anI)
   {
-#if !defined(GL_ES_VERSION_2_0)
-    const Standard_Integer aDrawBuffer = !myIsStereoBuffers ? stereoToMonoBuffer (theDrawBuffers[anI]) : theDrawBuffers[anI];
-#else
-    const Standard_Integer aDrawBuffer = theDrawBuffers[anI];
-#endif
-    if (aDrawBuffer < GL_COLOR_ATTACHMENT0 && aDrawBuffer != GL_NONE)
+    if (theDrawBuffers[anI] < GL_COLOR_ATTACHMENT0 && theDrawBuffers[anI] != GL_NONE)
     {
       useDefaultFbo = Standard_True;
     }
-    else if (aDrawBuffer != GL_NONE)
+    else
     {
-      myDrawBuffers.SetValue (anI, aDrawBuffer);
+      myDrawBuffers.SetValue (anI, theDrawBuffers[anI]);
     }
   }
   if (arbFBO != NULL && useDefaultFbo)
@@ -458,6 +520,35 @@ void OpenGl_Context::SetDrawBuffers (const Standard_Integer theNb, const Standar
   myFuncs->glDrawBuffers (theNb, (const GLenum*)theDrawBuffers);
 }
 
+// =======================================================================
+// function : SetFrameBufferSRGB
+// purpose  :
+// =======================================================================
+void OpenGl_Context::SetFrameBufferSRGB (bool theIsFbo, bool theIsFboSRgb)
+{
+  if (!hasFboSRGB)
+  {
+    myIsSRgbActive = false;
+    return;
+  }
+  myIsSRgbActive = ToRenderSRGB()
+               && (theIsFbo || myIsSRgbWindow)
+               && theIsFboSRgb;
+  if (!hasSRGBControl)
+  {
+    return;
+  }
+
+  if (myIsSRgbActive)
+  {
+    core11fwd->glEnable (GL_FRAMEBUFFER_SRGB);
+  }
+  else
+  {
+    core11fwd->glDisable (GL_FRAMEBUFFER_SRGB);
+  }
+}
+
 // =======================================================================
 // function : SetCullBackFaces
 // purpose  :
@@ -492,37 +583,31 @@ void OpenGl_Context::FetchState()
   if (core11 != NULL)
   {
     ::glGetIntegerv (GL_RENDER_MODE, &myRenderMode);
+    ::glGetIntegerv (GL_SHADE_MODEL, &myShadeModel);
   }
 
   // cache read buffers state
   ::glGetIntegerv (GL_READ_BUFFER, &myReadBuffer);
 
   // cache draw buffers state
-  myDrawBuffers.Clear();
+  if (myDrawBuffers.Length() < myMaxDrawBuffers)
+  {
+    myDrawBuffers.Resize (0, myMaxDrawBuffers - 1, false);
+  }
+  myDrawBuffers.Init (GL_NONE);
 
+  Standard_Integer aDrawBuffer = GL_NONE;
   if (myMaxDrawBuffers == 1)
   {
-    Standard_Integer aDrawBuffer;
-
     ::glGetIntegerv (GL_DRAW_BUFFER, &aDrawBuffer);
-
-    if (aDrawBuffer != GL_NONE)
-    {
-      myDrawBuffers.SetValue (0, aDrawBuffer);
-    }
+    myDrawBuffers.SetValue (0, aDrawBuffer);
   }
   else
   {
-    Standard_Integer aDrawBuffer;
-
     for (Standard_Integer anI = 0; anI < myMaxDrawBuffers; ++anI)
     {
       ::glGetIntegerv (GL_DRAW_BUFFER0 + anI, &aDrawBuffer);
-
-      if (aDrawBuffer != GL_NONE)
-      {
-        myDrawBuffers.SetValue (anI, aDrawBuffer);
-      }
+      myDrawBuffers.SetValue (anI, aDrawBuffer);
     }
   }
 #endif
@@ -553,7 +638,6 @@ Standard_Boolean OpenGl_Context::IsCurrent() const
 {
 #if defined(HAVE_EGL)
   if ((EGLDisplay )myDisplay  == EGL_NO_DISPLAY
-   || (EGLSurface )myWindow   == EGL_NO_SURFACE
    || (EGLContext )myGContext == EGL_NO_CONTEXT)
   {
     return Standard_False;
@@ -589,7 +673,6 @@ Standard_Boolean OpenGl_Context::MakeCurrent()
 {
 #if defined(HAVE_EGL)
   if ((EGLDisplay )myDisplay  == EGL_NO_DISPLAY
-   || (EGLSurface )myWindow   == EGL_NO_SURFACE
    || (EGLContext )myGContext == EGL_NO_CONTEXT)
   {
     Standard_ProgramError_Raise_if (myIsInitialized, "OpenGl_Context::Init() should be called before!");
@@ -754,6 +837,10 @@ Standard_Boolean OpenGl_Context::CheckExtension (const char* theExtName) const
 #endif
     return Standard_False;
   }
+  else if (caps->contextNoExtensions)
+  {
+    return Standard_False;
+  }
 
 #if !defined(GL_ES_VERSION_2_0)
   // available since OpenGL 3.0
@@ -967,32 +1054,47 @@ void OpenGl_Context::ReadGlVersion (Standard_Integer& theGlVerMajor,
   theGlVerMajor = 0;
   theGlVerMinor = 0;
 
-#ifdef GL_MAJOR_VERSION
-  // available since OpenGL 3.0 and OpenGL 3.0 ES
-  GLint aMajor = 0, aMinor = 0;
-  glGetIntegerv (GL_MAJOR_VERSION, &aMajor);
-  glGetIntegerv (GL_MINOR_VERSION, &aMinor);
-  // glGetError() sometimes does not report an error here even if
-  // GL does not know GL_MAJOR_VERSION and GL_MINOR_VERSION constants.
-  // This happens on some renderers like e.g. Cygwin MESA.
-  // Thus checking additionally if GL has put anything to
-  // the output variables.
-  if (::glGetError() == GL_NO_ERROR && aMajor != 0 && aMinor != 0)
-  {
-    theGlVerMajor = aMajor;
-    theGlVerMinor = aMinor;
-    return;
-  }
-  for (GLenum anErr = ::glGetError(), aPrevErr = GL_NO_ERROR;; aPrevErr = anErr, anErr = ::glGetError())
+  bool toCheckVer3 = true;
+#if defined(__EMSCRIPTEN__)
+  // WebGL 1.0 prints annoying invalid enumeration warnings to console.
+  toCheckVer3 = false;
+  if (EMSCRIPTEN_WEBGL_CONTEXT_HANDLE aWebGlCtx = emscripten_webgl_get_current_context())
   {
-    if (anErr == GL_NO_ERROR
-     || anErr == aPrevErr)
+    EmscriptenWebGLContextAttributes anAttribs = {};
+    if (emscripten_webgl_get_context_attributes (aWebGlCtx, &anAttribs) == EMSCRIPTEN_RESULT_SUCCESS)
     {
-      break;
+      toCheckVer3 = anAttribs.majorVersion >= 2;
     }
   }
 #endif
 
+  // Available since OpenGL 3.0 and OpenGL ES 3.0.
+  if (toCheckVer3)
+  {
+    GLint aMajor = 0, aMinor = 0;
+    glGetIntegerv (GL_MAJOR_VERSION, &aMajor);
+    glGetIntegerv (GL_MINOR_VERSION, &aMinor);
+    // glGetError() sometimes does not report an error here even if
+    // GL does not know GL_MAJOR_VERSION and GL_MINOR_VERSION constants.
+    // This happens on some renderers like e.g. Cygwin MESA.
+    // Thus checking additionally if GL has put anything to
+    // the output variables.
+    if (::glGetError() == GL_NO_ERROR && aMajor != 0 && aMinor != 0)
+    {
+      theGlVerMajor = aMajor;
+      theGlVerMinor = aMinor;
+      return;
+    }
+    for (GLenum anErr = ::glGetError(), aPrevErr = GL_NO_ERROR;; aPrevErr = anErr, anErr = ::glGetError())
+    {
+      if (anErr == GL_NO_ERROR
+       || anErr == aPrevErr)
+      {
+        break;
+      }
+    }
+  }
+
   // Read version string.
   // Notice that only first two numbers split by point '2.1 XXXXX' are significant.
   // Following trash (after space) is vendor-specific.
@@ -1169,24 +1271,42 @@ Standard_Boolean OpenGl_Context::IncludeMessage (const unsigned int theSource,
 // function : checkWrongVersion
 // purpose  :
 // ======================================================================
-void OpenGl_Context::checkWrongVersion (const Standard_Integer theGlVerMajor,
-                                        const Standard_Integer theGlVerMinor)
+void OpenGl_Context::checkWrongVersion (Standard_Integer theGlVerMajor, Standard_Integer theGlVerMinor,
+                                        const char* theLastFailedProc)
 {
   if (!IsGlGreaterEqual (theGlVerMajor, theGlVerMinor))
   {
     return;
   }
 
-  TCollection_ExtendedString aMsg = TCollection_ExtendedString()
-    + "Error! OpenGL context reports version "
-    + myGlVerMajor  + "." + myGlVerMinor
-    + " but does not export required functions for "
-    + theGlVerMajor + "." + theGlVerMinor;
-  PushMessage (GL_DEBUG_SOURCE_APPLICATION,
-               GL_DEBUG_TYPE_ERROR,
-               0,
-               GL_DEBUG_SEVERITY_HIGH,
-               aMsg);
+  PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+               TCollection_AsciiString()
+               + "Error! OpenGL context reports version "
+               + myGlVerMajor  + "." + myGlVerMinor
+               + " but does not export required functions for " + theGlVerMajor + "." + theGlVerMinor
+               + " (" + (theLastFailedProc != NULL ? theLastFailedProc : "") + ")\n"
+               + "Please report this issue to OpenGL driver vendor '" + myVendor + "'");
+
+  // lower internal version
+  if (theGlVerMinor > 0)
+  {
+    myGlVerMajor = theGlVerMajor;
+    myGlVerMinor = theGlVerMinor - 1;
+    return;
+  }
+#if defined(GL_ES_VERSION_2_0)
+  switch (theGlVerMajor)
+  {
+    case 3: myGlVerMajor = 2; myGlVerMinor = 0; return;
+  }
+#else
+  switch (theGlVerMajor)
+  {
+    case 2: myGlVerMajor = 1; myGlVerMinor = 5; return;
+    case 3: myGlVerMajor = 2; myGlVerMinor = 1; return;
+    case 4: myGlVerMajor = 3; myGlVerMinor = 3; return;
+  }
+#endif
 }
 
 // =======================================================================
@@ -1203,6 +1323,53 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   myMaxColorAttachments = 1;
   ReadGlVersion (myGlVerMajor, myGlVerMinor);
   myVendor = (const char* )::glGetString (GL_VENDOR);
+  myVendor.LowerCase();
+
+  // standard formats
+  mySupportedFormats->Clear();
+  mySupportedFormats->Add (Image_PixMap::ImgGray);
+  mySupportedFormats->Add (Image_PixMap::ImgAlpha);
+  mySupportedFormats->Add (Image_PixMap::ImgRGB);
+  mySupportedFormats->Add (Image_PixMap::ImgRGB32);
+  mySupportedFormats->Add (Image_PixMap::ImgRGBA);
+
+  if (caps->contextMajorVersionUpper != -1)
+  {
+    // synthetically restrict OpenGL version for testing
+    Standard_Integer aCtxVer[2] = { myGlVerMajor, myGlVerMinor };
+    bool isLowered = false;
+    if (myGlVerMajor > caps->contextMajorVersionUpper)
+    {
+      isLowered = true;
+      myGlVerMajor = caps->contextMajorVersionUpper;
+    #if defined(GL_ES_VERSION_2_0)
+      switch (myGlVerMajor)
+      {
+        case 2: myGlVerMinor = 0; break;
+      }
+    #else
+      switch (myGlVerMajor)
+      {
+        case 1: myGlVerMinor = 5; break;
+        case 2: myGlVerMinor = 1; break;
+        case 3: myGlVerMinor = 3; break;
+      }
+    #endif
+    }
+    if (caps->contextMinorVersionUpper != -1
+     && myGlVerMinor > caps->contextMinorVersionUpper)
+    {
+      isLowered = true;
+      myGlVerMinor = caps->contextMinorVersionUpper;
+    }
+    if (isLowered)
+    {
+      PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_MEDIUM,
+                   TCollection_AsciiString ("OpenGL version ") + aCtxVer[0] + "." + aCtxVer[1]
+                   + " has been lowered to " + myGlVerMajor + "." + myGlVerMinor);
+    }
+  }
+
   if (!caps->ffpEnable
    && !IsGlGreaterEqual (2, 0))
   {
@@ -1223,7 +1390,7 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   const bool isCoreProfile = false;
 #else
 
-  if (myVendor.Search ("NVIDIA") != -1)
+  if (myVendor.Search ("nvidia") != -1)
   {
     // Buffer detailed info: Buffer object 1 (bound to GL_ARRAY_BUFFER_ARB, usage hint is GL_STATIC_DRAW)
     // will use VIDEO memory as the source for buffer object operations.
@@ -1260,6 +1427,8 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   core15fwd  = NULL;
   core20     = NULL;
   core20fwd  = NULL;
+  core30     = NULL;
+  core30fwd  = NULL;
   core32     = NULL;
   core32back = NULL;
   core33     = NULL;
@@ -1272,6 +1441,8 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   core43back = NULL;
   core44     = NULL;
   core44back = NULL;
+  core45     = NULL;
+  core45back = NULL;
   arbTBO     = NULL;
   arbTboRGB32 = Standard_False;
   arbIns     = NULL;
@@ -1281,10 +1452,17 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   extGS      = NULL;
   myDefaultVao = 0;
 
+  //! Make record shorter to retrieve function pointer using variable with same name
+  const char* aLastFailedProc = NULL;
+  #define FindProcShort(theFunc) FindProcVerbose(aLastFailedProc, #theFunc, myFuncs->theFunc)
+
 #if defined(GL_ES_VERSION_2_0)
 
   hasTexRGBA8 = IsGlGreaterEqual (3, 0)
              || CheckExtension ("GL_OES_rgb8_rgba8");
+  hasTexSRGB  = IsGlGreaterEqual (3, 0);
+  hasFboSRGB  = IsGlGreaterEqual (3, 0);
+  hasSRGBControl = CheckExtension ("GL_EXT_sRGB_write_control");
   // NPOT textures has limited support within OpenGL ES 2.0
   // which are relaxed by OpenGL ES 3.0 or some extensions
   //arbNPTW     = IsGlGreaterEqual (3, 0)
@@ -1297,6 +1475,20 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   extAnis = CheckExtension ("GL_EXT_texture_filter_anisotropic");
   extPDS  = IsGlGreaterEqual (3, 0)
          || CheckExtension ("GL_OES_packed_depth_stencil");
+#ifdef __EMSCRIPTEN__
+  if (!extPDS
+    && checkEnableWebGlExtension (*this, "GL_WEBGL_depth_texture"))
+  {
+    extPDS = true; // WebGL 1.0 extension (in WebGL 2.0 core)
+  }
+#endif
+
+  if (extBgra)
+  {
+    // no BGR on OpenGL ES - only BGRA as extension
+    mySupportedFormats->Add (Image_PixMap::ImgBGR32);
+    mySupportedFormats->Add (Image_PixMap::ImgBGRA);
+  }
 
   core11fwd = (OpenGl_GlCore11Fwd* )(&(*myFuncs));
   if (IsGlGreaterEqual (2, 0))
@@ -1308,14 +1500,32 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
     arbFBO    = (OpenGl_ArbFBO*      )(&(*myFuncs));
   }
   if (IsGlGreaterEqual (3, 0)
-   && FindProc ("glBlitFramebuffer", myFuncs->glBlitFramebuffer))
+   && FindProcShort (glBlitFramebuffer))
   {
     arbFBOBlit = (OpenGl_ArbFBOBlit* )(&(*myFuncs));
   }
+  if (IsGlGreaterEqual (3, 0)
+   && FindProcShort (glGenSamplers)
+   && FindProcShort (glDeleteSamplers)
+   && FindProcShort (glIsSampler)
+   && FindProcShort (glBindSampler)
+   && FindProcShort (glSamplerParameteri)
+   && FindProcShort (glSamplerParameteriv)
+   && FindProcShort (glSamplerParameterf)
+   && FindProcShort (glSamplerParameterfv)
+   && FindProcShort (glGetSamplerParameteriv)
+   && FindProcShort (glGetSamplerParameterfv))
+   //&& FindProcShort (glSamplerParameterIiv) // only on Desktop or with extensions GL_OES_texture_border_clamp/GL_EXT_texture_border_clamp
+   //&& FindProcShort (glSamplerParameterIuiv)
+   //&& FindProcShort (glGetSamplerParameterIiv)
+   //&& FindProcShort (glGetSamplerParameterIuiv))
+  {
+    arbSamplerObject = (OpenGl_ArbSamplerObject* )(&(*myFuncs));
+  }
   extFragDepth = !IsGlGreaterEqual(3, 0)
                && CheckExtension ("GL_EXT_frag_depth");
   if (IsGlGreaterEqual (3, 1)
-   && FindProc ("glTexStorage2DMultisample", myFuncs->glTexStorage2DMultisample))
+   && FindProcShort (glTexStorage2DMultisample))
   {
     // MSAA RenderBuffers have been defined in OpenGL ES 3.0,
     // but MSAA Textures - only in OpenGL ES 3.1+
@@ -1333,94 +1543,402 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
     hasHighp = Standard_True;
   }
 
-  arbTexFloat = IsGlGreaterEqual (3, 0)
-             && FindProc ("glTexImage3D", myFuncs->glTexImage3D);
-
-  const Standard_Boolean hasTexBuffer32  = IsGlGreaterEqual (3, 2) && FindProc ("glTexBuffer", myFuncs->glTexBuffer);
-  const Standard_Boolean hasExtTexBuffer = CheckExtension ("GL_EXT_texture_buffer") && FindProc ("glTexBufferEXT", myFuncs->glTexBuffer);
+  arbTexFloat = (IsGlGreaterEqual (3, 0)
+              && FindProcShort (glTexImage3D))
+              || CheckExtension ("GL_OES_texture_float");
+  hasTexFloatLinear = arbTexFloat
+                   && CheckExtension ("GL_OES_texture_float_linear");
 
+  const bool hasTexBuffer32  = IsGlGreaterEqual (3, 2) && FindProcShort (glTexBuffer);
+  const bool hasExtTexBuffer = CheckExtension ("GL_EXT_texture_buffer") && FindProc ("glTexBufferEXT", myFuncs->glTexBuffer);
   if (hasTexBuffer32 || hasExtTexBuffer)
   {
     arbTBO = reinterpret_cast<OpenGl_ArbTBO*> (myFuncs.get());
   }
 
-  // initialize debug context extension
-  if (CheckExtension ("GL_KHR_debug"))
+  bool hasInstanced = IsGlGreaterEqual (3, 0)
+       && FindProcShort (glVertexAttribDivisor)
+       && FindProcShort (glDrawArraysInstanced)
+       && FindProcShort (glDrawElementsInstanced);
+  if (!hasInstanced)
   {
-    // this functionality become a part of OpenGL ES 3.2
-    arbDbg = NULL;
-    // According to GL_KHR_debug spec, all functions should have KHR suffix.
-    // However, some implementations can export these functions without suffix.
-    if (FindProc ("glDebugMessageControlKHR",  myFuncs->glDebugMessageControl)
-     && FindProc ("glDebugMessageInsertKHR",   myFuncs->glDebugMessageInsert)
-     && FindProc ("glDebugMessageCallbackKHR", myFuncs->glDebugMessageCallback)
-     && FindProc ("glGetDebugMessageLogKHR",   myFuncs->glGetDebugMessageLog))
-    {
-      arbDbg = (OpenGl_ArbDbg* )(&(*myFuncs));
-    }
-
-    if (arbDbg != NULL
-     && caps->contextDebug)
-    {
-      // setup default callback
-      myIsGlDebugCtx = Standard_True;
-      arbDbg->glDebugMessageCallback (debugCallbackWrap, this);
-      ::glEnable (GL_DEBUG_OUTPUT);
-      if (caps->contextSyncDebug)
-      {
-        // note that some broken implementations (e.g. simulators) might generate error message on this call
-        ::glEnable (GL_DEBUG_OUTPUT_SYNCHRONOUS);
-      }
-    }
+    hasInstanced = CheckExtension ("GL_ANGLE_instanced_arrays")
+       && FindProc ("glVertexAttribDivisorANGLE",   myFuncs->glVertexAttribDivisor)
+       && FindProc ("glDrawArraysInstancedANGLE",   myFuncs->glDrawArraysInstanced)
+       && FindProc ("glDrawElementsInstancedANGLE", myFuncs->glDrawElementsInstanced);
+  }
+  if (hasInstanced)
+  {
+    arbIns = (OpenGl_ArbIns* )(&(*myFuncs));
   }
 
-  extDrawBuffers = CheckExtension ("GL_EXT_draw_buffers") && FindProc ("glDrawBuffersEXT", myFuncs->glDrawBuffers);
-  arbDrawBuffers = CheckExtension ("GL_ARB_draw_buffers") && FindProc ("glDrawBuffersARB", myFuncs->glDrawBuffers);
+  const bool hasVAO = IsGlGreaterEqual (3, 0)
+       && FindProcShort (glBindVertexArray)
+       && FindProcShort (glDeleteVertexArrays)
+       && FindProcShort (glGenVertexArrays)
+       && FindProcShort (glIsVertexArray);
+  const bool hasMapBufferRange = IsGlGreaterEqual (3, 0)
+       && FindProcShort (glMapBufferRange)
+       && FindProcShort (glFlushMappedBufferRange);
 
-  if (IsGlGreaterEqual (3, 0) && FindProc ("glDrawBuffers", myFuncs->glDrawBuffers))
+  // load OpenGL ES 3.0 new functions
+  const bool has30es = IsGlGreaterEqual (3, 0)
+       && hasVAO
+       && hasMapBufferRange
+       && hasInstanced
+       && arbSamplerObject != NULL
+       && arbFBOBlit != NULL
+       && FindProcShort (glReadBuffer)
+       && FindProcShort (glDrawRangeElements)
+       && FindProcShort (glTexImage3D)
+       && FindProcShort (glTexSubImage3D)
+       && FindProcShort (glCopyTexSubImage3D)
+       && FindProcShort (glCompressedTexImage3D)
+       && FindProcShort (glCompressedTexSubImage3D)
+       && FindProcShort (glGenQueries)
+       && FindProcShort (glDeleteQueries)
+       && FindProcShort (glIsQuery)
+       && FindProcShort (glBeginQuery)
+       && FindProcShort (glEndQuery)
+       && FindProcShort (glGetQueryiv)
+       && FindProcShort (glGetQueryObjectuiv)
+       && FindProcShort (glUnmapBuffer)
+       && FindProcShort (glGetBufferPointerv)
+       && FindProcShort (glDrawBuffers)
+       && FindProcShort (glUniformMatrix2x3fv)
+       && FindProcShort (glUniformMatrix3x2fv)
+       && FindProcShort (glUniformMatrix2x4fv)
+       && FindProcShort (glUniformMatrix4x2fv)
+       && FindProcShort (glUniformMatrix3x4fv)
+       && FindProcShort (glUniformMatrix4x3fv)
+       && FindProcShort (glRenderbufferStorageMultisample)
+       && FindProcShort (glFramebufferTextureLayer)
+       && FindProcShort (glGetIntegeri_v)
+       && FindProcShort (glBeginTransformFeedback)
+       && FindProcShort (glEndTransformFeedback)
+       && FindProcShort (glBindBufferRange)
+       && FindProcShort (glBindBufferBase)
+       && FindProcShort (glTransformFeedbackVaryings)
+       && FindProcShort (glGetTransformFeedbackVarying)
+       && FindProcShort (glVertexAttribIPointer)
+       && FindProcShort (glGetVertexAttribIiv)
+       && FindProcShort (glGetVertexAttribIuiv)
+       && FindProcShort (glVertexAttribI4i)
+       && FindProcShort (glVertexAttribI4ui)
+       && FindProcShort (glVertexAttribI4iv)
+       && FindProcShort (glVertexAttribI4uiv)
+       && FindProcShort (glGetUniformuiv)
+       && FindProcShort (glGetFragDataLocation)
+       && FindProcShort (glUniform1ui)
+       && FindProcShort (glUniform2ui)
+       && FindProcShort (glUniform3ui)
+       && FindProcShort (glUniform4ui)
+       && FindProcShort (glUniform1uiv)
+       && FindProcShort (glUniform2uiv)
+       && FindProcShort (glUniform3uiv)
+       && FindProcShort (glUniform4uiv)
+       && FindProcShort (glClearBufferiv)
+       && FindProcShort (glClearBufferuiv)
+       && FindProcShort (glClearBufferfv)
+       && FindProcShort (glClearBufferfi)
+       && FindProcShort (glGetStringi)
+       && FindProcShort (glCopyBufferSubData)
+       && FindProcShort (glGetUniformIndices)
+       && FindProcShort (glGetActiveUniformsiv)
+       && FindProcShort (glGetUniformBlockIndex)
+       && FindProcShort (glGetActiveUniformBlockiv)
+       && FindProcShort (glGetActiveUniformBlockName)
+       && FindProcShort (glUniformBlockBinding)
+       && FindProcShort (glFenceSync)
+       && FindProcShort (glIsSync)
+       && FindProcShort (glDeleteSync)
+       && FindProcShort (glClientWaitSync)
+       && FindProcShort (glWaitSync)
+       && FindProcShort (glGetInteger64v)
+       && FindProcShort (glGetSynciv)
+       && FindProcShort (glGetInteger64i_v)
+       && FindProcShort (glGetBufferParameteri64v)
+       && FindProcShort (glBindTransformFeedback)
+       && FindProcShort (glDeleteTransformFeedbacks)
+       && FindProcShort (glGenTransformFeedbacks)
+       && FindProcShort (glIsTransformFeedback)
+       && FindProcShort (glPauseTransformFeedback)
+       && FindProcShort (glResumeTransformFeedback)
+       && FindProcShort (glGetProgramBinary)
+       && FindProcShort (glProgramBinary)
+       && FindProcShort (glProgramParameteri)
+       && FindProcShort (glInvalidateFramebuffer)
+       && FindProcShort (glInvalidateSubFramebuffer)
+       && FindProcShort (glTexStorage2D)
+       && FindProcShort (glTexStorage3D)
+       && FindProcShort (glGetInternalformativ);
+  if (!has30es)
   {
-    hasDrawBuffers = OpenGl_FeatureInCore;
+    checkWrongVersion (3, 0, aLastFailedProc);
   }
-  else if (extDrawBuffers || arbDrawBuffers)
+  else
   {
-    hasDrawBuffers = OpenGl_FeatureInExtensions;
+    core30    = (OpenGl_GlCore30*    )(&(*myFuncs));
+    core30fwd = (OpenGl_GlCore30Fwd* )(&(*myFuncs));
+    hasGetBufferData = true;
   }
 
-  hasFloatBuffer     = IsGlGreaterEqual (3, 2) ? OpenGl_FeatureInCore :
-                       CheckExtension ("GL_EXT_color_buffer_float") ? OpenGl_FeatureInExtensions 
-                                                                    : OpenGl_FeatureNotAvailable;
-  hasHalfFloatBuffer = IsGlGreaterEqual (3, 2) ? OpenGl_FeatureInCore :
-                       CheckExtension ("GL_EXT_color_buffer_half_float") ? OpenGl_FeatureInExtensions 
-                                                                         : OpenGl_FeatureNotAvailable;
-
-  oesSampleVariables = CheckExtension ("GL_OES_sample_variables");
-  hasSampleVariables = IsGlGreaterEqual (3, 2) ? OpenGl_FeatureInCore :
-                       oesSampleVariables ? OpenGl_FeatureInExtensions
-                                          : OpenGl_FeatureNotAvailable;
-#else
-
-  myTexClamp = IsGlGreaterEqual (1, 2) ? GL_CLAMP_TO_EDGE : GL_CLAMP;
-
-  hasTexRGBA8 = Standard_True;
-  arbDrawBuffers   = CheckExtension ("GL_ARB_draw_buffers");
-  arbNPTW          = CheckExtension ("GL_ARB_texture_non_power_of_two");
+  // load OpenGL ES 3.1 new functions
+  const bool has31es = IsGlGreaterEqual (3, 1)
+       && has30es
+       && FindProcShort (glDispatchCompute)
+       && FindProcShort (glDispatchComputeIndirect)
+       && FindProcShort (glDrawArraysIndirect)
+       && FindProcShort (glDrawElementsIndirect)
+       && FindProcShort (glFramebufferParameteri)
+       && FindProcShort (glGetFramebufferParameteriv)
+       && FindProcShort (glGetProgramInterfaceiv)
+       && FindProcShort (glGetProgramResourceIndex)
+       && FindProcShort (glGetProgramResourceName)
+       && FindProcShort (glGetProgramResourceiv)
+       && FindProcShort (glGetProgramResourceLocation)
+       && FindProcShort (glUseProgramStages)
+       && FindProcShort (glActiveShaderProgram)
+       && FindProcShort (glCreateShaderProgramv)
+       && FindProcShort (glBindProgramPipeline)
+       && FindProcShort (glDeleteProgramPipelines)
+       && FindProcShort (glGenProgramPipelines)
+       && FindProcShort (glIsProgramPipeline)
+       && FindProcShort (glGetProgramPipelineiv)
+       && FindProcShort (glProgramUniform1i)
+       && FindProcShort (glProgramUniform2i)
+       && FindProcShort (glProgramUniform3i)
+       && FindProcShort (glProgramUniform4i)
+       && FindProcShort (glProgramUniform1ui)
+       && FindProcShort (glProgramUniform2ui)
+       && FindProcShort (glProgramUniform3ui)
+       && FindProcShort (glProgramUniform4ui)
+       && FindProcShort (glProgramUniform1f)
+       && FindProcShort (glProgramUniform2f)
+       && FindProcShort (glProgramUniform3f)
+       && FindProcShort (glProgramUniform4f)
+       && FindProcShort (glProgramUniform1iv)
+       && FindProcShort (glProgramUniform2iv)
+       && FindProcShort (glProgramUniform3iv)
+       && FindProcShort (glProgramUniform4iv)
+       && FindProcShort (glProgramUniform1uiv)
+       && FindProcShort (glProgramUniform2uiv)
+       && FindProcShort (glProgramUniform3uiv)
+       && FindProcShort (glProgramUniform4uiv)
+       && FindProcShort (glProgramUniform1fv)
+       && FindProcShort (glProgramUniform2fv)
+       && FindProcShort (glProgramUniform3fv)
+       && FindProcShort (glProgramUniform4fv)
+       && FindProcShort (glProgramUniformMatrix2fv)
+       && FindProcShort (glProgramUniformMatrix3fv)
+       && FindProcShort (glProgramUniformMatrix4fv)
+       && FindProcShort (glProgramUniformMatrix2x3fv)
+       && FindProcShort (glProgramUniformMatrix3x2fv)
+       && FindProcShort (glProgramUniformMatrix2x4fv)
+       && FindProcShort (glProgramUniformMatrix4x2fv)
+       && FindProcShort (glProgramUniformMatrix3x4fv)
+       && FindProcShort (glProgramUniformMatrix4x3fv)
+       && FindProcShort (glValidateProgramPipeline)
+       && FindProcShort (glGetProgramPipelineInfoLog)
+       && FindProcShort (glBindImageTexture)
+       && FindProcShort (glGetBooleani_v)
+       && FindProcShort (glMemoryBarrier)
+       && FindProcShort (glMemoryBarrierByRegion)
+       && FindProcShort (glTexStorage2DMultisample)
+       && FindProcShort (glGetMultisamplefv)
+       && FindProcShort (glSampleMaski)
+       && FindProcShort (glGetTexLevelParameteriv)
+       && FindProcShort (glGetTexLevelParameterfv)
+       && FindProcShort (glBindVertexBuffer)
+       && FindProcShort (glVertexAttribFormat)
+       && FindProcShort (glVertexAttribIFormat)
+       && FindProcShort (glVertexAttribBinding)
+       && FindProcShort (glVertexBindingDivisor);
+  if (!has31es)
+  {
+    checkWrongVersion (3, 1, aLastFailedProc);
+  }
+
+  // initialize debug context extension
+  if (IsGlGreaterEqual (3, 2)
+   || CheckExtension ("GL_KHR_debug"))
+  {
+    // this functionality become a part of OpenGL ES 3.2
+    arbDbg = NULL;
+    if (IsGlGreaterEqual (3, 2)
+     && FindProcShort (glDebugMessageControl)
+     && FindProcShort (glDebugMessageInsert)
+     && FindProcShort (glDebugMessageCallback)
+     && FindProcShort (glGetDebugMessageLog))
+    {
+      arbDbg = (OpenGl_ArbDbg* )(&(*myFuncs));
+    }
+    // According to GL_KHR_debug spec, all functions should have KHR suffix.
+    // However, some implementations can export these functions without suffix.
+    else if (!IsGlGreaterEqual (3, 2)
+     && FindProc ("glDebugMessageControlKHR",  myFuncs->glDebugMessageControl)
+     && FindProc ("glDebugMessageInsertKHR",   myFuncs->glDebugMessageInsert)
+     && FindProc ("glDebugMessageCallbackKHR", myFuncs->glDebugMessageCallback)
+     && FindProc ("glGetDebugMessageLogKHR",   myFuncs->glGetDebugMessageLog))
+    {
+      arbDbg = (OpenGl_ArbDbg* )(&(*myFuncs));
+    }
+
+    if (arbDbg != NULL
+     && caps->contextDebug)
+    {
+      // setup default callback
+      myIsGlDebugCtx = Standard_True;
+      arbDbg->glDebugMessageCallback (debugCallbackWrap, this);
+      ::glEnable (GL_DEBUG_OUTPUT);
+      if (caps->contextSyncDebug)
+      {
+        // note that some broken implementations (e.g. simulators) might generate error message on this call
+        ::glEnable (GL_DEBUG_OUTPUT_SYNCHRONOUS);
+      }
+    }
+  }
+
+  // load OpenGL ES 3.2 new functions
+  const bool has32es = IsGlGreaterEqual (3, 2)
+       && has31es
+       && hasTexBuffer32
+       && arbDbg != NULL
+       && FindProcShort (glBlendBarrier)
+       && FindProcShort (glCopyImageSubData)
+       && FindProcShort (glPushDebugGroup)
+       && FindProcShort (glPopDebugGroup)
+       && FindProcShort (glObjectLabel)
+       && FindProcShort (glGetObjectLabel)
+       && FindProcShort (glObjectPtrLabel)
+       && FindProcShort (glGetObjectPtrLabel)
+       && FindProcShort (glGetPointerv)
+       && FindProcShort (glEnablei)
+       && FindProcShort (glDisablei)
+       && FindProcShort (glBlendEquationi)
+       && FindProcShort (glBlendEquationSeparatei)
+       && FindProcShort (glBlendFunci)
+       && FindProcShort (glBlendFuncSeparatei)
+       && FindProcShort (glColorMaski)
+       && FindProcShort (glIsEnabledi)
+       && FindProcShort (glDrawElementsBaseVertex)
+       && FindProcShort (glDrawRangeElementsBaseVertex)
+       && FindProcShort (glDrawElementsInstancedBaseVertex)
+       && FindProcShort (glFramebufferTexture)
+       && FindProcShort (glPrimitiveBoundingBox)
+       && FindProcShort (glGetGraphicsResetStatus)
+       && FindProcShort (glReadnPixels)
+       && FindProcShort (glGetnUniformfv)
+       && FindProcShort (glGetnUniformiv)
+       && FindProcShort (glGetnUniformuiv)
+       && FindProcShort (glMinSampleShading)
+       && FindProcShort (glPatchParameteri)
+       && FindProcShort (glTexParameterIiv)
+       && FindProcShort (glTexParameterIuiv)
+       && FindProcShort (glGetTexParameterIiv)
+       && FindProcShort (glGetTexParameterIuiv)
+       && FindProcShort (glSamplerParameterIiv)
+       && FindProcShort (glSamplerParameterIuiv)
+       && FindProcShort (glGetSamplerParameterIiv)
+       && FindProcShort (glGetSamplerParameterIuiv)
+       && FindProcShort (glTexBufferRange)
+       && FindProcShort (glTexStorage3DMultisample);
+  if (!has32es)
+  {
+    checkWrongVersion (3, 2, aLastFailedProc);
+  }
+
+  extDrawBuffers = CheckExtension ("GL_EXT_draw_buffers") && FindProc ("glDrawBuffersEXT", myFuncs->glDrawBuffers);
+  arbDrawBuffers = CheckExtension ("GL_ARB_draw_buffers") && FindProc ("glDrawBuffersARB", myFuncs->glDrawBuffers);
+
+  if (IsGlGreaterEqual (3, 0) && FindProcShort (glDrawBuffers))
+  {
+    hasDrawBuffers = OpenGl_FeatureInCore;
+  }
+  else if (extDrawBuffers || arbDrawBuffers)
+  {
+    hasDrawBuffers = OpenGl_FeatureInExtensions;
+  }
+
+  hasFloatBuffer     = IsGlGreaterEqual (3, 2) ? OpenGl_FeatureInCore :
+                       CheckExtension ("GL_EXT_color_buffer_float") ? OpenGl_FeatureInExtensions 
+                                                                    : OpenGl_FeatureNotAvailable;
+  hasHalfFloatBuffer = IsGlGreaterEqual (3, 2) ? OpenGl_FeatureInCore :
+                       CheckExtension ("GL_EXT_color_buffer_half_float") ? OpenGl_FeatureInExtensions 
+                                                                         : OpenGl_FeatureNotAvailable;
+
+  oesSampleVariables = CheckExtension ("GL_OES_sample_variables");
+  oesStdDerivatives  = CheckExtension ("GL_OES_standard_derivatives");
+  hasSampleVariables = IsGlGreaterEqual (3, 2) ? OpenGl_FeatureInCore :
+                       oesSampleVariables ? OpenGl_FeatureInExtensions
+                                          : OpenGl_FeatureNotAvailable;
+  hasGlslBitwiseOps = IsGlGreaterEqual (3, 0)
+                    ? OpenGl_FeatureInCore
+                    : OpenGl_FeatureNotAvailable;
+  // without hasHighp, dFdx/dFdy precision is considered too low for flat shading (visual artifacts)
+  hasFlatShading = IsGlGreaterEqual (3, 0)
+                 ? OpenGl_FeatureInCore
+                  : (oesStdDerivatives && hasHighp
+                   ? OpenGl_FeatureInExtensions
+                   : OpenGl_FeatureNotAvailable);
+  if (!IsGlGreaterEqual (3, 1)
+    && myVendor.Search("qualcomm") != -1)
+  {
+    // dFdx/dFdy are completely broken on tested Adreno devices with versions below OpenGl ES 3.1
+    hasFlatShading = OpenGl_FeatureNotAvailable;
+  }
+
+  hasGeometryStage = IsGlGreaterEqual (3, 2)
+                   ? OpenGl_FeatureInCore
+                   : (CheckExtension ("GL_EXT_geometry_shader") && CheckExtension ("GL_EXT_shader_io_blocks")
+                     ? OpenGl_FeatureInExtensions
+                     : OpenGl_FeatureNotAvailable);
+#else
+
+  myTexClamp = IsGlGreaterEqual (1, 2) ? GL_CLAMP_TO_EDGE : GL_CLAMP;
+
+  hasTexRGBA8 = Standard_True;
+  hasTexSRGB       = IsGlGreaterEqual (2, 1);
+  hasFboSRGB       = IsGlGreaterEqual (2, 1);
+  hasSRGBControl   = hasFboSRGB;
+  arbDrawBuffers   = CheckExtension ("GL_ARB_draw_buffers");
+  arbNPTW          = CheckExtension ("GL_ARB_texture_non_power_of_two");
   arbTexFloat      = IsGlGreaterEqual (3, 0)
                   || CheckExtension ("GL_ARB_texture_float");
+  hasTexFloatLinear = arbTexFloat;
   arbSampleShading = CheckExtension ("GL_ARB_sample_shading");
-  extBgra          = CheckExtension ("GL_EXT_bgra");
+  extBgra          = IsGlGreaterEqual (1, 2)
+                  || CheckExtension ("GL_EXT_bgra");
   extAnis          = CheckExtension ("GL_EXT_texture_filter_anisotropic");
   extPDS           = CheckExtension ("GL_EXT_packed_depth_stencil");
   atiMem           = CheckExtension ("GL_ATI_meminfo");
   nvxMem           = CheckExtension ("GL_NVX_gpu_memory_info");
 
+  if (extBgra)
+  {
+    mySupportedFormats->Add (Image_PixMap::ImgBGR);
+    mySupportedFormats->Add (Image_PixMap::ImgBGR32);
+    mySupportedFormats->Add (Image_PixMap::ImgBGRA);
+  }
+
   hasDrawBuffers = IsGlGreaterEqual (2, 0) ? OpenGl_FeatureInCore :
                    arbDrawBuffers ? OpenGl_FeatureInExtensions 
                                   : OpenGl_FeatureNotAvailable;
 
+  hasGlslBitwiseOps = IsGlGreaterEqual (3, 0)
+                    ? OpenGl_FeatureInCore
+                    : CheckExtension ("GL_EXT_gpu_shader4")
+                     ? OpenGl_FeatureInExtensions
+                     : OpenGl_FeatureNotAvailable;
+
   hasFloatBuffer = hasHalfFloatBuffer =  IsGlGreaterEqual (3, 0) ? OpenGl_FeatureInCore :
                                          CheckExtension ("GL_ARB_color_buffer_float") ? OpenGl_FeatureInExtensions
                                                                                       : OpenGl_FeatureNotAvailable;
 
+  hasGeometryStage = IsGlGreaterEqual (3, 2)
+                   ? OpenGl_FeatureInCore
+                   : OpenGl_FeatureNotAvailable;
+
   hasSampleVariables = IsGlGreaterEqual (4, 0) ? OpenGl_FeatureInCore :
                         arbSampleShading ? OpenGl_FeatureInExtensions
                                          : OpenGl_FeatureNotAvailable;
@@ -1437,16 +1955,46 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   {
     glGetIntegerv (GL_MAX_DRAW_BUFFERS,      &myMaxDrawBuffers);
     glGetIntegerv (GL_MAX_COLOR_ATTACHMENTS, &myMaxColorAttachments);
+    if (myDrawBuffers.Length() < myMaxDrawBuffers)
+    {
+      myDrawBuffers.Resize (0, myMaxDrawBuffers - 1, false);
+    }
   }
 
   glGetIntegerv (GL_MAX_TEXTURE_SIZE, &myMaxTexDim);
+#if !defined(GL_ES_VERSION_2_0)
+  if (IsGlGreaterEqual (1, 3) && core11 != NULL)
+  {
+    // this is a maximum of texture units for FFP functionality,
+    // usually smaller than combined texture units available for GLSL
+    glGetIntegerv (GL_MAX_TEXTURE_UNITS, &myMaxTexUnitsFFP);
+    myMaxTexCombined = myMaxTexUnitsFFP;
+  }
+#endif
+  if (IsGlGreaterEqual (2, 0))
+  {
+    glGetIntegerv (GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &myMaxTexCombined);
+  }
+  mySpriteTexUnit = myMaxTexCombined >= 2
+                  ? Graphic3d_TextureUnit_PointSprite
+                  : Graphic3d_TextureUnit_0;
+
+  GLint aMaxVPortSize[2] = {0, 0};
+  glGetIntegerv (GL_MAX_VIEWPORT_DIMS, aMaxVPortSize);
+  myMaxDumpSizeX = Min (aMaxVPortSize[0], myMaxTexDim);
+  myMaxDumpSizeY = Min (aMaxVPortSize[1], myMaxTexDim);
+  if (myVendor == "intel")
+  {
+    // Intel drivers have known bug with empty dump for images with width>=5462
+    myMaxDumpSizeX = Min (myMaxDumpSizeX, 4096);
+  }
 
   if (extAnis)
   {
     glGetIntegerv (GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &myAnisoMax);
   }
 
-  myClippingState.Init (myMaxClipPlanes);
+  myClippingState.Init();
 
 #if !defined(GL_ES_VERSION_2_0)
 
@@ -1465,9 +2013,7 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   bool has42 = false;
   bool has43 = false;
   bool has44 = false;
-
-  //! Make record shorter to retrieve function pointer using variable with same name
-  #define FindProcShort(theFunc) FindProc(#theFunc, myFuncs->theFunc)
+  bool has45 = false;
 
   // retrieve platform-dependent extensions
 #if defined(HAVE_EGL)
@@ -1536,6 +2082,10 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
        && FindProcShort (glTexImage3D)
        && FindProcShort (glTexSubImage3D)
        && FindProcShort (glCopyTexSubImage3D);
+  if (!has12)
+  {
+    checkWrongVersion (1, 2, aLastFailedProc);
+  }
 
   // load OpenGL 1.3 new functions
   has13 = IsGlGreaterEqual (1, 3)
@@ -1590,6 +2140,10 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
        && FindProcShort (glMultTransposeMatrixf)
        && FindProcShort (glMultTransposeMatrixd);
   }
+  if (!has13)
+  {
+    checkWrongVersion (1, 3, aLastFailedProc);
+  }
 
   // load OpenGL 1.4 new functions
   has14 = IsGlGreaterEqual (1, 4)
@@ -1600,6 +2154,10 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
        && FindProcShort (glPointParameterfv)
        && FindProcShort (glPointParameteri)
        && FindProcShort (glPointParameteriv);
+  if (!has14)
+  {
+    checkWrongVersion (1, 4, aLastFailedProc);
+  }
 
   // load OpenGL 1.5 new functions
   has15 = IsGlGreaterEqual (1, 5)
@@ -1622,6 +2180,19 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
        && FindProcShort (glUnmapBuffer)
        && FindProcShort (glGetBufferParameteriv)
        && FindProcShort (glGetBufferPointerv);
+  if (has15)
+  {
+    if (!isCoreProfile)
+    {
+      core15 = (OpenGl_GlCore15* )(&(*myFuncs));
+    }
+    core15fwd = (OpenGl_GlCore15Fwd* )(&(*myFuncs));
+    hasGetBufferData = true;
+  }
+  else
+  {
+    checkWrongVersion (1, 5, aLastFailedProc);
+  }
 
   // load OpenGL 2.0 new functions
   has20 = IsGlGreaterEqual (2, 0)
@@ -1718,6 +2289,32 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
        && FindProcShort (glVertexAttrib4uiv)
        && FindProcShort (glVertexAttrib4usv)
        && FindProcShort (glVertexAttribPointer);
+  if (has20)
+  {
+    const char* aGlslVer = (const char* )::glGetString (GL_SHADING_LANGUAGE_VERSION);
+    if (aGlslVer == NULL
+    || *aGlslVer == '\0')
+    {
+      // broken context has been detected
+      PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                   TCollection_AsciiString("Error! OpenGL context reports version ")
+                   + myGlVerMajor  + "." + myGlVerMinor + " but reports wrong GLSL version");
+      myGlVerMajor = 1;
+      myGlVerMinor = 5;
+    }
+    else
+    {
+      if (!isCoreProfile)
+      {
+        core20  = (OpenGl_GlCore20*    )(&(*myFuncs));
+      }
+      core20fwd = (OpenGl_GlCore20Fwd* )(&(*myFuncs));
+    }
+  }
+  else
+  {
+    checkWrongVersion (2, 0, aLastFailedProc);
+  }
 
   // load OpenGL 2.1 new functions
   has21 = IsGlGreaterEqual (2, 1)
@@ -1727,6 +2324,10 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
        && FindProcShort (glUniformMatrix4x2fv)
        && FindProcShort (glUniformMatrix3x4fv)
        && FindProcShort (glUniformMatrix4x3fv);
+  if (!has21)
+  {
+    checkWrongVersion (2, 1, aLastFailedProc);
+  }
 
   // load GL_ARB_framebuffer_object (added to OpenGL 3.0 core)
   const bool hasFBO = (IsGlGreaterEqual (3, 0) || CheckExtension ("GL_ARB_framebuffer_object"))
@@ -1826,6 +2427,10 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
        && FindProcShort (glClearBufferfv)
        && FindProcShort (glClearBufferfi)
        && FindProcShort (glGetStringi);
+  if (!has30)
+  {
+    checkWrongVersion (3, 0, aLastFailedProc);
+  }
 
   // load GL_ARB_uniform_buffer_object (added to OpenGL 3.1 core)
   const bool hasUBO = (IsGlGreaterEqual (3, 1) || CheckExtension ("GL_ARB_uniform_buffer_object"))
@@ -1847,6 +2452,12 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
     // but doesn't hardware accelerated by some ancient OpenGL 2.1 hardware (GeForce FX, RadeOn 9700 etc.)
     arbNPTW  = Standard_True;
     arbTexRG = Standard_True;
+
+    if (!isCoreProfile)
+    {
+      core30 = (OpenGl_GlCore30* )(&(*myFuncs));
+    }
+    core30fwd = (OpenGl_GlCore30Fwd* )(&(*myFuncs));
   }
 
   // load OpenGL 3.1 new functions
@@ -1857,6 +2468,32 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
        && FindProcShort (glDrawElementsInstanced)
        && FindProcShort (glTexBuffer)
        && FindProcShort (glPrimitiveRestartIndex);
+  if (has31)
+  {
+    arbTBO = (OpenGl_ArbTBO* )(&(*myFuncs));
+    arbIns = (OpenGl_ArbIns* )(&(*myFuncs));
+  }
+  else
+  {
+    checkWrongVersion (3, 1, aLastFailedProc);
+
+    // initialize TBO extension (ARB)
+    if (CheckExtension ("GL_ARB_texture_buffer_object")
+     && FindProc ("glTexBufferARB", myFuncs->glTexBuffer))
+    {
+      arbTBO = (OpenGl_ArbTBO* )(&(*myFuncs));
+    }
+
+    // initialize hardware instancing extension (ARB)
+    if (CheckExtension ("GL_ARB_draw_instanced")
+     && FindProc ("glDrawArraysInstancedARB",   myFuncs->glDrawArraysInstanced)
+     && FindProc ("glDrawElementsInstancedARB", myFuncs->glDrawElementsInstanced))
+    {
+      arbIns = (OpenGl_ArbIns* )(&(*myFuncs));
+    }
+  }
+
+  arbTboRGB32 = CheckExtension ("GL_ARB_texture_buffer_object_rgb32");
 
   // load GL_ARB_draw_elements_base_vertex (added to OpenGL 3.2 core)
   const bool hasDrawElemsBaseVert = (IsGlGreaterEqual (3, 2) || CheckExtension ("GL_ARB_draw_elements_base_vertex"))
@@ -1895,6 +2532,23 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
        && FindProcShort (glGetInteger64i_v)
        && FindProcShort (glGetBufferParameteri64v)
        && FindProcShort (glFramebufferTexture);
+  if (has32)
+  {
+    core32 = (OpenGl_GlCore32* )(&(*myFuncs));
+    if (isCoreProfile)
+    {
+      core32->glGenVertexArrays (1, &myDefaultVao);
+    }
+    else
+    {
+      core32back = (OpenGl_GlCore32Back* )(&(*myFuncs));
+    }
+    ::glGetIntegerv (GL_MAX_SAMPLES, &myMaxMsaaSamples);
+  }
+  else
+  {
+    checkWrongVersion (3, 2, aLastFailedProc);
+  }
 
   // load GL_ARB_blend_func_extended (added to OpenGL 3.3 core)
   const bool hasBlendFuncExtended = (IsGlGreaterEqual (3, 3) || CheckExtension ("GL_ARB_blend_func_extended"))
@@ -1917,6 +2571,10 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
        && FindProcShort (glGetSamplerParameterIiv)
        && FindProcShort (glGetSamplerParameterfv)
        && FindProcShort (glGetSamplerParameterIuiv);
+  if (hasSamplerObjects)
+  {
+    arbSamplerObject = (OpenGl_ArbSamplerObject* )(&(*myFuncs));
+  }
 
   // load GL_ARB_timer_query (added to OpenGL 3.3 core)
   const bool hasTimerQuery = (IsGlGreaterEqual (3, 3) || CheckExtension ("GL_ARB_timer_query"))
@@ -1980,6 +2638,18 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
        && hasTimerQuery
        && hasVertType21010101rev
        && FindProcShort (glVertexAttribDivisor);
+  if (has33)
+  {
+    core33 = (OpenGl_GlCore33* )(&(*myFuncs));
+    if (!isCoreProfile)
+    {
+      core33back = (OpenGl_GlCore33Back* )(&(*myFuncs));
+    }
+  }
+  else
+  {
+    checkWrongVersion (3, 3, aLastFailedProc);
+  }
 
   // load GL_ARB_draw_indirect (added to OpenGL 4.0 core)
   const bool hasDrawIndirect = (IsGlGreaterEqual (4, 0) || CheckExtension ("GL_ARB_draw_indirect"))
@@ -2053,6 +2723,14 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
       && FindProcShort (glBlendEquationSeparatei)
       && FindProcShort (glBlendFunci)
       && FindProcShort (glBlendFuncSeparatei);
+  if (has40)
+  {
+    arbTboRGB32 = Standard_True; // in core since OpenGL 4.0
+  }
+  else
+  {
+    checkWrongVersion (4, 0, aLastFailedProc);
+  }
 
   // load GL_ARB_ES2_compatibility (added to OpenGL 4.1 core)
   const bool hasES2Compatibility = (IsGlGreaterEqual (4, 1) || CheckExtension ("GL_ARB_ES2_compatibility"))
@@ -2164,6 +2842,18 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
        && hasSeparateShaderObjects
        && hasVertAttrib64bit
        && hasViewportArray;
+  if (has41)
+  {
+    core41 = (OpenGl_GlCore41* )(&(*myFuncs));
+    if (!isCoreProfile)
+    {
+      core41back = (OpenGl_GlCore41Back* )(&(*myFuncs));
+    }
+  }
+  else
+  {
+    checkWrongVersion (4, 1, aLastFailedProc);
+  }
 
   // load GL_ARB_base_instance (added to OpenGL 4.2 core)
   const bool hasBaseInstance = (IsGlGreaterEqual (4, 2) || CheckExtension ("GL_ARB_base_instance"))
@@ -2202,6 +2892,18 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
        && hasShaderAtomicCounters
        && hasShaderImgLoadStore
        && hasTextureStorage;
+  if (has42)
+  {
+    core42 = (OpenGl_GlCore42* )(&(*myFuncs));
+    if (!isCoreProfile)
+    {
+      core42back = (OpenGl_GlCore42Back* )(&(*myFuncs));
+    }
+  }
+  else
+  {
+    checkWrongVersion (4, 2, aLastFailedProc);
+  }
 
   has43 = IsGlGreaterEqual (4, 3)
        && FindProcShort (glClearBufferData)
@@ -2247,6 +2949,18 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
        && FindProcShort (glGetObjectLabel)
        && FindProcShort (glObjectPtrLabel)
        && FindProcShort (glGetObjectPtrLabel);
+  if (has43)
+  {
+    core43 = (OpenGl_GlCore43* )(&(*myFuncs));
+    if (!isCoreProfile)
+    {
+      core43back = (OpenGl_GlCore43Back* )(&(*myFuncs));
+    }
+  }
+  else
+  {
+    checkWrongVersion (4, 3, aLastFailedProc);
+  }
 
   // load GL_ARB_clear_texture (added to OpenGL 4.4 core)
   bool arbTexClear = (IsGlGreaterEqual (4, 4) || CheckExtension ("GL_ARB_clear_texture"))
@@ -2262,6 +2976,155 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
        && FindProcShort (glBindSamplers)
        && FindProcShort (glBindImageTextures)
        && FindProcShort (glBindVertexBuffers);
+  if (has44)
+  {
+    core44 = (OpenGl_GlCore44* )(&(*myFuncs));
+    if (!isCoreProfile)
+    {
+      core44back = (OpenGl_GlCore44Back* )(&(*myFuncs));
+    }
+  }
+  else
+  {
+    checkWrongVersion (4, 4, aLastFailedProc);
+  }
+
+  has45 = IsGlGreaterEqual (4, 5)
+       && FindProcShort (glBindVertexBuffers)
+       && FindProcShort (glClipControl)
+       && FindProcShort (glCreateTransformFeedbacks)
+       && FindProcShort (glTransformFeedbackBufferBase)
+       && FindProcShort (glTransformFeedbackBufferRange)
+       && FindProcShort (glGetTransformFeedbackiv)
+       && FindProcShort (glGetTransformFeedbacki_v)
+       && FindProcShort (glGetTransformFeedbacki64_v)
+       && FindProcShort (glCreateBuffers)
+       && FindProcShort (glNamedBufferStorage)
+       && FindProcShort (glNamedBufferData)
+       && FindProcShort (glNamedBufferSubData)
+       && FindProcShort (glCopyNamedBufferSubData)
+       && FindProcShort (glClearNamedBufferData)
+       && FindProcShort (glClearNamedBufferSubData)
+       && FindProcShort (glMapNamedBuffer)
+       && FindProcShort (glMapNamedBufferRange)
+       && FindProcShort (glUnmapNamedBuffer)
+       && FindProcShort (glFlushMappedNamedBufferRange)
+       && FindProcShort (glGetNamedBufferParameteriv)
+       && FindProcShort (glGetNamedBufferParameteri64v)
+       && FindProcShort (glGetNamedBufferPointerv)
+       && FindProcShort (glGetNamedBufferSubData)
+       && FindProcShort (glCreateFramebuffers)
+       && FindProcShort (glNamedFramebufferRenderbuffer)
+       && FindProcShort (glNamedFramebufferParameteri)
+       && FindProcShort (glNamedFramebufferTexture)
+       && FindProcShort (glNamedFramebufferTextureLayer)
+       && FindProcShort (glNamedFramebufferDrawBuffer)
+       && FindProcShort (glNamedFramebufferDrawBuffers)
+       && FindProcShort (glNamedFramebufferReadBuffer)
+       && FindProcShort (glInvalidateNamedFramebufferData)
+       && FindProcShort (glInvalidateNamedFramebufferSubData)
+       && FindProcShort (glClearNamedFramebufferiv)
+       && FindProcShort (glClearNamedFramebufferuiv)
+       && FindProcShort (glClearNamedFramebufferfv)
+       && FindProcShort (glClearNamedFramebufferfi)
+       && FindProcShort (glBlitNamedFramebuffer)
+       && FindProcShort (glCheckNamedFramebufferStatus)
+       && FindProcShort (glGetNamedFramebufferParameteriv)
+       && FindProcShort (glGetNamedFramebufferAttachmentParameteriv)
+       && FindProcShort (glCreateRenderbuffers)
+       && FindProcShort (glNamedRenderbufferStorage)
+       && FindProcShort (glNamedRenderbufferStorageMultisample)
+       && FindProcShort (glGetNamedRenderbufferParameteriv)
+       && FindProcShort (glCreateTextures)
+       && FindProcShort (glTextureBuffer)
+       && FindProcShort (glTextureBufferRange)
+       && FindProcShort (glTextureStorage1D)
+       && FindProcShort (glTextureStorage2D)
+       && FindProcShort (glTextureStorage3D)
+       && FindProcShort (glTextureStorage2DMultisample)
+       && FindProcShort (glTextureStorage3DMultisample)
+       && FindProcShort (glTextureSubImage1D)
+       && FindProcShort (glTextureSubImage2D)
+       && FindProcShort (glTextureSubImage3D)
+       && FindProcShort (glCompressedTextureSubImage1D)
+       && FindProcShort (glCompressedTextureSubImage2D)
+       && FindProcShort (glCompressedTextureSubImage3D)
+       && FindProcShort (glCopyTextureSubImage1D)
+       && FindProcShort (glCopyTextureSubImage2D)
+       && FindProcShort (glCopyTextureSubImage3D)
+       && FindProcShort (glTextureParameterf)
+       && FindProcShort (glTextureParameterfv)
+       && FindProcShort (glTextureParameteri)
+       && FindProcShort (glTextureParameterIiv)
+       && FindProcShort (glTextureParameterIuiv)
+       && FindProcShort (glTextureParameteriv)
+       && FindProcShort (glGenerateTextureMipmap)
+       && FindProcShort (glBindTextureUnit)
+       && FindProcShort (glGetTextureImage)
+       && FindProcShort (glGetCompressedTextureImage)
+       && FindProcShort (glGetTextureLevelParameterfv)
+       && FindProcShort (glGetTextureLevelParameteriv)
+       && FindProcShort (glGetTextureParameterfv)
+       && FindProcShort (glGetTextureParameterIiv)
+       && FindProcShort (glGetTextureParameterIuiv)
+       && FindProcShort (glGetTextureParameteriv)
+       && FindProcShort (glCreateVertexArrays)
+       && FindProcShort (glDisableVertexArrayAttrib)
+       && FindProcShort (glEnableVertexArrayAttrib)
+       && FindProcShort (glVertexArrayElementBuffer)
+       && FindProcShort (glVertexArrayVertexBuffer)
+       && FindProcShort (glVertexArrayVertexBuffers)
+       && FindProcShort (glVertexArrayAttribBinding)
+       && FindProcShort (glVertexArrayAttribFormat)
+       && FindProcShort (glVertexArrayAttribIFormat)
+       && FindProcShort (glVertexArrayAttribLFormat)
+       && FindProcShort (glVertexArrayBindingDivisor)
+       && FindProcShort (glGetVertexArrayiv)
+       && FindProcShort (glGetVertexArrayIndexediv)
+       && FindProcShort (glGetVertexArrayIndexed64iv)
+       && FindProcShort (glCreateSamplers)
+       && FindProcShort (glCreateProgramPipelines)
+       && FindProcShort (glCreateQueries)
+       && FindProcShort (glGetQueryBufferObjecti64v)
+       && FindProcShort (glGetQueryBufferObjectiv)
+       && FindProcShort (glGetQueryBufferObjectui64v)
+       && FindProcShort (glGetQueryBufferObjectuiv)
+       && FindProcShort (glMemoryBarrierByRegion)
+       && FindProcShort (glGetTextureSubImage)
+       && FindProcShort (glGetCompressedTextureSubImage)
+       && FindProcShort (glGetGraphicsResetStatus)
+       && FindProcShort (glGetnCompressedTexImage)
+       && FindProcShort (glGetnTexImage)
+       && FindProcShort (glGetnUniformdv)
+       && FindProcShort (glGetnUniformfv)
+       && FindProcShort (glGetnUniformiv)
+       && FindProcShort (glGetnUniformuiv)
+       && FindProcShort (glReadnPixels)
+       && FindProcShort (glGetnMapdv)
+       && FindProcShort (glGetnMapfv)
+       && FindProcShort (glGetnMapiv)
+       && FindProcShort (glGetnPixelMapfv)
+       && FindProcShort (glGetnPixelMapuiv)
+       && FindProcShort (glGetnPixelMapusv)
+       && FindProcShort (glGetnPolygonStipple)
+       && FindProcShort (glGetnColorTable)
+       && FindProcShort (glGetnConvolutionFilter)
+       && FindProcShort (glGetnSeparableFilter)
+       && FindProcShort (glGetnHistogram)
+       && FindProcShort (glGetnMinmax)
+       && FindProcShort (glTextureBarrier);
+  if (has45)
+  {
+    core45 = (OpenGl_GlCore45* )(&(*myFuncs));
+    if (!isCoreProfile)
+    {
+      core45back = (OpenGl_GlCore45Back* )(&(*myFuncs));
+    }
+  }
+  else
+  {
+    checkWrongVersion (4, 5, aLastFailedProc);
+  }
 
   // initialize debug context extension
   if (CheckExtension ("GL_ARB_debug_output"))
@@ -2296,24 +3159,6 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
     }
   }
 
-  // initialize TBO extension (ARB)
-  if (!has31
-   && CheckExtension ("GL_ARB_texture_buffer_object")
-   && FindProc ("glTexBufferARB", myFuncs->glTexBuffer))
-  {
-    arbTBO = (OpenGl_ArbTBO* )(&(*myFuncs));
-  }
-  arbTboRGB32 = CheckExtension ("GL_ARB_texture_buffer_object_rgb32");
-
-  // initialize hardware instancing extension (ARB)
-  if (!has31
-   && CheckExtension ("GL_ARB_draw_instanced")
-   && FindProc ("glDrawArraysInstancedARB",   myFuncs->glDrawArraysInstanced)
-   && FindProc ("glDrawElementsInstancedARB", myFuncs->glDrawElementsInstanced))
-  {
-    arbIns = (OpenGl_ArbIns* )(&(*myFuncs));
-  }
-
   // initialize FBO extension (ARB)
   if (hasFBO)
   {
@@ -2351,116 +3196,26 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
     arbTexBindless = (OpenGl_ArbTexBindless* )(&(*myFuncs));
   }
 
-  if (!has12)
-  {
-    checkWrongVersion (1, 2);
-    myGlVerMajor = 1;
-    myGlVerMinor = 1;
-    return;
-  }
-  else if (!has13)
-  {
-    checkWrongVersion (1, 3);
-    myGlVerMajor = 1;
-    myGlVerMinor = 2;
-    return;
-  }
-  else if (!has14)
-  {
-    checkWrongVersion (1, 4);
-    myGlVerMajor = 1;
-    myGlVerMinor = 3;
-    return;
-  }
-  else if (!has15)
-  {
-    checkWrongVersion (1, 5);
-    myGlVerMajor = 1;
-    myGlVerMinor = 4;
-    return;
-  }
-  if (!isCoreProfile)
-  {
-    core15 = (OpenGl_GlCore15* )(&(*myFuncs));
-  }
-  core15fwd = (OpenGl_GlCore15Fwd* )(&(*myFuncs));
-
-  if (!has20)
-  {
-    checkWrongVersion (2, 0);
-    myGlVerMajor = 1;
-    myGlVerMinor = 5;
-    return;
-  }
-
-  const char* aGlslVer = (const char* )::glGetString (GL_SHADING_LANGUAGE_VERSION);
-  if (aGlslVer == NULL
-  || *aGlslVer == '\0')
-  {
-    // broken context has been detected
-    TCollection_ExtendedString aMsg = TCollection_ExtendedString()
-      + "Error! OpenGL context reports version "
-      + myGlVerMajor  + "." + myGlVerMinor
-      + " but reports wrong GLSL version";
-    PushMessage (GL_DEBUG_SOURCE_APPLICATION,
-                 GL_DEBUG_TYPE_ERROR,
-                 0,
-                 GL_DEBUG_SEVERITY_HIGH,
-                 aMsg);
-    myGlVerMajor = 1;
-    myGlVerMinor = 5;
-    return;
-  }
-
-  if (!isCoreProfile)
-  {
-    core20  = (OpenGl_GlCore20*    )(&(*myFuncs));
-  }
-  core20fwd = (OpenGl_GlCore20Fwd* )(&(*myFuncs));
-
-  if (!has21)
-  {
-    checkWrongVersion (2, 1);
-    myGlVerMajor = 2;
-    myGlVerMinor = 0;
-    return;
-  }
-
-  if (!has30)
-  {
-    checkWrongVersion (3, 0);
-    myGlVerMajor = 2;
-    myGlVerMinor = 1;
-    return;
-  }
-
-  // MSAA RenderBuffers have been defined in OpenGL 3.0,
-  // but MSAA Textures - only in OpenGL 3.2+
-  if (!has32
-   && CheckExtension ("GL_ARB_texture_multisample")
-   && FindProcShort (glTexImage2DMultisample))
-  {
-    GLint aNbColorSamples = 0, aNbDepthSamples = 0;
-    ::glGetIntegerv (GL_MAX_COLOR_TEXTURE_SAMPLES, &aNbColorSamples);
-    ::glGetIntegerv (GL_MAX_DEPTH_TEXTURE_SAMPLES, &aNbDepthSamples);
-    myMaxMsaaSamples = Min (aNbColorSamples, aNbDepthSamples);
-  }
-  if (!has43
-   && CheckExtension ("GL_ARB_texture_storage_multisample")
-   && FindProcShort (glTexStorage2DMultisample))
-  {
-    //
-  }
-
-  if (!has31)
+  if (has30)
   {
-    checkWrongVersion (3, 1);
-    myGlVerMajor = 3;
-    myGlVerMinor = 0;
-    return;
+    // MSAA RenderBuffers have been defined in OpenGL 3.0,
+    // but MSAA Textures - only in OpenGL 3.2+
+    if (!has32
+     && CheckExtension ("GL_ARB_texture_multisample")
+     && FindProcShort (glTexImage2DMultisample))
+    {
+      GLint aNbColorSamples = 0, aNbDepthSamples = 0;
+      ::glGetIntegerv (GL_MAX_COLOR_TEXTURE_SAMPLES, &aNbColorSamples);
+      ::glGetIntegerv (GL_MAX_DEPTH_TEXTURE_SAMPLES, &aNbDepthSamples);
+      myMaxMsaaSamples = Min (aNbColorSamples, aNbDepthSamples);
+    }
+    if (!has43
+     && CheckExtension ("GL_ARB_texture_storage_multisample")
+     && FindProcShort (glTexStorage2DMultisample))
+    {
+      //
+    }
   }
-  arbTBO = (OpenGl_ArbTBO* )(&(*myFuncs));
-  arbIns = (OpenGl_ArbIns* )(&(*myFuncs));
 
   // check whether ray tracing mode is supported
   myHasRayTracing = has31
@@ -2473,105 +3228,121 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
 
   // check whether adaptive screen sampling in ray tracing mode is supported
   myHasRayTracingAdaptiveSampling = myHasRayTracing
-                                 && has44
-                                 && CheckExtension ("GL_NV_shader_atomic_float");
-
-  if (!has32)
-  {
-    checkWrongVersion (3, 2);
-    myGlVerMajor = 3;
-    myGlVerMinor = 1;
-    return;
-  }
-  core32 = (OpenGl_GlCore32* )(&(*myFuncs));
-  if (isCoreProfile)
-  {
-    core32->glGenVertexArrays (1, &myDefaultVao);
-  }
-  else
-  {
-    core32back = (OpenGl_GlCore32Back* )(&(*myFuncs));
-  }
-  ::glGetIntegerv (GL_MAX_SAMPLES, &myMaxMsaaSamples);
-
-  if (!has33)
-  {
-    checkWrongVersion (3, 3);
-    myGlVerMajor = 3;
-    myGlVerMinor = 2;
-    return;
-  }
-  core33 = (OpenGl_GlCore33* )(&(*myFuncs));
-  if (!isCoreProfile)
-  {
-    core33back = (OpenGl_GlCore33Back* )(&(*myFuncs));
-  }
-
-  // initialize sampler object
-  myTexSampler = new OpenGl_Sampler();
-  myTexSampler->Init (*this);
-
-  if (!has40)
-  {
-    checkWrongVersion (4, 0);
-    myGlVerMajor = 3;
-    myGlVerMinor = 3;
-    return;
-  }
-  arbTboRGB32 = Standard_True; // in core since OpenGL 4.0
+                                 && has44;
+  myHasRayTracingAdaptiveSamplingAtomic = myHasRayTracingAdaptiveSampling
+                                       && CheckExtension ("GL_NV_shader_atomic_float");
+#endif
 
-  if (!has41)
-  {
-    checkWrongVersion (4, 1);
-    myGlVerMajor = 4;
-    myGlVerMinor = 0;
-    return;
-  }
-  core41 = (OpenGl_GlCore41* )(&(*myFuncs));
-  if (!isCoreProfile)
-  {
-    core41back = (OpenGl_GlCore41Back* )(&(*myFuncs));
+  if (arbFBO != NULL
+   && hasFboSRGB)
+  {
+    // Detect if window buffer is considered by OpenGL as sRGB-ready
+    // (linear RGB color written by shader is automatically converted into sRGB)
+    // or not (offscreen FBO should be blit into window buffer with gamma correction).
+    const GLenum aDefWinBuffer =
+    #if !defined(GL_ES_VERSION_2_0)
+      GL_BACK_LEFT;
+    #else
+      GL_BACK;
+    #endif
+    GLint aWinColorEncoding = 0; // GL_LINEAR
+    arbFBO->glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, aDefWinBuffer, GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING, &aWinColorEncoding);
+    ResetErrors (true);
+    myIsSRgbWindow = aWinColorEncoding == GL_SRGB;
+
+    // On desktop OpenGL, pixel formats are almost always sRGB-ready, even when not requested;
+    // it is safe behavior on desktop where GL_FRAMEBUFFER_SRGB is disabled by default
+    // (contrary to OpenGL ES, where it is enabled by default).
+    // NVIDIA drivers, however, always return GL_LINEAR even for sRGB-ready pixel formats on Windows platform,
+    // while AMD and Intel report GL_SRGB as expected.
+    // macOS drivers seems to be also report GL_LINEAR even for [NSColorSpace sRGBColorSpace].
+  #if !defined(GL_ES_VERSION_2_0)
+  #ifdef __APPLE__
+    myIsSRgbWindow = true;
+  #else
+    if (!myIsSRgbWindow
+      && myVendor.Search ("nvidia") != -1)
+    {
+      myIsSRgbWindow = true;
+    }
+  #endif
+  #endif
+    if (!myIsSRgbWindow)
+    {
+      Message::SendTrace ("OpenGl_Context, warning: window buffer is not sRGB-ready.\n"
+                          "Check OpenGL window creation parameters for optimal performance.");
+    }
   }
 
-  if(!has42)
-  {
-    checkWrongVersion (4, 2);
-    myGlVerMajor = 4;
-    myGlVerMinor = 1;
-    return;
-  }
-  core42 = (OpenGl_GlCore42* )(&(*myFuncs));
-  if (!isCoreProfile)
+  if (arbTexFloat)
   {
-    core42back = (OpenGl_GlCore42Back* )(&(*myFuncs));
+    mySupportedFormats->Add (Image_Format_GrayF);
+    mySupportedFormats->Add (Image_Format_AlphaF);
+    mySupportedFormats->Add (Image_Format_RGBF);
+    mySupportedFormats->Add (Image_Format_RGBAF);
+    if (arbTexRG)
+    {
+      mySupportedFormats->Add (Image_Format_RGF);
+    }
+    if (extBgra)
+    {
+    #if !defined(GL_ES_VERSION_2_0)
+      mySupportedFormats->Add (Image_Format_BGRF);
+    #endif
+      mySupportedFormats->Add (Image_Format_BGRAF);
+    }
   }
 
-  if (!has43)
-  {
-    checkWrongVersion (4, 3);
-    myGlVerMajor = 4;
-    myGlVerMinor = 2;
-    return;
-  }
-  core43 = (OpenGl_GlCore43* )(&(*myFuncs));
-  if (!isCoreProfile)
+#ifdef __EMSCRIPTEN__
+  if (checkEnableWebGlExtension (*this, "GL_WEBGL_compressed_texture_s3tc")) // GL_WEBGL_compressed_texture_s3tc_srgb for sRGB formats
   {
-    core43back = (OpenGl_GlCore43Back* )(&(*myFuncs));
+    mySupportedFormats->Add (Image_CompressedFormat_RGB_S3TC_DXT1);
+    mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT1);
+    mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT3);
+    mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT5);
   }
-
-  if (!has44)
+#else
+  if (CheckExtension ("GL_EXT_texture_compression_s3tc")) // GL_EXT_texture_sRGB for sRGB formats
   {
-    checkWrongVersion (4, 4);
-    myGlVerMajor = 4;
-    myGlVerMinor = 3;
-    return;
+    mySupportedFormats->Add (Image_CompressedFormat_RGB_S3TC_DXT1);
+    mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT1);
+    mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT3);
+    mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT5);
   }
-  core44 = (OpenGl_GlCore44* )(&(*myFuncs));
-  if (!isCoreProfile)
+  else
   {
-    core44back = (OpenGl_GlCore44Back* )(&(*myFuncs));
+    if (CheckExtension ("GL_EXT_texture_compression_dxt1"))
+    {
+      mySupportedFormats->Add (Image_CompressedFormat_RGB_S3TC_DXT1);
+      mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT1);
+    }
+    if (CheckExtension ("GL_ANGLE_texture_compression_dxt3"))
+    {
+      mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT3);
+    }
+    if (CheckExtension ("GL_ANGLE_texture_compression_dxt5"))
+    {
+      mySupportedFormats->Add (Image_CompressedFormat_RGBA_S3TC_DXT5);
+    }
   }
 #endif
+
+  // check whether PBR shading model is supported
+  myHasPBR = arbFBO != NULL
+          && myMaxTexCombined >= 4
+          && arbTexRG
+          && arbTexFloat
+          && (IsGlGreaterEqual (3, 0)
+        #if !defined(GL_ES_VERSION_2_0)
+          || (IsGlGreaterEqual (2, 1) && CheckExtension ("GL_EXT_gpu_shader4"))
+        #endif
+             );
+  if (myHasPBR)
+  {
+    myPBREnvLUTTexUnit       = static_cast<Graphic3d_TextureUnit>(myMaxTexCombined + Graphic3d_TextureUnit_PbrEnvironmentLUT);
+    myPBRDiffIBLMapSHTexUnit = static_cast<Graphic3d_TextureUnit>(myMaxTexCombined + Graphic3d_TextureUnit_PbrIblDiffuseSH);
+    myPBRSpecIBLMapTexUnit   = static_cast<Graphic3d_TextureUnit>(myMaxTexCombined + Graphic3d_TextureUnit_PbrIblSpecular);
+  }
 }
 
 // =======================================================================
@@ -2755,12 +3526,12 @@ void OpenGl_Context::DiagnosticInformation (TColStd_IndexedDataMapOfStringString
   if ((theFlags & Graphic3d_DiagnosticInfo_NativePlatform) != 0)
   {
   #if defined(HAVE_EGL)
-    addInfo (theDict, "EGLVersion",    ::eglQueryString ((Aspect_Display)myDisplay, EGL_VERSION));
-    addInfo (theDict, "EGLVendor",     ::eglQueryString ((Aspect_Display)myDisplay, EGL_VENDOR));
-    addInfo (theDict, "EGLClientAPIs", ::eglQueryString ((Aspect_Display)myDisplay, EGL_CLIENT_APIS));
+    addInfo (theDict, "EGLVersion",    ::eglQueryString ((EGLDisplay )myDisplay, EGL_VERSION));
+    addInfo (theDict, "EGLVendor",     ::eglQueryString ((EGLDisplay )myDisplay, EGL_VENDOR));
+    addInfo (theDict, "EGLClientAPIs", ::eglQueryString ((EGLDisplay )myDisplay, EGL_CLIENT_APIS));
     if ((theFlags & Graphic3d_DiagnosticInfo_Extensions) != 0)
     {
-      addInfo (theDict, "EGLExtensions", ::eglQueryString ((Aspect_Display)myDisplay, EGL_EXTENSIONS));
+      addInfo (theDict, "EGLExtensions", ::eglQueryString ((EGLDisplay )myDisplay, EGL_EXTENSIONS));
     }
   #elif defined(_WIN32)
     if ((theFlags & Graphic3d_DiagnosticInfo_Extensions) != 0
@@ -2794,10 +3565,34 @@ void OpenGl_Context::DiagnosticInformation (TColStd_IndexedDataMapOfStringString
 
   if ((theFlags & Graphic3d_DiagnosticInfo_Device) != 0)
   {
+    Standard_Integer aDriverVer[2] = {};
+    ReadGlVersion (aDriverVer[0], aDriverVer[1]);
     addInfo (theDict, "GLvendor",    (const char*)::glGetString (GL_VENDOR));
     addInfo (theDict, "GLdevice",    (const char*)::glGetString (GL_RENDERER));
+  #ifdef __EMSCRIPTEN__
+    if (checkEnableWebGlExtension (*this, "GL_WEBGL_debug_renderer_info"))
+    {
+      if (const char* aVendor = (const char*)::glGetString (0x9245))
+      {
+        addInfo (theDict, "GLunmaskedVendor", aVendor);
+      }
+      if (const char* aDevice = (const char*)::glGetString (0x9246))
+      {
+        addInfo (theDict, "GLunmaskedDevice", aDevice);
+      }
+    }
+  #endif
+
     addInfo (theDict, "GLversion",   (const char*)::glGetString (GL_VERSION));
-    addInfo (theDict, "GLSLversion", (const char*)::glGetString (GL_SHADING_LANGUAGE_VERSION));
+    if (myGlVerMajor != aDriverVer[0]
+     || myGlVerMinor != aDriverVer[1])
+    {
+      addInfo (theDict, "GLversionOcct", TCollection_AsciiString (myGlVerMajor) + "." + TCollection_AsciiString (myGlVerMinor));
+    }
+    if (IsGlGreaterEqual (2, 0))
+    {
+      addInfo (theDict, "GLSLversion", (const char*)::glGetString (GL_SHADING_LANGUAGE_VERSION));
+    }
     if (myIsGlDebugCtx)
     {
       addInfo (theDict, "GLdebug", "ON");
@@ -2807,6 +3602,8 @@ void OpenGl_Context::DiagnosticInformation (TColStd_IndexedDataMapOfStringString
   if ((theFlags & Graphic3d_DiagnosticInfo_Limits) != 0)
   {
     addInfo (theDict, "Max texture size", TCollection_AsciiString(myMaxTexDim));
+    addInfo (theDict, "Max FBO dump size", TCollection_AsciiString() + myMaxDumpSizeX + "x" + myMaxDumpSizeY);
+    addInfo (theDict, "Max combined texture units", TCollection_AsciiString(myMaxTexCombined));
     addInfo (theDict, "Max MSAA samples", TCollection_AsciiString(myMaxMsaaSamples));
   }
 
@@ -2884,7 +3681,7 @@ void OpenGl_Context::ReleaseResource (const TCollection_AsciiString& theKey,
   {
     return;
   }
-  auto& aRes = mySharedResources->Find (theKey);
+  const Handle(OpenGl_Resource)& aRes = mySharedResources->Find (theKey);
   if (aRes->GetRefCount() > 1)
   {
     return;
@@ -2932,7 +3729,7 @@ void OpenGl_Context::ReleaseDelayed()
       continue;
     }
 
-    auto& aRes = mySharedResources->ChangeFind (aKey);
+    const Handle(OpenGl_Resource)& aRes = mySharedResources->ChangeFind (aKey);
     if (aRes->GetRefCount() > 1)
     {
       // should be only 1 instance in mySharedResources
@@ -2953,6 +3750,119 @@ void OpenGl_Context::ReleaseDelayed()
   }
 }
 
+// =======================================================================
+// function : BindTextures
+// purpose  :
+// =======================================================================
+Handle(OpenGl_TextureSet) OpenGl_Context::BindTextures (const Handle(OpenGl_TextureSet)& theTextures,
+                                                        const Handle(OpenGl_ShaderProgram)& theProgram)
+{
+  const Standard_Integer aTextureSetBits = !theTextures.IsNull() ? theTextures->TextureSetBits() : 0;
+  const Standard_Integer aProgramBits    = !theProgram.IsNull() ? theProgram->TextureSetBits() : 0;
+  Standard_Integer aMissingBits = aProgramBits & ~aTextureSetBits;
+  if (aMissingBits != 0
+   && myTextureRgbaBlack.IsNull())
+  {
+    // allocate mock textures
+    myTextureRgbaBlack = new OpenGl_Texture();
+    myTextureRgbaWhite = new OpenGl_Texture();
+    Image_PixMap anImage;
+    anImage.InitZero (Image_Format_RGBA, 2, 2, 0, (Standard_Byte )0);
+    if (!myTextureRgbaBlack->Init (this, OpenGl_TextureFormat::Create<GLubyte, 4>(), Graphic3d_Vec2i (2, 2), Graphic3d_TOT_2D, &anImage))
+    {
+      PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
+                    "Error: unable to create unit mock PBR texture map.");
+    }
+    anImage.InitZero (Image_Format_RGBA, 2, 2, 0, (Standard_Byte )255);
+    if (!myTextureRgbaWhite->Init (this, OpenGl_TextureFormat::Create<GLubyte, 4>(), Graphic3d_Vec2i (2, 2), Graphic3d_TOT_2D, &anImage))
+    {
+      PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
+                    "Error: unable to create normal mock PBR texture map.");
+    }
+  }
+
+  Handle(OpenGl_TextureSet) anOldTextures = myActiveTextures;
+  if (myActiveTextures != theTextures)
+  {
+    Handle(OpenGl_Context) aThisCtx (this);
+    for (OpenGl_TextureSetPairIterator aSlotIter (myActiveTextures, theTextures); aSlotIter.More(); aSlotIter.Next())
+    {
+      const Graphic3d_TextureUnit aTexUnit = aSlotIter.Unit();
+      const OpenGl_Texture* aTextureOld = aSlotIter.Texture1();
+      const OpenGl_Texture* aTextureNew = aSlotIter.Texture2();
+      if (aTextureNew == aTextureOld)
+      {
+        continue;
+      }
+
+      if (aTextureNew != NULL
+       && aTextureNew->IsValid())
+      {
+        if (aTexUnit >= myMaxTexCombined)
+        {
+          PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                       TCollection_AsciiString("Texture unit ") + aTexUnit + " for " + aTextureNew->ResourceId() + " exceeds hardware limit " + myMaxTexCombined);
+          continue;
+        }
+
+        aTextureNew->Bind (aThisCtx, aTexUnit);
+        if (aTextureNew->Sampler()->ToUpdateParameters())
+        {
+          if (aTextureNew->Sampler()->IsImmutable())
+          {
+            aTextureNew->Sampler()->Init (aThisCtx, *aTextureNew);
+          }
+          else
+          {
+            OpenGl_Sampler::applySamplerParams (aThisCtx, aTextureNew->Sampler()->Parameters(), aTextureNew->Sampler().get(), aTextureNew->GetTarget(), aTextureNew->MaxMipmapLevel());
+          }
+        }
+      #if !defined(GL_ES_VERSION_2_0)
+        if (core11 != NULL)
+        {
+          OpenGl_Sampler::applyGlobalTextureParams (aThisCtx, *aTextureNew, aTextureNew->Sampler()->Parameters());
+        }
+      #endif
+      }
+      else if (aTextureOld != NULL
+            && aTextureOld->IsValid())
+      {
+        aTextureOld->Unbind (aThisCtx, aTexUnit);
+      #if !defined(GL_ES_VERSION_2_0)
+        if (core11 != NULL)
+        {
+          OpenGl_Sampler::resetGlobalTextureParams (aThisCtx, *aTextureOld, aTextureOld->Sampler()->Parameters());
+        }
+      #endif
+      }
+    }
+    myActiveTextures = theTextures;
+  }
+
+  if (myActiveMockTextures != aMissingBits)
+  {
+    myActiveMockTextures = aMissingBits;
+    for (Standard_Integer aBitIter = 0; aMissingBits != 0; ++aBitIter)
+    {
+      Standard_Integer aUnitMask = 1 << aBitIter;
+      if ((aUnitMask & aMissingBits) != 0)
+      {
+        aMissingBits = aMissingBits & ~aUnitMask;
+        if (aBitIter == Graphic3d_TextureUnit_Normal)
+        {
+          myTextureRgbaBlack->Bind (this, static_cast<Graphic3d_TextureUnit>(aBitIter));
+        }
+        else
+        {
+          myTextureRgbaWhite->Bind (this, static_cast<Graphic3d_TextureUnit>(aBitIter));
+        }
+      }
+    }
+  }
+
+  return anOldTextures;
+}
+
 // =======================================================================
 // function : BindProgram
 // purpose  :
@@ -3016,12 +3926,12 @@ Handle(OpenGl_FrameBuffer) OpenGl_Context::SetDefaultFrameBuffer (const Handle(O
 // function : SetShadingMaterial
 // purpose  :
 // =======================================================================
-void OpenGl_Context::SetShadingMaterial (const OpenGl_AspectFace* theAspect,
+void OpenGl_Context::SetShadingMaterial (const OpenGl_Aspects* theAspect,
                                          const Handle(Graphic3d_PresentationAttributes)& theHighlight)
 {
-  const Handle(Graphic3d_AspectFillArea3d)& anAspect = (!theHighlight.IsNull() && !theHighlight->BasicFillAreaAspect().IsNull())
-                                                      ?  theHighlight->BasicFillAreaAspect()
-                                                      :  theAspect->Aspect();
+  const Handle(Graphic3d_Aspects)& anAspect = (!theHighlight.IsNull() && !theHighlight->BasicFillAreaAspect().IsNull())
+                                            ?  (const Handle(Graphic3d_Aspects)& )theHighlight->BasicFillAreaAspect()
+                                            :  theAspect->Aspect();
 
   const bool toDistinguish = anAspect->Distinguish();
   const bool toMapTexture  = anAspect->ToMapTexture();
@@ -3034,10 +3944,10 @@ void OpenGl_Context::SetShadingMaterial (const OpenGl_AspectFace* theAspect,
                                        ? anAspect->BackInteriorColor()
                                        : aFrontIntColor;
 
-  myMatFront.Init (aMatFrontSrc, aFrontIntColor);
+  myMatFront.Init (*this, aMatFrontSrc, aFrontIntColor);
   if (toDistinguish)
   {
-    myMatBack.Init (aMatBackSrc, aBackIntColor);
+    myMatBack.Init (*this, aMatBackSrc, aBackIntColor);
   }
   else
   {
@@ -3055,40 +3965,59 @@ void OpenGl_Context::SetShadingMaterial (const OpenGl_AspectFace* theAspect,
   Standard_ShortReal anAlphaBack  = 1.0f;
   if (CheckIsTransparent (theAspect, theHighlight, anAlphaFront, anAlphaBack))
   {
-    myMatFront.Diffuse.a() = anAlphaFront;
-    myMatBack .Diffuse.a() = anAlphaBack;
+    myMatFront.Common.Diffuse.a() = anAlphaFront;
+    myMatBack .Common.Diffuse.a() = anAlphaBack;
+
+    myMatFront.Pbr.BaseColor.a() = anAlphaFront;
+    myMatBack .Pbr.BaseColor.a() = anAlphaBack;
   }
 
   // do not update material properties in case of zero reflection mode,
   // because GL lighting will be disabled by OpenGl_PrimitiveArray::DrawArray() anyway.
-  if (theAspect->IsNoLighting())
+  const OpenGl_MaterialState& aMatState = myShaderManager->MaterialState();
+  float anAlphaCutoff = anAspect->AlphaMode() == Graphic3d_AlphaMode_Mask
+                      ? anAspect->AlphaCutoff()
+                      : ShortRealLast();
+  if (anAspect->ToDrawEdges())
+  {
+    if (anAspect->InteriorStyle() == Aspect_IS_EMPTY
+     || (anAspect->InteriorStyle() == Aspect_IS_SOLID
+      && anAspect->EdgeColorRGBA().Alpha() < 1.0f))
+    {
+      anAlphaCutoff = 0.285f;
+    }
+  }
+  if (theAspect->ShadingModel() == Graphic3d_TOSM_UNLIT)
   {
-    return;
+    if (anAlphaCutoff == aMatState.AlphaCutoff())
+    {
+      return;
+    }
   }
-
-  if (myMatFront    == myShaderManager->MaterialState().FrontMaterial()
-   && myMatBack     == myShaderManager->MaterialState().BackMaterial()
-   && toDistinguish == myShaderManager->MaterialState().ToDistinguish()
-   && toMapTexture  == myShaderManager->MaterialState().ToMapTexture())
+  else if (myMatFront    == aMatState.FrontMaterial()
+        && myMatBack     == aMatState.BackMaterial()
+        && toDistinguish == aMatState.ToDistinguish()
+        && toMapTexture  == aMatState.ToMapTexture()
+        && anAlphaCutoff == aMatState.AlphaCutoff())
   {
     return;
   }
 
-  myShaderManager->UpdateMaterialStateTo (myMatFront, myMatBack, toDistinguish, toMapTexture);
+  myShaderManager->UpdateMaterialStateTo (myMatFront, myMatBack, anAlphaCutoff, toDistinguish, toMapTexture);
 }
 
 // =======================================================================
 // function : CheckIsTransparent
 // purpose  :
 // =======================================================================
-Standard_Boolean OpenGl_Context::CheckIsTransparent (const OpenGl_AspectFace* theAspect,
+Standard_Boolean OpenGl_Context::CheckIsTransparent (const OpenGl_Aspects* theAspect,
                                                      const Handle(Graphic3d_PresentationAttributes)& theHighlight,
                                                      Standard_ShortReal& theAlphaFront,
                                                      Standard_ShortReal& theAlphaBack)
 {
-  const Handle(Graphic3d_AspectFillArea3d)& anAspect = (!theHighlight.IsNull() && !theHighlight->BasicFillAreaAspect().IsNull())
-                                                      ?  theHighlight->BasicFillAreaAspect()
-                                                      :  theAspect->Aspect();
+  const Handle(Graphic3d_Aspects)& anAspect = (!theHighlight.IsNull() && !theHighlight->BasicFillAreaAspect().IsNull())
+                                            ?  (const Handle(Graphic3d_Aspects)& )theHighlight->BasicFillAreaAspect()
+                                            :  theAspect->Aspect();
 
   const bool toDistinguish = anAspect->Distinguish();
   const Graphic3d_MaterialAspect& aMatFrontSrc = anAspect->FrontMaterial();
@@ -3109,9 +4038,12 @@ Standard_Boolean OpenGl_Context::CheckIsTransparent (const OpenGl_AspectFace* th
     theAlphaBack  = aMatBackSrc .Alpha();
   }
 
-  const bool isTransparent = theAlphaFront < 1.0f
-                          || theAlphaBack  < 1.0f;
-  return isTransparent;
+  if (anAspect->AlphaMode() == Graphic3d_AlphaMode_BlendAuto)
+  {
+    return theAlphaFront < 1.0f
+        || theAlphaBack  < 1.0f;
+  }
+  return anAspect->AlphaMode() == Graphic3d_AlphaMode_Blend;
 }
 
 // =======================================================================
@@ -3122,7 +4054,10 @@ void OpenGl_Context::SetColor4fv (const OpenGl_Vec4& theColor)
 {
   if (!myActiveProgram.IsNull())
   {
-    myActiveProgram->SetUniform (this, myActiveProgram->GetStateLocation (OpenGl_OCCT_COLOR), theColor);
+    if (const OpenGl_ShaderUniformLocation& aLoc = myActiveProgram->GetStateLocation (OpenGl_OCCT_COLOR))
+    {
+      myActiveProgram->SetUniform (this, aLoc, Vec4FromQuantityColor (theColor));
+    }
   }
 #if !defined(GL_ES_VERSION_2_0)
   else if (core11 != NULL)
@@ -3139,60 +4074,47 @@ void OpenGl_Context::SetColor4fv (const OpenGl_Vec4& theColor)
 void OpenGl_Context::SetTypeOfLine (const Aspect_TypeOfLine  theType,
                                     const Standard_ShortReal theFactor)
 {
-  Standard_Integer aPattern = 0xFFFF;
-  switch (theType)
-  {
-    case Aspect_TOL_DASH:
-    {
-      aPattern = 0xFFC0;
-      break;
-    }
-    case Aspect_TOL_DOT:
-    {
-      aPattern = 0xCCCC;
-      break;
-    }
-    case Aspect_TOL_DOTDASH:
-    {
-      aPattern = 0xFF18;
-      break;
-    }
-    case Aspect_TOL_EMPTY:
-    case Aspect_TOL_SOLID:
-    {
-      aPattern = 0xFFFF;
-      break;
-    }
-    case Aspect_TOL_USERDEFINED:
-    {
-      aPattern = 0xFF24;
-      break;
-    }
-  }
+  SetLineStipple (theFactor, Graphic3d_Aspects::DefaultLinePatternForType (theType));
+}
 
+// =======================================================================
+// function : SetLineStipple
+// purpose  :
+// =======================================================================
+void OpenGl_Context::SetLineStipple (const Standard_ShortReal theFactor,
+                                     const uint16_t thePattern)
+{
   if (!myActiveProgram.IsNull())
   {
-    myActiveProgram->SetUniform (this, "uPattern", aPattern);
-    myActiveProgram->SetUniform (this, "uFactor",  theFactor);
+    if (const OpenGl_ShaderUniformLocation aPatternLoc = myActiveProgram->GetStateLocation (OpenGl_OCCT_LINE_STIPPLE_PATTERN))
+    {
+      if (hasGlslBitwiseOps != OpenGl_FeatureNotAvailable)
+      {
+        myActiveProgram->SetUniform (this, aPatternLoc, (Standard_Integer )thePattern);
+      }
+      else
+      {
+        Standard_Integer aPatArr[16] = {};
+        for (unsigned int aBit = 0; aBit < 16; ++aBit)
+        {
+          aPatArr[aBit] = ((unsigned int)(thePattern) & (1U << aBit)) != 0 ? 1 : 0;
+        }
+        myActiveProgram->SetUniform (this, aPatternLoc, 16, aPatArr);
+      }
+      myActiveProgram->SetUniform (this, myActiveProgram->GetStateLocation (OpenGl_OCCT_LINE_STIPPLE_FACTOR), theFactor);
+    }
     return;
   }
 
 #if !defined(GL_ES_VERSION_2_0)
-  if (aPattern != 0xFFFF)
+  if (thePattern != 0xFFFF)
   {
-  #ifdef HAVE_GL2PS
-    if (IsFeedback())
-    {
-      gl2psEnable (GL2PS_LINE_STIPPLE);
-    }
-  #endif
-
     if (core11 != NULL)
     {
       core11fwd->glEnable (GL_LINE_STIPPLE);
 
       core11->glLineStipple (static_cast<GLint>    (theFactor),
-                             static_cast<GLushort> (aPattern));
+                             static_cast<GLushort> (thePattern));
     }
   }
   else
@@ -3201,13 +4123,6 @@ void OpenGl_Context::SetTypeOfLine (const Aspect_TypeOfLine  theType,
     {
       core11fwd->glDisable (GL_LINE_STIPPLE);
     }
-
-  #ifdef HAVE_GL2PS
-    if (IsFeedback())
-    {
-      gl2psDisable (GL2PS_LINE_STIPPLE);
-    }
-  #endif
   }
 #endif
 }
@@ -3223,25 +4138,23 @@ void OpenGl_Context::SetLineWidth (const Standard_ShortReal theWidth)
     // glLineWidth() is still defined within Core Profile, but has no effect with values != 1.0f
     core11fwd->glLineWidth (theWidth * myLineWidthScale);
   }
-#ifdef HAVE_GL2PS
-  if (IsFeedback())
-  {
-    gl2psLineWidth (theWidth);
-  }
-#endif
 }
 
 // =======================================================================
 // function : SetTextureMatrix
 // purpose  :
 // =======================================================================
-void OpenGl_Context::SetTextureMatrix (const Handle(Graphic3d_TextureParams)& theParams)
+void OpenGl_Context::SetTextureMatrix (const Handle(Graphic3d_TextureParams)& theParams,
+                                       const Standard_Boolean theIsTopDown)
 {
   if (theParams.IsNull())
   {
     return;
   }
-  else if (!myActiveProgram.IsNull())
+
+  const Graphic3d_Vec2& aScale = theParams->Scale();
+  const Graphic3d_Vec2& aTrans = theParams->Translation();
+  if (!myActiveProgram.IsNull())
   {
     const GLint aUniLoc = myActiveProgram->GetStateLocation (OpenGl_OCCT_TEXTURE_TRSF2D);
     if (aUniLoc == OpenGl_ShaderProgram::INVALID_LOCATION)
@@ -3250,12 +4163,19 @@ void OpenGl_Context::SetTextureMatrix (const Handle(Graphic3d_TextureParams)& th
     }
 
     // pack transformation parameters
-    OpenGl_Vec4 aTrsf[2];
-    aTrsf[0].x()  = -theParams->Translation().x();
-    aTrsf[0].y()  = -theParams->Translation().y();
-    aTrsf[0].zw() = theParams->Scale();
-    aTrsf[1].x()  = std::sin (-theParams->Rotation() * static_cast<float> (M_PI / 180.0));
-    aTrsf[1].y()  = std::cos (-theParams->Rotation() * static_cast<float> (M_PI / 180.0));
+    OpenGl_Vec4 aTrsf[2] =
+    {
+      OpenGl_Vec4 (-aTrans.x(), -aTrans.y(), aScale.x(), aScale.y()),
+      OpenGl_Vec4 (static_cast<float> (std::sin (-theParams->Rotation() * M_PI / 180.0)),
+                   static_cast<float> (std::cos (-theParams->Rotation() * M_PI / 180.0)),
+                   0.0f, 0.0f)
+    };
+    if (caps->isTopDownTextureUV != theIsTopDown)
+    {
+      // flip V
+      aTrsf[0].y() = -aTrans.y() + 1.0f / aScale.y();
+      aTrsf[0].w() = -aScale.y();
+    }
     myActiveProgram->SetUniform (this, aUniLoc, 2, aTrsf);
     return;
   }
@@ -3268,11 +4188,18 @@ void OpenGl_Context::SetTextureMatrix (const Handle(Graphic3d_TextureParams)& th
 
     core11->glMatrixMode (GL_TEXTURE);
     OpenGl_Mat4 aTextureMat;
-    const Graphic3d_Vec2& aScale = theParams->Scale();
-    const Graphic3d_Vec2& aTrans = theParams->Translation();
-    Graphic3d_TransformUtils::Scale     (aTextureMat,  aScale.x(),  aScale.y(), 1.0f);
-    Graphic3d_TransformUtils::Translate (aTextureMat, -aTrans.x(), -aTrans.y(), 0.0f);
-    Graphic3d_TransformUtils::Rotate    (aTextureMat, -theParams->Rotation(), 0.0f, 0.0f, 1.0f);
+    if (caps->isTopDownTextureUV != theIsTopDown)
+    {
+      // flip V
+      Graphic3d_TransformUtils::Scale     (aTextureMat,  aScale.x(), -aScale.y(), 1.0f);
+      Graphic3d_TransformUtils::Translate (aTextureMat, -aTrans.x(), -aTrans.y() + 1.0f / aScale.y(), 0.0f);
+    }
+    else
+    {
+      Graphic3d_TransformUtils::Scale     (aTextureMat,  aScale.x(),  aScale.y(), 1.0f);
+      Graphic3d_TransformUtils::Translate (aTextureMat, -aTrans.x(), -aTrans.y(), 0.0f);
+    }
+    Graphic3d_TransformUtils::Rotate (aTextureMat, -theParams->Rotation(), 0.0f, 0.0f, 1.0f);
     core11->glLoadMatrixf (aTextureMat);
     core11->glMatrixMode (aMatrixMode);
   }
@@ -3357,6 +4284,29 @@ Standard_Boolean OpenGl_Context::SetGlNormalizeEnabled (Standard_Boolean isEnabl
   return anOldGlNormalize;
 }
 
+// =======================================================================
+// function : SetShadeModel
+// purpose  :
+// =======================================================================
+void OpenGl_Context::SetShadeModel (Graphic3d_TypeOfShadingModel theModel)
+{
+#if !defined(GL_ES_VERSION_2_0)
+  if (core11 != NULL)
+  {
+    const Standard_Integer aModel = theModel == Graphic3d_TOSM_FACET
+                                 || theModel == Graphic3d_TOSM_PBR_FACET ? GL_FLAT : GL_SMOOTH;
+    if (myShadeModel == aModel)
+    {
+      return;
+    }
+    myShadeModel = aModel;
+    core11->glShadeModel (aModel);
+  }
+#else
+  (void )theModel;
+#endif
+}
+
 // =======================================================================
 // function : SetPolygonMode
 // purpose  :
@@ -3425,6 +4375,80 @@ Standard_Integer OpenGl_Context::SetPolygonHatchStyle (const Handle(Graphic3d_Ha
   return myHatchStyles->SetTypeOfHatch (this, theStyle);
 }
 
+// =======================================================================
+// function : SetPolygonOffset
+// purpose  :
+// =======================================================================
+void OpenGl_Context::SetPolygonOffset (const Graphic3d_PolygonOffset& theOffset)
+{
+  const bool toFillOld = (myPolygonOffset.Mode & Aspect_POM_Fill) == Aspect_POM_Fill;
+  const bool toFillNew = (theOffset.Mode       & Aspect_POM_Fill) == Aspect_POM_Fill;
+  if (toFillNew != toFillOld)
+  {
+    if (toFillNew)
+    {
+      glEnable (GL_POLYGON_OFFSET_FILL);
+    }
+    else
+    {
+      glDisable (GL_POLYGON_OFFSET_FILL);
+    }
+  }
+
+#if !defined(GL_ES_VERSION_2_0)
+  const bool toLineOld = (myPolygonOffset.Mode & Aspect_POM_Line) == Aspect_POM_Line;
+  const bool toLineNew = (theOffset.Mode       & Aspect_POM_Line) == Aspect_POM_Line;
+  if (toLineNew != toLineOld)
+  {
+    if (toLineNew)
+    {
+      glEnable (GL_POLYGON_OFFSET_LINE);
+    }
+    else
+    {
+      glDisable (GL_POLYGON_OFFSET_LINE);
+    }
+  }
+
+  const bool toPointOld = (myPolygonOffset.Mode & Aspect_POM_Point) == Aspect_POM_Point;
+  const bool toPointNew = (theOffset.Mode       & Aspect_POM_Point) == Aspect_POM_Point;
+  if (toPointNew != toPointOld)
+  {
+    if (toPointNew)
+    {
+      glEnable (GL_POLYGON_OFFSET_POINT);
+    }
+    else
+    {
+      glDisable (GL_POLYGON_OFFSET_POINT);
+    }
+  }
+#endif
+
+  if (myPolygonOffset.Factor != theOffset.Factor
+   || myPolygonOffset.Units  != theOffset.Units)
+  {
+    glPolygonOffset (theOffset.Factor, theOffset.Units);
+  }
+  myPolygonOffset = theOffset;
+}
+
+// =======================================================================
+// function : SetCamera
+// purpose  :
+// =======================================================================
+void OpenGl_Context::SetCamera (const Handle(Graphic3d_Camera)& theCamera)
+{
+  myCamera = theCamera;
+  if (!theCamera.IsNull())
+  {
+    ProjectionState.SetCurrent (theCamera->ProjectionMatrixF());
+    WorldViewState .SetCurrent (theCamera->OrientationMatrixF());
+    ApplyProjectionMatrix();
+    ApplyWorldViewMatrix();
+  }
+}
+
 // =======================================================================
 // function : ApplyModelWorldMatrix
 // purpose  :
@@ -3548,3 +4572,158 @@ void OpenGl_Context::DisableFeatures() const
   }
 #endif
 }
+
+// =======================================================================
+// function : SetColorMask
+// purpose  :
+// =======================================================================
+bool OpenGl_Context::SetColorMask (bool theToWriteColor)
+{
+  const GLboolean toWrite = theToWriteColor ? GL_TRUE : GL_FALSE;
+  glColorMask (toWrite, toWrite, toWrite, toWrite);
+
+  const bool anOldValue = myColorMask;
+  myColorMask = theToWriteColor;
+  return anOldValue;
+}
+
+// =======================================================================
+// function : SetSampleAlphaToCoverage
+// purpose  :
+// =======================================================================
+bool OpenGl_Context::SetSampleAlphaToCoverage (bool theToEnable)
+{
+  bool toEnable = myAllowAlphaToCov && theToEnable;
+  if (myAlphaToCoverage == toEnable)
+  {
+    return myAlphaToCoverage;
+  }
+
+  if (core15fwd != NULL)
+  {
+    if (toEnable)
+    {
+      //core15fwd->core15fwd->glSampleCoverage (1.0f, GL_FALSE);
+      core15fwd->glEnable (GL_SAMPLE_ALPHA_TO_COVERAGE);
+    }
+    else
+    {
+      core15fwd->glDisable (GL_SAMPLE_ALPHA_TO_COVERAGE);
+    }
+  }
+
+  const bool anOldValue = myAlphaToCoverage;
+  myAlphaToCoverage = toEnable;
+  return anOldValue;
+}
+
+// =======================================================================
+// function : GetBufferSubData
+// purpose  :
+// =======================================================================
+bool OpenGl_Context::GetBufferSubData (GLenum theTarget, GLintptr theOffset, GLsizeiptr theSize, void* theData)
+{
+  if (!hasGetBufferData)
+  {
+    return false;
+  }
+#ifdef __EMSCRIPTEN__
+  EM_ASM_(
+  {
+    Module.ctx.getBufferSubData($0, $1, HEAPU8.subarray($2, $2 + $3));
+  }, theTarget, theOffset, theData, theSize);
+  return true;
+#elif defined(GL_ES_VERSION_2_0)
+  if (void* aData = core30fwd->glMapBufferRange (theTarget, theOffset, theSize, GL_MAP_READ_BIT))
+  {
+    memcpy (theData, aData, theSize);
+    core30fwd->glUnmapBuffer (theTarget);
+    return true;
+  }
+  return false;
+#else
+  core15fwd->glGetBufferSubData (theTarget, theOffset, theSize, theData);
+  return true;
+#endif
+}
+
+// =======================================================================
+// function : DumpJson
+// purpose  :
+// =======================================================================
+void OpenGl_Context::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
+{
+  OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
+
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myAnisoMax)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myTexClamp)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMaxTexDim)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMaxTexCombined)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMaxDumpSizeX)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMaxDumpSizeY)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMaxClipPlanes)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMaxMsaaSamples)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMaxDrawBuffers)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myMaxColorAttachments)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myGlVerMajor)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myGlVerMinor)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsInitialized)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsStereoBuffers)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsGlNormalizeEnabled)
+
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myHasRayTracing)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myHasRayTracingTextures)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myHasRayTracingAdaptiveSampling)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myHasRayTracingAdaptiveSamplingAtomic)
+
+  for (int i = 0; i < 4; i++)
+  {
+    OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myViewport[i])
+  }
+
+  for (int i = 0; i < 4; i++)
+  {
+    OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myViewportVirt[i])
+  }
+
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myPointSpriteOrig)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myRenderMode)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myPolygonMode)
+  OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myPolygonOffset)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myToCullBackFaces)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myReadBuffer)
+
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myDefaultVao)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myColorMask)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myAllowAlphaToCov)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myAlphaToCoverage)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsGlDebugCtx)
+
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myResolution)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myResolutionRatio)
+
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myLineWidthScale)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myLineFeather)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myRenderScale)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myRenderScaleInv)
+  
+  OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &ModelWorldState)
+  OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &WorldViewState)
+  OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &ProjectionState)
+}
+
+// =======================================================================
+// function : DumpJsonOpenGlState
+// purpose  :
+// =======================================================================
+void OpenGl_Context::DumpJsonOpenGlState (Standard_OStream& theOStream, Standard_Integer)
+{
+  GLboolean isEnableBlend = glIsEnabled (GL_BLEND);
+  GLboolean isEnableCullFace = glIsEnabled (GL_CULL_FACE);
+  GLboolean isEnableDepthTest = glIsEnabled (GL_DEPTH_TEST);
+  
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, isEnableBlend)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, isEnableCullFace)
+  OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, isEnableDepthTest)
+}
+