0030748: Visualization - Marker displayed in immediate layer ruins QT Quick view...
[occt.git] / src / OpenGl / OpenGl_ShaderProgram.cxx
index 4931090..9b10c93 100755 (executable)
@@ -14,6 +14,7 @@
 // commercial license or contractual agreement.
 
 #include <OSD_File.hxx>
+#include <OSD_Environment.hxx>
 #include <OSD_Protection.hxx>
 
 #include <Graphic3d_Buffer.hxx>
 #include <OpenGl_Context.hxx>
 #include <OpenGl_ShaderProgram.hxx>
 #include <OpenGl_ShaderManager.hxx>
+#include <OpenGl_ArbTexBindless.hxx>
 
-IMPLEMENT_STANDARD_HANDLE (OpenGl_ShaderProgram, OpenGl_Resource)
-IMPLEMENT_STANDARD_RTTIEXT(OpenGl_ShaderProgram, OpenGl_Resource)
+#include <OpenGl_GlCore32.hxx>
+
+#include "../Shaders/Shaders_DeclarationsImpl_glsl.pxx"
+#include "../Shaders/Shaders_Declarations_glsl.pxx"
+
+#ifdef _WIN32
+  #include <malloc.h> // for alloca()
+#endif
+
+IMPLEMENT_STANDARD_RTTIEXT(OpenGl_ShaderProgram, OpenGl_NamedResource)
 
 OpenGl_VariableSetterSelector OpenGl_ShaderProgram::mySetterSelector = OpenGl_VariableSetterSelector();
 
@@ -47,7 +57,7 @@ Standard_CString OpenGl_ShaderProgram::PredefinedKeywords[] =
   "occProjectionMatrixInverseTranspose", // OpenGl_OCC_PROJECTION_MATRIX_INVERSE_TRANSPOSE
 
   "occClipPlaneEquations", // OpenGl_OCC_CLIP_PLANE_EQUATIONS
-  "occClipPlaneSpaces",    // OpenGl_OCC_CLIP_PLANE_SPACES
+  "occClipPlaneChains",    // OpenGl_OCC_CLIP_PLANE_CHAINS
   "occClipPlaneCount",     // OpenGl_OCC_CLIP_PLANE_COUNT
 
   "occLightSourcesCount",  // OpenGl_OCC_LIGHT_SOURCE_COUNT
@@ -55,14 +65,47 @@ Standard_CString OpenGl_ShaderProgram::PredefinedKeywords[] =
   "occLightSources",       // OpenGl_OCC_LIGHT_SOURCE_PARAMS
   "occLightAmbient",       // OpenGl_OCC_LIGHT_AMBIENT
 
-  "occActiveSampler",      // OpenGl_OCCT_ACTIVE_SAMPLER
   "occTextureEnable",      // OpenGl_OCCT_TEXTURE_ENABLE
   "occDistinguishingMode", // OpenGl_OCCT_DISTINGUISH_MODE
   "occFrontMaterial",      // OpenGl_OCCT_FRONT_MATERIAL
-  "occBackMaterial"        // OpenGl_OCCT_BACK_MATERIAL
+  "occBackMaterial",       // OpenGl_OCCT_BACK_MATERIAL
+  "occAlphaCutoff",        // OpenGl_OCCT_ALPHA_CUTOFF
+  "occColor",              // OpenGl_OCCT_COLOR
+
+  "occOitOutput",          // OpenGl_OCCT_OIT_OUTPUT
+  "occOitDepthFactor",     // OpenGl_OCCT_OIT_DEPTH_FACTOR
 
+  "occTexTrsf2d",          // OpenGl_OCCT_TEXTURE_TRSF2D
+  "occPointSize",          // OpenGl_OCCT_POINT_SIZE
+
+  "occViewport",           // OpenGl_OCCT_VIEWPORT
+  "occLineWidth",          // OpenGl_OCCT_LINE_WIDTH
+  "occLineFeather",        // OpenGl_OCCT_LINE_FEATHER
+  "occWireframeColor",     // OpenGl_OCCT_WIREFRAME_COLOR
+  "occIsQuadMode",         // OpenGl_OCCT_QUAD_MODE_STATE
+
+  "occOrthoScale",         // OpenGl_OCCT_ORTHO_SCALE
+  "occSilhouetteThickness" // OpenGl_OCCT_SILHOUETTE_THICKNESS
 };
 
+namespace
+{
+  //! Convert Graphic3d_TypeOfShaderObject enumeration into OpenGL enumeration.
+  static GLenum shaderTypeToGl (Graphic3d_TypeOfShaderObject theType)
+  {
+    switch (theType)
+    {
+      case Graphic3d_TOS_VERTEX:          return GL_VERTEX_SHADER;
+      case Graphic3d_TOS_FRAGMENT:        return GL_FRAGMENT_SHADER;
+      case Graphic3d_TOS_GEOMETRY:        return GL_GEOMETRY_SHADER;
+      case Graphic3d_TOS_TESS_CONTROL:    return GL_TESS_CONTROL_SHADER;
+      case Graphic3d_TOS_TESS_EVALUATION: return GL_TESS_EVALUATION_SHADER;
+      case Graphic3d_TOS_COMPUTE:         return GL_COMPUTE_SHADER;
+    }
+    return 0;
+  }
+}
+
 // =======================================================================
 // function : OpenGl_VariableSetterSelector
 // purpose  : Creates new variable setter selector
