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