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