@@ -113,16 +156,20 @@ void OpenGl_VariableSetterSelector::Set (const Handle(OpenGl_Context)&
 // function : OpenGl_ShaderProgram
 // purpose  : Creates uninitialized shader program
 // =======================================================================
-OpenGl_ShaderProgram::OpenGl_ShaderProgram (const Handle(Graphic3d_ShaderProgram)& theProxy)
-: myProgramID (NO_PROGRAM),
+OpenGl_ShaderProgram::OpenGl_ShaderProgram (const Handle(Graphic3d_ShaderProgram)& theProxy,
+                                            const TCollection_AsciiString& theId)
+: OpenGl_NamedResource (!theProxy.IsNull() ? theProxy->GetId() : theId),
+  myProgramID (NO_PROGRAM),
   myProxy     (theProxy),
-  myShareCount(1)
+  myShareCount(1),
+  myNbLightsMax (0),
+  myNbClipPlanesMax (0),
+  myNbFragOutputs (1),
+  myHasAlphaTest (false),
+  myHasWeightOitOutput (false),
+  myHasTessShader (false)
 {
   memset (myCurrentState, 0, sizeof (myCurrentState));
-  for (GLint aVar = 0; aVar < OpenGl_OCCT_NUMBER_OF_STATE_VARIABLES; ++aVar)
-  {
-    myStateLocations[aVar] = INVALID_LOCATION;
-  }
 }
 
 // =======================================================================
@@ -132,128 +179,264 @@ OpenGl_ShaderProgram::OpenGl_ShaderProgram (const Handle(Graphic3d_ShaderProgram
 Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)&     theCtx,
                                                    const Graphic3d_ShaderObjectList& theShaders)
 {
+  myHasTessShader = false;
   if (theCtx.IsNull() || !Create (theCtx))
   {
     return Standard_False;
   }
 
-  OSD_File aDeclFile     (Graphic3d_ShaderProgram::ShadersFolder() + "/Declarations.glsl");
-  OSD_File aDeclImplFile (Graphic3d_ShaderProgram::ShadersFolder() + "/DeclarationsImpl.glsl");
-  if (!aDeclFile.Exists()
-   || !aDeclImplFile.Exists())
+  TCollection_AsciiString aHeaderVer = !myProxy.IsNull() ? myProxy->Header() : TCollection_AsciiString();
+  int aShaderMask = 0;
+  for (Graphic3d_ShaderObjectList::Iterator anIter (theShaders); anIter.More(); anIter.Next())
   {
-    const TCollection_ExtendedString aMsg = "Error! Failed to load OCCT shader declarations file";
-    theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
-                         GL_DEBUG_TYPE_ERROR_ARB,
-                         0,
-                         GL_DEBUG_SEVERITY_HIGH_ARB,
-                         aMsg);
-    return Standard_False;
+    aShaderMask |= anIter.Value()->Type();
   }
-
-  TCollection_AsciiString aDeclarations;
-  aDeclFile.Open (OSD_ReadOnly, OSD_Protection());
-  aDeclFile.Read (aDeclarations, (int)aDeclFile.Size());
-  aDeclFile.Close();
-
-  TCollection_AsciiString aDeclImpl;
-  aDeclImplFile.Open (OSD_ReadOnly, OSD_Protection());
-  aDeclImplFile.Read (aDeclImpl, (int)aDeclImplFile.Size());
-  aDeclImplFile.Close();
-  aDeclarations += aDeclImpl;
-
-  for (Graphic3d_ShaderObjectList::Iterator anIter (theShaders);
-       anIter.More(); anIter.Next())
+  myHasTessShader = (aShaderMask & (Graphic3d_TOS_TESS_CONTROL | Graphic3d_TOS_TESS_EVALUATION)) != 0;
+  myNbFragOutputs = !myProxy.IsNull() ? myProxy->NbFragmentOutputs() : 1;
+  myHasAlphaTest  = !myProxy.IsNull() && myProxy->HasAlphaTest();
+  myHasWeightOitOutput = !myProxy.IsNull() ? myProxy->HasWeightOitOutput() && myNbFragOutputs >= 2 : 1;
+
+  // detect the minimum GLSL version required for defined Shader Objects
+#if defined(GL_ES_VERSION_2_0)
+  if (myHasTessShader)
   {
-    if (!anIter.Value()->IsDone())
+    if (!theCtx->IsGlGreaterEqual (3, 2))
     {
-      const TCollection_ExtendedString aMsg = "Error! Failed to get shader source";
-      theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
-                           GL_DEBUG_TYPE_ERROR_ARB,
-                           0,
-                           GL_DEBUG_SEVERITY_HIGH_ARB,
-                           aMsg);
-      return Standard_False;
+      theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                           "Error! Tessellation shader requires OpenGL ES 3.2+");
+      return false;
     }
-
-    Handle(OpenGl_ShaderObject) aShader;
-
-    // Note: Add support of other shader types here
-    switch (anIter.Value()->Type())
+    else if (aHeaderVer.IsEmpty())
+    {
+      aHeaderVer = "#version 320 es";
+    }
+  }
+  else if ((aShaderMask & Graphic3d_TOS_GEOMETRY) != 0)
+  {
+    switch (theCtx->hasGeometryStage)
     {
-      case Graphic3d_TOS_VERTEX:
-        aShader = new OpenGl_ShaderObject (GL_VERTEX_SHADER);
+      case OpenGl_FeatureNotAvailable:
+      {
+        theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                             "Error! Geometry shader requires OpenGL ES 3.2+ or GL_EXT_geometry_shader");
+        return false;
+      }
+      case OpenGl_FeatureInExtensions:
+      {
+        if (aHeaderVer.IsEmpty())
+        {
+          aHeaderVer = "#version 310 es";
+        }
         break;
-      case Graphic3d_TOS_FRAGMENT:
-        aShader = new OpenGl_ShaderObject (GL_FRAGMENT_SHADER);
+      }
+      case OpenGl_FeatureInCore:
+      {
+        if (aHeaderVer.IsEmpty())
+        {
+          aHeaderVer = "#version 320 es";
+        }
         break;
+      }
+    }
+  }
+  else if ((aShaderMask & Graphic3d_TOS_COMPUTE) != 0)
+  {
+    if (!theCtx->IsGlGreaterEqual (3, 1))
+    {
+      theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                           "Error! Compute shaders require OpenGL ES 3.1+");
+      return false;
+    }
+    else if (aHeaderVer.IsEmpty())
+    {
+      aHeaderVer = "#version 310 es";
+    }
+  }
+#else
+  if ((aShaderMask & Graphic3d_TOS_COMPUTE) != 0)
+  {
+    if (!theCtx->IsGlGreaterEqual (4, 3))
+    {
+      theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                           "Error! Compute shaders require OpenGL 4.3+");
+      return 0;
+    }
+    else if (aHeaderVer.IsEmpty())
+    {
+      aHeaderVer = "#version 430";
     }
