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