1e485c587a774f9037d70cd645f4d23d1ea49f1f
[occt.git] / src / OpenGl / OpenGl_ShaderObject.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 <Graphic3d_ShaderObject.hxx>
17 #include <OpenGl_Context.hxx>
18 #include <OpenGl_ShaderObject.hxx>
19 #include <OSD_Path.hxx>
20 #include <Standard_Assert.hxx>
21 #include <TCollection_AsciiString.hxx>
22
23 #ifdef _WIN32
24   #include <malloc.h> // for alloca()
25 #endif
26
27 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_ShaderObject,OpenGl_Resource)
28
29 // =======================================================================
30 // function : CreateFromSource
31 // purpose  :
32 // =======================================================================
33 Handle(Graphic3d_ShaderObject) OpenGl_ShaderObject::CreateFromSource (TCollection_AsciiString& theSource,
34                                                                       Graphic3d_TypeOfShaderObject theType,
35                                                                       const ShaderVariableList& theUniforms,
36                                                                       const ShaderVariableList& theStageInOuts,
37                                                                       const TCollection_AsciiString& theInName,
38                                                                       const TCollection_AsciiString& theOutName,
39                                                                       Standard_Integer theNbGeomInputVerts)
40 {
41   TCollection_AsciiString aSrcUniforms, aSrcInOuts, aSrcInStructs, aSrcOutStructs;
42   for (ShaderVariableList::Iterator anUniformIter (theUniforms); anUniformIter.More(); anUniformIter.Next())
43   {
44     const ShaderVariable& aVar = anUniformIter.Value();
45     if ((aVar.Stages & theType) != 0)
46     {
47       aSrcUniforms += TCollection_AsciiString("\nuniform ") + aVar.Name + ";";
48     }
49   }
50   for (ShaderVariableList::Iterator aVarListIter (theStageInOuts); aVarListIter.More(); aVarListIter.Next())
51   {
52     const ShaderVariable& aVar = aVarListIter.Value();
53     Standard_Integer aStageLower = IntegerLast(), aStageUpper = IntegerFirst();
54     Standard_Integer aNbStages = 0;
55     for (Standard_Integer aStageIter = Graphic3d_TOS_VERTEX; aStageIter <= (Standard_Integer )Graphic3d_TOS_COMPUTE; aStageIter = aStageIter << 1)
56     {
57       if ((aVar.Stages & aStageIter) != 0)
58       {
59         ++aNbStages;
60         aStageLower = Min (aStageLower, aStageIter);
61         aStageUpper = Max (aStageUpper, aStageIter);
62       }
63     }
64     if ((Standard_Integer )theType < aStageLower
65      || (Standard_Integer )theType > aStageUpper)
66     {
67       continue;
68     }
69
70     const Standard_Boolean hasGeomStage = theNbGeomInputVerts > 0
71                                        && aStageLower <  Graphic3d_TOS_GEOMETRY
72                                        && aStageUpper >= Graphic3d_TOS_GEOMETRY;
73     if (hasGeomStage
74     || !theInName.IsEmpty()
75     || !theOutName.IsEmpty())
76     {
77       if (aSrcInStructs.IsEmpty()
78        && aSrcOutStructs.IsEmpty())
79       {
80         if (theType == aStageLower)
81         {
82           aSrcOutStructs = "\nout VertexData\n{";
83         }
84         else if (theType == aStageUpper)
85         {
86           aSrcInStructs = "\nin VertexData\n{";
87         }
88         else // requires theInName/theOutName
89         {
90           aSrcInStructs  = "\nin  VertexData\n{";
91           aSrcOutStructs = "\nout VertexData\n{";
92         }
93       }
94     }
95
96     if (!aSrcInStructs.IsEmpty()
97      || !aSrcOutStructs.IsEmpty())
98     {
99       if (!aSrcInStructs.IsEmpty())
100       {
101         aSrcInStructs  += TCollection_AsciiString("\n  ") + aVar.Name + ";";
102       }
103       if (!aSrcOutStructs.IsEmpty())
104       {
105         aSrcOutStructs += TCollection_AsciiString("\n  ") + aVar.Name + ";";
106       }
107     }
108     else
109     {
110       if (theType == aStageLower)
111       {
112         aSrcInOuts += TCollection_AsciiString("\nTHE_SHADER_OUT ") + aVar.Name + ";";
113       }
114       else if (theType == aStageUpper)
115       {
116         aSrcInOuts += TCollection_AsciiString("\nTHE_SHADER_IN ") + aVar.Name + ";";
117       }
118     }
119   }
120
121   if (!aSrcInStructs.IsEmpty()
122    && theType == Graphic3d_TOS_GEOMETRY)
123   {
124     aSrcInStructs  += TCollection_AsciiString ("\n} ") + theInName  + "[" + theNbGeomInputVerts + "];";
125   }
126   else if (!aSrcInStructs.IsEmpty())
127   {
128     aSrcInStructs += "\n}";
129     if (!theInName.IsEmpty())
130     {
131       aSrcInStructs += " ";
132       aSrcInStructs += theInName;
133     }
134     aSrcInStructs += ";";
135   }
136   else if (!aSrcOutStructs.IsEmpty())
137   {
138     aSrcOutStructs += "\n}";
139     if (!theInName.IsEmpty())
140     {
141       aSrcOutStructs += " ";
142       aSrcOutStructs += theOutName;
143     }
144     aSrcOutStructs += ";";
145   }
146
147   theSource.Prepend (aSrcUniforms + aSrcInStructs + aSrcOutStructs + aSrcInOuts);
148   return Graphic3d_ShaderObject::CreateFromSource (theType, theSource);
149 }
150
151 // =======================================================================
152 // function : OpenGl_ShaderObject
153 // purpose  : Creates uninitialized shader object
154 // =======================================================================
155 OpenGl_ShaderObject::OpenGl_ShaderObject (GLenum theType)
156 : myType     (theType),
157   myShaderID (NO_SHADER)
158 {
159   //
160 }
161
162 // =======================================================================
163 // function : ~OpenGl_ShaderObject
164 // purpose  : Releases resources of shader object
165 // =======================================================================
166 OpenGl_ShaderObject::~OpenGl_ShaderObject()
167 {
168   Release (NULL);
169 }
170
171 // =======================================================================
172 // function : LoadSource
173 // purpose  : Loads shader source code
174 // =======================================================================
175 Standard_Boolean OpenGl_ShaderObject::LoadSource (const Handle(OpenGl_Context)&  theCtx,
176                                                   const TCollection_AsciiString& theSource)
177 {
178   if (myShaderID == NO_SHADER)
179   {
180     return Standard_False;
181   }
182
183   const GLchar* aLines = theSource.ToCString();
184   theCtx->core20fwd->glShaderSource (myShaderID, 1, &aLines, NULL);
185   return Standard_True;
186 }
187
188 // =======================================================================
189 // function : Compile
190 // purpose  : Compiles the shader object
191 // =======================================================================
192 Standard_Boolean OpenGl_ShaderObject::Compile (const Handle(OpenGl_Context)& theCtx)
193 {
194   if (myShaderID == NO_SHADER)
195   {
196     return Standard_False;
197   }
198
199   // Try to compile shader
200   theCtx->core20fwd->glCompileShader (myShaderID);
201
202   // Check compile status
203   GLint aStatus = GL_FALSE;
204   theCtx->core20fwd->glGetShaderiv (myShaderID, GL_COMPILE_STATUS, &aStatus);
205   return aStatus != GL_FALSE;
206 }
207
208 // =======================================================================
209 // function : FetchInfoLog
210 // purpose  : Fetches information log of the last compile operation
211 // =======================================================================
212 Standard_Boolean OpenGl_ShaderObject::FetchInfoLog (const Handle(OpenGl_Context)& theCtx,
213                                                     TCollection_AsciiString&      theLog)
214 {
215   if (myShaderID == NO_SHADER)
216   {
217     return Standard_False;
218   }
219
220   // Load information log of the compiler
221   GLint aLength = 0;
222   theCtx->core20fwd->glGetShaderiv (myShaderID, GL_INFO_LOG_LENGTH, &aLength);
223   if (aLength > 0)
224   {
225     GLchar* aLog = (GLchar*) alloca (aLength);
226     memset (aLog, 0, aLength);
227     theCtx->core20fwd->glGetShaderInfoLog (myShaderID, aLength, NULL, aLog);
228     theLog = aLog;
229   }
230
231   return Standard_True;
232 }
233
234 // =======================================================================
235 // function : Create
236 // purpose  : Creates new empty shader object of specified type
237 // =======================================================================
238 Standard_Boolean OpenGl_ShaderObject::Create (const Handle(OpenGl_Context)& theCtx)
239 {
240   if (myShaderID == NO_SHADER
241    && theCtx->core20fwd != NULL)
242   {
243     myShaderID = theCtx->core20fwd->glCreateShader (myType);
244   }
245
246   return myShaderID != NO_SHADER;
247 }
248
249 // =======================================================================
250 // function : Release
251 // purpose  : Destroys shader object
252 // =======================================================================
253 void OpenGl_ShaderObject::Release (OpenGl_Context* theCtx)
254 {
255   if (myShaderID == NO_SHADER)
256   {
257     return;
258   }
259
260   Standard_ASSERT_RETURN (theCtx != NULL,
261     "OpenGl_ShaderObject destroyed without GL context! Possible GPU memory leakage...",);
262
263   if (theCtx->core20fwd != NULL
264    && theCtx->IsValid())
265   {
266     theCtx->core20fwd->glDeleteShader (myShaderID);
267   }
268   myShaderID = NO_SHADER;
269 }