+  }
+  else if (myHasTessShader)
+  {
+    if (!theCtx->IsGlGreaterEqual (4, 0))
+    {
+      theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                           "Error! Tessellation shaders require OpenGL 4.0+");
+      return 0;
+    }
+    else if (aHeaderVer.IsEmpty())
+    {
+      aHeaderVer = "#version 400";
+    }
+  }
+  else if ((aShaderMask & Graphic3d_TOS_GEOMETRY) != 0)
+  {
+    if (!theCtx->IsGlGreaterEqual (3, 2))
+    {
+      theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                           "Error! Geometry shaders require OpenGL 3.2+");
+      return 0;
+    }
+    else if (aHeaderVer.IsEmpty())
+    {
+      aHeaderVer = "#version 150";
+    }
+  }
+#endif
 
-    // Is unsupported shader type?
-    if (aShader.IsNull())
+  for (Graphic3d_ShaderObjectList::Iterator anIter (theShaders); anIter.More(); anIter.Next())
+  {
+    if (!anIter.Value()->IsDone())
     {
-      TCollection_ExtendedString aMsg = "Error! Unsupported shader type";
-      theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
-                           GL_DEBUG_TYPE_ERROR_ARB,
-                           0,
-                           GL_DEBUG_SEVERITY_HIGH_ARB,
-                           aMsg);
+      const TCollection_ExtendedString aMsg = "Error! Failed to get shader source";
+      theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aMsg);
       return Standard_False;
     }
 
+    const GLenum aShaderType = shaderTypeToGl (anIter.Value()->Type());
+    if (aShaderType == 0)
+    {
+      return Standard_False;
+    }
+
+    Handle(OpenGl_ShaderObject) aShader = new OpenGl_ShaderObject (aShaderType);
     if (!aShader->Create (theCtx))
     {
       aShader->Release (theCtx.operator->());
       return Standard_False;
     }
 
-    TCollection_AsciiString aSource = aDeclarations + anIter.Value()->Source();
-    if (anIter.Value()->Type() == Graphic3d_TOS_VERTEX)
+    TCollection_AsciiString anExtensions = "// Enable extensions used in OCCT GLSL programs\n";
+    if (myNbFragOutputs > 1)
     {
-      aSource = TCollection_AsciiString ("#define VERTEX_SHADER\n") + aSource;
-    }
+      if (theCtx->hasDrawBuffers)
+      {
+        anExtensions += "#define OCC_ENABLE_draw_buffers\n";
+        if (myHasWeightOitOutput)
+        {
+          anExtensions += "#define OCC_WRITE_WEIGHT_OIT_COVERAGE\n";
+        }
+      }
+      else
+      {
+        theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                             "Error! Multiple draw buffers required by the program, but aren't supported by OpenGL");
+        return Standard_False;
+      }
 
-    if (!aShader->LoadSource (theCtx, aSource))
+      if (theCtx->hasDrawBuffers == OpenGl_FeatureInExtensions)
+      {
+        if (theCtx->arbDrawBuffers)
+        {
+          anExtensions += "#extension GL_ARB_draw_buffers : enable\n";
+        }
+        else if (theCtx->extDrawBuffers)
+        {
+          anExtensions += "#extension GL_EXT_draw_buffers : enable\n";
+        }
+      }
+    }
+    if (myHasAlphaTest)
     {
-      const TCollection_ExtendedString aMsg = "Error! Failed to set shader source";
-      theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
-                           GL_DEBUG_TYPE_ERROR_ARB,
-                           0,
-                           GL_DEBUG_SEVERITY_HIGH_ARB,
-                           aMsg);
-      aShader->Release (theCtx.operator->());
-      return Standard_False;
+      anExtensions += "#define OCC_ALPHA_TEST\n";
     }
 
