0030700: Visualization, TKOpenGl - support PBR Metallic-Roughness shading model
[occt.git] / src / OpenGl / OpenGl_ShaderProgram.cxx
1 // Created on: 2013-09-19
2 // Created by: Denis BOGOLEPOV
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <OSD_File.hxx>
17 #include <OSD_Environment.hxx>
18 #include <OSD_Protection.hxx>
19
20 #include <Graphic3d_Buffer.hxx>
21 #include <Standard_Assert.hxx>
22 #include <Standard_Atomic.hxx>
23 #include <TCollection_ExtendedString.hxx>
24
25 #include <OpenGl_Context.hxx>
26 #include <OpenGl_ShaderProgram.hxx>
27 #include <OpenGl_ShaderManager.hxx>
28 #include <OpenGl_ArbTexBindless.hxx>
29
30 #include <OpenGl_GlCore32.hxx>
31
32 #include "../Shaders/Shaders_DeclarationsImpl_glsl.pxx"
33 #include "../Shaders/Shaders_Declarations_glsl.pxx"
34
35 #ifdef _WIN32
36   #include <malloc.h> // for alloca()
37 #endif
38
39 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_ShaderProgram, OpenGl_NamedResource)
40
41 OpenGl_VariableSetterSelector OpenGl_ShaderProgram::mySetterSelector = OpenGl_VariableSetterSelector();
42
43 // Declare OCCT-specific OpenGL/GLSL shader variables
44 Standard_CString OpenGl_ShaderProgram::PredefinedKeywords[] =
45 {
46   "occModelWorldMatrix",                 // OpenGl_OCC_MODEL_WORLD_MATRIX
47   "occWorldViewMatrix",                  // OpenGl_OCC_WORLD_VIEW_MATRIX
48   "occProjectionMatrix",                 // OpenGl_OCC_PROJECTION_MATRIX
49   "occModelWorldMatrixInverse",          // OpenGl_OCC_MODEL_WORLD_MATRIX_INVERSE
50   "occWorldViewMatrixInverse",           // OpenGl_OCC_WORLD_VIEW_MATRIX_INVERSE
51   "occProjectionMatrixInverse",          // OpenGl_OCC_PROJECTION_MATRIX_INVERSE
52   "occModelWorldMatrixTranspose",        // OpenGl_OCC_MODEL_WORLD_MATRIX_TRANSPOSE
53   "occWorldViewMatrixTranspose",         // OpenGl_OCC_WORLD_VIEW_MATRIX_TRANSPOSE
54   "occProjectionMatrixTranspose",        // OpenGl_OCC_PROJECTION_MATRIX_TRANSPOSE
55   "occModelWorldMatrixInverseTranspose", // OpenGl_OCC_MODEL_WORLD_MATRIX_INVERSE_TRANSPOSE
56   "occWorldViewMatrixInverseTranspose",  // OpenGl_OCC_WORLD_VIEW_MATRIX_INVERSE_TRANSPOSE
57   "occProjectionMatrixInverseTranspose", // OpenGl_OCC_PROJECTION_MATRIX_INVERSE_TRANSPOSE
58
59   "occClipPlaneEquations",  // OpenGl_OCC_CLIP_PLANE_EQUATIONS
60   "occClipPlaneChains",     // OpenGl_OCC_CLIP_PLANE_CHAINS
61   "occClipPlaneCount",      // OpenGl_OCC_CLIP_PLANE_COUNT
62
63   "occLightSourcesCount",   // OpenGl_OCC_LIGHT_SOURCE_COUNT
64   "occLightSourcesTypes",   // OpenGl_OCC_LIGHT_SOURCE_TYPES
65   "occLightSources",        // OpenGl_OCC_LIGHT_SOURCE_PARAMS
66   "occLightAmbient",        // OpenGl_OCC_LIGHT_AMBIENT
67
68   "occTextureEnable",       // OpenGl_OCCT_TEXTURE_ENABLE
69   "occDistinguishingMode",  // OpenGl_OCCT_DISTINGUISH_MODE
70   "occPbrFrontMaterial",    // OpenGl_OCCT_PBR_FRONT_MATERIAL
71   "occPbrBackMaterial",     // OpenGl_OCCT_PBR_BACK_MATERIAL
72   "occFrontMaterial",       // OpenGl_OCCT_COMMON_FRONT_MATERIAL
73   "occBackMaterial",        // OpenGl_OCCT_COMMON_BACK_MATERIAL
74   "occAlphaCutoff",         // OpenGl_OCCT_ALPHA_CUTOFF
75   "occColor",               // OpenGl_OCCT_COLOR
76
77   "occOitOutput",           // OpenGl_OCCT_OIT_OUTPUT
78   "occOitDepthFactor",      // OpenGl_OCCT_OIT_DEPTH_FACTOR
79
80   "occTexTrsf2d",           // OpenGl_OCCT_TEXTURE_TRSF2D
81   "occPointSize",           // OpenGl_OCCT_POINT_SIZE
82
83   "occViewport",            // OpenGl_OCCT_VIEWPORT
84   "occLineWidth",           // OpenGl_OCCT_LINE_WIDTH
85   "occLineFeather",         // OpenGl_OCCT_LINE_FEATHER
86   "occStipplePattern",      // OpenGl_OCCT_LINE_STIPPLE_PATTERN
87   "occStippleFactor",       // OpenGl_OCCT_LINE_STIPPLE_FACTOR
88   "occWireframeColor",      // OpenGl_OCCT_WIREFRAME_COLOR
89   "occIsQuadMode",          // OpenGl_OCCT_QUAD_MODE_STATE
90
91   "occOrthoScale",          // OpenGl_OCCT_ORTHO_SCALE
92   "occSilhouetteThickness", // OpenGl_OCCT_SILHOUETTE_THICKNESS
93
94   "occNbSpecIBLLevels"      // OpenGl_OCCT_NB_SPEC_IBL_LEVELS
95 };
96
97 namespace
98 {
99   //! Convert Graphic3d_TypeOfShaderObject enumeration into OpenGL enumeration.
100   static GLenum shaderTypeToGl (Graphic3d_TypeOfShaderObject theType)
101   {
102     switch (theType)
103     {
104       case Graphic3d_TOS_VERTEX:          return GL_VERTEX_SHADER;
105       case Graphic3d_TOS_FRAGMENT:        return GL_FRAGMENT_SHADER;
106       case Graphic3d_TOS_GEOMETRY:        return GL_GEOMETRY_SHADER;
107       case Graphic3d_TOS_TESS_CONTROL:    return GL_TESS_CONTROL_SHADER;
108       case Graphic3d_TOS_TESS_EVALUATION: return GL_TESS_EVALUATION_SHADER;
109       case Graphic3d_TOS_COMPUTE:         return GL_COMPUTE_SHADER;
110     }
111     return 0;
112   }
113 }
114
115 // =======================================================================
116 // function : OpenGl_VariableSetterSelector
117 // purpose  : Creates new variable setter selector
118 // =======================================================================
119 OpenGl_VariableSetterSelector::OpenGl_VariableSetterSelector()
120 {
121   // Note: Add new variable setters here
122   mySetterList = OpenGl_HashMapInitializer::CreateListOf<size_t, OpenGl_SetterInterface*>
123     (Graphic3d_UniformValueTypeID<int>::ID,          new OpenGl_VariableSetter<int>())
124     (Graphic3d_UniformValueTypeID<float>::ID,        new OpenGl_VariableSetter<float>())
125     (Graphic3d_UniformValueTypeID<OpenGl_Vec2>::ID,  new OpenGl_VariableSetter<OpenGl_Vec2>())
126     (Graphic3d_UniformValueTypeID<OpenGl_Vec3>::ID,  new OpenGl_VariableSetter<OpenGl_Vec3>())
127     (Graphic3d_UniformValueTypeID<OpenGl_Vec4>::ID,  new OpenGl_VariableSetter<OpenGl_Vec4>())
128     (Graphic3d_UniformValueTypeID<OpenGl_Vec2i>::ID, new OpenGl_VariableSetter<OpenGl_Vec2i>())
129     (Graphic3d_UniformValueTypeID<OpenGl_Vec3i>::ID, new OpenGl_VariableSetter<OpenGl_Vec3i>())
130     (Graphic3d_UniformValueTypeID<OpenGl_Vec4i>::ID, new OpenGl_VariableSetter<OpenGl_Vec4i>());
131 }
132
133 // =======================================================================
134 // function : ~OpenGl_VariableSetterSelector
135 // purpose  : Releases memory resources of variable setter selector
136 // =======================================================================
137 OpenGl_VariableSetterSelector::~OpenGl_VariableSetterSelector()
138 {
139   for (OpenGl_SetterList::Iterator anIt (mySetterList); anIt.More(); anIt.Next())
140   {
141     delete anIt.Value();
142   }
143
144   mySetterList.Clear();
145 }
146
147 // =======================================================================
148 // function : Set
149 // purpose  : Sets generic variable to specified shader program
150 // =======================================================================
151 void OpenGl_VariableSetterSelector::Set (const Handle(OpenGl_Context)&           theCtx,
152                                          const Handle(Graphic3d_ShaderVariable)& theVariable,
153                                          OpenGl_ShaderProgram*                   theProgram) const
154 {
155   Standard_ASSERT_RETURN (mySetterList.IsBound (theVariable->Value()->TypeID()),
156     "The type of user-defined uniform variable is not supported...", );
157
158   mySetterList.Find (theVariable->Value()->TypeID())->Set (theCtx, theVariable, theProgram);
159 }
160
161 // =======================================================================
162 // function : OpenGl_ShaderProgram
163 // purpose  : Creates uninitialized shader program
164 // =======================================================================
165 OpenGl_ShaderProgram::OpenGl_ShaderProgram (const Handle(Graphic3d_ShaderProgram)& theProxy,
166                                             const TCollection_AsciiString& theId)
167 : OpenGl_NamedResource (!theProxy.IsNull() ? theProxy->GetId() : theId),
168   myProgramID (NO_PROGRAM),
169   myProxy     (theProxy),
170   myShareCount(1),
171   myNbLightsMax (0),
172   myNbClipPlanesMax (0),
173   myNbFragOutputs (1),
174   myHasAlphaTest (false),
175   myHasWeightOitOutput (false),
176   myHasTessShader (false)
177 {
178   memset (myCurrentState, 0, sizeof (myCurrentState));
179 }
180
181 // =======================================================================
182 // function : Initialize
183 // purpose  : Initializes program object with the list of shader objects
184 // =======================================================================
185 Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)&     theCtx,
186                                                    const Graphic3d_ShaderObjectList& theShaders)
187 {
188   myHasTessShader = false;
189   if (theCtx.IsNull() || !Create (theCtx))
190   {
191     return Standard_False;
192   }
193
194   TCollection_AsciiString aHeaderVer = !myProxy.IsNull() ? myProxy->Header() : TCollection_AsciiString();
195   int aShaderMask = 0;
196   for (Graphic3d_ShaderObjectList::Iterator anIter (theShaders); anIter.More(); anIter.Next())
197   {
198     aShaderMask |= anIter.Value()->Type();
199   }
200   myHasTessShader = (aShaderMask & (Graphic3d_TOS_TESS_CONTROL | Graphic3d_TOS_TESS_EVALUATION)) != 0;
201   myNbFragOutputs = !myProxy.IsNull() ? myProxy->NbFragmentOutputs() : 1;
202   myHasAlphaTest  = !myProxy.IsNull() && myProxy->HasAlphaTest();
203   myHasWeightOitOutput = !myProxy.IsNull() ? myProxy->HasWeightOitOutput() && myNbFragOutputs >= 2 : 1;
204
205   // detect the minimum GLSL version required for defined Shader Objects
206 #if defined(GL_ES_VERSION_2_0)
207   if (myHasTessShader)
208   {
209     if (!theCtx->IsGlGreaterEqual (3, 2))
210     {
211       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
212                            "Error! Tessellation shader requires OpenGL ES 3.2+");
213       return false;
214     }
215     else if (aHeaderVer.IsEmpty())
216     {
217       aHeaderVer = "#version 320 es";
218     }
219   }
220   else if ((aShaderMask & Graphic3d_TOS_GEOMETRY) != 0)
221   {
222     switch (theCtx->hasGeometryStage)
223     {
224       case OpenGl_FeatureNotAvailable:
225       {
226         theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
227                              "Error! Geometry shader requires OpenGL ES 3.2+ or GL_EXT_geometry_shader");
228         return false;
229       }
230       case OpenGl_FeatureInExtensions:
231       {
232         if (aHeaderVer.IsEmpty())
233         {
234           aHeaderVer = "#version 310 es";
235         }
236         break;
237       }
238       case OpenGl_FeatureInCore:
239       {
240         if (aHeaderVer.IsEmpty())
241         {
242           aHeaderVer = "#version 320 es";
243         }
244         break;
245       }
246     }
247   }
248   else if ((aShaderMask & Graphic3d_TOS_COMPUTE) != 0)
249   {
250     if (!theCtx->IsGlGreaterEqual (3, 1))
251     {
252       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
253                            "Error! Compute shaders require OpenGL ES 3.1+");
254       return false;
255     }
256     else if (aHeaderVer.IsEmpty())
257     {
258       aHeaderVer = "#version 310 es";
259     }
260   }
261 #else
262   if ((aShaderMask & Graphic3d_TOS_COMPUTE) != 0)
263   {
264     if (!theCtx->IsGlGreaterEqual (4, 3))
265     {
266       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
267                            "Error! Compute shaders require OpenGL 4.3+");
268       return 0;
269     }
270     else if (aHeaderVer.IsEmpty())
271     {
272       aHeaderVer = "#version 430";
273     }
274   }
275   else if (myHasTessShader)
276   {
277     if (!theCtx->IsGlGreaterEqual (4, 0))
278     {
279       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
280                            "Error! Tessellation shaders require OpenGL 4.0+");
281       return 0;
282     }
283     else if (aHeaderVer.IsEmpty())
284     {
285       aHeaderVer = "#version 400";
286     }
287   }
288   else if ((aShaderMask & Graphic3d_TOS_GEOMETRY) != 0)
289   {
290     if (!theCtx->IsGlGreaterEqual (3, 2))
291     {
292       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
293                            "Error! Geometry shaders require OpenGL 3.2+");
294       return 0;
295     }
296     else if (aHeaderVer.IsEmpty())
297     {
298       aHeaderVer = "#version 150";
299     }
300   }
301 #endif
302
303   for (Graphic3d_ShaderObjectList::Iterator anIter (theShaders); anIter.More(); anIter.Next())
304   {
305     if (!anIter.Value()->IsDone())
306     {
307       const TCollection_ExtendedString aMsg = "Error! Failed to get shader source";
308       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aMsg);
309       return Standard_False;
310     }
311
312     const GLenum aShaderType = shaderTypeToGl (anIter.Value()->Type());
313     if (aShaderType == 0)
314     {
315       return Standard_False;
316     }
317
318     Handle(OpenGl_ShaderObject) aShader = new OpenGl_ShaderObject (aShaderType);
319     if (!aShader->Create (theCtx))
320     {
321       aShader->Release (theCtx.operator->());
322       return Standard_False;
323     }
324
325     TCollection_AsciiString anExtensions = "// Enable extensions used in OCCT GLSL programs\n";
326     if (myNbFragOutputs > 1)
327     {
328       if (theCtx->hasDrawBuffers)
329       {
330         anExtensions += "#define OCC_ENABLE_draw_buffers\n";
331         if (myHasWeightOitOutput)
332         {
333           anExtensions += "#define OCC_WRITE_WEIGHT_OIT_COVERAGE\n";
334         }
335       }
336       else
337       {
338         theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
339                              "Error! Multiple draw buffers required by the program, but aren't supported by OpenGL");
340         return Standard_False;
341       }
342
343       if (theCtx->hasDrawBuffers == OpenGl_FeatureInExtensions)
344       {
345         if (theCtx->arbDrawBuffers)
346         {
347           anExtensions += "#extension GL_ARB_draw_buffers : enable\n";
348         }
349         else if (theCtx->extDrawBuffers)
350         {
351           anExtensions += "#extension GL_EXT_draw_buffers : enable\n";
352         }
353       }
354     }
355     if (myHasAlphaTest)
356     {
357       anExtensions += "#define OCC_ALPHA_TEST\n";
358     }
359
360     if (theCtx->hasSampleVariables == OpenGl_FeatureInExtensions)
361     {
362 #if defined(GL_ES_VERSION_2_0)
363       if (theCtx->oesSampleVariables)
364       {
365         anExtensions += "#extension GL_OES_sample_variables : enable\n";
366       }
367 #else
368       if (theCtx->arbSampleShading)
369       {
370         anExtensions += "#extension GL_ARB_sample_shading : enable\n";
371       }
372 #endif
373     }
374 #if defined(GL_ES_VERSION_2_0)
375     if (theCtx->hasGeometryStage == OpenGl_FeatureInExtensions)
376     {
377       anExtensions += "#extension GL_EXT_geometry_shader : enable\n"
378                       "#extension GL_EXT_shader_io_blocks : enable\n";
379     }
380 #endif
381
382     TCollection_AsciiString aPrecisionHeader;
383     if (anIter.Value()->Type() == Graphic3d_TOS_FRAGMENT)
384     {
385     #if defined(GL_ES_VERSION_2_0)
386       aPrecisionHeader = theCtx->hasHighp
387                        ? "precision highp float;\n"
388                          "precision highp int;\n"
389                        : "precision mediump float;\n"
390                          "precision mediump int;\n";
391     #endif
392     }
393
394     TCollection_AsciiString aHeaderType;
395     switch (anIter.Value()->Type())
396     {
397       case Graphic3d_TOS_COMPUTE:         { aHeaderType = "#define COMPUTE_SHADER\n";         break; }
398       case Graphic3d_TOS_VERTEX:          { aHeaderType = "#define VERTEX_SHADER\n";          break; }
399       case Graphic3d_TOS_TESS_CONTROL:    { aHeaderType = "#define TESS_CONTROL_SHADER\n";    break; }
400       case Graphic3d_TOS_TESS_EVALUATION: { aHeaderType = "#define TESS_EVALUATION_SHADER\n"; break; }
401       case Graphic3d_TOS_GEOMETRY:        { aHeaderType = "#define GEOMETRY_SHADER\n";        break; }
402       case Graphic3d_TOS_FRAGMENT:        { aHeaderType = "#define FRAGMENT_SHADER\n";        break; }
403     }
404
405     TCollection_AsciiString aHeaderConstants;
406     myNbLightsMax     = !myProxy.IsNull() ? myProxy->NbLightsMax() : 0;
407     myNbClipPlanesMax = !myProxy.IsNull() ? myProxy->NbClipPlanesMax() : 0;
408     aHeaderConstants += TCollection_AsciiString("#define THE_MAX_LIGHTS ") + myNbLightsMax + "\n";
409     aHeaderConstants += TCollection_AsciiString("#define THE_MAX_CLIP_PLANES ") + myNbClipPlanesMax + "\n";
410     aHeaderConstants += TCollection_AsciiString("#define THE_NB_FRAG_OUTPUTS ") + myNbFragOutputs + "\n";
411     if (!myProxy.IsNull()
412       && myProxy->HasDefaultSampler())
413     {
414       aHeaderConstants += "#define THE_HAS_DEFAULT_SAMPLER\n";
415     }
416     if (!myProxy.IsNull()
417       && myProxy->IsPBR())
418     {
419       aHeaderConstants += "#define THE_IS_PBR\n";
420     }
421
422     const TCollection_AsciiString aSource = aHeaderVer                     // #version   - header defining GLSL version, should be first
423                                           + (!aHeaderVer.IsEmpty() ? "\n" : "")
424                                           + anExtensions                   // #extension - list of enabled extensions,   should be second
425                                           + aPrecisionHeader               // precision  - default precision qualifiers, should be before any code
426                                           + aHeaderType                    // auxiliary macros defining a shader stage (type)
427                                           + aHeaderConstants
428                                           + Shaders_Declarations_glsl      // common declarations (global constants and Vertex Shader inputs)
429                                           + Shaders_DeclarationsImpl_glsl
430                                           + anIter.Value()->Source();      // the source code itself (defining main() function)
431     if (!aShader->LoadAndCompile (theCtx, myResourceId, aSource))
432     {
433       aShader->Release (theCtx.operator->());
434       return Standard_False;
435     }
436
437     if (theCtx->caps->glslDumpLevel)
438     {
439       TCollection_AsciiString anOutputSource = aSource;
440       if (theCtx->caps->glslDumpLevel == OpenGl_ShaderProgramDumpLevel_Short)
441       {
442         anOutputSource = aHeaderVer
443                        + (!aHeaderVer.IsEmpty() ? "\n" : "")
444                        + anExtensions
445                        + aPrecisionHeader
446                        + aHeaderType
447                        + aHeaderConstants
448                        + anIter.Value()->Source();
449       }
450       aShader->DumpSourceCode (theCtx, myResourceId, anOutputSource);
451     }
452
453     if (!AttachShader (theCtx, aShader))
454     {
455       aShader->Release (theCtx.operator->());
456       return Standard_False;
457     }
458   }
459
460   // bind locations for pre-defined Vertex Attributes
461   SetAttributeName (theCtx, Graphic3d_TOA_POS,   "occVertex");
462   SetAttributeName (theCtx, Graphic3d_TOA_NORM,  "occNormal");
463   SetAttributeName (theCtx, Graphic3d_TOA_UV,    "occTexCoord");
464   SetAttributeName (theCtx, Graphic3d_TOA_COLOR, "occVertColor");
465
466   // bind custom Vertex Attributes
467   if (!myProxy.IsNull())
468   {
469     for (Graphic3d_ShaderAttributeList::Iterator anAttribIter (myProxy->VertexAttributes());
470          anAttribIter.More(); anAttribIter.Next())
471     {
472       SetAttributeName (theCtx, anAttribIter.Value()->Location(), anAttribIter.Value()->Name().ToCString());
473     }
474   }
475
476   if (!Link (theCtx))
477   {
478     return Standard_False;
479   }
480
481   // set uniform defaults
482   const Handle(OpenGl_ShaderProgram)& anOldProgram = theCtx->ActiveProgram();
483   theCtx->core20fwd->glUseProgram (myProgramID);
484   if (const OpenGl_ShaderUniformLocation aLocTexEnable = GetStateLocation (OpenGl_OCCT_TEXTURE_ENABLE))
485   {
486     SetUniform (theCtx, aLocTexEnable, 0); // Off
487   }
488   if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occActiveSampler"))
489   {
490     SetUniform (theCtx, aLocSampler, GLint(Graphic3d_TextureUnit_0));
491   }
492   if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occSamplerBaseColor"))
493   {
494     SetUniform (theCtx, aLocSampler, GLint(Graphic3d_TextureUnit_BaseColor));
495   }
496   if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occSamplerPointSprite"))
497   {
498     SetUniform (theCtx, aLocSampler, GLint(theCtx->SpriteTextureUnit()));
499   }
500   if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occDiffIBLMapSHCoeffs"))
501   {
502     SetUniform (theCtx, aLocSampler, GLint(theCtx->PBRDiffIBLMapSHTexUnit()));
503   }
504   if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occSpecIBLMap"))
505   {
506     SetUniform (theCtx, aLocSampler, GLint(theCtx->PBRSpecIBLMapTexUnit()));
507   }
508   if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occEnvLUT"))
509   {
510     SetUniform (theCtx, aLocSampler, GLint(theCtx->PBREnvLUTTexUnit()));
511   }
512
513   const TCollection_AsciiString aSamplerNamePrefix ("occSampler");
514   const Standard_Integer aNbUnitsMax = Max (theCtx->MaxCombinedTextureUnits(), Graphic3d_TextureUnit_NB);
515   for (GLint aUnitIter = 0; aUnitIter < aNbUnitsMax; ++aUnitIter)
516   {
517     const TCollection_AsciiString aName = aSamplerNamePrefix + aUnitIter;
518     if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, aName.ToCString()))
519     {
520       SetUniform (theCtx, aLocSampler, aUnitIter);
521     }
522   }
523
524   theCtx->core20fwd->glUseProgram (!anOldProgram.IsNull() ? anOldProgram->ProgramId() : OpenGl_ShaderProgram::NO_PROGRAM);
525   return Standard_True;
526 }
527
528 // =======================================================================
529 // function : ~OpenGl_ShaderProgram
530 // purpose  : Releases resources of shader program
531 // =======================================================================
532 OpenGl_ShaderProgram::~OpenGl_ShaderProgram()
533 {
534   Release (NULL);
535 }
536
537 // =======================================================================
538 // function : AttachShader
539 // purpose  : Attaches shader object to the program object
540 // =======================================================================
541 Standard_Boolean OpenGl_ShaderProgram::AttachShader (const Handle(OpenGl_Context)&      theCtx,
542                                                      const Handle(OpenGl_ShaderObject)& theShader)
543 {
544   if (myProgramID == NO_PROGRAM || theShader.IsNull())
545   {
546     return Standard_False;
547   }
548
549   for (OpenGl_ShaderList::Iterator anIter (myShaderObjects); anIter.More(); anIter.Next())
550   {
551     if (theShader == anIter.Value())
552     {
553       return Standard_False;
554     }
555   }
556
557   myShaderObjects.Append (theShader);
558   theCtx->core20fwd->glAttachShader (myProgramID, theShader->myShaderID);
559   return Standard_True;
560 }
561
562 // =======================================================================
563 // function : DetachShader
564 // purpose  : Detaches shader object to the program object
565 // =======================================================================
566 Standard_Boolean OpenGl_ShaderProgram::DetachShader (const Handle(OpenGl_Context)&      theCtx,
567                                                      const Handle(OpenGl_ShaderObject)& theShader)
568 {
569   if (myProgramID == NO_PROGRAM
570    || theShader.IsNull())
571   {
572     return Standard_False;
573   }
574
575   OpenGl_ShaderList::Iterator anIter (myShaderObjects);
576   while (anIter.More())
577   {
578     if (theShader == anIter.Value())
579     {
580       myShaderObjects.Remove (anIter);
581       break;
582     }
583
584     anIter.Next();
585   }
586
587   if (!anIter.More())
588   {
589     return Standard_False;
590   }
591
592   theCtx->core20fwd->glDetachShader (myProgramID, theShader->myShaderID);
593   return Standard_True;
594 }
595
596 // =======================================================================
597 // function : Link
598 // purpose  : Links the program object
599 // =======================================================================
600 Standard_Boolean OpenGl_ShaderProgram::link (const Handle(OpenGl_Context)& theCtx)
601 {
602   if (myProgramID == NO_PROGRAM)
603   {
604     return Standard_False;
605   }
606
607   GLint aStatus = GL_FALSE;
608   theCtx->core20fwd->glLinkProgram (myProgramID);
609   theCtx->core20fwd->glGetProgramiv (myProgramID, GL_LINK_STATUS, &aStatus);
610   if (aStatus == GL_FALSE)
611   {
612     return Standard_False;
613   }
614
615   memset (myCurrentState, 0, sizeof (myCurrentState));
616   for (GLint aVar = 0; aVar < OpenGl_OCCT_NUMBER_OF_STATE_VARIABLES; ++aVar)
617   {
618     myStateLocations[aVar] = GetUniformLocation (theCtx, PredefinedKeywords[aVar]);
619   }
620   return Standard_True;
621 }
622
623 // =======================================================================
624 // function : Link
625 // purpose  :
626 // =======================================================================
627 Standard_Boolean OpenGl_ShaderProgram::Link (const Handle(OpenGl_Context)& theCtx,
628                                              bool theIsVerbose)
629 {
630   if (!theIsVerbose)
631   {
632     return link (theCtx);
633   }
634
635   if (!link (theCtx))
636   {
637     TCollection_AsciiString aLog;
638     FetchInfoLog (theCtx, aLog);
639     if (aLog.IsEmpty())
640     {
641       aLog = "Linker log is empty.";
642     }
643     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
644                          TCollection_AsciiString ("Failed to link program object [") + myResourceId + "]! Linker log:\n" + aLog);
645     return false;
646   }
647   else if (theCtx->caps->glslWarnings)
648   {
649     TCollection_AsciiString aLog;
650     FetchInfoLog (theCtx, aLog);
651     if (!aLog.IsEmpty()
652      && !aLog.IsEqual ("No errors.\n"))
653     {
654       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_LOW,
655                            TCollection_AsciiString ("GLSL linker log [") + myResourceId +"]:\n" + aLog);
656     }
657   }
658   return true;
659 }
660
661 // =======================================================================
662 // function : FetchInfoLog
663 // purpose  : Fetches information log of the last link operation
664 // =======================================================================
665 Standard_Boolean OpenGl_ShaderProgram::FetchInfoLog (const Handle(OpenGl_Context)& theCtx,
666                                                      TCollection_AsciiString&      theOutput)
667 {
668   if (myProgramID == NO_PROGRAM)
669   {
670     return Standard_False;
671   }
672
673   GLint aLength = 0;
674   theCtx->core20fwd->glGetProgramiv (myProgramID, GL_INFO_LOG_LENGTH, &aLength);
675   if (aLength > 0)
676   {
677     GLchar* aLog = (GLchar*) alloca (aLength);
678     memset (aLog, 0, aLength);
679     theCtx->core20fwd->glGetProgramInfoLog (myProgramID, aLength, NULL, aLog);
680     theOutput = aLog;
681   }
682   return Standard_True;
683 }
684
685 // =======================================================================
686 // function : ApplyVariables
687 // purpose  : Fetches uniform variables from proxy shader program
688 // =======================================================================
689 Standard_Boolean OpenGl_ShaderProgram::ApplyVariables(const Handle(OpenGl_Context)& theCtx)
690 {
691   if (myProxy.IsNull() || myProxy->Variables().IsEmpty())
692   {
693     return Standard_False;
694   }
695
696   for (Graphic3d_ShaderVariableList::Iterator anIter (myProxy->Variables()); anIter.More(); anIter.Next())
697   {
698     mySetterSelector.Set (theCtx, anIter.Value(), this);
699   }
700
701   myProxy->ClearVariables();
702   return Standard_True;
703 }
704
705 // =======================================================================
706 // function : GetUniformLocation
707 // purpose  : Returns location (index) of the specific uniform variable
708 // =======================================================================
709 OpenGl_ShaderUniformLocation OpenGl_ShaderProgram::GetUniformLocation (const Handle(OpenGl_Context)& theCtx,
710                                                                        const GLchar*                 theName) const
711 {
712   return OpenGl_ShaderUniformLocation (myProgramID != NO_PROGRAM
713                                      ? theCtx->core20fwd->glGetUniformLocation (myProgramID, theName)
714                                      : INVALID_LOCATION);
715 }
716
717 // =======================================================================
718 // function : GetAttributeLocation
719 // purpose  : Returns location (index) of the generic vertex attribute
720 // =======================================================================
721 GLint OpenGl_ShaderProgram::GetAttributeLocation (const Handle(OpenGl_Context)& theCtx,
722                                                   const GLchar*                 theName) const
723 {
724   return myProgramID != NO_PROGRAM
725        ? theCtx->core20fwd->glGetAttribLocation (myProgramID, theName)
726        : INVALID_LOCATION;
727 }
728
729 // =======================================================================
730 // function : GetUniform
731 // purpose  : Returns the value of the integer uniform variable
732 // =======================================================================
733 Standard_Boolean OpenGl_ShaderProgram::GetUniform (const Handle(OpenGl_Context)& theCtx,
734                                                    const GLchar*                 theName,
735                                                    OpenGl_Vec4i&                 theValue) const
736 {
737   return GetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue);
738 }
739
740 // =======================================================================
741 // function : GetUniform
742 // purpose  : Returns the value of the integer uniform variable
743 // =======================================================================
744 Standard_Boolean OpenGl_ShaderProgram::GetUniform (const Handle(OpenGl_Context)& theCtx,
745                                                    GLint                         theLocation,
746                                                    OpenGl_Vec4i&                 theValue) const
747 {
748   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
749   {
750     return Standard_False;
751   }
752
753   theCtx->core20fwd->glGetUniformiv (myProgramID, theLocation, theValue);
754   return Standard_True;
755 }
756
757 // =======================================================================
758 // function : GetUniform
759 // purpose  : Returns the value of the floating-point uniform variable
760 // =======================================================================
761 Standard_Boolean OpenGl_ShaderProgram::GetUniform (const Handle(OpenGl_Context)& theCtx,
762                                                    const GLchar*                 theName,
763                                                    OpenGl_Vec4&                  theValue) const
764 {
765   return GetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue);
766 }
767
768 // =======================================================================
769 // function : GetUniform
770 // purpose  : Returns the value of the floating-point uniform variable
771 // =======================================================================
772 Standard_Boolean OpenGl_ShaderProgram::GetUniform (const Handle(OpenGl_Context)& theCtx,
773                                                    GLint                         theLocation,
774                                                    OpenGl_Vec4&                  theValue) const
775 {
776   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
777   {
778     return Standard_False;
779   }
780
781   theCtx->core20fwd->glGetUniformfv (myProgramID, theLocation, theValue);
782   return Standard_True;
783 }
784
785 // =======================================================================
786 // function : GetAttribute
787 // purpose  : Returns the integer vertex attribute
788 // =======================================================================
789 Standard_Boolean OpenGl_ShaderProgram::GetAttribute (const Handle(OpenGl_Context)& theCtx,
790                                                      const GLchar*                 theName,
791                                                      OpenGl_Vec4i&                 theValue) const
792 {
793   return GetAttribute (theCtx, GetAttributeLocation (theCtx, theName), theValue);
794 }
795
796 // =======================================================================
797 // function : GetAttribute
798 // purpose  : Returns the integer vertex attribute
799 // =======================================================================
800 Standard_Boolean OpenGl_ShaderProgram::GetAttribute (const Handle(OpenGl_Context)& theCtx,
801                                                      GLint                         theIndex,
802                                                      OpenGl_Vec4i&                 theValue) const
803 {
804   if (myProgramID == NO_PROGRAM || theIndex == INVALID_LOCATION)
805   {
806     return Standard_False;
807   }
808
809   theCtx->core20fwd->glGetVertexAttribiv (theIndex, GL_CURRENT_VERTEX_ATTRIB, theValue);
810   return Standard_True;
811 }
812
813 // =======================================================================
814 // function : GetAttribute
815 // purpose  : Returns the floating-point vertex attribute
816 // =======================================================================
817 Standard_Boolean OpenGl_ShaderProgram::GetAttribute (const Handle(OpenGl_Context)& theCtx,
818                                                      const GLchar*                 theName,
819                                                      OpenGl_Vec4&                  theValue) const
820 {
821   return GetAttribute (theCtx, GetAttributeLocation (theCtx, theName), theValue);
822 }
823
824 // =======================================================================
825 // function : GetAttribute
826 // purpose  : Returns the floating-point vertex attribute
827 // =======================================================================
828 Standard_Boolean OpenGl_ShaderProgram::GetAttribute (const Handle(OpenGl_Context)& theCtx,
829                                                      GLint                         theIndex,
830                                                      OpenGl_Vec4&                  theValue) const
831 {
832   if (myProgramID == NO_PROGRAM || theIndex == INVALID_LOCATION)
833   {
834     return Standard_False;
835   }
836
837   theCtx->core20fwd->glGetVertexAttribfv (theIndex, GL_CURRENT_VERTEX_ATTRIB, theValue);
838   return Standard_True;
839 }
840
841 // =======================================================================
842 // function : SetAttributeName
843 // purpose  :
844 // =======================================================================
845 Standard_Boolean OpenGl_ShaderProgram::SetAttributeName (const Handle(OpenGl_Context)& theCtx,
846                                                          GLint                         theIndex,
847                                                          const GLchar*                 theName)
848 {
849   theCtx->core20fwd->glBindAttribLocation (myProgramID, theIndex, theName);
850   return Standard_True;
851 }
852
853 // =======================================================================
854 // function : SetAttribute
855 // purpose  :
856 // =======================================================================
857 Standard_Boolean OpenGl_ShaderProgram::SetAttribute (const Handle(OpenGl_Context)& theCtx,
858                                                      const GLchar*                 theName,
859                                                      GLfloat                       theValue)
860 {
861   return SetAttribute (theCtx, GetAttributeLocation (theCtx, theName), theValue);
862 }
863
864 // =======================================================================
865 // function : SetAttribute
866 // purpose  :
867 // =======================================================================
868 Standard_Boolean OpenGl_ShaderProgram::SetAttribute (const Handle(OpenGl_Context)& theCtx,
869                                                      GLint                         theIndex,
870                                                      GLfloat                       theValue)
871 {
872   if (myProgramID == NO_PROGRAM || theIndex == INVALID_LOCATION)
873   {
874     return Standard_False;
875   }
876
877   theCtx->core20fwd->glVertexAttrib1f (theIndex, theValue);
878   return Standard_True;
879 }
880
881 // =======================================================================
882 // function : SetAttribute
883 // purpose  :
884 // =======================================================================
885 Standard_Boolean OpenGl_ShaderProgram::SetAttribute (const Handle(OpenGl_Context)& theCtx,
886                                                      const GLchar*                 theName,
887                                                      const OpenGl_Vec2&            theValue)
888 {
889   return SetAttribute (theCtx, GetAttributeLocation (theCtx, theName), theValue);
890 }
891
892 // =======================================================================
893 // function : SetAttribute
894 // purpose  :
895 // =======================================================================
896 Standard_Boolean OpenGl_ShaderProgram::SetAttribute (const Handle(OpenGl_Context)& theCtx,
897                                                      GLint                         theIndex,
898                                                      const OpenGl_Vec2&            theValue)
899 {
900   if (myProgramID == NO_PROGRAM || theIndex == INVALID_LOCATION)
901   {
902     return Standard_False;
903   }
904
905   theCtx->core20fwd->glVertexAttrib2fv (theIndex, theValue);
906   return Standard_True;
907 }
908
909 // =======================================================================
910 // function : SetAttribute
911 // purpose  :
912 // =======================================================================
913 Standard_Boolean OpenGl_ShaderProgram::SetAttribute (const Handle(OpenGl_Context)& theCtx,
914                                                      const GLchar*                 theName,
915                                                      const OpenGl_Vec3&            theValue)
916 {
917   return SetAttribute (theCtx, GetAttributeLocation (theCtx, theName), theValue);
918 }
919
920 // =======================================================================
921 // function : SetAttribute
922 // purpose  :
923 // =======================================================================
924 Standard_Boolean OpenGl_ShaderProgram::SetAttribute (const Handle(OpenGl_Context)& theCtx,
925                                                      GLint                         theIndex,
926                                                      const OpenGl_Vec3&            theValue)
927 {
928   if (myProgramID == NO_PROGRAM || theIndex == INVALID_LOCATION)
929   {
930     return Standard_False;
931   }
932
933   theCtx->core20fwd->glVertexAttrib3fv (theIndex, theValue);
934   return Standard_True;
935 }
936
937 // =======================================================================
938 // function : SetAttribute
939 // purpose  :
940 // =======================================================================
941 Standard_Boolean OpenGl_ShaderProgram::SetAttribute (const Handle(OpenGl_Context)& theCtx,
942                                                      const GLchar*                 theName,
943                                                      const OpenGl_Vec4&            theValue)
944 {
945   return SetAttribute (theCtx, GetAttributeLocation (theCtx, theName), theValue);
946 }
947
948 // =======================================================================
949 // function : SetAttribute
950 // purpose  :
951 // =======================================================================
952 Standard_Boolean OpenGl_ShaderProgram::SetAttribute (const Handle(OpenGl_Context)& theCtx,
953                                                      GLint                         theIndex,
954                                                      const OpenGl_Vec4&            theValue)
955 {
956   if (myProgramID == NO_PROGRAM || theIndex == INVALID_LOCATION)
957   {
958     return Standard_False;
959   }
960
961   theCtx->core20fwd->glVertexAttrib4fv (theIndex, theValue);
962   return Standard_True;
963 }
964
965 // =======================================================================
966 // function : SetUniform
967 // purpose  : Specifies the value of the integer uniform variable
968 // =======================================================================
969 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
970                                                    const GLchar*                 theName,
971                                                    GLint                         theValue)
972 {
973   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue);
974 }
975
976 // =======================================================================
977 // function : SetUniform
978 // purpose  : Specifies the value of the integer uniform variable
979 // =======================================================================
980 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
981                                                    GLint                         theLocation,
982                                                    GLint                         theValue)
983 {
984   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
985   {
986     return Standard_False;
987   }
988
989   theCtx->core20fwd->glUniform1i (theLocation, theValue);
990   return Standard_True;
991 }
992
993 // =======================================================================
994 // function : SetUniform
995 // purpose  :
996 // =======================================================================
997 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
998                                                    const GLchar*                 theName,
999                                                    const OpenGl_Vec2u&           theValue)
1000 {
1001   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue);
1002 }
1003
1004 // =======================================================================
1005 // function : SetUniform
1006 // purpose  :
1007 // =======================================================================
1008 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1009                                                    GLint                         theLocation,
1010                                                    const OpenGl_Vec2u&           theValue)
1011 {
1012   if (theCtx->core32 == NULL || myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1013   {
1014     return Standard_False;
1015   }
1016
1017 #if !defined(GL_ES_VERSION_2_0)
1018   theCtx->core32->glUniform2uiv (theLocation, 1, theValue.GetData());
1019   return Standard_True;
1020 #else
1021   (void )theValue;
1022   return Standard_False;
1023 #endif
1024 }
1025
1026 // =======================================================================
1027 // function : SetUniform
1028 // purpose  :
1029 // =======================================================================
1030 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1031                                                    const GLchar*                 theName,
1032                                                    const GLsizei                 theCount,
1033                                                    const OpenGl_Vec2u*           theValue)
1034 {
1035   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theCount, theValue);
1036 }
1037
1038 // =======================================================================
1039 // function : SetUniform
1040 // purpose  :
1041 // =======================================================================
1042 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1043                                                    GLint                         theLocation,
1044                                                    const GLsizei                 theCount,
1045                                                    const OpenGl_Vec2u*           theValue)
1046 {
1047   if (theCtx->core32 == NULL || myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1048   {
1049     return Standard_False;
1050   }
1051
1052 #if !defined(GL_ES_VERSION_2_0)
1053   theCtx->core32->glUniform2uiv (theLocation, theCount, theValue->GetData());
1054   return Standard_True;
1055 #else
1056   (void )theCount;
1057   (void )theValue;
1058   return Standard_False;
1059 #endif
1060 }
1061
1062 // =======================================================================
1063 // function : SetUniform
1064 // purpose  : Specifies the value of the floating-point uniform variable
1065 // =======================================================================
1066 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1067                                                    const GLchar*                 theName,
1068                                                    GLfloat                       theValue)
1069 {
1070   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue);
1071 }
1072
1073 // =======================================================================
1074 // function : SetUniform
1075 // purpose  : Specifies the value of the floating-point uniform variable
1076 // =======================================================================
1077 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1078                                                    GLint                         theLocation,
1079                                                    GLfloat                       theValue)
1080 {
1081   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1082   {
1083     return Standard_False;
1084   }
1085
1086   theCtx->core20fwd->glUniform1f (theLocation, theValue);
1087   return Standard_True;
1088 }
1089
1090 // =======================================================================
1091 // function : SetUniform
1092 // purpose  : Specifies the value of the integer uniform 2D vector
1093 // =======================================================================
1094 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1095                                                    const GLchar*                 theName,
1096                                                    const OpenGl_Vec2i&           theValue)
1097 {
1098   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue);
1099 }
1100
1101 // =======================================================================
1102 // function : SetUniform
1103 // purpose  : Specifies the value of the integer uniform 2D vector
1104 // =======================================================================
1105 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1106                                                    GLint                         theLocation,
1107                                                    const OpenGl_Vec2i&           theValue)
1108 {
1109   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1110   {
1111     return Standard_False;
1112   }
1113
1114   theCtx->core20fwd->glUniform2iv (theLocation, 1, theValue);
1115   return Standard_True;
1116 }
1117
1118 // =======================================================================
1119 // function : SetUniform
1120 // purpose  : Specifies the value of the integer uniform 3D vector
1121 // =======================================================================
1122 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1123                                                    const GLchar*                 theName,
1124                                                    const OpenGl_Vec3i&           theValue)
1125 {
1126   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue);
1127 }
1128
1129 // =======================================================================
1130 // function : SetUniform
1131 // purpose  : Specifies the value of the integer uniform 3D vector
1132 // =======================================================================
1133 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1134                                                    GLint                         theLocation,
1135                                                    const OpenGl_Vec3i&           theValue)
1136 {
1137   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1138   {
1139     return Standard_False;
1140   }
1141
1142   theCtx->core20fwd->glUniform3iv (theLocation, 1, theValue);
1143   return Standard_True;
1144 }
1145
1146 // =======================================================================
1147 // function : SetUniform
1148 // purpose  : Specifies the value of the integer uniform 4D vector
1149 // =======================================================================
1150 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1151                                                    const GLchar*                 theName,
1152                                                    const OpenGl_Vec4i&           theValue)
1153 {
1154   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue);
1155 }
1156
1157 // =======================================================================
1158 // function : SetUniform
1159 // purpose  : Specifies the value of the integer uniform 4D vector
1160 // =======================================================================
1161 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1162                                                    GLint                         theLocation,
1163                                                    const OpenGl_Vec4i&           theValue)
1164 {
1165   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1166   {
1167     return Standard_False;
1168   }
1169
1170   theCtx->core20fwd->glUniform4iv (theLocation, 1, theValue);
1171   return Standard_True;
1172 }
1173
1174 // =======================================================================
1175 // function : SetUniform
1176 // purpose  : Specifies the value of the floating-point uniform 2D vector
1177 // =======================================================================
1178 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1179                                                    const GLchar*                 theName,
1180                                                    const OpenGl_Vec2&            theValue)
1181 {
1182   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue);
1183 }
1184
1185 // =======================================================================
1186 // function : SetUniform
1187 // purpose  : Specifies the value of the floating-point uniform 2D vector
1188 // =======================================================================
1189 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1190                                                    GLint                         theLocation,
1191                                                    const OpenGl_Vec2&            theValue)
1192 {
1193   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1194   {
1195     return Standard_False;
1196   }
1197
1198   theCtx->core20fwd->glUniform2fv (theLocation, 1, theValue);
1199   return Standard_True;
1200 }
1201
1202 // =======================================================================
1203 // function : SetUniform
1204 // purpose  : Specifies the value of the floating-point uniform 3D vector
1205 // =======================================================================
1206 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1207                                                    const GLchar*                 theName,
1208                                                    const OpenGl_Vec3&            theValue)
1209 {
1210   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue);
1211 }
1212
1213 // =======================================================================
1214 // function : SetUniform
1215 // purpose  : Specifies the value of the floating-point uniform 3D vector
1216 // =======================================================================
1217 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1218                                                    GLint                         theLocation,
1219                                                    const OpenGl_Vec3&            theValue)
1220 {
1221   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1222   {
1223     return Standard_False;
1224   }
1225
1226   theCtx->core20fwd->glUniform3fv (theLocation, 1, theValue);
1227   return Standard_True;
1228 }
1229
1230 // =======================================================================
1231 // function : SetUniform
1232 // purpose  : Specifies the value of the floating-point uniform 4D vector
1233 // =======================================================================
1234 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1235                                                    const GLchar*                 theName,
1236                                                    const OpenGl_Vec4&            theValue)
1237 {
1238   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue);
1239 }
1240
1241 // =======================================================================
1242 // function : SetUniform
1243 // purpose  : Specifies the value of the floating-point uniform 4D vector
1244 // =======================================================================
1245 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1246                                                    GLint                         theLocation,
1247                                                    const OpenGl_Vec4&            theValue)
1248 {
1249   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1250   {
1251     return Standard_False;
1252   }
1253
1254   theCtx->core20fwd->glUniform4fv (theLocation, 1, theValue);
1255   return Standard_True;
1256 }
1257
1258 // =======================================================================
1259 // function : SetUniform
1260 // purpose  : Specifies the value of the floating-point uniform 4x4 matrix
1261 // =======================================================================
1262 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1263                                                    const GLchar*                 theName,
1264                                                    const OpenGl_Mat4&            theValue,
1265                                                    GLboolean                     theTranspose)
1266 {
1267   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue, theTranspose);
1268 }
1269
1270 // =======================================================================
1271 // function : SetUniform
1272 // purpose  : Specifies the value of the floating-point uniform 4x4 matrix
1273 // =======================================================================
1274 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1275                                                    GLint                         theLocation,
1276                                                    const OpenGl_Mat4&            theValue,
1277                                                    GLboolean                     theTranspose)
1278 {
1279   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1280   {
1281     return Standard_False;
1282   }
1283
1284   theCtx->core20fwd->glUniformMatrix4fv (theLocation, 1, GL_FALSE, theTranspose ? theValue.Transposed() : theValue);
1285   return Standard_True;
1286 }
1287
1288 // =======================================================================
1289 // function : SetUniform
1290 // purpose  : Specifies the value of the floating-point uniform 4x4 matrix
1291 // =======================================================================
1292 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1293                                                    const GLchar*                 theName,
1294                                                    const OpenGl_Matrix&          theValue,
1295                                                    GLboolean                     theTranspose)
1296 {
1297   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue, theTranspose);
1298 }
1299
1300 // =======================================================================
1301 // function : SetUniform
1302 // purpose  : Specifies the value of the floating-point uniform 4x4 matrix
1303 // =======================================================================
1304 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1305                                                    GLint                         theLocation,
1306                                                    const OpenGl_Matrix&          theValue,
1307                                                    GLboolean                     theTranspose)
1308 {
1309   return SetUniform (theCtx, theLocation, OpenGl_Mat4::Map (*theValue.mat), theTranspose);
1310 }
1311
1312 // =======================================================================
1313 // function : SetUniform
1314 // purpose  : Specifies the value of the float uniform array
1315 // =======================================================================
1316 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1317                                                    GLint                         theLocation,
1318                                                    GLuint                        theCount,
1319                                                    const Standard_ShortReal*     theData)
1320 {
1321   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1322   {
1323     return Standard_False;
1324   }
1325
1326   theCtx->core20fwd->glUniform1fv (theLocation, theCount, theData);
1327   return Standard_True;
1328 }
1329
1330 // =======================================================================
1331 // function : SetUniform
1332 // purpose  : Specifies the value of the float2 uniform array
1333 // =======================================================================
1334 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1335                                                    GLint                         theLocation,
1336                                                    GLuint                        theCount,
1337                                                    const OpenGl_Vec2*            theData)
1338 {
1339   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1340   {
1341     return Standard_False;
1342   }
1343
1344   theCtx->core20fwd->glUniform2fv (theLocation, theCount, theData[0].GetData());
1345   return Standard_True;
1346 }
1347
1348 // =======================================================================
1349 // function : SetUniform
1350 // purpose  : Specifies the value of the float3 uniform array
1351 // =======================================================================
1352 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1353                                                    GLint                         theLocation,
1354                                                    GLuint                        theCount,
1355                                                    const OpenGl_Vec3*            theData)
1356 {
1357   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1358   {
1359     return Standard_False;
1360   }
1361
1362   theCtx->core20fwd->glUniform3fv (theLocation, theCount, theData[0].GetData());
1363   return Standard_True;
1364 }
1365
1366 // =======================================================================
1367 // function : SetUniform
1368 // purpose  : Specifies the value of the float4 uniform array
1369 // =======================================================================
1370 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1371                                                    GLint                         theLocation,
1372                                                    GLuint                        theCount,
1373                                                    const OpenGl_Vec4*            theData)
1374 {
1375   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1376   {
1377     return Standard_False;
1378   }
1379
1380   theCtx->core20fwd->glUniform4fv (theLocation, theCount, theData[0].GetData());
1381   return Standard_True;
1382 }
1383
1384 // =======================================================================
1385 // function : SetUniform
1386 // purpose  : Specifies the value of the integer uniform array
1387 // =======================================================================
1388 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1389                                                    GLint                         theLocation,
1390                                                    GLuint                        theCount,
1391                                                    const Standard_Integer*       theData)
1392 {
1393   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1394   {
1395     return Standard_False;
1396   }
1397
1398   theCtx->core20fwd->glUniform1iv (theLocation, theCount, theData);
1399   return Standard_True;
1400 }
1401
1402 // =======================================================================
1403 // function : SetUniform
1404 // purpose  : Specifies the value of the int2 uniform array
1405 // =======================================================================
1406 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1407                                                    GLint                         theLocation,
1408                                                    GLuint                        theCount,
1409                                                    const OpenGl_Vec2i*           theData)
1410 {
1411   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1412   {
1413     return Standard_False;
1414   }
1415
1416   theCtx->core20fwd->glUniform2iv (theLocation, theCount, theData[0].GetData());
1417   return Standard_True;
1418 }
1419
1420 // =======================================================================
1421 // function : SetUniform
1422 // purpose  : Specifies the value of the int3 uniform array
1423 // =======================================================================
1424 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1425                                                    GLint                         theLocation,
1426                                                    GLuint                        theCount,
1427                                                    const OpenGl_Vec3i*           theData)
1428 {
1429   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1430   {
1431     return Standard_False;
1432   }
1433
1434   theCtx->core20fwd->glUniform3iv (theLocation, theCount, theData[0].GetData());
1435   return Standard_True;
1436 }
1437
1438 // =======================================================================
1439 // function : SetUniform
1440 // purpose  : Specifies the value of the int4 uniform array
1441 // =======================================================================
1442 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1443                                                    GLint                         theLocation,
1444                                                    GLuint                        theCount,
1445                                                    const OpenGl_Vec4i*           theData)
1446 {
1447   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1448   {
1449     return Standard_False;
1450   }
1451
1452   theCtx->core20fwd->glUniform4iv (theLocation, theCount, theData[0].GetData());
1453   return Standard_True;
1454 }
1455
1456 // =======================================================================
1457 // function : SetSampler
1458 // purpose  : Specifies the value of the sampler uniform variable
1459 // =======================================================================
1460 Standard_Boolean OpenGl_ShaderProgram::SetSampler (const Handle(OpenGl_Context)& theCtx,
1461                                                    const GLchar*                 theName,
1462                                                    const Graphic3d_TextureUnit   theTextureUnit)
1463 {
1464   return SetSampler (theCtx, GetUniformLocation (theCtx, theName), theTextureUnit);
1465 }
1466
1467 // =======================================================================
1468 // function : SetSampler
1469 // purpose  : Specifies the value of the sampler uniform variable
1470 // =======================================================================
1471 Standard_Boolean OpenGl_ShaderProgram::SetSampler (const Handle(OpenGl_Context)& theCtx,
1472                                                    GLint                         theLocation,
1473                                                    const Graphic3d_TextureUnit   theTextureUnit)
1474 {
1475   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1476   {
1477     return Standard_False;
1478   }
1479
1480   theCtx->core20fwd->glUniform1i (theLocation, theTextureUnit);
1481   return Standard_True;
1482 }
1483
1484 // =======================================================================
1485 // function : Create
1486 // purpose  : Creates new empty shader program of specified type
1487 // =======================================================================
1488 Standard_Boolean OpenGl_ShaderProgram::Create (const Handle(OpenGl_Context)& theCtx)
1489 {
1490   if (myProgramID == NO_PROGRAM
1491    && theCtx->core20fwd != NULL)
1492   {
1493     myProgramID = theCtx->core20fwd->glCreateProgram();
1494   }
1495
1496   return myProgramID != NO_PROGRAM;
1497 }
1498
1499 // =======================================================================
1500 // function : Release
1501 // purpose  : Destroys shader program
1502 // =======================================================================
1503 void OpenGl_ShaderProgram::Release (OpenGl_Context* theCtx)
1504 {
1505   if (myProgramID == NO_PROGRAM)
1506   {
1507     return;
1508   }
1509
1510   Standard_ASSERT_RETURN (theCtx != NULL,
1511     "OpenGl_ShaderProgram destroyed without GL context! Possible GPU memory leakage...",);
1512
1513   for (OpenGl_ShaderList::Iterator anIter (myShaderObjects); anIter.More(); anIter.Next())
1514   {
1515     if (!anIter.Value().IsNull())
1516     {
1517       anIter.ChangeValue()->Release (theCtx);
1518       anIter.ChangeValue().Nullify();
1519     }
1520   }
1521
1522   if (theCtx->core20fwd != NULL
1523    && theCtx->IsValid())
1524   {
1525     theCtx->core20fwd->glDeleteProgram (myProgramID);
1526   }
1527
1528   myProgramID = NO_PROGRAM;
1529 }
1530
1531 // =======================================================================
1532 // function : UpdateDebugDump
1533 // purpose  :
1534 // =======================================================================
1535 Standard_Boolean OpenGl_ShaderProgram::UpdateDebugDump (const Handle(OpenGl_Context)& theCtx,
1536                                                         const TCollection_AsciiString& theFolder,
1537                                                         Standard_Boolean theToBeautify,
1538                                                         Standard_Boolean theToReset)
1539 {
1540   if (myProgramID == NO_PROGRAM)
1541   {
1542     return Standard_False;
1543   }
1544
1545   TCollection_AsciiString aFolder = theFolder;
1546   if (aFolder.IsEmpty())
1547   {
1548     OSD_Environment aShaderVar ("CSF_ShadersDirectoryDump");
1549     aFolder = aShaderVar.Value();
1550     if (aFolder.IsEmpty())
1551     {
1552       aFolder = ".";
1553     }
1554   }
1555
1556   bool hasUpdates = false;
1557   for (OpenGl_ShaderList::Iterator anIter (myShaderObjects); anIter.More(); anIter.Next())
1558   {
1559     if (!anIter.Value().IsNull())
1560     {
1561       // desktop OpenGL (but not OpenGL ES) allows multiple shaders of the same stage to be attached,
1562       // but here we expect only single source per stage
1563       hasUpdates = anIter.ChangeValue()->updateDebugDump (theCtx, myResourceId, aFolder, theToBeautify, theToReset) || hasUpdates;
1564     }
1565   }
1566   if (hasUpdates)
1567   {
1568     return Link (theCtx);
1569   }
1570   return Standard_False;
1571 }