0031279: Visualization, TKOpenGl - environment background is misplaced within Ray...
[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 (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1060   {
1061     return false;
1062   }
1063
1064 #if !defined(GL_ES_VERSION_2_0)
1065   if (theCtx->core32 != NULL)
1066   {
1067     theCtx->core32->glUniform2uiv (theLocation, 1, theValue.GetData());
1068     return true;
1069   }
1070 #else
1071   if (theCtx->core30fwd != NULL)
1072   {
1073     theCtx->core30fwd->glUniform2uiv (theLocation, 1, theValue.GetData());
1074     return true;
1075   }
1076 #endif
1077   return false;
1078 }
1079
1080 // =======================================================================
1081 // function : SetUniform
1082 // purpose  :
1083 // =======================================================================
1084 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1085                                                    const GLchar*                 theName,
1086                                                    const GLsizei                 theCount,
1087                                                    const OpenGl_Vec2u*           theValue)
1088 {
1089   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theCount, theValue);
1090 }
1091
1092 // =======================================================================
1093 // function : SetUniform
1094 // purpose  :
1095 // =======================================================================
1096 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1097                                                    GLint                         theLocation,
1098                                                    const GLsizei                 theCount,
1099                                                    const OpenGl_Vec2u*           theValue)
1100 {
1101   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1102   {
1103     return false;
1104   }
1105
1106 #if !defined(GL_ES_VERSION_2_0)
1107   if (theCtx->core32 != NULL)
1108   {
1109     theCtx->core32->glUniform2uiv (theLocation, theCount, theValue->GetData());
1110     return true;
1111   }
1112 #else
1113   if (theCtx->core30fwd != NULL)
1114   {
1115     theCtx->core30fwd->glUniform2uiv (theLocation, theCount, theValue->GetData());
1116     return true;
1117   }
1118 #endif
1119   return false;
1120 }
1121
1122 // =======================================================================
1123 // function : SetUniform
1124 // purpose  : Specifies the value of the floating-point uniform variable
1125 // =======================================================================
1126 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1127                                                    const GLchar*                 theName,
1128                                                    GLfloat                       theValue)
1129 {
1130   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue);
1131 }
1132
1133 // =======================================================================
1134 // function : SetUniform
1135 // purpose  : Specifies the value of the floating-point uniform variable
1136 // =======================================================================
1137 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1138                                                    GLint                         theLocation,
1139                                                    GLfloat                       theValue)
1140 {
1141   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1142   {
1143     return Standard_False;
1144   }
1145
1146   theCtx->core20fwd->glUniform1f (theLocation, theValue);
1147   return Standard_True;
1148 }
1149
1150 // =======================================================================
1151 // function : SetUniform
1152 // purpose  : Specifies the value of the integer uniform 2D vector
1153 // =======================================================================
1154 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1155                                                    const GLchar*                 theName,
1156                                                    const OpenGl_Vec2i&           theValue)
1157 {
1158   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue);
1159 }
1160
1161 // =======================================================================
1162 // function : SetUniform
1163 // purpose  : Specifies the value of the integer uniform 2D vector
1164 // =======================================================================
1165 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1166                                                    GLint                         theLocation,
1167                                                    const OpenGl_Vec2i&           theValue)
1168 {
1169   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1170   {
1171     return Standard_False;
1172   }
1173
1174   theCtx->core20fwd->glUniform2iv (theLocation, 1, theValue);
1175   return Standard_True;
1176 }
1177
1178 // =======================================================================
1179 // function : SetUniform
1180 // purpose  : Specifies the value of the integer uniform 3D vector
1181 // =======================================================================
1182 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1183                                                    const GLchar*                 theName,
1184                                                    const OpenGl_Vec3i&           theValue)
1185 {
1186   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue);
1187 }
1188
1189 // =======================================================================
1190 // function : SetUniform
1191 // purpose  : Specifies the value of the integer uniform 3D vector
1192 // =======================================================================
1193 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1194                                                    GLint                         theLocation,
1195                                                    const OpenGl_Vec3i&           theValue)
1196 {
1197   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1198   {
1199     return Standard_False;
1200   }
1201
1202   theCtx->core20fwd->glUniform3iv (theLocation, 1, theValue);
1203   return Standard_True;
1204 }
1205
1206 // =======================================================================
1207 // function : SetUniform
1208 // purpose  : Specifies the value of the integer uniform 4D vector
1209 // =======================================================================
1210 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1211                                                    const GLchar*                 theName,
1212                                                    const OpenGl_Vec4i&           theValue)
1213 {
1214   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue);
1215 }
1216
1217 // =======================================================================
1218 // function : SetUniform
1219 // purpose  : Specifies the value of the integer uniform 4D vector
1220 // =======================================================================
1221 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1222                                                    GLint                         theLocation,
1223                                                    const OpenGl_Vec4i&           theValue)
1224 {
1225   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1226   {
1227     return Standard_False;
1228   }
1229
1230   theCtx->core20fwd->glUniform4iv (theLocation, 1, theValue);
1231   return Standard_True;
1232 }
1233
1234 // =======================================================================
1235 // function : SetUniform
1236 // purpose  : Specifies the value of the floating-point uniform 2D vector
1237 // =======================================================================
1238 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1239                                                    const GLchar*                 theName,
1240                                                    const OpenGl_Vec2&            theValue)
1241 {
1242   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue);
1243 }
1244
1245 // =======================================================================
1246 // function : SetUniform
1247 // purpose  : Specifies the value of the floating-point uniform 2D vector
1248 // =======================================================================
1249 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1250                                                    GLint                         theLocation,
1251                                                    const OpenGl_Vec2&            theValue)
1252 {
1253   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1254   {
1255     return Standard_False;
1256   }
1257
1258   theCtx->core20fwd->glUniform2fv (theLocation, 1, theValue);
1259   return Standard_True;
1260 }
1261
1262 // =======================================================================
1263 // function : SetUniform
1264 // purpose  : Specifies the value of the floating-point uniform 3D vector
1265 // =======================================================================
1266 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1267                                                    const GLchar*                 theName,
1268                                                    const OpenGl_Vec3&            theValue)
1269 {
1270   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue);
1271 }
1272
1273 // =======================================================================
1274 // function : SetUniform
1275 // purpose  : Specifies the value of the floating-point uniform 3D vector
1276 // =======================================================================
1277 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1278                                                    GLint                         theLocation,
1279                                                    const OpenGl_Vec3&            theValue)
1280 {
1281   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1282   {
1283     return Standard_False;
1284   }
1285
1286   theCtx->core20fwd->glUniform3fv (theLocation, 1, theValue);
1287   return Standard_True;
1288 }
1289
1290 // =======================================================================
1291 // function : SetUniform
1292 // purpose  : Specifies the value of the floating-point uniform 4D vector
1293 // =======================================================================
1294 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1295                                                    const GLchar*                 theName,
1296                                                    const OpenGl_Vec4&            theValue)
1297 {
1298   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue);
1299 }
1300
1301 // =======================================================================
1302 // function : SetUniform
1303 // purpose  : Specifies the value of the floating-point uniform 4D vector
1304 // =======================================================================
1305 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1306                                                    GLint                         theLocation,
1307                                                    const OpenGl_Vec4&            theValue)
1308 {
1309   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1310   {
1311     return Standard_False;
1312   }
1313
1314   theCtx->core20fwd->glUniform4fv (theLocation, 1, theValue);
1315   return Standard_True;
1316 }
1317
1318 // =======================================================================
1319 // function : SetUniform
1320 // purpose  : Specifies the value of the floating-point uniform 4x4 matrix
1321 // =======================================================================
1322 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1323                                                    const GLchar*                 theName,
1324                                                    const OpenGl_Mat4&            theValue,
1325                                                    GLboolean                     theTranspose)
1326 {
1327   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue, theTranspose);
1328 }
1329
1330 // =======================================================================
1331 // function : SetUniform
1332 // purpose  : Specifies the value of the floating-point uniform 4x4 matrix
1333 // =======================================================================
1334 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1335                                                    GLint                         theLocation,
1336                                                    const OpenGl_Mat4&            theValue,
1337                                                    GLboolean                     theTranspose)
1338 {
1339   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1340   {
1341     return Standard_False;
1342   }
1343
1344   theCtx->core20fwd->glUniformMatrix4fv (theLocation, 1, GL_FALSE, theTranspose ? theValue.Transposed() : theValue);
1345   return Standard_True;
1346 }
1347
1348 // =======================================================================
1349 // function : SetUniform
1350 // purpose  : Specifies the value of the floating-point uniform 4x4 matrix
1351 // =======================================================================
1352 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1353                                                    const GLchar*                 theName,
1354                                                    const OpenGl_Matrix&          theValue,
1355                                                    GLboolean                     theTranspose)
1356 {
1357   return SetUniform (theCtx, GetUniformLocation (theCtx, theName), theValue, theTranspose);
1358 }
1359
1360 // =======================================================================
1361 // function : SetUniform
1362 // purpose  : Specifies the value of the floating-point uniform 4x4 matrix
1363 // =======================================================================
1364 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1365                                                    GLint                         theLocation,
1366                                                    const OpenGl_Matrix&          theValue,
1367                                                    GLboolean                     theTranspose)
1368 {
1369   return SetUniform (theCtx, theLocation, OpenGl_Mat4::Map (*theValue.mat), theTranspose);
1370 }
1371
1372 // =======================================================================
1373 // function : SetUniform
1374 // purpose  : Specifies the value of the float uniform array
1375 // =======================================================================
1376 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1377                                                    GLint                         theLocation,
1378                                                    GLuint                        theCount,
1379                                                    const Standard_ShortReal*     theData)
1380 {
1381   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1382   {
1383     return Standard_False;
1384   }
1385
1386   theCtx->core20fwd->glUniform1fv (theLocation, theCount, theData);
1387   return Standard_True;
1388 }
1389
1390 // =======================================================================
1391 // function : SetUniform
1392 // purpose  : Specifies the value of the float2 uniform array
1393 // =======================================================================
1394 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1395                                                    GLint                         theLocation,
1396                                                    GLuint                        theCount,
1397                                                    const OpenGl_Vec2*            theData)
1398 {
1399   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1400   {
1401     return Standard_False;
1402   }
1403
1404   theCtx->core20fwd->glUniform2fv (theLocation, theCount, theData[0].GetData());
1405   return Standard_True;
1406 }
1407
1408 // =======================================================================
1409 // function : SetUniform
1410 // purpose  : Specifies the value of the float3 uniform array
1411 // =======================================================================
1412 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1413                                                    GLint                         theLocation,
1414                                                    GLuint                        theCount,
1415                                                    const OpenGl_Vec3*            theData)
1416 {
1417   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1418   {
1419     return Standard_False;
1420   }
1421
1422   theCtx->core20fwd->glUniform3fv (theLocation, theCount, theData[0].GetData());
1423   return Standard_True;
1424 }
1425
1426 // =======================================================================
1427 // function : SetUniform
1428 // purpose  : Specifies the value of the float4 uniform array
1429 // =======================================================================
1430 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1431                                                    GLint                         theLocation,
1432                                                    GLuint                        theCount,
1433                                                    const OpenGl_Vec4*            theData)
1434 {
1435   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1436   {
1437     return Standard_False;
1438   }
1439
1440   theCtx->core20fwd->glUniform4fv (theLocation, theCount, theData[0].GetData());
1441   return Standard_True;
1442 }
1443
1444 // =======================================================================
1445 // function : SetUniform
1446 // purpose  : Specifies the value of the integer uniform array
1447 // =======================================================================
1448 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1449                                                    GLint                         theLocation,
1450                                                    GLuint                        theCount,
1451                                                    const Standard_Integer*       theData)
1452 {
1453   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1454   {
1455     return Standard_False;
1456   }
1457
1458   theCtx->core20fwd->glUniform1iv (theLocation, theCount, theData);
1459   return Standard_True;
1460 }
1461
1462 // =======================================================================
1463 // function : SetUniform
1464 // purpose  : Specifies the value of the int2 uniform array
1465 // =======================================================================
1466 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1467                                                    GLint                         theLocation,
1468                                                    GLuint                        theCount,
1469                                                    const OpenGl_Vec2i*           theData)
1470 {
1471   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1472   {
1473     return Standard_False;
1474   }
1475
1476   theCtx->core20fwd->glUniform2iv (theLocation, theCount, theData[0].GetData());
1477   return Standard_True;
1478 }
1479
1480 // =======================================================================
1481 // function : SetUniform
1482 // purpose  : Specifies the value of the int3 uniform array
1483 // =======================================================================
1484 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1485                                                    GLint                         theLocation,
1486                                                    GLuint                        theCount,
1487                                                    const OpenGl_Vec3i*           theData)
1488 {
1489   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1490   {
1491     return Standard_False;
1492   }
1493
1494   theCtx->core20fwd->glUniform3iv (theLocation, theCount, theData[0].GetData());
1495   return Standard_True;
1496 }
1497
1498 // =======================================================================
1499 // function : SetUniform
1500 // purpose  : Specifies the value of the int4 uniform array
1501 // =======================================================================
1502 Standard_Boolean OpenGl_ShaderProgram::SetUniform (const Handle(OpenGl_Context)& theCtx,
1503                                                    GLint                         theLocation,
1504                                                    GLuint                        theCount,
1505                                                    const OpenGl_Vec4i*           theData)
1506 {
1507   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1508   {
1509     return Standard_False;
1510   }
1511
1512   theCtx->core20fwd->glUniform4iv (theLocation, theCount, theData[0].GetData());
1513   return Standard_True;
1514 }
1515
1516 // =======================================================================
1517 // function : SetSampler
1518 // purpose  : Specifies the value of the sampler uniform variable
1519 // =======================================================================
1520 Standard_Boolean OpenGl_ShaderProgram::SetSampler (const Handle(OpenGl_Context)& theCtx,
1521                                                    const GLchar*                 theName,
1522                                                    const Graphic3d_TextureUnit   theTextureUnit)
1523 {
1524   return SetSampler (theCtx, GetUniformLocation (theCtx, theName), theTextureUnit);
1525 }
1526
1527 // =======================================================================
1528 // function : SetSampler
1529 // purpose  : Specifies the value of the sampler uniform variable
1530 // =======================================================================
1531 Standard_Boolean OpenGl_ShaderProgram::SetSampler (const Handle(OpenGl_Context)& theCtx,
1532                                                    GLint                         theLocation,
1533                                                    const Graphic3d_TextureUnit   theTextureUnit)
1534 {
1535   if (myProgramID == NO_PROGRAM || theLocation == INVALID_LOCATION)
1536   {
1537     return Standard_False;
1538   }
1539
1540   theCtx->core20fwd->glUniform1i (theLocation, theTextureUnit);
1541   return Standard_True;
1542 }
1543
1544 // =======================================================================
1545 // function : Create
1546 // purpose  : Creates new empty shader program of specified type
1547 // =======================================================================
1548 Standard_Boolean OpenGl_ShaderProgram::Create (const Handle(OpenGl_Context)& theCtx)
1549 {
1550   if (myProgramID == NO_PROGRAM
1551    && theCtx->core20fwd != NULL)
1552   {
1553     myProgramID = theCtx->core20fwd->glCreateProgram();
1554   }
1555
1556   return myProgramID != NO_PROGRAM;
1557 }
1558
1559 // =======================================================================
1560 // function : Release
1561 // purpose  : Destroys shader program
1562 // =======================================================================
1563 void OpenGl_ShaderProgram::Release (OpenGl_Context* theCtx)
1564 {
1565   if (myProgramID == NO_PROGRAM)
1566   {
1567     return;
1568   }
1569
1570   Standard_ASSERT_RETURN (theCtx != NULL,
1571     "OpenGl_ShaderProgram destroyed without GL context! Possible GPU memory leakage...",);
1572
1573   for (OpenGl_ShaderList::Iterator anIter (myShaderObjects); anIter.More(); anIter.Next())
1574   {
1575     if (!anIter.Value().IsNull())
1576     {
1577       anIter.ChangeValue()->Release (theCtx);
1578       anIter.ChangeValue().Nullify();
1579     }
1580   }
1581
1582   if (theCtx->core20fwd != NULL
1583    && theCtx->IsValid())
1584   {
1585     theCtx->core20fwd->glDeleteProgram (myProgramID);
1586   }
1587
1588   myProgramID = NO_PROGRAM;
1589 }
1590
1591 // =======================================================================
1592 // function : UpdateDebugDump
1593 // purpose  :
1594 // =======================================================================
1595 Standard_Boolean OpenGl_ShaderProgram::UpdateDebugDump (const Handle(OpenGl_Context)& theCtx,
1596                                                         const TCollection_AsciiString& theFolder,
1597                                                         Standard_Boolean theToBeautify,
1598                                                         Standard_Boolean theToReset)
1599 {
1600   if (myProgramID == NO_PROGRAM)
1601   {
1602     return Standard_False;
1603   }
1604
1605   TCollection_AsciiString aFolder = theFolder;
1606   if (aFolder.IsEmpty())
1607   {
1608     OSD_Environment aShaderVar ("CSF_ShadersDirectoryDump");
1609     aFolder = aShaderVar.Value();
1610     if (aFolder.IsEmpty())
1611     {
1612       aFolder = ".";
1613     }
1614   }
1615
1616   bool hasUpdates = false;
1617   for (OpenGl_ShaderList::Iterator anIter (myShaderObjects); anIter.More(); anIter.Next())
1618   {
1619     if (!anIter.Value().IsNull())
1620     {
1621       // desktop OpenGL (but not OpenGL ES) allows multiple shaders of the same stage to be attached,
1622       // but here we expect only single source per stage
1623       hasUpdates = anIter.ChangeValue()->updateDebugDump (theCtx, myResourceId, aFolder, theToBeautify, theToReset) || hasUpdates;
1624     }
1625   }
1626   if (hasUpdates)
1627   {
1628     return Link (theCtx);
1629   }
1630   return Standard_False;
1631 }