-    if (!aShader->Compile (theCtx))
+    if (theCtx->hasSampleVariables == OpenGl_FeatureInExtensions)
     {
-      TCollection_AsciiString aLog;
-      aShader->FetchInfoLog (theCtx, aLog);
-      if (aLog.IsEmpty())
+#if defined(GL_ES_VERSION_2_0)
+      if (theCtx->oesSampleVariables)
+      {
+        anExtensions += "#extension GL_OES_sample_variables : enable\n";
+      }
+#else
+      if (theCtx->arbSampleShading)
       {
-        aLog = "Compilation log is empty.";
+        anExtensions += "#extension GL_ARB_sample_shading : enable\n";
       }
-      theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
-                           GL_DEBUG_TYPE_ERROR_ARB,
-                           0,
-                           GL_DEBUG_SEVERITY_HIGH_ARB,
-                           TCollection_ExtendedString ("Failed to compile shader object. Compilation log:\n") + aLog);
+#endif
+    }
+#if defined(GL_ES_VERSION_2_0)
+    if (theCtx->hasGeometryStage == OpenGl_FeatureInExtensions)
+    {
+      anExtensions += "#extension GL_EXT_geometry_shader : enable\n"
+                      "#extension GL_EXT_shader_io_blocks : enable\n";
+    }
+#endif
+
+    TCollection_AsciiString aPrecisionHeader;
+    if (anIter.Value()->Type() == Graphic3d_TOS_FRAGMENT)
+    {
+    #if defined(GL_ES_VERSION_2_0)
+      aPrecisionHeader = theCtx->hasHighp
+                       ? "precision highp float;\n"
+                         "precision highp int;\n"
+                       : "precision mediump float;\n"
+                         "precision mediump int;\n";
+    #endif
+    }
+
+    TCollection_AsciiString aHeaderType;
+    switch (anIter.Value()->Type())
+    {
+      case Graphic3d_TOS_COMPUTE:         { aHeaderType = "#define COMPUTE_SHADER\n";         break; }
+      case Graphic3d_TOS_VERTEX:          { aHeaderType = "#define VERTEX_SHADER\n";          break; }
+      case Graphic3d_TOS_TESS_CONTROL:    { aHeaderType = "#define TESS_CONTROL_SHADER\n";    break; }
+      case Graphic3d_TOS_TESS_EVALUATION: { aHeaderType = "#define TESS_EVALUATION_SHADER\n"; break; }
+      case Graphic3d_TOS_GEOMETRY:        { aHeaderType = "#define GEOMETRY_SHADER\n";        break; }
+      case Graphic3d_TOS_FRAGMENT:        { aHeaderType = "#define FRAGMENT_SHADER\n";        break; }
+    }
+
+    TCollection_AsciiString aHeaderConstants;
+    myNbLightsMax     = !myProxy.IsNull() ? myProxy->NbLightsMax() : 0;
+    myNbClipPlanesMax = !myProxy.IsNull() ? myProxy->NbClipPlanesMax() : 0;
+    aHeaderConstants += TCollection_AsciiString("#define THE_MAX_LIGHTS ") + myNbLightsMax + "\n";
+    aHeaderConstants += TCollection_AsciiString("#define THE_MAX_CLIP_PLANES ") + myNbClipPlanesMax + "\n";
+    aHeaderConstants += TCollection_AsciiString("#define THE_NB_FRAG_OUTPUTS ") + myNbFragOutputs + "\n";
+    if (!myProxy.IsNull()
+      && myProxy->HasDefaultSampler())
+    {
+      aHeaderConstants += "#define THE_HAS_DEFAULT_SAMPLER\n";
+    }
+
+    const TCollection_AsciiString aSource = aHeaderVer                     // #version   - header defining GLSL version, should be first
+                                          + (!aHeaderVer.IsEmpty() ? "\n" : "")
+                                          + anExtensions                   // #extension - list of enabled extensions,   should be second
+                                          + aPrecisionHeader               // precision  - default precision qualifiers, should be before any code
+                                          + aHeaderType                    // auxiliary macros defining a shader stage (type)
+                                          + aHeaderConstants
+                                          + Shaders_Declarations_glsl      // common declarations (global constants and Vertex Shader inputs)
+                                          + Shaders_DeclarationsImpl_glsl
+                                          + anIter.Value()->Source();      // the source code itself (defining main() function)
+    if (!aShader->LoadAndCompile (theCtx, myResourceId, aSource))
+    {
       aShader->Release (theCtx.operator->());
       return Standard_False;
     }
-    else if (theCtx->caps->glslWarnings)
+
+    if (theCtx->caps->glslDumpLevel)
     {
-      TCollection_AsciiString aLog;
-      aShader->FetchInfoLog (theCtx, aLog);
-      if (!aLog.IsEmpty()
-       && !aLog.IsEqual ("No errors.\n"))
+      TCollection_AsciiString anOutputSource = aSource;
+      if (theCtx->caps->glslDumpLevel == OpenGl_ShaderProgramDumpLevel_Short)
       {
-        theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
-                             GL_DEBUG_TYPE_PORTABILITY_ARB,
-                             0,
-                             GL_DEBUG_SEVERITY_LOW_ARB,
-                             TCollection_ExtendedString ("Shader compilation log:\n") + aLog);
+        anOutputSource = aHeaderVer
+                       + (!aHeaderVer.IsEmpty() ? "\n" : "")
+                       + anExtensions
+                       + aPrecisionHeader
+                       + aHeaderType
+                       + aHeaderConstants
+                       + anIter.Value()->Source();
       }
+      aShader->DumpSourceCode (theCtx, myResourceId, anOutputSource);
     }
 
     if (!AttachShader (theCtx, aShader))
@@ -267,38 +450,55 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)&
   SetAttributeName (theCtx, Graphic3d_TOA_POS,   "occVertex");
   SetAttributeName (theCtx, Graphic3d_TOA_NORM,  "occNormal");
   SetAttributeName (theCtx, Graphic3d_TOA_UV,    "occTexCoord");
-  SetAttributeName (theCtx, Graphic3d_TOA_COLOR, "occColor");
+  SetAttributeName (theCtx, Graphic3d_TOA_COLOR, "occVertColor");
 
-  if (!Link (theCtx))
+  // bind custom Vertex Attributes
+  if (!myProxy.IsNull())
   {
-    TCollection_AsciiString aLog;
-    FetchInfoLog (theCtx, aLog);
-    if (aLog.IsEmpty())
+    for (Graphic3d_ShaderAttributeList::Iterator anAttribIter (myProxy->VertexAttributes());
+         anAttribIter.More(); anAttribIter.Next())
     {
-      aLog = "Linker log is empty.";
+      SetAttributeName (theCtx, anAttribIter.Value()->Location(), anAttribIter.Value()->Name().ToCString());
     }
-    theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
-                         GL_DEBUG_TYPE_ERROR_ARB,
-                         0,
-                         GL_DEBUG_SEVERITY_HIGH_ARB,
-                         TCollection_ExtendedString ("Failed to link program object! Linker log:\n") + aLog);
+  }
+
+  if (!Link (theCtx))
+  {
     return Standard_False;
   }
