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