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