-  else if (theCtx->caps->glslWarnings)
+
+  // set uniform defaults
+  const Handle(OpenGl_ShaderProgram)& anOldProgram = theCtx->ActiveProgram();
+  theCtx->core20fwd->glUseProgram (myProgramID);
+  if (const OpenGl_ShaderUniformLocation aLocTexEnable = GetStateLocation (OpenGl_OCCT_TEXTURE_ENABLE))
   {
-    TCollection_AsciiString aLog;
-    FetchInfoLog (theCtx, aLog);
-    if (!aLog.IsEmpty()
-     && !aLog.IsEqual ("No errors.\n"))
+    SetUniform (theCtx, aLocTexEnable, 0); // Off
+  }
+  if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occActiveSampler"))
+  {
+    SetUniform (theCtx, aLocSampler, GLint(Graphic3d_TextureUnit_0));
+  }
+  if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occSamplerBaseColor"))
+  {
+    SetUniform (theCtx, aLocSampler, GLint(Graphic3d_TextureUnit_BaseColor));
+  }
+  if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occSamplerPointSprite"))
+  {
+    SetUniform (theCtx, aLocSampler, GLint(theCtx->SpriteTextureUnit()));
+  }
+
+  const TCollection_AsciiString aSamplerNamePrefix ("occSampler");
+  const Standard_Integer aNbUnitsMax = Max (theCtx->MaxCombinedTextureUnits(), Graphic3d_TextureUnit_NB);
+  for (GLint aUnitIter = 0; aUnitIter < aNbUnitsMax; ++aUnitIter)
+  {
+    const TCollection_AsciiString aName = aSamplerNamePrefix + aUnitIter;
+    if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, aName.ToCString()))
     {
-      theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION_ARB,
-                           GL_DEBUG_TYPE_PORTABILITY_ARB,
-                           0,
-                           GL_DEBUG_SEVERITY_LOW_ARB,
-                           TCollection_ExtendedString ("GLSL linker log:\n") + aLog);
+      SetUniform (theCtx, aLocSampler, aUnitIter);
     }
   }
 
+  theCtx->core20fwd->glUseProgram (!anOldProgram.IsNull() ? anOldProgram->ProgramId() : OpenGl_ShaderProgram::NO_PROGRAM);
   return Standard_True;
 }
 
@@ -332,7 +532,7 @@ Standard_Boolean OpenGl_ShaderProgram::AttachShader (const Handle(OpenGl_Context
   }
 
   myShaderObjects.Append (theShader);
-  theCtx->core20->glAttachShader (myProgramID, theShader->myShaderID);
+  theCtx->core20fwd->glAttachShader (myProgramID, theShader->myShaderID);
   return Standard_True;
 }
 
@@ -366,7 +566,7 @@ Standard_Boolean OpenGl_ShaderProgram::DetachShader (const Handle(OpenGl_Context
     return Standard_False;
   }
 
-  theCtx->core20->glDetachShader (myProgramID, theShader->myShaderID);
+  theCtx->core20fwd->glDetachShader (myProgramID, theShader->myShaderID);
   return Standard_True;
 }
 
