JOGL v2.6.0-rc-20250712
JOGL, High-Performance Graphics Binding for Java™ (public API).
ShaderState.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 java.util.ArrayList;
32import java.util.HashMap;
33import java.util.Iterator;
34
35import com.jogamp.opengl.GL;
36import com.jogamp.opengl.GL2ES2;
37import com.jogamp.opengl.GLArrayData;
38import com.jogamp.opengl.GLException;
39import com.jogamp.opengl.GLUniformData;
40
41import jogamp.opengl.Debug;
42
43import com.jogamp.common.ExceptionUtils;
44import com.jogamp.common.os.Platform;
45import com.jogamp.common.util.PropertyAccess;
46import com.jogamp.opengl.util.GLArrayDataEditable;
47
48/**
49 * ShaderState allows to sharing data between shader programs,
50 * while updating the attribute and uniform locations when switching.
51 * <p>
52 * This allows seamless switching of programs using <i>almost</i> same data
53 * but performing different artifacts.
54 * </p>
55 * <p>
56 * A {@link #useProgram(GL2ES2, boolean) used} ShaderState is attached to the current GL context
57 * and can be retrieved via {@link #getShaderState(GL)}.
58 * </p>
59 */
60public final class ShaderState {
61 public static final boolean DEBUG;
62
63 static {
64 Debug.initSingleton();
65 DEBUG = PropertyAccess.isPropertyDefined("jogl.debug.GLSLState", true);
66 }
67
68 public ShaderState() {
69 }
70
71 public boolean verbose() { return verbose; }
72
73 public void setVerbose(final boolean v) { verbose = DEBUG || v; }
74
75 /**
76 * Returns the attached user object for the given name to this ShaderState.
77 */
78 public final Object getAttachedObject(final String name) {
79 return attachedObjectsByString.get(name);
80 }
81
82 /**
83 * Attach user object for the given name to this ShaderState.
84 * Returns the previously set object or null.
85 *
86 * @return the previous mapped object or null if none
87 */
88 public final Object attachObject(final String name, final Object obj) {
89 return attachedObjectsByString.put(name, obj);
90 }
91
92 /**
93 * @param name name of the mapped object to detach
94 *
95 * @return the previous mapped object or null if none
96 */
97 public final Object detachObject(final String name) {
98 return attachedObjectsByString.remove(name);
99 }
100
101 /**
102 * Turns the shader program on or off.<br>
103 *
104 * @throws GLException if no program is attached
105 *
106 * @see com.jogamp.opengl.util.glsl.ShaderState#useProgram(GL2ES2, boolean)
107 */
108 public synchronized void useProgram(final GL2ES2 gl, final boolean on) throws GLException {
109 if(null==shaderProgram) { throw new GLException("No program is attached"); }
110 if(on) {
111 if(shaderProgram.linked()) {
112 shaderProgram.useProgram(gl, true);
113 if(resetAllShaderData) {
114 resetAllAttributes(gl);
115 resetAllUniforms(gl);
116 }
117 } else {
118 if(resetAllShaderData) {
119 setAllAttributes(gl);
120 }
121 if(!shaderProgram.link(gl, System.err)) {
122 throw new GLException("could not link program: "+shaderProgram);
123 }
124 shaderProgram.useProgram(gl, true);
125 if(resetAllShaderData) {
126 resetAllUniforms(gl);
127 }
128 }
129 resetAllShaderData = false;
130 } else {
131 shaderProgram.useProgram(gl, false);
132 }
133 }
134
135 public boolean linked() {
136 return (null!=shaderProgram)?shaderProgram.linked():false;
137 }
138
139 public boolean inUse() {
140 return (null!=shaderProgram)?shaderProgram.inUse():false;
141 }
142
143 /**
144 * Attach or switch a shader program
145 *
146 * <p>Attaching a shader program the first time,
147 * as well as switching to another program on the fly,
148 * while managing all attribute and uniform data.</p>
149 *
150 * <p>[Re]sets all data and use program in case of a program switch.</p>
151 *
152 * <p>Use program, {@link #useProgram(GL2ES2, boolean)},
153 * if <code>enable</code> is <code>true</code>.</p>
154 *
155 * @return true if shader program was attached, otherwise false (already attached)
156 *
157 * @throws GLException if program was not linked and linking fails
158 */
159 public synchronized boolean attachShaderProgram(final GL2ES2 gl, final ShaderProgram prog, final boolean enable) throws GLException {
160 if(verbose) {
161 final int curId = (null!=shaderProgram)?shaderProgram.id():-1;
162 final int newId = (null!=prog)?prog.id():-1;
163 System.err.println("ShaderState: attachShaderProgram: "+curId+" -> "+newId+" (enable: "+enable+")\n\t"+shaderProgram+"\n\t"+prog);
164 if(DEBUG) {
165 ExceptionUtils.dumpStack(System.err);
166 }
167 }
168 if(null!=shaderProgram) {
169 if(shaderProgram.equals(prog)) {
170 if(enable) {
171 useProgram(gl, true);
172 }
173 // nothing else to do ..
174 if(verbose) {
175 System.err.println("ShaderState: attachShaderProgram: No switch, equal id: "+shaderProgram.id()+", enabling "+enable);
176 }
177 return false;
178 }
179 if(shaderProgram.inUse()) {
180 if(null != prog && enable) {
181 shaderProgram.notifyNotInUse();
182 } else {
183 // no new 'enabled' program - disable
184 useProgram(gl, false);
185 }
186 }
187 resetAllShaderData = true;
188 }
189
190 // register new one
191 shaderProgram = prog;
192
193 if(null!=shaderProgram) {
194 // [re]set all data and use program if switching program,
195 // or use program if program is linked
196 if(resetAllShaderData || enable) {
197 useProgram(gl, true); // may reset all data
198 if(!enable) {
199 useProgram(gl, false);
200 }
201 }
202 }
203 if(DEBUG) {
204 System.err.println("Info: attachShaderProgram: END");
205 }
206 return true;
207 }
208
210
211 /**
212 * Calls {@link #release(GL2ES2, boolean, boolean, boolean) release(gl, true, true, true)}
213 *
214 * @see #glReleaseAllVertexAttributes
215 * @see #glReleaseAllUniforms
216 * @see #release(GL2ES2, boolean, boolean, boolean)
217 */
218 public synchronized void destroy(final GL2ES2 gl) {
219 release(gl, true, true, true);
220 attachedObjectsByString.clear();
221 }
222
223 /**
224 * Calls {@link #release(GL2ES2, boolean, boolean, boolean) release(gl, false, false, false)}
225 *
226 * @see #glReleaseAllVertexAttributes
227 * @see #glReleaseAllUniforms
228 * @see #release(GL2ES2, boolean, boolean, boolean)
229 */
230 public synchronized void releaseAllData(final GL2ES2 gl) {
231 release(gl, false, false, false);
232 }
233
234 /**
235 * @see #glReleaseAllVertexAttributes
236 * @see #glReleaseAllUniforms
237 * @see ShaderProgram#release(GL2ES2, boolean)
238 */
239 public synchronized void release(final GL2ES2 gl, final boolean destroyBoundAttributes, final boolean destroyShaderProgram, final boolean destroyShaderCode) {
240 if(null!=shaderProgram && shaderProgram.linked() ) {
241 shaderProgram.useProgram(gl, false);
242 }
243 if(destroyBoundAttributes) {
244 for(final Iterator<GLArrayData> iter = managedAttributes.iterator(); iter.hasNext(); ) {
245 iter.next().destroy(gl);
246 }
247 }
250 if(null!=shaderProgram && destroyShaderProgram) {
251 shaderProgram.release(gl, destroyShaderCode);
252 }
253 }
254
255 //
256 // Shader attribute handling
257 //
258
259 /**
260 * Gets the cached location of a shader attribute.
261 *
262 * @return -1 if there is no such attribute available,
263 * otherwise >= 0
264 *
265 * @see #bindAttribLocation(GL2ES2, int, String)
266 * @see #bindAttribLocation(GL2ES2, int, GLArrayData)
267 * @see #getAttribLocation(GL2ES2, String)
268 * @see GL2ES2#glGetAttribLocation(int, String)
269 */
270 public int getCachedAttribLocation(final String name) {
271 final Integer idx = activeAttribLocationMap.get(name);
272 return (null!=idx)?idx.intValue():-1;
273 }
274
275 /**
276 * Get the previous cached vertex attribute data.
277 *
278 * @return the GLArrayData object, null if not previously set.
279 *
280 * @see #ownAttribute(GLArrayData, boolean)
281 *
282 * @see #glEnableVertexAttribArray
283 * @see #glDisableVertexAttribArray
284 * @see #glVertexAttribPointer
285 * @see #getVertexAttribPointer
286 * @see #glReleaseAllVertexAttributes
287 * @see #glResetAllVertexAttributes
288 * @see ShaderProgram#glReplaceShader
289 */
290 public GLArrayData getAttribute(final String name) {
291 return activeAttribDataMap.get(name);
292 }
293
294 public boolean isActiveAttribute(final GLArrayData attribute) {
295 return attribute == activeAttribDataMap.get(attribute.getName());
296 }
297
298 /**
299 * Binds or unbinds the {@link GLArrayData} lifecycle to this ShaderState.
300 *
301 * <p>If an attribute location is cached (ie {@link #bindAttribLocation(GL2ES2, int, String)})
302 * it is promoted to the {@link GLArrayData} instance.</p>
303 *
304 * <p>The attribute will be destroyed with {@link #destroy(GL2ES2)}
305 * and it's location will be reset when switching shader with {@link #attachShaderProgram(GL2ES2, ShaderProgram)}.</p>
306 *
307 * <p>The data will not be transfered to the GPU, use {@link #vertexAttribPointer(GL2ES2, GLArrayData)} additionally.</p>
308 *
309 * <p>The data will also be {@link GLArrayData#associate(Object, boolean) associated} with this ShaderState.</p>
310 *
311 * @param attribute the {@link GLArrayData} which lifecycle shall be managed
312 * @param own true if <i>owning</i> shall be performs, false if <i>disowning</i>.
313 *
314 * @see #bindAttribLocation(GL2ES2, int, String)
315 * @see #getAttribute(String)
316 * @see GLArrayData#associate(Object, boolean)
317 */
318 public void ownAttribute(final GLArrayData attribute, final boolean own) {
319 if(own) {
320 final int location = getCachedAttribLocation(attribute.getName());
321 if(0<=location) {
322 attribute.setLocation(location);
323 }
324 managedAttributes.add(managedAttributes.size(), attribute);
325 } else {
326 managedAttributes.remove(attribute);
327 }
328 attribute.associate(this, own);
329 }
330
331 public boolean ownsAttribute(final GLArrayData attribute) {
332 return managedAttributes.contains(attribute);
333 }
334
335 /**
336 * Binds a shader attribute to a location.
337 * Multiple names can be bound to one location.
338 * The value will be cached and can be retrieved via {@link #getCachedAttribLocation(String)}
339 * before or after linking.
340 *
341 * @throws GLException if no program is attached
342 * @throws GLException if the program is already linked
343 *
344 * @see com.jogamp.opengl.GL2ES2#glBindAttribLocation(int, int, String)
345 * @see #getAttribLocation(GL2ES2, String)
346 * @see #getCachedAttribLocation(String)
347 */
348 public void bindAttribLocation(final GL2ES2 gl, final int location, final String name) {
349 if(null==shaderProgram) throw new GLException("No program is attached");
350 if(shaderProgram.linked()) throw new GLException("Program is already linked");
351 activeAttribLocationMap.put(name, Integer.valueOf(location));
352 gl.glBindAttribLocation(shaderProgram.program(), location, name);
353 }
354
355 /**
356 * Binds a shader {@link GLArrayData} attribute to a location.
357 * Multiple names can be bound to one location.
358 * The value will be cached and can be retrieved via {@link #getCachedAttribLocation(String)}
359 * and {@link #getAttribute(String)}before or after linking.
360 * The {@link GLArrayData}'s location will be set as well.
361 *
362 * @throws GLException if no program is attached
363 * @throws GLException if the program is already linked
364 *
365 * @see com.jogamp.opengl.GL2ES2#glBindAttribLocation(int, int, String)
366 * @see #getAttribLocation(GL2ES2, String)
367 * @see #getCachedAttribLocation(String)
368 * @see #getAttribute(String)
369 */
370 public void bindAttribLocation(final GL2ES2 gl, final int location, final GLArrayData data) {
371 if(null==shaderProgram) throw new GLException("No program is attached");
372 if(shaderProgram.linked()) throw new GLException("Program is already linked");
373 final String name = data.getName();
374 activeAttribLocationMap.put(name, Integer.valueOf(location));
375 data.setLocation(gl, shaderProgram.program(), location);
376 activeAttribDataMap.put(data.getName(), data);
377 gl.glBindAttribLocation(shaderProgram.program(), location, name);
378 }
379
380 /**
381 * Gets the location of a shader attribute with given <code>name</code>.<br>
382 * Uses either the cached value {@link #getCachedAttribLocation(String)} if valid,
383 * or the GLSL queried via {@link GL2ES2#glGetAttribLocation(int, String)}.<br>
384 * The location will be cached.
385 *
386 * @return -1 if there is no such attribute available,
387 * otherwise >= 0
388 * @throws GLException if no program is attached
389 * @throws GLException if the program is not linked and no location was cached.
390 *
391 * @see #getCachedAttribLocation(String)
392 * @see #bindAttribLocation(GL2ES2, int, GLArrayData)
393 * @see #bindAttribLocation(GL2ES2, int, String)
394 * @see GL2ES2#glGetAttribLocation(int, String)
395 */
396 public int getAttribLocation(final GL2ES2 gl, final String name) {
397 if(null==shaderProgram) throw new GLException("No program is attached");
398 int location = getCachedAttribLocation(name);
399 if(0>location) {
400 if(!shaderProgram.linked()) throw new GLException("Program is not linked");
401 location = gl.glGetAttribLocation(shaderProgram.program(), name);
402 if(0<=location) {
403 activeAttribLocationMap.put(name, Integer.valueOf(location));
404 if(DEBUG) {
405 System.err.println("ShaderState: glGetAttribLocation: "+name+", loc: "+location);
406 }
407 } else if(verbose) {
408 System.err.println("ShaderState: glGetAttribLocation failed, no location for: "+name+", loc: "+location);
409 if(DEBUG) {
410 ExceptionUtils.dumpStack(System.err);
411 }
412 }
413 }
414 return location;
415 }
416
417 /**
418 * Validates and returns the location of a shader attribute.<br>
419 * Uses either the cached value {@link #getCachedAttribLocation(String)} if valid,
420 * or the GLSL queried via {@link GL2ES2#glGetAttribLocation(int, String)}.<br>
421 * The location will be cached and set in the
422 * {@link GLArrayData} object.
423 *
424 * @return -1 if there is no such attribute available,
425 * otherwise >= 0
426 *
427 * @throws GLException if no program is attached
428 * @throws GLException if the program is not linked and no location was cached.
429 *
430 * @see #getCachedAttribLocation(String)
431 * @see #bindAttribLocation(GL2ES2, int, GLArrayData)
432 * @see #bindAttribLocation(GL2ES2, int, String)
433 * @see GL2ES2#glGetAttribLocation(int, String)
434 * @see #getAttribute(String)
435 */
436 public int getAttribLocation(final GL2ES2 gl, final GLArrayData data) {
437 if(null==shaderProgram) throw new GLException("No program is attached");
438 final String name = data.getName();
439 int location = getCachedAttribLocation(name);
440 if(0<=location) {
441 data.setLocation(location);
442 } else {
443 if(!shaderProgram.linked()) throw new GLException("Program is not linked");
444 location = data.setLocation(gl, shaderProgram.program());
445 if(0<=location) {
446 activeAttribLocationMap.put(name, Integer.valueOf(location));
447 if(DEBUG) {
448 System.err.println("ShaderState: glGetAttribLocation: "+name+", loc: "+location);
449 }
450 } else if(verbose) {
451 System.err.println("ShaderState: glGetAttribLocation failed, no location for: "+name+", loc: "+location);
452 if(DEBUG) {
453 ExceptionUtils.dumpStack(System.err);
454 }
455 }
456 }
457 activeAttribDataMap.put(data.getName(), data);
458 return location;
459 }
460
461 //
462 // Enabled Vertex Arrays and its data
463 //
464
465 /**
466 * @return true if the named attribute is enable
467 */
468 public final boolean isVertexAttribArrayEnabled(final String name) {
469 final Boolean v = activedAttribEnabledMap.get(name);
470 return null != v && v.booleanValue();
471 }
472
473 /**
474 * @return true if the {@link GLArrayData} attribute is enable
475 */
476 public final boolean isVertexAttribArrayEnabled(final GLArrayData data) {
477 return isVertexAttribArrayEnabled(data.getName());
478 }
479
480 private boolean enableVertexAttribArray(final GL2ES2 gl, final String name, int location) {
481 activedAttribEnabledMap.put(name, Boolean.TRUE);
482 if(0>location) {
483 location = getAttribLocation(gl, name);
484 if(0>location) {
485 if(verbose) {
486 System.err.println("ShaderState: glEnableVertexAttribArray failed, no index for: "+name);
487 if(DEBUG) {
488 ExceptionUtils.dumpStack(System.err);
489 }
490 }
491 return false;
492 }
493 }
494 if(DEBUG) {
495 System.err.println("ShaderState: glEnableVertexAttribArray: "+name+", loc: "+location);
496 }
497 gl.glEnableVertexAttribArray(location);
498 return true;
499 }
500
501 /**
502 * Enables a vertex attribute array.
503 *
504 * This method retrieves the the location via {@link #getAttribLocation(GL2ES2, GLArrayData)}
505 * hence {@link #enableVertexAttribArray(GL2ES2, GLArrayData)} shall be preferred.
506 *
507 * Even if the attribute is not found in the current shader,
508 * it is marked enabled in this state.
509 *
510 * @return false, if the name is not found, otherwise true
511 *
512 * @throws GLException if the program is not linked and no location was cached.
513 *
514 * @see #glEnableVertexAttribArray
515 * @see #glDisableVertexAttribArray
516 * @see #glVertexAttribPointer
517 * @see #getVertexAttribPointer
518 */
519 public boolean enableVertexAttribArray(final GL2ES2 gl, final String name) {
520 return enableVertexAttribArray(gl, name, -1);
521 }
522
523
524 /**
525 * Enables a vertex attribute array, usually invoked by {@link GLArrayDataEditable#enableBuffer(GL, boolean)}.
526 *
527 * This method uses the {@link GLArrayData}'s location if set
528 * and is the preferred alternative to {@link #enableVertexAttribArray(GL2ES2, String)}.
529 * If data location is unset it will be retrieved via {@link #getAttribLocation(GL2ES2, GLArrayData)} set
530 * and cached in this state.
531 *
532 * Even if the attribute is not found in the current shader,
533 * it is marked enabled in this state.
534 *
535 * @return false, if the name is not found, otherwise true
536 *
537 * @throws GLException if the program is not linked and no location was cached.
538 *
539 * @see #glEnableVertexAttribArray
540 * @see #glDisableVertexAttribArray
541 * @see #glVertexAttribPointer
542 * @see #getVertexAttribPointer
543 * @see GLArrayDataEditable#enableBuffer(GL, boolean)
544 */
545 public boolean enableVertexAttribArray(final GL2ES2 gl, final GLArrayData data) {
546 if(0 > data.getLocation()) {
547 getAttribLocation(gl, data);
548 } else {
549 // ensure data is the current bound one
550 activeAttribDataMap.put(data.getName(), data);
551 }
552 return enableVertexAttribArray(gl, data.getName(), data.getLocation());
553 }
554
555 private boolean disableVertexAttribArray(final GL2ES2 gl, final String name, int location) {
556 activedAttribEnabledMap.put(name, Boolean.FALSE);
557 if(0>location) {
558 location = getAttribLocation(gl, name);
559 if(0>location) {
560 if(verbose) {
561 System.err.println("ShaderState: glDisableVertexAttribArray failed, no index for: "+name);
562 if(DEBUG) {
563 ExceptionUtils.dumpStack(System.err);
564 }
565 }
566 return false;
567 }
568 }
569 if(DEBUG) {
570 System.err.println("ShaderState: glDisableVertexAttribArray: "+name);
571 }
572 gl.glDisableVertexAttribArray(location);
573 return true;
574 }
575
576 /**
577 * Disables a vertex attribute array
578 *
579 * This method retrieves the the location via {@link #getAttribLocation(GL2ES2, GLArrayData)}
580 * hence {@link #disableVertexAttribArray(GL2ES2, GLArrayData)} shall be preferred.
581 *
582 * Even if the attribute is not found in the current shader,
583 * it is removed from this state enabled list.
584 *
585 * @return false, if the name is not found, otherwise true
586 *
587 * @throws GLException if no program is attached
588 * @throws GLException if the program is not linked and no location was cached.
589 *
590 * @see #glEnableVertexAttribArray
591 * @see #glDisableVertexAttribArray
592 * @see #glVertexAttribPointer
593 * @see #getVertexAttribPointer
594 */
595 public boolean disableVertexAttribArray(final GL2ES2 gl, final String name) {
596 return disableVertexAttribArray(gl, name, -1);
597 }
598
599 /**
600 * Disables a vertex attribute array
601 *
602 * This method uses the {@link GLArrayData}'s location if set
603 * and is the preferred alternative to {@link #disableVertexAttribArray(GL2ES2, String)}.
604 * If data location is unset it will be retrieved via {@link #getAttribLocation(GL2ES2, GLArrayData)} set
605 * and cached in this state.
606 *
607 * Even if the attribute is not found in the current shader,
608 * it is removed from this state enabled list.
609 *
610 * @return false, if the name is not found, otherwise true
611 *
612 * @throws GLException if no program is attached
613 * @throws GLException if the program is not linked and no location was cached.
614 *
615 * @see #glEnableVertexAttribArray
616 * @see #glDisableVertexAttribArray
617 * @see #glVertexAttribPointer
618 * @see #getVertexAttribPointer
619 */
620 public boolean disableVertexAttribArray(final GL2ES2 gl, final GLArrayData data) {
621 if(0 > data.getLocation()) {
622 getAttribLocation(gl, data);
623 }
624 return disableVertexAttribArray(gl, data.getName(), data.getLocation());
625 }
626
627 /**
628 * Set the {@link GLArrayData} vertex attribute data, if it's location is valid, i.e. &ge; 0.
629 * <p>
630 * This method uses the {@link GLArrayData}'s location if valid, i.e. &ge; 0.<br/>
631 * If data's location is invalid, it will be retrieved via {@link #getAttribLocation(GL2ES2, GLArrayData)},
632 * set and cached in this state.
633 * </p>
634 *
635 * @return false, if the location could not be determined, otherwise true
636 *
637 * @throws GLException if no program is attached
638 * @throws GLException if the program is not linked and no location was cached.
639 *
640 * @see #glEnableVertexAttribArray
641 * @see #glDisableVertexAttribArray
642 * @see #glVertexAttribPointer
643 * @see #getVertexAttribPointer
644 */
645 public boolean vertexAttribPointer(final GL2ES2 gl, final GLArrayData data) {
646 int location = data.getLocation();
647 if(0 > location) {
648 location = getAttribLocation(gl, data);
649 }
650 if(0 <= location) {
651 // only pass the data, if the attribute exists in the current shader
652 if(DEBUG) {
653 System.err.println("ShaderState: glVertexAttribPointer: "+data);
654 }
655 gl.glVertexAttribPointer(data);
656 return true;
657 }
658 return false;
659 }
660
661 /**
662 * Releases all mapped vertex attribute data,
663 * disables all enabled attributes and loses all indices
664 *
665 * @see #glEnableVertexAttribArray
666 * @see #glDisableVertexAttribArray
667 * @see #glVertexAttribPointer
668 * @see #getVertexAttribPointer
669 * @see #glReleaseAllVertexAttributes
670 * @see #glResetAllVertexAttributes
671 * @see #glResetAllVertexAttributes
672 * @see ShaderProgram#glReplaceShader
673 */
674 public void releaseAllAttributes(final GL2ES2 gl) {
675 if(null!=shaderProgram) {
676 for(final Iterator<GLArrayData> iter = activeAttribDataMap.values().iterator(); iter.hasNext(); ) {
677 disableVertexAttribArray(gl, iter.next());
678 }
679 for(final Iterator<String> iter = activedAttribEnabledMap.keySet().iterator(); iter.hasNext(); ) {
680 disableVertexAttribArray(gl, iter.next());
681 }
682 }
683 activeAttribDataMap.clear();
684 activedAttribEnabledMap.clear();
685 activeAttribLocationMap.clear();
686 managedAttributes.clear();
687 }
688
689 /**
690 * Disables all vertex attribute arrays.
691 *
692 * Their enabled stated will be removed from this state only
693 * if 'removeFromState' is true.
694 *
695 * This method purpose is more for debugging.
696 *
697 * @see #glEnableVertexAttribArray
698 * @see #glDisableVertexAttribArray
699 * @see #glVertexAttribPointer
700 * @see #getVertexAttribPointer
701 * @see #glReleaseAllVertexAttributes
702 * @see #glResetAllVertexAttributes
703 * @see #glResetAllVertexAttributes
704 * @see ShaderProgram#glReplaceShader
705 */
706 public void disableAllVertexAttributeArrays(final GL2ES2 gl, final boolean removeFromState) {
707 for(final Iterator<String> iter = activedAttribEnabledMap.keySet().iterator(); iter.hasNext(); ) {
708 final String name = iter.next();
709 if(removeFromState) {
710 activedAttribEnabledMap.remove(name);
711 }
712 final int index = getAttribLocation(gl, name);
713 if(0<=index) {
715 }
716 }
717 }
718
719 private final void relocateAttribute(final GL2ES2 gl, final GLArrayData attribute) {
720 // get new location .. note: 'activeAttribLocationMap' is cleared before
721 final String name = attribute.getName();
722 final int loc = attribute.setLocation(gl, shaderProgram.program());
723 if(0<=loc) {
724 activeAttribLocationMap.put(name, Integer.valueOf(loc));
725 if(DEBUG) {
726 System.err.println("ShaderState: relocateAttribute: "+name+", loc: "+loc);
727 }
729 // enable attrib, VBO and pass location/data
731 }
732
733 if( attribute.isVBO() ) {
734 gl.glBindBuffer(GL.GL_ARRAY_BUFFER, attribute.getVBOName());
735 gl.glVertexAttribPointer(attribute);
737 } else {
738 gl.glVertexAttribPointer(attribute);
739 }
740 }
741 }
742
743 /**
744 * Reset all previously enabled mapped vertex attribute data.
745 *
746 * <p>
747 * Attribute data is bound to the GL state, i.e. VBO data itself will not be updated.
748 * </p>
749 *
750 * <p>
751 * Attribute location and it's data assignment is bound to the program,
752 * hence both are updated.
753 * </p>
754 *
755 * <p>
756 * Note: Such update could only be prevented,
757 * if tracking am attribute/program dirty flag.
758 * </p>
759 *
760 * @throws GLException is the program is not linked
761 *
762 * @see #attachShaderProgram(GL2ES2, ShaderProgram)
763 */
764 private final void resetAllAttributes(final GL2ES2 gl) {
765 if(!shaderProgram.linked()) throw new GLException("Program is not linked");
766 activeAttribLocationMap.clear();
767
768 for(int i=0; i<managedAttributes.size(); i++) {
769 managedAttributes.get(i).setLocation(-1);
770 }
771 for(final Iterator<GLArrayData> iter = activeAttribDataMap.values().iterator(); iter.hasNext(); ) {
772 relocateAttribute(gl, iter.next());
773 }
774 }
775
776 private final void setAttribute(final GL2ES2 gl, final GLArrayData attribute) {
777 // get new location ..
778 final String name = attribute.getName();
779 final int loc = attribute.getLocation();
780
781 if(0<=loc) {
782 bindAttribLocation(gl, loc, name);
783
785 // enable attrib, VBO and pass location/data
786 gl.glEnableVertexAttribArray(loc);
787 }
788
789 if( attribute.isVBO() ) {
790 gl.glBindBuffer(GL.GL_ARRAY_BUFFER, attribute.getVBOName());
791 gl.glVertexAttribPointer(attribute);
792 gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);
793 } else {
794 gl.glVertexAttribPointer(attribute);
795 }
796 }
797 }
798
799 /**
800 * preserves the attribute location .. (program not linked)
801 */
802 private final void setAllAttributes(final GL2ES2 gl) {
803 for(final Iterator<GLArrayData> iter = activeAttribDataMap.values().iterator(); iter.hasNext(); ) {
804 setAttribute(gl, iter.next());
805 }
806 }
807
808 //
809 // Shader Uniform handling
810 //
811
812 /**
813 * Gets the cached location of the shader uniform.
814 *
815 * @return -1 if there is no such uniform available,
816 * otherwise >= 0
817 */
818 public final int getCachedUniformLocation(final String name) {
819 final Integer idx = activeUniformLocationMap.get(name);
820 return (null!=idx)?idx.intValue():-1;
821 }
822
823 /**
824 * Bind the {@link GLUniform} lifecycle to this ShaderState.
825 *
826 * <p>If a uniform location is cached it is promoted to the {@link GLUniformData} instance.</p>
827 *
828 * <p>The attribute will be destroyed with {@link #destroy(GL2ES2)}
829 * and it's location will be reset when switching shader with {@link #attachShaderProgram(GL2ES2, ShaderProgram)}.</p>
830 *
831 * <p>The data will not be transfered to the GPU, use {@link #uniform(GL2ES2, GLUniformData)} additionally.</p>
832 *
833 * @param uniform the {@link GLUniformData} which lifecycle shall be managed
834 *
835 * @see #getUniform(String)
836 */
837 public void ownUniform(final GLUniformData uniform) {
838 final int location = getCachedUniformLocation(uniform.getName());
839 if(0<=location) {
840 uniform.setLocation(location);
841 }
842 activeUniformDataMap.put(uniform.getName(), uniform);
843 managedUniforms.add(uniform);
844 }
845
846 public boolean ownsUniform(final GLUniformData uniform) {
847 return managedUniforms.contains(uniform);
848 }
849
850 /**
851 * Gets the location of a shader uniform with given <code>name</code>.<br>
852 * Uses either the cached value {@link #getCachedUniformLocation(String)} if valid,
853 * or the GLSL queried via {@link GL2ES2#glGetUniformLocation(int, String)}.<br>
854 * The location will be cached.
855 * <p>
856 * The current shader program ({@link #attachShaderProgram(GL2ES2, ShaderProgram)})
857 * must be in use ({@link #useProgram(GL2ES2, boolean) }) !</p>
858 *
859 * @return -1 if there is no such attribute available,
860 * otherwise >= 0
861
862 * @throws GLException is the program is not linked
863 *
864 * @see #glGetUniformLocation
865 * @see com.jogamp.opengl.GL2ES2#glGetUniformLocation
866 * @see #getUniformLocation
867 * @see ShaderProgram#glReplaceShader
868 */
869 public final int getUniformLocation(final GL2ES2 gl, final String name) {
870 if(!shaderProgram.inUse()) throw new GLException("Program is not in use");
871 int location = getCachedUniformLocation(name);
872 if(0>location) {
873 if(!shaderProgram.linked()) throw new GLException("Program is not linked");
874 location = gl.glGetUniformLocation(shaderProgram.program(), name);
875 if(0<=location) {
876 activeUniformLocationMap.put(name, Integer.valueOf(location));
877 } else if(verbose) {
878 System.err.println("ShaderState: glUniform failed, no location for: "+name+", index: "+location);
879 if(DEBUG) {
880 ExceptionUtils.dumpStack(System.err);
881 }
882 }
883 }
884 return location;
885 }
886
887 /**
888 * Validates and returns the location of a shader uniform.<br>
889 * Uses either the cached value {@link #getCachedUniformLocation(String)} if valid,
890 * or the GLSL queried via {@link GL2ES2#glGetUniformLocation(int, String)}.<br>
891 * The location will be cached and set in the
892 * {@link GLUniformData} object.
893 * <p>
894 * The current shader program ({@link #attachShaderProgram(GL2ES2, ShaderProgram)})
895 * must be in use ({@link #useProgram(GL2ES2, boolean) }) !</p>
896 *
897 * @return -1 if there is no such attribute available,
898 * otherwise >= 0
899
900 * @throws GLException is the program is not linked
901 *
902 * @see #glGetUniformLocation
903 * @see com.jogamp.opengl.GL2ES2#glGetUniformLocation
904 * @see #getUniformLocation
905 * @see ShaderProgram#glReplaceShader
906 */
907 public int getUniformLocation(final GL2ES2 gl, final GLUniformData data) {
908 if(!shaderProgram.inUse()) throw new GLException("Program is not in use");
909 final String name = data.getName();
910 int location = getCachedUniformLocation(name);
911 if(0<=location) {
912 data.setLocation(location);
913 } else {
914 if(!shaderProgram.linked()) throw new GLException("Program is not linked");
915 location = data.setLocation(gl, shaderProgram.program());
916 if(0<=location) {
917 activeUniformLocationMap.put(name, Integer.valueOf(location));
918 } else if(verbose) {
919 System.err.println("ShaderState: glUniform failed, no location for: "+name+", index: "+location);
920 if(DEBUG) {
921 ExceptionUtils.dumpStack(System.err);
922 }
923 }
924 }
925 activeUniformDataMap.put(name, data);
926 return location;
927 }
928
929 /**
930 * Set the uniform data, if it's location is valid, i.e. &ge; 0.
931 * <p>
932 * This method uses the {@link GLUniformData}'s location if valid, i.e. &ge; 0.<br/>
933 * If data's location is invalid, it will be retrieved via {@link #getUniformLocation(GL2ES2, GLUniformData)},
934 * set and cached in this state.
935 * </p>
936 *
937 * @return false, if the location could not be determined, otherwise true
938 *
939 * @see #glGetUniformLocation
940 * @see com.jogamp.opengl.GL2ES2#glGetUniformLocation
941 * @see com.jogamp.opengl.GL2ES2#glUniform
942 * @see #getUniformLocation
943 * @see ShaderProgram#glReplaceShader
944 */
945 public boolean uniform(final GL2ES2 gl, final GLUniformData data) {
946 if(!shaderProgram.inUse()) throw new GLException("Program is not in use");
947 int location = data.getLocation();
948 if(0>location) {
949 location = getUniformLocation(gl, data);
950 }
951 if(0<=location) {
952 // only pass the data, if the uniform exists in the current shader
953 if(DEBUG) {
954 System.err.println("ShaderState: glUniform: "+data);
955 }
956 gl.glUniform(data);
957 return true;
958 }
959 return false;
960 }
961
962 /**
963 * Get the uniform data, previously set.
964 *
965 * @return the GLUniformData object, null if not previously set.
966 */
967 public GLUniformData getUniform(final String name) {
968 return activeUniformDataMap.get(name);
969 }
970
971 /**
972 * Releases all mapped uniform data
973 * and loses all indices
974 */
975 public void releaseAllUniforms(final GL2ES2 gl) {
976 activeUniformDataMap.clear();
977 activeUniformLocationMap.clear();
978 managedUniforms.clear();
979 }
980
981 /**
982 * Reset all previously mapped uniform data
983 * <p>
984 * Uniform data and location is bound to the program,
985 * hence both are updated.
986 * </p>
987 * <p>
988 * Note: Such update could only be prevented,
989 * if tracking a uniform/program dirty flag.
990 * </p>
991 *
992 * @throws GLException is the program is not in use
993 *
994 * @see #attachShaderProgram(GL2ES2, ShaderProgram)
995 */
996 private final void resetAllUniforms(final GL2ES2 gl) {
997 if(!shaderProgram.inUse()) throw new GLException("Program is not in use");
998 activeUniformLocationMap.clear();
999 for(final Iterator<GLUniformData> iter = managedUniforms.iterator(); iter.hasNext(); ) {
1000 iter.next().setLocation(-1);
1001 }
1002 for(final Iterator<GLUniformData> iter = activeUniformDataMap.values().iterator(); iter.hasNext(); ) {
1003 final GLUniformData data = iter.next();
1004 final int loc = data.setLocation(gl, shaderProgram.program());
1005 if( 0 <= loc ) {
1006 // only pass the data, if the uniform exists in the current shader
1007 activeUniformLocationMap.put(data.getName(), Integer.valueOf(loc));
1008 if(DEBUG) {
1009 System.err.println("ShaderState: resetAllUniforms: "+data);
1010 }
1011 gl.glUniform(data);
1012 }
1013 }
1014 }
1015
1016 public StringBuilder toString(StringBuilder sb, final boolean alsoUnlocated) {
1017 if(null==sb) {
1018 sb = new StringBuilder();
1019 }
1020
1021 sb.append("ShaderState[ ");
1022
1023 sb.append(Platform.getNewline()).append(" ");
1024 if(null != shaderProgram) {
1025 shaderProgram.toString(sb);
1026 } else {
1027 sb.append("ShaderProgram: null");
1028 }
1029 sb.append(Platform.getNewline()).append(" enabledAttributes [");
1030 {
1031 final Iterator<String> names = activedAttribEnabledMap.keySet().iterator();
1032 final Iterator<Boolean> values = activedAttribEnabledMap.values().iterator();
1033 while( names.hasNext() ) {
1034 sb.append(Platform.getNewline()).append(" ").append(names.next()).append(": ").append(values.next());
1035 }
1036 }
1037 sb.append(Platform.getNewline()).append(" ],").append(" activeAttributes [");
1038 for(final Iterator<GLArrayData> iter = activeAttribDataMap.values().iterator(); iter.hasNext(); ) {
1039 final GLArrayData ad = iter.next();
1040 if( alsoUnlocated || 0 <= ad.getLocation() ) {
1041 sb.append(Platform.getNewline()).append(" ").append(ad);
1042 }
1043 }
1044 sb.append(Platform.getNewline()).append(" ],").append(" managedAttributes [");
1045 for(final Iterator<GLArrayData> iter = managedAttributes.iterator(); iter.hasNext(); ) {
1046 final GLArrayData ad = iter.next();
1047 if( alsoUnlocated || 0 <= ad.getLocation() ) {
1048 sb.append(Platform.getNewline()).append(" ").append(ad);
1049 }
1050 }
1051 sb.append(Platform.getNewline()).append(" ],").append(" activeUniforms [");
1052 for(final Iterator<GLUniformData> iter=activeUniformDataMap.values().iterator(); iter.hasNext(); ) {
1053 final GLUniformData ud = iter.next();
1054 if( alsoUnlocated || 0 <= ud.getLocation() ) {
1055 sb.append(Platform.getNewline()).append(" ").append(ud);
1056 }
1057 }
1058 sb.append(Platform.getNewline()).append(" ],").append(" managedUniforms [");
1059 for(final Iterator<GLUniformData> iter = managedUniforms.iterator(); iter.hasNext(); ) {
1060 final GLUniformData ud = iter.next();
1061 if( alsoUnlocated || 0 <= ud.getLocation() ) {
1062 sb.append(Platform.getNewline()).append(" ").append(ud);
1063 }
1064 }
1065 sb.append(Platform.getNewline()).append(" ]").append(Platform.getNewline()).append("]");
1066 return sb;
1067 }
1068
1069 @Override
1070 public String toString() {
1071 return toString(null, DEBUG).toString();
1072 }
1073
1074 private boolean verbose = DEBUG;
1075 private ShaderProgram shaderProgram=null;
1076
1077 private final HashMap<String, Boolean> activedAttribEnabledMap = new HashMap<String, Boolean>();
1078 private final HashMap<String, Integer> activeAttribLocationMap = new HashMap<String, Integer>();
1079 private final HashMap<String, GLArrayData> activeAttribDataMap = new HashMap<String, GLArrayData>();
1080 private final ArrayList<GLArrayData> managedAttributes = new ArrayList<GLArrayData>();
1081
1082 private final HashMap<String, Integer> activeUniformLocationMap = new HashMap<String, Integer>();
1083 private final HashMap<String, GLUniformData> activeUniformDataMap = new HashMap<String, GLUniformData>();
1084 private final ArrayList<GLUniformData> managedUniforms = new ArrayList<GLUniformData>();
1085
1086 private final HashMap<String, Object> attachedObjectsByString = new HashMap<String, Object>();
1087 private boolean resetAllShaderData = false;
1088}
1089
A generic exception for OpenGL errors used throughout the binding as a substitute for RuntimeExceptio...
GLSL uniform data wrapper encapsulating data to be uploaded to the GPU as a uniform.
String getName()
Return the uniform name as used in the shader.
int setLocation(final int location)
Sets the given location of the shader uniform.
StringBuilder toString(StringBuilder sb)
int program()
Returns the shader program name, which is non zero if valid.
synchronized void useProgram(final GL2ES2 gl, boolean on)
synchronized void release(final GL2ES2 gl)
Detaches all shader codes and deletes the program, but leaves the shader code intact.
synchronized boolean link(final GL2ES2 gl, final PrintStream verboseOut)
Links the shader code to the program.
ShaderState allows to sharing data between shader programs, while updating the attribute and uniform ...
void ownAttribute(final GLArrayData attribute, final boolean own)
Binds or unbinds the GLArrayData lifecycle to this ShaderState.
void releaseAllUniforms(final GL2ES2 gl)
Releases all mapped uniform data and loses all indices.
int getAttribLocation(final GL2ES2 gl, final String name)
Gets the location of a shader attribute with given name.
boolean ownsAttribute(final GLArrayData attribute)
boolean vertexAttribPointer(final GL2ES2 gl, final GLArrayData data)
Set the GLArrayData vertex attribute data, if it's location is valid, i.e.
final int getUniformLocation(final GL2ES2 gl, final String name)
Gets the location of a shader uniform with given name.
int getCachedAttribLocation(final String name)
Gets the cached location of a shader attribute.
boolean ownsUniform(final GLUniformData uniform)
int getAttribLocation(final GL2ES2 gl, final GLArrayData data)
Validates and returns the location of a shader attribute.
final Object getAttachedObject(final String name)
Returns the attached user object for the given name to this ShaderState.
synchronized void useProgram(final GL2ES2 gl, final boolean on)
Turns the shader program on or off.
synchronized boolean attachShaderProgram(final GL2ES2 gl, final ShaderProgram prog, final boolean enable)
Attach or switch a shader program.
GLUniformData getUniform(final String name)
Get the uniform data, previously set.
boolean disableVertexAttribArray(final GL2ES2 gl, final GLArrayData data)
Disables a vertex attribute array.
void bindAttribLocation(final GL2ES2 gl, final int location, final GLArrayData data)
Binds a shader GLArrayData attribute to a location.
void disableAllVertexAttributeArrays(final GL2ES2 gl, final boolean removeFromState)
Disables all vertex attribute arrays.
boolean isActiveAttribute(final GLArrayData attribute)
StringBuilder toString(StringBuilder sb, final boolean alsoUnlocated)
final Object detachObject(final String name)
final Object attachObject(final String name, final Object obj)
Attach user object for the given name to this ShaderState.
synchronized void destroy(final GL2ES2 gl)
Calls release(gl, true, true, true).
synchronized void releaseAllData(final GL2ES2 gl)
Calls release(gl, false, false, false).
boolean uniform(final GL2ES2 gl, final GLUniformData data)
Set the uniform data, if it's location is valid, i.e.
void releaseAllAttributes(final GL2ES2 gl)
Releases all mapped vertex attribute data, disables all enabled attributes and loses all indices.
boolean disableVertexAttribArray(final GL2ES2 gl, final String name)
Disables a vertex attribute array.
final boolean isVertexAttribArrayEnabled(final String name)
final boolean isVertexAttribArrayEnabled(final GLArrayData data)
boolean enableVertexAttribArray(final GL2ES2 gl, final GLArrayData data)
Enables a vertex attribute array, usually invoked by GLArrayDataEditable#enableBuffer(GL,...
boolean enableVertexAttribArray(final GL2ES2 gl, final String name)
Enables a vertex attribute array.
final int getCachedUniformLocation(final String name)
Gets the cached location of the shader uniform.
int getUniformLocation(final GL2ES2 gl, final GLUniformData data)
Validates and returns the location of a shader uniform.
synchronized void release(final GL2ES2 gl, final boolean destroyBoundAttributes, final boolean destroyShaderProgram, final boolean destroyShaderCode)
GLArrayData getAttribute(final String name)
Get the previous cached vertex attribute data.
void ownUniform(final GLUniformData uniform)
Bind the GLUniform lifecycle to this ShaderState.
void bindAttribLocation(final GL2ES2 gl, final int location, final String name)
Binds a shader attribute to a location.
void glVertexAttribPointer(int index, int size, int type, boolean normalized, int stride, long pointer_buffer_offset)
Entry point to C language function: void {@native glVertexAttribPointer}(GLuint index,...
void glBindAttribLocation(int program, int index, String name)
Entry point to C language function: void {@native glBindAttribLocation}(GLuint program,...
void glEnableVertexAttribArray(int index)
Entry point to C language function: void {@native glEnableVertexAttribArray}(GLuint index) Part of...
int glGetAttribLocation(int program, String name)
Entry point to C language function: GLint {@native glGetAttribLocation}(GLuint program,...
void glUniform(GLUniformData data)
int glGetUniformLocation(int program, String name)
Entry point to C language function: GLint {@native glGetUniformLocation}(GLuint program,...
void glDisableVertexAttribArray(int index)
Entry point to C language function: void {@native glDisableVertexAttribArray}(GLuint index) Part o...
The total number of bytes hold by the referenced buffer is: getComponentSize()* getComponentNumber() ...
int setLocation(int v)
Sets the given location of the shader attribute.
boolean isVBO()
Determines whether the data is server side (VBO) and enabled, or a client side array (false).
String getName()
The name of the reflecting shader array attribute.
int getVBOName()
The VBO name or 0 if not a VBO.
void associate(Object obj, boolean enable)
Implementation and type dependent object association.
int getLocation()
Returns the shader attribute location for this name, -1 if not yet determined.
void glBindBuffer(int target, int buffer)
Entry point to C language function: void {@native glBindBuffer}(GLenum target, GLuint buffer) Part...
static final int GL_ARRAY_BUFFER
GL_VERSION_1_5, GL_ES_VERSION_2_0, GL_VERSION_ES_1_0, GL_ARB_vertex_buffer_object Alias for: GL_ARRAY...
Definition: GL.java:633