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