@@ -374,7 +574,7 @@ Standard_Boolean OpenGl_ShaderProgram::DetachShader (const Handle(OpenGl_Context
 // function : Link
 // purpose  : Links the program object
 // =======================================================================
-Standard_Boolean OpenGl_ShaderProgram::Link (const Handle(OpenGl_Context)& theCtx)
+Standard_Boolean OpenGl_ShaderProgram::link (const Handle(OpenGl_Context)& theCtx)
 {
   if (myProgramID == NO_PROGRAM)
   {
@@ -382,13 +582,14 @@ Standard_Boolean OpenGl_ShaderProgram::Link (const Handle(OpenGl_Context)& theCt
   }
 
   GLint aStatus = GL_FALSE;
-  theCtx->core20->glLinkProgram (myProgramID);
-  theCtx->core20->glGetProgramiv (myProgramID, GL_LINK_STATUS, &aStatus);
+  theCtx->core20fwd->glLinkProgram (myProgramID);
+  theCtx->core20fwd->glGetProgramiv (myProgramID, GL_LINK_STATUS, &aStatus);
   if (aStatus == GL_FALSE)
   {
     return Standard_False;
   }
 
+  memset (myCurrentState, 0, sizeof (myCurrentState));
   for (GLint aVar = 0; aVar < OpenGl_OCCT_NUMBER_OF_STATE_VARIABLES; ++aVar)
   {
     myStateLocations[aVar] = GetUniformLocation (theCtx, PredefinedKeywords[aVar]);
@@ -396,6 +597,44 @@ Standard_Boolean OpenGl_ShaderProgram::Link (const Handle(OpenGl_Context)& theCt
   return Standard_True;
 }
 
+// =======================================================================
+// function : Link
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_ShaderProgram::Link (const Handle(OpenGl_Context)& theCtx,
+                                             bool theIsVerbose)
+{
+  if (!theIsVerbose)
+  {
+    return link (theCtx);
+  }
+
+  if (!link (theCtx))
+  {
+    TCollection_AsciiString aLog;
+    FetchInfoLog (theCtx, aLog);
+    if (aLog.IsEmpty())
+    {
+      aLog = "Linker log is empty.";
+    }
+    theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                         TCollection_AsciiString ("Failed to link program object [") + myResourceId + "]! Linker log:\n" + aLog);
+    return false;
+  }
+  else if (theCtx->caps->glslWarnings)
+  {
+    TCollection_AsciiString aLog;
+    FetchInfoLog (theCtx, aLog);
+    if (!aLog.IsEmpty()
+     && !aLog.IsEqual ("No errors.\n"))
+    {
+      theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_LOW,
+                           TCollection_AsciiString ("GLSL linker log [") + myResourceId +"]:\n" + aLog);
+    }
+  }
+  return true;
+}
+
 // =======================================================================
 // function : FetchInfoLog
 // purpose  : Fetches information log of the last link operation
@@ -409,12 +648,12 @@ Standard_Boolean OpenGl_ShaderProgram::FetchInfoLog (const Handle(OpenGl_Context
   }
 
   GLint aLength = 0;
-  theCtx->core20->glGetProgramiv (myProgramID, GL_INFO_LOG_LENGTH, &aLength);
+  theCtx->core20fwd->glGetProgramiv (myProgramID, GL_INFO_LOG_LENGTH, &aLength);
   if (aLength > 0)
   {
     GLchar* aLog = (GLchar*) alloca (aLength);
     memset (aLog, 0, aLength);
-    theCtx->core20->glGetProgramInfoLog (myProgramID, aLength, NULL, aLog);
+    theCtx->core20fwd->glGetProgramInfoLog (myProgramID, aLength, NULL, aLog);
     theOutput = aLog;
   }
   return Standard_True;
@@ -440,42 +679,16 @@ Standard_Boolean OpenGl_ShaderProgram::ApplyVariables(const Handle(OpenGl_Contex
   return Standard_True;
 }
 
-// =======================================================================
-// function : ActiveState
-// purpose  : Returns index of last modification for specified state type
-// =======================================================================
-Standard_Size OpenGl_ShaderProgram::ActiveState (const OpenGl_UniformStateType theType) const
-{
-  if (theType < MaxStateTypes)
-  {
-    return myCurrentState[theType];
-  }
-  return 0;
-}
-
-// =======================================================================
-// function : UpdateState
-// purpose  : Updates index of last modification for specified state type
-// =======================================================================
-void OpenGl_ShaderProgram::UpdateState (const OpenGl_UniformStateType theType,
-                                        const Standard_Size           theIndex)
-{
-  if (theType < MaxStateTypes)
-  {
-    myCurrentState[theType] = theIndex;
-  }
-}
-
 // =======================================================================
 // function : GetUniformLocation
 // purpose  : Returns location (index) of the specific uniform variable
 // =======================================================================
-GLint OpenGl_ShaderProgram::GetUniformLocation (const Handle(OpenGl_Context)& theCtx,
-                                                const GLchar*                 theName) const
+OpenGl_ShaderUniformLocation OpenGl_ShaderProgram::GetUniformLocation (const Handle(OpenGl_Context)& theCtx,
+                                                                       const GLchar*                 theName) const
 {
-  return myProgramID != NO_PROGRAM
-       ? theCtx->core20->glGetUniformLocation (myProgramID, theName)
-       : INVALID_LOCATION;
+  return OpenGl_ShaderUniformLocation (myProgramID != NO_PROGRAM
+                                     ? theCtx->core20fwd->glGetUniformLocation (myProgramID, theName)
+                                     : INVALID_LOCATION);
 }
 
 // =======================================================================
@@ -486,23 +699,10 @@ GLint OpenGl_ShaderProgram::GetAttributeLocation (const Handle(OpenGl_Context)&
                                                   const GLchar*                 theName) const
 {
   return myProgramID != NO_PROGRAM
-       ? theCtx->core20->glGetAttribLocation (myProgramID, theName)
+       ? theCtx->core20fwd->glGetAttribLocation (myProgramID, theName)
        : INVALID_LOCATION;
 }
 
-// =======================================================================
-// function : GetStateLocation
-// purpose  : Returns location of the OCCT state uniform variable
-// =======================================================================
-GLint OpenGl_ShaderProgram::GetStateLocation (const GLuint theVariable) const
-{
-  if (theVariable < OpenGl_OCCT_NUMBER_OF_STATE_VARIABLES)
-  {
-    return myStateLocations[theVariable];
-  }
-  return INVALID_LOCATION;
-}
-
 // =======================================================================
 // function : GetUniform
 // purpose  : Returns the value of the integer uniform variable
@@ -527,7 +727,7 @@ Standard_Boolean OpenGl_ShaderProgram::GetUniform (const Handle(OpenGl_Context)&
     return Standard_False;
   }
 
-  theCtx->core20->glGetUniformiv (myProgramID, theLocation, theValue);
+  theCtx->core20fwd->glGetUniformiv (myProgramID, theLocation, theValue);
   return Standard_True;
 }
 
@@ -555,7 +755,7 @@ Standard_Boolean OpenGl_ShaderProgram::GetUniform (const Handle(OpenGl_Context)&
     return Standard_False;
   }
 
-  theCtx->core20->glGetUniformfv (myProgramID, theLocation, theValue);
+  theCtx->core20fwd->glGetUniformfv (myProgramID, theLocation, theValue);
   return Standard_True;
 }
 
@@ -583,7 +783,7 @@ Standard_Boolean OpenGl_ShaderProgram::GetAttribute (const Handle(OpenGl_Context
     return Standard_False;
   }
 
-  theCtx->core20->glGetVertexAttribiv (theIndex, GL_CURRENT_VERTEX_ATTRIB, theValue);
+  theCtx->core20fwd->glGetVertexAttribiv (theIndex, GL_CURRENT_VERTEX_ATTRIB, theValue);
   return Standard_True;
 }
 
@@ -611,7 +811,7 @@ Standard_Boolean OpenGl_ShaderProgram::GetAttribute (const Handle(OpenGl_Context
     return Standard_False;
   }
 
-  theCtx->core20->glGetVertexAttribfv (theIndex, GL_CURRENT_VERTEX_ATTRIB, theValue);
+  theCtx->core20fwd->glGetVertexAttribfv (theIndex, GL_CURRENT_VERTEX_ATTRIB, theValue);
   return Standard_True;
 }
 
@@ -626,7 +826,7 @@ Standard_Boolean OpenGl_ShaderProgram::SetAttributeName (const Handle(OpenGl_Con
   theCtx->core20fwd->glBindAttribLocation (myProgramID, theIndex, theName);
   return Standard_True;
 }
-  
+
 // =======================================================================
 // function : SetAttribute
 // purpose  :
@@ -763,8 +963,77 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
     return Standard_False;
   }
 
-  theCtx->core20->glUniform1i (theLocation, theValue);
+  theCtx->core20fwd->glUniform1i (theLocation, theValue);
+  return Standard_True;
+}
+
+// =======================================================================
+// function : SetUniform
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
+                                                   const GLchar*                 theName,
+                                                   const OpenGl_Vec2u&           theValue)
+{
+  return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue);
+}
+
+// =======================================================================
+// function : SetUniform
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
+                                                   GLint                         theLocation,
+                                                   const OpenGl_Vec2u&           theValue)
+{
+  if (theCtx->core32 == NULL || myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
+  {
+    return Standard_False;
+  }
+
+#if !defined(GL_ES_VERSION_2_0)
+  theCtx->core32->glUniform2uiv (theLocation, 1, theValue.GetData());
+  return Standard_True;
+#else
+  (void )theValue;
+  return Standard_False;
+#endif
+}
+
+// =======================================================================
+// function : SetUniform
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
+                                                   const GLchar*                 theName,
+                                                   const GLsizei                 theCount,
+                                                   const OpenGl_Vec2u*           theValue)
+{
+  return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theCount, theValue);
+}
+
+// =======================================================================
+// function : SetUniform
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
+                                                   GLint                         theLocation,
+                                                   const GLsizei                 theCount,
+                                                   const OpenGl_Vec2u*           theValue)
+{
+  if (theCtx->core32 == NULL || myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
+  {
+    return Standard_False;
+  }
+
+#if !defined(GL_ES_VERSION_2_0)
+  theCtx->core32->glUniform2uiv (theLocation, theCount, theValue->GetData());
   return Standard_True;
+#else
+  (void )theCount;
+  (void )theValue;
+  return Standard_False;
+#endif
 }
 
 // =======================================================================
@@ -791,7 +1060,7 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
     return Standard_False;
   }
 
