1 // Created on: 2013-09-19
2 // Created by: Denis BOGOLEPOV
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <Graphic3d_ShaderObject.hxx>
18 #include <OpenGl_Context.hxx>
19 #include <OpenGl_ShaderObject.hxx>
20 #include <OSD_Path.hxx>
21 #include <Standard_Assert.hxx>
22 #include <TCollection_AsciiString.hxx>
23 #include <TCollection_ExtendedString.hxx>
26 #include <malloc.h> // for alloca()
29 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_ShaderObject,OpenGl_Resource)
31 //! Puts line numbers to the output of GLSL program source code.
32 static TCollection_AsciiString putLineNumbers (const TCollection_AsciiString& theSource)
34 std::stringstream aStream;
35 theSource.Print (aStream);
37 Standard_Integer aLineNumber = 1;
38 TCollection_AsciiString aResultSource;
39 while (std::getline (aStream, aLine))
41 TCollection_AsciiString anAsciiString = TCollection_AsciiString (aLine.c_str());
42 anAsciiString.Prepend (TCollection_AsciiString ("\n") + TCollection_AsciiString (aLineNumber) + ": ");
43 aResultSource += anAsciiString;
49 // =======================================================================
50 // function : CreateFromSource
52 // =======================================================================
53 Handle(Graphic3d_ShaderObject) OpenGl_ShaderObject::CreateFromSource (TCollection_AsciiString& theSource,
54 Graphic3d_TypeOfShaderObject theType,
55 const ShaderVariableList& theUniforms,
56 const ShaderVariableList& theStageInOuts,
57 const TCollection_AsciiString& theInName,
58 const TCollection_AsciiString& theOutName,
59 Standard_Integer theNbGeomInputVerts)
61 if (theSource.IsEmpty())
63 return Handle(Graphic3d_ShaderObject)();
66 TCollection_AsciiString aSrcUniforms, aSrcInOuts, aSrcInStructs, aSrcOutStructs;
67 for (ShaderVariableList::Iterator anUniformIter (theUniforms); anUniformIter.More(); anUniformIter.Next())
69 const ShaderVariable& aVar = anUniformIter.Value();
70 if ((aVar.Stages & theType) != 0)
72 aSrcUniforms += TCollection_AsciiString("\nuniform ") + aVar.Name + ";";
75 for (ShaderVariableList::Iterator aVarListIter (theStageInOuts); aVarListIter.More(); aVarListIter.Next())
77 const ShaderVariable& aVar = aVarListIter.Value();
78 Standard_Integer aStageLower = IntegerLast(), aStageUpper = IntegerFirst();
79 Standard_Integer aNbStages = 0;
80 for (Standard_Integer aStageIter = Graphic3d_TOS_VERTEX; aStageIter <= (Standard_Integer )Graphic3d_TOS_COMPUTE; aStageIter = aStageIter << 1)
82 if ((aVar.Stages & aStageIter) != 0)
85 aStageLower = Min (aStageLower, aStageIter);
86 aStageUpper = Max (aStageUpper, aStageIter);
89 if ((Standard_Integer )theType < aStageLower
90 || (Standard_Integer )theType > aStageUpper)
95 const Standard_Boolean hasGeomStage = theNbGeomInputVerts > 0
96 && aStageLower < Graphic3d_TOS_GEOMETRY
97 && aStageUpper >= Graphic3d_TOS_GEOMETRY;
98 const Standard_Boolean isAllStagesVar = aStageLower == Graphic3d_TOS_VERTEX
99 && aStageUpper == Graphic3d_TOS_FRAGMENT;
101 || !theInName.IsEmpty()
102 || !theOutName.IsEmpty())
104 if (aSrcInStructs.IsEmpty()
105 && aSrcOutStructs.IsEmpty()
108 if (theType == aStageLower)
110 aSrcOutStructs = "\nout VertexData\n{";
112 else if (theType == aStageUpper)
114 aSrcInStructs = "\nin VertexData\n{";
116 else // requires theInName/theOutName
118 aSrcInStructs = "\nin VertexData\n{";
119 aSrcOutStructs = "\nout VertexData\n{";
125 && (!aSrcInStructs.IsEmpty()
126 || !aSrcOutStructs.IsEmpty()))
128 if (!aSrcInStructs.IsEmpty())
130 aSrcInStructs += TCollection_AsciiString("\n ") + aVar.Name + ";";
132 if (!aSrcOutStructs.IsEmpty())
134 aSrcOutStructs += TCollection_AsciiString("\n ") + aVar.Name + ";";
139 if (theType == aStageLower)
141 aSrcInOuts += TCollection_AsciiString("\nTHE_SHADER_OUT ") + aVar.Name + ";";
143 else if (theType == aStageUpper)
145 aSrcInOuts += TCollection_AsciiString("\nTHE_SHADER_IN ") + aVar.Name + ";";
150 if (theType == Graphic3d_TOS_GEOMETRY)
152 aSrcUniforms.Prepend (TCollection_AsciiString()
153 + "\nlayout (triangles) in;"
154 "\nlayout (triangle_strip, max_vertices = " + theNbGeomInputVerts + ") out;");
156 if (!aSrcInStructs.IsEmpty()
157 && theType == Graphic3d_TOS_GEOMETRY)
159 aSrcInStructs += TCollection_AsciiString ("\n} ") + theInName + "[" + theNbGeomInputVerts + "];";
161 else if (!aSrcInStructs.IsEmpty())
163 aSrcInStructs += "\n}";
164 if (!theInName.IsEmpty())
166 aSrcInStructs += " ";
167 aSrcInStructs += theInName;
169 aSrcInStructs += ";";
171 if (!aSrcOutStructs.IsEmpty())
173 aSrcOutStructs += "\n}";
174 if (!theOutName.IsEmpty())
176 aSrcOutStructs += " ";
177 aSrcOutStructs += theOutName;
179 aSrcOutStructs += ";";
182 theSource.Prepend (aSrcUniforms + aSrcInStructs + aSrcOutStructs + aSrcInOuts);
183 return Graphic3d_ShaderObject::CreateFromSource (theType, theSource);
186 // =======================================================================
187 // function : OpenGl_ShaderObject
188 // purpose : Creates uninitialized shader object
189 // =======================================================================
190 OpenGl_ShaderObject::OpenGl_ShaderObject (GLenum theType)
192 myShaderID (NO_SHADER)
197 // =======================================================================
198 // function : ~OpenGl_ShaderObject
199 // purpose : Releases resources of shader object
200 // =======================================================================
201 OpenGl_ShaderObject::~OpenGl_ShaderObject()
206 // =======================================================================
207 // function : LoadAndCompile
209 // =======================================================================
210 Standard_Boolean OpenGl_ShaderObject::LoadAndCompile (const Handle(OpenGl_Context)& theCtx,
211 const TCollection_AsciiString& theSource,
213 bool theToPrintSource)
217 return LoadSource (theCtx, theSource)
221 if (!LoadSource (theCtx, theSource))
223 if (theToPrintSource)
225 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, theSource);
227 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, "Error! Failed to set shader source");
228 Release (theCtx.operator->());
232 if (!Compile (theCtx))
234 if (theToPrintSource)
236 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, putLineNumbers (theSource));
238 TCollection_AsciiString aLog;
239 FetchInfoLog (theCtx, aLog);
242 aLog = "Compilation log is empty.";
244 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
245 TCollection_AsciiString ("Failed to compile shader object. Compilation log:\n") + aLog);
246 Release (theCtx.operator->());
249 else if (theCtx->caps->glslWarnings)
251 TCollection_AsciiString aLog;
252 FetchInfoLog (theCtx, aLog);
254 && !aLog.IsEqual ("No errors.\n"))
256 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_LOW,
257 TCollection_AsciiString ("Shader compilation log:\n") + aLog);
263 // =======================================================================
264 // function : LoadSource
265 // purpose : Loads shader source code
266 // =======================================================================
267 Standard_Boolean OpenGl_ShaderObject::LoadSource (const Handle(OpenGl_Context)& theCtx,
268 const TCollection_AsciiString& theSource)
270 if (myShaderID == NO_SHADER)
272 return Standard_False;
275 const GLchar* aLines = theSource.ToCString();
276 theCtx->core20fwd->glShaderSource (myShaderID, 1, &aLines, NULL);
277 return Standard_True;
280 // =======================================================================
281 // function : Compile
282 // purpose : Compiles the shader object
283 // =======================================================================
284 Standard_Boolean OpenGl_ShaderObject::Compile (const Handle(OpenGl_Context)& theCtx)
286 if (myShaderID == NO_SHADER)
288 return Standard_False;
291 // Try to compile shader
292 theCtx->core20fwd->glCompileShader (myShaderID);
294 // Check compile status
295 GLint aStatus = GL_FALSE;
296 theCtx->core20fwd->glGetShaderiv (myShaderID, GL_COMPILE_STATUS, &aStatus);
297 return aStatus != GL_FALSE;
300 // =======================================================================
301 // function : FetchInfoLog
302 // purpose : Fetches information log of the last compile operation
303 // =======================================================================
304 Standard_Boolean OpenGl_ShaderObject::FetchInfoLog (const Handle(OpenGl_Context)& theCtx,
305 TCollection_AsciiString& theLog)
307 if (myShaderID == NO_SHADER)
309 return Standard_False;
312 // Load information log of the compiler
314 theCtx->core20fwd->glGetShaderiv (myShaderID, GL_INFO_LOG_LENGTH, &aLength);
317 GLchar* aLog = (GLchar*) alloca (aLength);
318 memset (aLog, 0, aLength);
319 theCtx->core20fwd->glGetShaderInfoLog (myShaderID, aLength, NULL, aLog);
323 return Standard_True;
326 // =======================================================================
328 // purpose : Creates new empty shader object of specified type
329 // =======================================================================
330 Standard_Boolean OpenGl_ShaderObject::Create (const Handle(OpenGl_Context)& theCtx)
332 if (myShaderID == NO_SHADER
333 && theCtx->core20fwd != NULL)
335 myShaderID = theCtx->core20fwd->glCreateShader (myType);
338 return myShaderID != NO_SHADER;
341 // =======================================================================
342 // function : Release
343 // purpose : Destroys shader object
344 // =======================================================================
345 void OpenGl_ShaderObject::Release (OpenGl_Context* theCtx)
347 if (myShaderID == NO_SHADER)
352 Standard_ASSERT_RETURN (theCtx != NULL,
353 "OpenGl_ShaderObject destroyed without GL context! Possible GPU memory leakage...",);
355 if (theCtx->core20fwd != NULL
356 && theCtx->IsValid())
358 theCtx->core20fwd->glDeleteShader (myShaderID);
360 myShaderID = NO_SHADER;