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