-  theCtx->core20->glUniform1f (theLocation, theValue);
+  theCtx->core20fwd->glUniform1f (theLocation, theValue);
   return Standard_True;
 }
 
@@ -819,7 +1088,7 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
     return Standard_False;
   }
 
-  theCtx->core20->glUniform2iv (theLocation, 1, theValue);
+  theCtx->core20fwd->glUniform2iv (theLocation, 1, theValue);
   return Standard_True;
 }
 
@@ -847,7 +1116,7 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
     return Standard_False;
   }
 
-  theCtx->core20->glUniform3iv (theLocation, 1, theValue);
+  theCtx->core20fwd->glUniform3iv (theLocation, 1, theValue);
   return Standard_True;
 }
 
@@ -875,7 +1144,7 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
     return Standard_False;
   }
 
-  theCtx->core20->glUniform4iv (theLocation, 1, theValue);
+  theCtx->core20fwd->glUniform4iv (theLocation, 1, theValue);
   return Standard_True;
 }
 
@@ -903,7 +1172,7 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
     return Standard_False;
   }
 
-  theCtx->core20->glUniform2fv (theLocation, 1, theValue);
+  theCtx->core20fwd->glUniform2fv (theLocation, 1, theValue);
   return Standard_True;
 }
 
@@ -931,7 +1200,7 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
     return Standard_False;
   }
 
-  theCtx->core20->glUniform3fv (theLocation, 1, theValue);
+  theCtx->core20fwd->glUniform3fv (theLocation, 1, theValue);
   return Standard_True;
 }
 
@@ -959,7 +1228,7 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
     return Standard_False;
   }
 
-  theCtx->core20->glUniform4fv (theLocation, 1, theValue);
+  theCtx->core20fwd->glUniform4fv (theLocation, 1, theValue);
   return Standard_True;
 }
 
@@ -969,7 +1238,7 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
 // =======================================================================
 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
                                                    const GLchar*                 theName,
-                                                   const OpenGl_Matrix&          theValue,
+                                                   const OpenGl_Mat4&            theValue,
                                                    GLboolean                     theTranspose)
 {
   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue, theTranspose);
@@ -981,7 +1250,7 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
 // =======================================================================
 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
                                                    GLint                         theLocation,
-                                                   const OpenGl_Matrix&          theValue,
+                                                   const OpenGl_Mat4&            theValue,
                                                    GLboolean                     theTranspose)
 {
   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
@@ -989,7 +1258,7 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
     return Standard_False;
   }
 
-  theCtx->core20->glUniformMatrix4fv (theLocation, 1, theTranspose, *theValue.mat);
+  theCtx->core20fwd->glUniformMatrix4fv (theLocation, 1, GL_FALSE, theTranspose ? theValue.Transposed() : theValue);
   return Standard_True;
 }
 
@@ -999,7 +1268,7 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
 // =======================================================================
 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
                                                    const GLchar*                 theName,
-                                                   const Tmatrix3&               theValue,
+                                                   const OpenGl_Matrix&          theValue,
                                                    GLboolean                     theTranspose)
 {
   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue, theTranspose);
@@ -1011,16 +1280,10 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
 // =======================================================================
 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
                                                    GLint                         theLocation,
-                                                   const Tmatrix3&               theValue,
+                                                   const OpenGl_Matrix&          theValue,
                                                    GLboolean                     theTranspose)
 {
-  if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
-  {
-    return Standard_False;
-  }
-
-  theCtx->core20->glUniformMatrix4fv (theLocation, 1, theTranspose, *theValue);
-  return Standard_True;
+  return SetUniform (theCtx, theLocation, OpenGl_Mat4::Map (*theValue.mat), theTranspose);
 }
 
 // =======================================================================
@@ -1037,7 +1300,7 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
     return Standard_False;
   }
 
-  theCtx->core20->glUniform1fv (theLocation, theCount, theData);
+  theCtx->core20fwd->glUniform1fv (theLocation, theCount, theData);
   return Standard_True;
 }
 
