JOGL v2.6.0-rc-20250712
JOGL, High-Performance Graphics Binding for Java™ (public API).
ShaderProgram.java
Go to the documentation of this file.
1/**
2 * Copyright 2010 JogAmp Community. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of JogAmp Community.
27 */
28
29package com.jogamp.opengl.util.glsl;
30
31import com.jogamp.opengl.*;
32
33import com.jogamp.common.os.Platform;
34
35import java.util.HashSet;
36import java.util.Iterator;
37import java.io.PrintStream;
38
39public final class ShaderProgram {
40
41 public ShaderProgram() {
42 id = getNextID();
43 }
44
45 public boolean linked() {
46 return programLinked;
47 }
48
49 public boolean inUse() {
50 return programInUse;
51 }
52
53 /** Returns the shader program name, which is non zero if valid. */
54 public int program() { return shaderProgram; }
55
56 /**
57 * returns the uniq shader id as an integer
58 */
59 public int id() { return id; }
60
61 /**
62 * Detaches all shader codes and deletes the program.
63 * Destroys the shader codes as well.
64 * Calls release(gl, true)
65 *
66 * @see #release(GL2ES2, boolean)
67 */
68 public synchronized void destroy(final GL2ES2 gl) {
69 release(gl, true);
70 }
71
72 /**
73 * Detaches all shader codes and deletes the program,
74 * but leaves the shader code intact.
75 * Calls release(gl, false)
76 *
77 * @see #release(GL2ES2, boolean)
78 */
79 public synchronized void release(final GL2ES2 gl) {
80 release(gl, false);
81 }
82
83 /**
84 * Detaches all shader codes and deletes the program.
85 * If <code>destroyShaderCode</code> is true it destroys the shader codes as well.
86 */
87 public synchronized void release(final GL2ES2 gl, final boolean destroyShaderCode) {
88 if( programLinked ) {
89 useProgram(gl, false);
90 }
91 for(final Iterator<ShaderCode> iter=allShaderCode.iterator(); iter.hasNext(); ) {
92 final ShaderCode shaderCode = iter.next();
93 if(attachedShaderCode.remove(shaderCode)) {
94 ShaderUtil.detachShader(gl, shaderProgram, shaderCode.shader());
95 }
96 if(destroyShaderCode) {
97 shaderCode.destroy(gl);
98 }
99 }
100 allShaderCode.clear();
101 attachedShaderCode.clear();
102 if( 0 != shaderProgram ) {
103 gl.glDeleteProgram(shaderProgram);
104 shaderProgram=0;
105 }
106 programLinked=false;
107 }
108
109 //
110 // ShaderCode handling
111 //
112
113 /**
114 * Adds a new shader to this program.
115 *
116 * <p>This command does not compile and attach the shader,
117 * use {@link #add(GL2ES2, ShaderCode)} for this purpose.</p>
118 */
119 public synchronized void add(final ShaderCode shaderCode) throws GLException {
120 allShaderCode.add(shaderCode);
121 }
122
123 public synchronized boolean contains(final ShaderCode shaderCode) {
124 return allShaderCode.contains(shaderCode);
125 }
126
127 /**
128 * Warning slow O(n) operation ..
129 * @param id
130 * @return
131 */
132 public synchronized ShaderCode getShader(final int id) {
133 for(final Iterator<ShaderCode> iter=allShaderCode.iterator(); iter.hasNext(); ) {
134 final ShaderCode shaderCode = iter.next();
135 if(shaderCode.id() == id) {
136 return shaderCode;
137 }
138 }
139 return null;
140 }
141
142 //
143 // ShaderCode / Program handling
144 //
145
146 /**
147 * Creates the empty GL program object using {@link GL2ES2#glCreateProgram()},
148 * if not already created.
149 *
150 * @param gl
151 * @return true if shader program is valid, i.e. not zero
152 */
153 public synchronized final boolean init(final GL2ES2 gl) {
154 if( 0 == shaderProgram ) {
155 shaderProgram = gl.glCreateProgram();
156 }
157 return 0 != shaderProgram;
158 }
159
160 /**
161 * Adds a new shader to a this non running program.
162 *
163 * <p>Compiles and attaches the shader, if not done yet.</p>
164 *
165 * @return true if the shader was successfully added, false if compilation failed.
166 */
167 public synchronized boolean add(final GL2ES2 gl, final ShaderCode shaderCode, final PrintStream verboseOut) {
168 if( !init(gl) ) { return false; }
169 if( allShaderCode.add(shaderCode) ) {
170 if( !shaderCode.compile(gl, verboseOut) ) {
171 return false;
172 }
173 if( attachedShaderCode.add(shaderCode) ) {
174 ShaderUtil.attachShader(gl, shaderProgram, shaderCode.shader());
175 }
176 }
177 return true;
178 }
179
180 /**
181 * Replace a shader in a program and re-links the program.
182 *
183 * @param gl
184 * @param oldShader the to be replace Shader
185 * @param newShader the new ShaderCode
186 * @param verboseOut the optional verbose output stream
187 *
188 * @return true if all steps are valid, shader compilation, attachment and linking; otherwise false.
189 *
190 * @see ShaderState#glEnableVertexAttribArray
191 * @see ShaderState#glDisableVertexAttribArray
192 * @see ShaderState#glVertexAttribPointer
193 * @see ShaderState#getVertexAttribPointer
194 * @see ShaderState#glReleaseAllVertexAttributes
195 * @see ShaderState#glResetAllVertexAttributes
196 * @see ShaderState#glResetAllVertexAttributes
197 * @see ShaderState#glResetAllVertexAttributes
198 */
199 public synchronized boolean replaceShader(final GL2ES2 gl, final ShaderCode oldShader, final ShaderCode newShader, final PrintStream verboseOut) {
200 if(!init(gl) || !newShader.compile(gl, verboseOut)) {
201 return false;
202 }
203
204 final boolean shaderWasInUse = inUse();
205 if(shaderWasInUse) {
206 useProgram(gl, false);
207 }
208
209 if(null != oldShader && allShaderCode.remove(oldShader)) {
210 if(attachedShaderCode.remove(oldShader)) {
211 ShaderUtil.detachShader(gl, shaderProgram, oldShader.shader());
212 }
213 }
214
215 add(newShader);
216 if(attachedShaderCode.add(newShader)) {
217 ShaderUtil.attachShader(gl, shaderProgram, newShader.shader());
218 }
219
220 gl.glLinkProgram(shaderProgram);
221
222 programLinked = ShaderUtil.isProgramLinkStatusValid(gl, shaderProgram, verboseOut);
223 if ( programLinked && shaderWasInUse ) {
224 useProgram(gl, true);
225 }
226 return programLinked;
227 }
228
229 /**
230 * Links the shader code to the program.
231 *
232 * <p>Compiles and attaches the shader code to the program if not done by yet</p>
233 *
234 * <p>Within this process, all GL resources (shader and program objects) are created if necessary.</p>
235 *
236 * @param gl
237 * @param verboseOut
238 * @return true if program was successfully linked and is valid, otherwise false
239 *
240 * @see #init(GL2ES2)
241 */
242 public synchronized boolean link(final GL2ES2 gl, final PrintStream verboseOut) {
243 if( !init(gl) ) {
244 programLinked = false; // mark unlinked due to user attempt to [re]link
245 return false;
246 }
247
248 for(final Iterator<ShaderCode> iter=allShaderCode.iterator(); iter.hasNext(); ) {
249 final ShaderCode shaderCode = iter.next();
250 if(!shaderCode.compile(gl, verboseOut)) {
251 programLinked = false; // mark unlinked due to user attempt to [re]link
252 return false;
253 }
254 if(attachedShaderCode.add(shaderCode)) {
255 ShaderUtil.attachShader(gl, shaderProgram, shaderCode.shader());
256 }
257 }
258
259 // Link the program
260 gl.glLinkProgram(shaderProgram);
261
262 programLinked = ShaderUtil.isProgramLinkStatusValid(gl, shaderProgram, verboseOut);
263
264 return programLinked;
265 }
266
267 @Override
268 public boolean equals(final Object obj) {
269 if(this == obj) { return true; }
270 if(obj instanceof ShaderProgram) {
271 return id()==((ShaderProgram)obj).id();
272 }
273 return false;
274 }
275
276 @Override
277 public int hashCode() {
278 return id;
279 }
280
281 public StringBuilder toString(StringBuilder sb) {
282 if(null == sb) {
283 sb = new StringBuilder();
284 }
285 sb.append("ShaderProgram[id=").append(id);
286 sb.append(", linked="+programLinked+", inUse="+programInUse+", program: "+shaderProgram+", "+allShaderCode.size()+" code: ");
287 if( 0 < allShaderCode.size() ) {
288 for(final Iterator<ShaderCode> iter=allShaderCode.iterator(); iter.hasNext(); ) {
289 sb.append(Platform.getNewline()).append(" ").append(iter.next());
290 }
291 } else {
292 sb.append("none");
293 }
294 sb.append("]");
295 return sb;
296 }
297
298 @Override
299 public String toString() {
300 return toString(null).toString();
301 }
302
303 /**
304 * Performs {@link GL2ES2#glValidateProgram(int)} via {@link ShaderUtil#isProgramExecStatusValid(GL, int, PrintStream)}.
305 * @see ShaderUtil#isProgramExecStatusValid(GL, int, PrintStream)
306 **/
307 public synchronized boolean validateProgram(final GL2ES2 gl, final PrintStream verboseOut) {
308 return ShaderUtil.isProgramExecStatusValid(gl, shaderProgram, verboseOut);
309 }
310
311 public synchronized void useProgram(final GL2ES2 gl, boolean on) {
312 if(on && !programLinked) {
313 System.err.println("Error: ShaderProgram.useProgram(on "+on+") not linked: "+this);
314 throw new GLException("Program is not linked");
315 }
316 if(programInUse==on) { return; }
317 if( 0 == shaderProgram ) {
318 on = false;
319 }
320 gl.glUseProgram( on ? shaderProgram : 0 );
321 programInUse = on;
322 }
323 public synchronized void notifyNotInUse() {
324 programInUse = false;
325 }
326
327 public void dumpSource(final PrintStream out) {
328 out.println();
329 out.println(toString());
330 for(final Iterator<ShaderCode> iter=allShaderCode.iterator(); iter.hasNext(); ) {
331 iter.next().dumpSource(out);
332 }
333 out.println();
334 }
335
336 private boolean programLinked = false;
337 private boolean programInUse = false;
338 private int shaderProgram = 0; // non zero is valid!
339 private final HashSet<ShaderCode> allShaderCode = new HashSet<ShaderCode>();
340 private final HashSet<ShaderCode> attachedShaderCode = new HashSet<ShaderCode>();
341 private final int id;
342
343 private static synchronized int getNextID() {
344 return nextID++;
345 }
346 private static int nextID = 1;
347}
348
A generic exception for OpenGL errors used throughout the binding as a substitute for RuntimeExceptio...
Convenient shader code class to use and instantiate vertex or fragment programs.
Definition: ShaderCode.java:75
boolean compile(final GL2ES2 gl)
StringBuilder toString(StringBuilder sb)
int program()
Returns the shader program name, which is non zero if valid.
synchronized boolean contains(final ShaderCode shaderCode)
synchronized final boolean init(final GL2ES2 gl)
Creates the empty GL program object using GL2ES2#glCreateProgram(), if not already created.
synchronized void destroy(final GL2ES2 gl)
Detaches all shader codes and deletes the program.
synchronized void useProgram(final GL2ES2 gl, boolean on)
void dumpSource(final PrintStream out)
synchronized void release(final GL2ES2 gl)
Detaches all shader codes and deletes the program, but leaves the shader code intact.
synchronized void release(final GL2ES2 gl, final boolean destroyShaderCode)
Detaches all shader codes and deletes the program.
synchronized boolean add(final GL2ES2 gl, final ShaderCode shaderCode, final PrintStream verboseOut)
Adds a new shader to a this non running program.
synchronized boolean link(final GL2ES2 gl, final PrintStream verboseOut)
Links the shader code to the program.
synchronized ShaderCode getShader(final int id)
Warning slow O(n) operation .
synchronized boolean validateProgram(final GL2ES2 gl, final PrintStream verboseOut)
Performs GL2ES2#glValidateProgram(int) via ShaderUtil#isProgramExecStatusValid(GL,...
synchronized void add(final ShaderCode shaderCode)
Adds a new shader to this program.
synchronized boolean replaceShader(final GL2ES2 gl, final ShaderCode oldShader, final ShaderCode newShader, final PrintStream verboseOut)
Replace a shader in a program and re-links the program.
int id()
returns the uniq shader id as an integer
static boolean isProgramExecStatusValid(final GL _gl, final int programObj, final PrintStream verboseOut)
Performs GL2ES2#glValidateProgram(int).
static boolean isProgramLinkStatusValid(final GL _gl, final int programObj, final PrintStream verboseOut)
static void attachShader(final GL _gl, final int program, final IntBuffer shaders)
static void detachShader(final GL _gl, final int program, final IntBuffer shaders)
int glCreateProgram()
Entry point to C language function: GLuint {@native glCreateProgram}() Part of GL_ES_VERSION_2_0,...
void glUseProgram(int program)
Entry point to C language function: void {@native glUseProgram}(GLuint program) Part of GL_ES_VERS...
void glDeleteProgram(int program)
Entry point to C language function: void {@native glDeleteProgram}(GLuint program) Part of GL_ES_V...
void glLinkProgram(int program)
Entry point to C language function: void {@native glLinkProgram}(GLuint program) Part of GL_ES_VER...