1 /**************************************************************************\
2  * Copyright (c) Kongsberg Oil & Gas Technologies AS
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32 
33 #include "shaders/SoGLSLShaderObject.h"
34 #include "coindefs.h"
35 
36 #include <cassert>
37 #include <cstdio>
38 #include <Inventor/errors/SoDebugError.h>
39 #include <Inventor/system/gl.h>
40 
41 #include "glue/glp.h"
42 #include "rendering/SoGL.h"
43 #include "shaders/SoGLSLShaderParameter.h"
44 
45 static int32_t soglshaderobject_idcounter = 1;
46 
47 // *************************************************************************
48 
SoGLSLShaderObject(const uint32_t cachecontext)49 SoGLSLShaderObject::SoGLSLShaderObject(const uint32_t cachecontext)
50   : SoGLShaderObject(cachecontext)
51 {
52   this->programHandle = 0;
53   this->shaderHandle = 0;
54   this->isattached = FALSE;
55   this->programid = 0;
56 }
57 
~SoGLSLShaderObject()58 SoGLSLShaderObject::~SoGLSLShaderObject()
59 {
60   // make sure we don't detach, since the program might have been
61   // destructed already. FIXME: investigate if not calling detach will
62   // lead to memory leaks. pederb, 2006-10-17
63   this->isattached = FALSE;
64   this->unload();
65 }
66 
67 // *************************************************************************
68 
69 SoShader::Type
shaderType(void) const70 SoGLSLShaderObject::shaderType(void) const
71 {
72   return SoShader::GLSL_SHADER;
73 }
74 
75 SbBool
isLoaded(void) const76 SoGLSLShaderObject::isLoaded(void) const
77 {
78   return (this->shaderHandle != 0);
79 }
80 
81 void
load(const char * srcStr)82 SoGLSLShaderObject::load(const char* srcStr)
83 {
84   this->unload();
85   this->setParametersDirty(TRUE);
86 
87   GLint flag;
88   GLenum sType;
89 
90   switch (this->getShaderType()) {
91   default:
92     assert(0 &&" unknown shader type");
93   case VERTEX:
94     sType = GL_VERTEX_SHADER_ARB;
95     break;
96   case FRAGMENT:
97     sType = GL_FRAGMENT_SHADER_ARB;
98     break;
99   case GEOMETRY:
100     sType = GL_GEOMETRY_SHADER_EXT;
101     break;
102   }
103 
104   this->shaderHandle = this->glctx->glCreateShaderObjectARB(sType);
105   this->programid = 0;
106 
107   if (this->shaderHandle == 0) return;
108   this->programid = soglshaderobject_idcounter++;
109 
110   this->glctx->glShaderSourceARB(this->shaderHandle, 1, (const COIN_GLchar **)&srcStr, NULL);
111   this->glctx->glCompileShaderARB(this->shaderHandle);
112 
113   if (SoGLSLShaderObject::didOpenGLErrorOccur("SoGLSLShaderObject::load()")) {
114     this->shaderHandle = 0;
115     return;
116   }
117 
118   this->glctx->glGetObjectParameterivARB(this->shaderHandle,
119                                          GL_OBJECT_COMPILE_STATUS_ARB,
120                                          &flag);
121   SoGLSLShaderObject::printInfoLog(this->GLContext(), this->shaderHandle,
122                                    this->getShaderType());
123 
124   if (!flag) this->shaderHandle = 0;
125 }
126 
127 void
unload(void)128 SoGLSLShaderObject::unload(void)
129 {
130   this->detach();
131   if (this->shaderHandle) { this->glctx->glDeleteObjectARB(this->shaderHandle); }
132   this->shaderHandle = 0;
133   this->programHandle = 0;
134   this->programid = 0;
135 }
136 
137 SoGLShaderParameter *
getNewParameter(void) const138 SoGLSLShaderObject::getNewParameter(void) const
139 {
140   return new SoGLSLShaderParameter();
141 }
142 
143 // *************************************************************************
144 
145 void
attach(COIN_GLhandle programHandle)146 SoGLSLShaderObject::attach(COIN_GLhandle programHandle)
147 {
148   if (programHandle <= 0 || this->programHandle == programHandle) return;
149 
150   detach();
151 
152   if (this->shaderHandle) {
153     this->programHandle = programHandle;
154     this->glctx->glAttachObjectARB(this->programHandle, this->shaderHandle);
155     this->isattached = TRUE;
156   }
157 }
158 
159 void
detach(void)160 SoGLSLShaderObject::detach(void)
161 {
162   if (this->isattached && this->programHandle && this->shaderHandle) {
163     this->glctx->glDetachObjectARB(this->programHandle, this->shaderHandle);
164     this->isattached = FALSE;
165     this->programHandle = 0;
166   }
167 }
168 
169 SbBool
isAttached(void) const170 SoGLSLShaderObject::isAttached(void) const
171 {
172   return this->isattached;
173 }
174 
175 void
printInfoLog(const cc_glglue * g,COIN_GLhandle handle,int objType)176 SoGLSLShaderObject::printInfoLog(const cc_glglue * g, COIN_GLhandle handle, int objType)
177 {
178   GLint length = 0;
179 
180   g->glGetObjectParameterivARB(handle, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
181 
182   if (length > 1) {
183     COIN_GLchar *infoLog = new COIN_GLchar[length];
184     GLsizei charsWritten = 0;
185     g->glGetInfoLogARB(handle, length, &charsWritten, infoLog);
186     SbString s("GLSL");
187     switch (objType) {
188     case 0: s += "vertexShader "; break;
189     case 1: s += "fragmentShader "; break;
190     case 2: s += "geometryShader "; break;
191     default: ;// do nothing
192     }
193     SoDebugError::postInfo("SoGLSLShaderObject::printInfoLog",
194                            "%s log: '%s'",
195                            s.getString(), infoLog);
196     delete [] infoLog;
197   }
198 }
199 
200 SbBool
didOpenGLErrorOccur(const SbString & source)201 SoGLSLShaderObject::didOpenGLErrorOccur(const SbString & source)
202 {
203   SbBool retCode = FALSE;
204   SbBool glerror_debug = sogl_glerror_debugging();
205 
206   // only do a glFlush if COIN_GLERROR_DEBUGGING is set since it can
207   // degrade performance a lot. If glFlush is not executed here, gl
208   // errors from the shaders might not get caught until after the
209   // geometry is rendered, which makes debugging really confusing.
210   if (glerror_debug) {
211     glFlush();
212   }
213 
214   GLenum glErr = glGetError();
215   while (glErr != GL_NO_ERROR) {
216     SoDebugError::post(source.getString(), "error: '%s' %s",
217                        coin_glerror_string(glErr),
218                        glerror_debug ? "":
219                        "(set envvar COIN_GLERROR_DEBUGGING=1 "
220                        "and re-run to get more information)");
221 
222     retCode = TRUE;
223     glErr = glGetError();
224   }
225   return retCode;
226 }
227 
228 #include <cstdio>
229 #include <Inventor/SbName.h>
230 #include <Inventor/nodes/SoShaderParameter.h>
231 #include <Inventor/elements/SoGLMultiTextureImageElement.h>
232 #include <Inventor/elements/SoLightModelElement.h>
233 #include <Inventor/actions/SoAction.h>
234 #include <cstdio>
235 
236 void
updateCoinParameter(SoState * COIN_UNUSED_ARG (state),const SbName & name,SoShaderParameter * param,const int value)237 SoGLSLShaderObject::updateCoinParameter(SoState * COIN_UNUSED_ARG(state), const SbName & name, SoShaderParameter * param, const int value)
238 {
239   COIN_GLhandle pHandle = this->programHandle;
240   if (pHandle) {
241     const cc_glglue * glue = this->GLContext();
242 
243     // FIXME: set up a dict for the supported Coin variables
244     SoShaderParameter1i * p = (SoShaderParameter1i*) param;
245 
246     if (p) {
247       if (p->value.getValue() != value) p->value = value;
248     }
249     else {
250       GLint location = glue->glGetUniformLocationARB(pHandle,
251                                                      (const COIN_GLchar *)name.getString());
252 
253 #if 0
254       fprintf(stderr,"action: %s, name: %s, loc: %d, handle: %p\n",
255               state->getAction()->getTypeId().getName().getString(),
256               name.getString(), location, pHandle);
257 #endif
258       if (location >= 0) {
259         glue->glUniform1iARB(location, value);
260       }
261     }
262   }
263 }
264