@@ -1055,7 +1318,7 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
     return Standard_False;
   }
 
-  theCtx->core20->glUniform2fv (theLocation, theCount, theData[0].GetData());
+  theCtx->core20fwd->glUniform2fv (theLocation, theCount, theData[0].GetData());
   return Standard_True;
 }
 
@@ -1073,7 +1336,7 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
     return Standard_False;
   }
 
-  theCtx->core20->glUniform3fv (theLocation, theCount, theData[0].GetData());
+  theCtx->core20fwd->glUniform3fv (theLocation, theCount, theData[0].GetData());
   return Standard_True;
 }
 
@@ -1091,7 +1354,7 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
     return Standard_False;
   }
 
-  theCtx->core20->glUniform4fv (theLocation, theCount, theData[0].GetData());
+  theCtx->core20fwd->glUniform4fv (theLocation, theCount, theData[0].GetData());
   return Standard_True;
 }
 
@@ -1109,7 +1372,7 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
     return Standard_False;
   }
 
-  theCtx->core20->glUniform1iv (theLocation, theCount, theData);
+  theCtx->core20fwd->glUniform1iv (theLocation, theCount, theData);
   return Standard_True;
 }
 
@@ -1127,7 +1390,7 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
     return Standard_False;
   }
 
-  theCtx->core20->glUniform2iv (theLocation, theCount, theData[0].GetData());
+  theCtx->core20fwd->glUniform2iv (theLocation, theCount, theData[0].GetData());
   return Standard_True;
 }
 
@@ -1145,7 +1408,7 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
     return Standard_False;
   }
 
-  theCtx->core20->glUniform3iv (theLocation, theCount, theData[0].GetData());
+  theCtx->core20fwd->glUniform3iv (theLocation, theCount, theData[0].GetData());
   return Standard_True;
 }
 
@@ -1163,7 +1426,7 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
     return Standard_False;
   }
 
-  theCtx->core20->glUniform4iv (theLocation, theCount, theData[0].GetData());
+  theCtx->core20fwd->glUniform4iv (theLocation, theCount, theData[0].GetData());
   return Standard_True;
 }
 
@@ -1173,7 +1436,7 @@ Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)&
 // =======================================================================
 Standard_Boolean OpenGl_ShaderProgram::SetSampler (const Handle(OpenGl_Context)& theCtx,
                                                    const GLchar*                 theName,
-                                                   const GLenum                  theTextureUnit)
+                                                   const Graphic3d_TextureUnit   theTextureUnit)
 {
   return SetSampler (theCtx, GetUniformLocation (theCtx, theName), theTextureUnit);
 }
@@ -1184,14 +1447,14 @@ Standard_Boolean OpenGl_ShaderProgram::SetSampler (const Handle(OpenGl_Context)&
 // =======================================================================
 Standard_Boolean OpenGl_ShaderProgram::SetSampler (const Handle(OpenGl_Context)& theCtx,
                                                    GLint                         theLocation,
-                                                   const GLenum                  theTextureUnit)
+                                                   const Graphic3d_TextureUnit   theTextureUnit)
 {
   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
   {
     return Standard_False;
   }
 
-  theCtx->core20->glUniform1i (theLocation, theTextureUnit);
+  theCtx->core20fwd->glUniform1i (theLocation, theTextureUnit);
   return Standard_True;
 }
 
@@ -1202,9 +1465,9 @@ Standard_Boolean OpenGl_ShaderProgram::SetSampler (const Handle(OpenGl_Context)&
 Standard_Boolean OpenGl_ShaderProgram::Create (const Handle(OpenGl_Context)& theCtx)
 {
   if (myProgramID == NO_PROGRAM
-   && theCtx->core20 != NULL)
+   && theCtx->core20fwd != NULL)
   {
-    myProgramID = theCtx->core20->glCreateProgram();
+    myProgramID = theCtx->core20fwd->glCreateProgram();
   }
 
   return myProgramID != NO_PROGRAM;
@@ -1233,11 +1496,53 @@ void OpenGl_ShaderProgram::Release (OpenGl_Context* theCtx)
     }
   }
 
-  if (theCtx->core20 != NULL
+  if (theCtx->core20fwd != NULL
    && theCtx->IsValid())
   {
-    theCtx->core20->glDeleteProgram (myProgramID);
+    theCtx->core20fwd->glDeleteProgram (myProgramID);
   }
 
   myProgramID = NO_PROGRAM;
 }
+
+// =======================================================================
+// function : UpdateDebugDump
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_ShaderProgram::UpdateDebugDump (const Handle(OpenGl_Context)& theCtx,
+                                                        const TCollection_AsciiString& theFolder,
+                                                        Standard_Boolean theToBeautify,
+                                                        Standard_Boolean theToReset)
+{
+  if (myProgramID == NO_PROGRAM)
+  {
+    return Standard_False;
+  }
+
+  TCollection_AsciiString aFolder = theFolder;
+  if (aFolder.IsEmpty())
+  {
+    OSD_Environment aShaderVar ("CSF_ShadersDirectoryDump");
+    aFolder = aShaderVar.Value();
+    if (aFolder.IsEmpty())
+    {
+      aFolder = ".";
+    }
+  }
+
+  bool hasUpdates = false;
+  for (OpenGl_ShaderList::Iterator anIter (myShaderObjects); anIter.More(); anIter.Next())
+  {
+    if (!anIter.Value().IsNull())
+    {
+      // desktop OpenGL (but not OpenGL ES) allows multiple shaders of the same stage to be attached,
+      // but here we expect only single source per stage
+      hasUpdates = anIter.ChangeValue()->updateDebugDump (theCtx, myResourceId, aFolder, theToBeautify, theToReset) || hasUpdates;
+    }
+  }
+  if (hasUpdates)
+  {
+    return Link (theCtx);
+  }
+  return Standard_False;
+}