JOGL v2.6.0-rc-20250706
JOGL, High-Performance Graphics Binding for Java™ (public API).
FBObject.java
Go to the documentation of this file.
1/**
2 * Copyright 2012-2023 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;
30
31import java.util.Arrays;
32
33import com.jogamp.common.ExceptionUtils;
34import com.jogamp.common.util.PropertyAccess;
35import com.jogamp.opengl.FBObject.Attachment.Type;
36
37import jogamp.opengl.Debug;
38
39/**
40 * Core utility class simplifying usage of framebuffer objects (FBO)
41 * with all {@link GLProfile}s.
42 * <p>
43 * Supports on-the-fly reconfiguration of dimension and multisample buffers via {@link #reset(GL, int, int, int, boolean)}
44 * while preserving the {@link Attachment} references.
45 * </p>
46 * <p>
47 * Integrates default read/write framebuffers via {@link GLContext#getDefaultReadFramebuffer()} and {@link GLContext#getDefaultReadFramebuffer()},
48 * which is being hooked at {@link GL#glBindFramebuffer(int, int)} when the default (<code>zero</code>) framebuffer is selected.
49 * </p>
50 *
51 * <p>FIXME: Implement support for {@link Type#DEPTH_TEXTURE}, {@link Type#STENCIL_TEXTURE} .</p>
52 */
53public class FBObject {
54 protected static final boolean DEBUG;
55 private static final int USER_MAX_TEXTURE_SIZE;
56 private static final boolean FBOResizeQuirk = false;
57
58 static {
59 Debug.initSingleton();
60 DEBUG = Debug.debug("FBObject");
61 USER_MAX_TEXTURE_SIZE = PropertyAccess.getIntProperty("jogl.debug.FBObject.MaxTextureSize", true, 0);
62 }
63
64 private static enum DetachAction { NONE, DISPOSE, RECREATE };
65
66 /**
67 * Generic color buffer FBO attachment, either of type {@link ColorAttachment} or {@link TextureAttachment}.
68 * <p>Always an instance of {@link Attachment}.</p>
69 */
70 public static interface Colorbuffer {
71 /**
72 * Initializes the color buffer and set it's parameter, if uninitialized, i.e. name is <code>zero</code>.
73 * @return <code>true</code> if newly initialized, otherwise <code>false</code>.
74 * @throws GLException if buffer generation or setup fails. The just created buffer name will be deleted in this case.
75 */
76 boolean initialize(final GL gl) throws GLException;
77
78 /**
79 * Releases the color buffer if initialized, i.e. name is not <code>zero</code>.
80 * @throws GLException if buffer release fails.
81 */
82 void free(final GL gl) throws GLException;
83
84 /**
85 * Writes the internal format to the given GLCapabilities object.
86 * @param caps the destination for format bits
87 * @param rgba8Avail whether rgba8 is available
88 */
89 void formatToGLCapabilities(final GLCapabilities caps, final boolean rgba8Avail);
90
91 /**
92 * Returns <code>true</code> if instance is of type {@link TextureAttachment}
93 * and <code>false</code> if instance is of type {@link ColorAttachment}.
94 */
96
97 /**
98 * Casts this object to a {@link TextureAttachment} reference, see {@link #isTextureAttachment()}.
99 * @throws GLException if this object is not of type {@link TextureAttachment}
100 * @see #isTextureAttachment()
101 */
103
104 /**
105 * Casts this object to a {@link ColorAttachment} reference, see {@link #isTextureAttachment()}.
106 * @throws GLException if this object is not of type {@link ColorAttachment}
107 * @see #isTextureAttachment()
108 */
110
111 /** internal format of colorbuffer */
113
114 /** width of colorbuffer */
115 int getWidth();
116
117 /** height of colorbuffer */
119
120 /** colorbuffer name [1..max] */
121 int getName();
122 }
123
124 /** Common super class of all FBO attachments */
125 public static abstract class Attachment {
126 public enum Type {
127 NONE, DEPTH, STENCIL, DEPTH_STENCIL, COLOR, COLOR_TEXTURE, DEPTH_TEXTURE, STENCIL_TEXTURE;
128
129 /**
130 * Returns {@link #COLOR}, {@link #DEPTH}, {@link #STENCIL} or {@link #DEPTH_STENCIL}
131 * @throws IllegalArgumentException if <code>format</code> cannot be handled.
132 */
133 public static Type determine(final int format) throws IllegalArgumentException {
134 switch(format) {
135 case GL.GL_RGBA4:
136 case GL.GL_RGB5_A1:
137 case GL.GL_RGB565:
138 case GL.GL_RGB8:
139 case GL.GL_RGBA8:
140 return Type.COLOR;
144 return Type.DEPTH;
148 return Type.STENCIL;
150 return Type.DEPTH_STENCIL;
151 default:
152 throw new IllegalArgumentException("format invalid: "+toHexString(format));
153 }
154 }
155 };
156 /**
157 * Interface abstraction to allow custom definitions of {@link Attachment}'s storage.
158 * <p>
159 * Please see {@link #setStorage(GL, Attachment)} for details.
160 * </p>
161 */
162 public static interface StorageDefinition {
163 /**
164 * Set or create the {@link Attachment}'s storage after generating its name and binding it to the target.
165 * Typical examples for standard definitions as implemented in {@link Attachment} specializations are:
166 * <pre>
167 * // Renderbuffer (Color, Debt, Stencil, ..) storage definition w/o multisamples
168 * gl.glRenderbufferStorage(GL.GL_RENDERBUFFER, a.format, a.getWidth(), a.getHeight());
169 * // Renderbuffer (Color, Debt, Stencil, ..) storage definition with multisamples
170 * gl.glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, samples, a.format, a.getWidth(), a.getHeight());
171 * // TextureAttachment
172 * gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, format, getWidth(), getHeight(), 0, dataFormat, dataType, null);
173 * </pre>
174 * The storage is setup within {@link Attachment#initialize(GL)} and hence the {@link Attachment}
175 * instance's {@link Attachment#setStorageDefinition(StorageDefinition)}.
176 *
177 * @param gl current {@link GL} instance
178 * @param a instance of the {@link Attachment} this {@link StorageDefinition} has been assigned to via {@link Attachment#setStorageDefinition(StorageDefinition)}.
179 */
180 public void setStorage(final GL gl, final Attachment a);
181 }
182
183 /** immutable type [{@link #COLOR}, {@link #DEPTH}, {@link #STENCIL}, {@link #COLOR_TEXTURE}, {@link #DEPTH_TEXTURE}, {@link #STENCIL_TEXTURE} ] */
184 public final Type type;
185
186 /** immutable the internal format */
187 public final int format;
188
189 private int width, height;
190
191 private int name;
192
193 /** Every implementation needs to have set their default instance via {@link #setStorageDefinition(StorageDefinition). */
194 private StorageDefinition storageDefinition;
195
196 protected Attachment(final Type type, final int iFormat, final int width, final int height, final int name) {
197 this.type = type;
198 this.format = iFormat;
199 this.width = width;
200 this.height = height;
201 this.name = name;
202 }
203
204 /**
205 * Override implementation default {@link StorageDefinition}
206 * @see {@link StorageDefinition#setStorage(GL, Attachment)}
207 */
208 public void setStorageDefinition(final StorageDefinition sd) { this.storageDefinition = sd; }
209
210 /**
211 * Accessor to call {@link StorageDefinition#setStorage(GL, Attachment)} within {@link #initialize(GL)} for implementations of {@link Attachment}.
212 */
213 protected final void setStorage(final GL gl) { storageDefinition.setStorage(gl, this); }
214
215 /**
216 * Writes the internal format to the given GLCapabilities object.
217 * @param caps the destination for format bits
218 * @param rgba8Avail whether rgba8 is available
219 */
220 public final void formatToGLCapabilities(final GLCapabilities caps, final boolean rgba8Avail) {
221 final int _format;
222 switch(format) {
223 case GL.GL_RGBA:
224 case 4:
225 _format = rgba8Avail ? GL.GL_RGBA8 : GL.GL_RGBA4;
226 break;
227 case GL.GL_RGB:
228 case 3:
229 _format = rgba8Avail ? GL.GL_RGB8 : GL.GL_RGB565;
230 break;
231 default:
232 _format = format;
233 }
234 switch(_format) {
235 case GL.GL_RGBA4:
236 caps.setRedBits(4);
237 caps.setGreenBits(4);
238 caps.setBlueBits(4);
239 caps.setAlphaBits(4);
240 break;
241 case GL.GL_RGB5_A1:
242 caps.setRedBits(5);
243 caps.setGreenBits(5);
244 caps.setBlueBits(5);
245 caps.setAlphaBits(1);
246 break;
247 case GL.GL_RGB565:
248 caps.setRedBits(5);
249 caps.setGreenBits(6);
250 caps.setBlueBits(5);
251 caps.setAlphaBits(0);
252 break;
253 case GL.GL_RGB8:
254 caps.setRedBits(8);
255 caps.setGreenBits(8);
256 caps.setBlueBits(8);
257 caps.setAlphaBits(0);
258 break;
259 case GL.GL_RGBA8:
260 caps.setRedBits(8);
261 caps.setGreenBits(8);
262 caps.setBlueBits(8);
263 caps.setAlphaBits(8);
264 break;
266 caps.setDepthBits(16);
267 break;
269 caps.setDepthBits(24);
270 break;
272 caps.setDepthBits(32);
273 break;
275 caps.setStencilBits(1);
276 break;
278 caps.setStencilBits(4);
279 break;
281 caps.setStencilBits(8);
282 break;
284 caps.setDepthBits(24);
285 caps.setStencilBits(8);
286 break;
287 default:
288 throw new IllegalArgumentException("format invalid: "+toHexString(format));
289 }
290 }
291
292 /** immutable internal format of attachment */
293 public final int getFormat() { return format; }
294
295 /** width of attachment */
296 public final int getWidth() { return width; }
297 /** height of attachment */
298 public final int getHeight() { return height; }
299 /* pp */ final void setSize(final int w, final int h) { width = w; height = h; }
300
301 /** buffer name [1..max], maybe a texture or renderbuffer name, depending on type. */
302 public final int getName() { return name; }
303 /* pp */ final void setName(final int n) { name = n; }
304
305 /**
306 * Initializes the attachment and set it's parameter, if uninitialized, i.e. name is <code>zero</code>.
307 * <pre>
308 final boolean init = 0 == name;
309 if( init ) {
310 do init ..
311 }
312 return init;
313 * </pre>
314 * @return <code>true</code> if newly initialized, otherwise <code>false</code>.
315 * @throws GLException if buffer generation or setup fails. The just created buffer name will be deleted in this case.
316 */
317 public abstract boolean initialize(final GL gl) throws GLException;
318
319 /**
320 * Releases the attachment if initialized, i.e. name is not <code>zero</code>.
321 * <pre>
322 if(0 != name) {
323 do free ..
324 name = 0;
325 }
326 * </pre>
327 * @throws GLException if buffer release fails.
328 */
329 public abstract void free(final GL gl) throws GLException;
330
331 /**
332 * <p>
333 * Comparison by {@link #type}, {@link #format}, {@link #width}, {@link #height} and {@link #name}.
334 * </p>
335 * {@inheritDoc}
336 */
337 @Override
338 public boolean equals(final Object o) {
339 if( this == o ) return true;
340 if( ! ( o instanceof Attachment ) ) return false;
341 final Attachment a = (Attachment)o;
342 return type == a.type &&
343 format == a.format &&
344 width == a.width &&
345 height== a.height &&
346 name == a.name ;
347 }
348
349 /**
350 * <p>
351 * Hashed by {@link #type}, {@link #format}, {@link #width}, {@link #height} and {@link #name}.
352 * </p>
353 * {@inheritDoc}
354 */
355 @Override
356 public int hashCode() {
357 // 31 * x == (x << 5) - x
358 int hash = 31 + type.ordinal();
359 hash = ((hash << 5) - hash) + format;
360 hash = ((hash << 5) - hash) + width;
361 hash = ((hash << 5) - hash) + height;
362 hash = ((hash << 5) - hash) + name;
363 return hash;
364 }
365
366 int objectHashCode() { return super.hashCode(); }
367
368 @Override
369 public String toString() {
370 return getClass().getSimpleName()+"[type "+type+", format "+toHexString(format)+", "+width+"x"+height+
371 "; name "+toHexString(name)+", obj "+toHexString(objectHashCode())+"]";
372 }
373
374 public static Type getType(final int attachmentPoint, final int maxColorAttachments) {
375 if( GL.GL_COLOR_ATTACHMENT0 <= attachmentPoint && attachmentPoint < GL.GL_COLOR_ATTACHMENT0+maxColorAttachments ) {
376 return Type.COLOR;
377 }
378 switch(attachmentPoint) {
380 return Type.DEPTH;
382 return Type.STENCIL;
383 default:
384 throw new IllegalArgumentException("Invalid attachment point "+toHexString(attachmentPoint));
385 }
386 }
387 }
388
389 /** Other renderbuffer attachment which maybe a colorbuffer, depth or stencil. */
390 public static class RenderAttachment extends Attachment {
391 private int samples;
392
393 /**
394 * @param type allowed types are {@link Type#DEPTH_STENCIL} {@link Type#DEPTH}, {@link Type#STENCIL} or {@link Type#COLOR}
395 * @param iFormat
396 * @param samples
397 * @param width
398 * @param height
399 * @param name
400 */
401 public RenderAttachment(final Type type, final int iFormat, final int samples, final int width, final int height, final int name) {
402 super(validateType(type), iFormat, width, height, name);
403 this.setStorageDefinition(defStorageDefinition);
404 this.samples = samples;
405 }
406
407 /** number of samples, or zero for no multisampling */
408 public final int getSamples() { return samples; }
409 /* pp */ final void setSamples(final int s) { samples = s; }
410
411 private static Type validateType(final Type type) {
412 switch(type) {
413 case DEPTH_STENCIL:
414 case DEPTH:
415 case STENCIL:
416 case COLOR:
417 return type;
418 default:
419 throw new IllegalArgumentException("Invalid type: "+type);
420 }
421 }
422
423 /**
424 * <p>
425 * Comparison by {@link #type}, {@link #format}, {@link #samples}, {@link #width}, {@link #height} and {@link #name}.
426 * </p>
427 * {@inheritDoc}
428 */
429 @Override
430 public boolean equals(final Object o) {
431 if( this == o ) return true;
432 if( ! ( o instanceof RenderAttachment ) ) return false;
433 return super.equals(o) &&
434 samples == ((RenderAttachment)o).samples;
435 }
436
437 /**
438 * <p>
439 * Hashed by {@link #type}, {@link #format}, {@link #samples}, {@link #width}, {@link #height} and {@link #name}.
440 * </p>
441 * {@inheritDoc}
442 */
443 @Override
444 public int hashCode() {
445 // 31 * x == (x << 5) - x
446 int hash = super.hashCode();
447 hash = ((hash << 5) - hash) + samples;
448 return hash;
449 }
450
451 @Override
452 public boolean initialize(final GL gl) throws GLException {
453 final boolean init = 0 == getName();
454 if( init ) {
455 final boolean checkError = DEBUG || GLContext.DEBUG_GL;
456 if( checkError ) {
457 checkPreGLError(gl);
458 }
459 final int[] name = new int[] { -1 };
460 gl.glGenRenderbuffers(1, name, 0);
461 setName(name[0]);
462
463 gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, getName());
464 setStorage(gl);
465 if( checkError ) {
466 final int glerr = gl.glGetError();
467 if(GL.GL_NO_ERROR != glerr) {
468 gl.glDeleteRenderbuffers(1, name, 0);
469 setName(0);
470 throw new GLException("GL Error "+toHexString(glerr)+" while creating "+this);
471 }
472 }
473 if(DEBUG) {
474 System.err.println("Attachment.init.X: "+this);
475 }
476 }
477 return init;
478 }
479 private final StorageDefinition defStorageDefinition = new StorageDefinition() {
480 @Override
481 public void setStorage(final GL gl, final Attachment a) {
482 // a == this.super for this instance
483 if( samples > 0 ) {
485 } else {
487 }
488 } };
489
490 @Override
491 public void free(final GL gl) {
492 final int[] name = new int[] { getName() };
493 if( 0 != name[0] ) {
494 if(DEBUG) {
495 System.err.println("Attachment.free.0: "+this);
496 }
497 gl.glDeleteRenderbuffers(1, name, 0);
498 setName(0);
499 }
500 }
501
502 @Override
503 public String toString() {
504 return getClass().getSimpleName()+"[type "+type+", format "+toHexString(format)+", samples "+samples+", "+getWidth()+"x"+getHeight()+
505 ", name "+toHexString(getName())+", obj "+toHexString(objectHashCode())+"]";
506 }
507 }
508
509 /** Color render buffer FBO attachment */
510 public static class ColorAttachment extends RenderAttachment implements Colorbuffer {
511 public ColorAttachment(final int iFormat, final int samples, final int width, final int height, final int name) {
512 super(Type.COLOR, iFormat, samples, width, height, name);
513 }
514 @Override
515 public final boolean isTextureAttachment() { return false; }
516 @Override
517 public final TextureAttachment getTextureAttachment() { throw new GLException("Not a TextureAttachment, but ColorAttachment"); }
518 @Override
519 public final ColorAttachment getColorAttachment() { return this; }
520 }
521
522 /** Texture FBO attachment */
523 public static class TextureAttachment extends Attachment implements Colorbuffer {
524 /** details of the texture setup */
526
527 /**
528 * @param type allowed types are [ {@link Type#COLOR_TEXTURE}, {@link Type#DEPTH_TEXTURE}, {@link Type#STENCIL_TEXTURE} ]
529 * @param iFormat
530 * @param width
531 * @param height
532 * @param dataFormat
533 * @param dataType
534 * @param magFilter
535 * @param minFilter
536 * @param wrapS
537 * @param wrapT
538 * @param name
539 */
540 public TextureAttachment(final Type type, final int iFormat, final int width, final int height, final int dataFormat, final int dataType,
541 final int magFilter, final int minFilter, final int wrapS, final int wrapT, final int name) {
542 super(validateType(type), iFormat, width, height, name);
543 this.setStorageDefinition(defStorageDefinition);
544 this.dataFormat = dataFormat;
545 this.dataType = dataType;
546 this.magFilter = magFilter;
547 this.minFilter = minFilter;
548 this.wrapS = wrapS;
549 this.wrapT = wrapT;
550 }
551
552 private static Type validateType(final Type type) {
553 switch(type) {
554 case COLOR_TEXTURE:
555 case DEPTH_TEXTURE:
556 case STENCIL_TEXTURE:
557 return type;
558 default:
559 throw new IllegalArgumentException("Invalid type: "+type);
560 }
561 }
562
563 /**
564 * Initializes the texture and set it's parameter, if uninitialized, i.e. name is <code>zero</code>.
565 * @throws GLException if texture generation and setup fails. The just created texture name will be deleted in this case.
566 */
567 @Override
568 public boolean initialize(final GL gl) throws GLException {
569 final boolean init = 0 == getName();
570 if( init ) {
571 final boolean checkError = DEBUG || GLContext.DEBUG_GL;
572 if( checkError ) {
573 checkPreGLError(gl);
574 }
575 final int[] name = new int[] { -1 };
576 gl.glGenTextures(1, name, 0);
577 if(0 == name[0]) {
578 throw new GLException("null texture, "+this);
579 }
580 setName(name[0]);
581
582 gl.glBindTexture(GL.GL_TEXTURE_2D, name[0]);
583 if( 0 < magFilter ) {
585 }
586 if( 0 < minFilter ) {
588 }
589 if( 0 < wrapS ) {
591 }
592 if( 0 < wrapT ) {
594 }
595 if( checkError ) {
596 boolean preTexImage2D = true;
597 int glerr = gl.glGetError();
598 if(GL.GL_NO_ERROR == glerr) {
599 preTexImage2D = false;
600 setStorage(gl);
601 glerr = gl.glGetError();
602 }
603 if(GL.GL_NO_ERROR != glerr) {
604 gl.glDeleteTextures(1, name, 0);
605 setName(0);
606 throw new GLException("GL Error "+toHexString(glerr)+" while creating (pre TexImage2D "+preTexImage2D+") "+this);
607 }
608 } else {
609 setStorage(gl);
610 }
611 if(DEBUG) {
612 System.err.println("Attachment.init.X: "+this);
613 }
614 }
615 return init;
616 }
617 private final StorageDefinition defStorageDefinition = new StorageDefinition() {
618 @Override
619 public void setStorage(final GL gl, final Attachment a) {
620 // a == this.super for this instance
622 } };
623
624 @Override
625 public void free(final GL gl) {
626 final int[] name = new int[] { getName() };
627 if( 0 != name[0] ) {
628 if(DEBUG) {
629 System.err.println("Attachment.free.0: "+this);
630 }
631 gl.glDeleteTextures(1, name, 0);
632 setName(0);
633 }
634 }
635
636 @Override
637 public final boolean isTextureAttachment() { return true; }
638 @Override
639 public final TextureAttachment getTextureAttachment() { return this; }
640 @Override
641 public final ColorAttachment getColorAttachment() { throw new GLException("Not a ColorAttachment, but TextureAttachment"); }
642
643 @Override
644 public String toString() {
645 return getClass().getSimpleName()+"[type "+type+", target GL_TEXTURE_2D, level 0, format "+toHexString(format)+
646 ", "+getWidth()+"x"+getHeight()+", border 0, dataFormat "+toHexString(dataFormat)+
647 ", dataType "+toHexString(dataType)+
648 "; min/mag "+toHexString(minFilter)+"/"+toHexString(magFilter)+
649 ", wrap S/T "+toHexString(wrapS)+"/"+toHexString(wrapT)+
650 "; name "+toHexString(getName())+", obj "+toHexString(objectHashCode())+"]";
651 }
652 }
653 static String toHexString(final int v) {
654 return "0x"+Integer.toHexString(v);
655 }
656
657 /**
658 * Creates a color {@link TextureAttachment}, i.e. type {@link Type#COLOR_TEXTURE},
659 * selecting the texture data type and format automatically.
660 *
661 * <p>Using default min/mag filter {@link GL#GL_NEAREST} and default wrapS/wrapT {@link GL#GL_CLAMP_TO_EDGE}.</p>
662 *
663 * @param gl the used {@link GLContext}'s {@link GL} object
664 * @param alpha set to <code>true</code> if you request alpha channel, otherwise <code>false</code>;
665 * @param width texture width
666 * @param height texture height
667 * @return the created and uninitialized color {@link TextureAttachment}
668 */
669 public static final TextureAttachment createColorTextureAttachment(final GL gl, final boolean alpha, final int width, final int height) {
671 }
672
673 /**
674 * Creates a color {@link TextureAttachment}, i.e. type {@link Type#COLOR_TEXTURE},
675 * selecting the texture data type and format automatically.
676 * <p>
677 * For GLES3, sampling-sink format <b>must be equal</b> w/ the sampling-source {@link Colorbuffer},
678 * see details below. Implementation aligns w/ {@link #createColorAttachment(boolean)}
679 * and is enforced via {@link #sampleSinkExFormatMismatch(GL)}.
680 * </p>
681 * <p>
682 * ES3 BlitFramebuffer Requirements: OpenGL ES 3.0.2 p194: 4.3.2 Copying Pixels
683 * <pre>
684 * If SAMPLE_BUFFERS for the read framebuffer is greater than zero, no copy
685 * is performed and an INVALID_OPERATION error is generated if the formats of
686 * the read and draw framebuffers are not identical or if the source and destination
687 * rectangles are not defined with the same (X0, Y 0) and (X1, Y 1) bounds.
688 * </pre>
689 * Texture and Renderbuffer format details:
690 * <pre>
691 * ES2 Base iFormat: OpenGL ES 2.0.24 p66: 3.7.1 Texture Image Specification, Table 3.8
692 * ALPHA, LUMINANCE, LUMINANCE_ALPHA, RGB, RGBA
693 *
694 * ES3 Base iFormat: OpenGL ES 3.0.2 p125: 3.8.3 Texture Image Specification, Table 3.11
695 * ALPHA, LUMINANCE, LUMINANCE_ALPHA, RGB, RGBA
696 * DEPTH_COMPONENT, STENCIL_COMPONENT, RED, RG
697 *
698 * ES3 Required Texture and Renderbuffer iFormat: OpenGL ES 3.0.2 p126: 3.8.3 Texture Image Specification
699 * - RGBA32I, RGBA32UI, RGBA16I, RGBA16UI, RGBA8, RGBA8I,
700 * RGBA8UI, SRGB8_ALPHA8, RGB10_A2, RGB10_A2UI, RGBA4, and
701 * RGB5_A1.
702 * - RGB8 and RGB565.
703 * - RG32I, RG32UI, RG16I, RG16UI, RG8, RG8I, and RG8UI.
704 * - R32I, R32UI, R16I, R16UI, R8, R8I, and R8UI.
705 * </pre>
706 * </p>
707 *
708 * @param gl the used {@link GLContext}'s {@link GL} object
709 * @param alpha set to <code>true</code> if you request alpha channel, otherwise <code>false</code>;
710 * @param width texture width
711 * @param height texture height
712 * @param magFilter if > 0 value for {@link GL#GL_TEXTURE_MAG_FILTER}
713 * @param minFilter if > 0 value for {@link GL#GL_TEXTURE_MIN_FILTER}
714 * @param wrapS if > 0 value for {@link GL#GL_TEXTURE_WRAP_S}
715 * @param wrapT if > 0 value for {@link GL#GL_TEXTURE_WRAP_T}
716 * @return the created and uninitialized color {@link TextureAttachment}
717 */
718 public static final TextureAttachment createColorTextureAttachment(final GL gl, final boolean alpha, final int width, final int height,
719 final int magFilter, final int minFilter, final int wrapS, final int wrapT) {
720 final int internalFormat, dataFormat, dataType;
721 if(gl.isGLES3()) {
722 internalFormat = alpha ? GL.GL_RGBA8 : GL.GL_RGB8;
723 dataFormat = alpha ? GL.GL_RGBA : GL.GL_RGB;
724 dataType = GL.GL_UNSIGNED_BYTE;
725 } else if(gl.isGLES()) {
726 internalFormat = alpha ? GL.GL_RGBA : GL.GL_RGB;
727 dataFormat = alpha ? GL.GL_RGBA : GL.GL_RGB;
728 dataType = GL.GL_UNSIGNED_BYTE;
729 } else {
730 internalFormat = alpha ? GL.GL_RGBA8 : GL.GL_RGB8;
731 // textureInternalFormat = alpha ? GL.GL_RGBA : GL.GL_RGB;
732 // textureInternalFormat = alpha ? 4 : 3;
733 dataFormat = alpha ? GL.GL_BGRA : GL.GL_RGB;
734 dataType = alpha ? GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV : GL.GL_UNSIGNED_BYTE;
735 }
736 return createColorTextureAttachment(internalFormat, width, height, dataFormat, dataType, magFilter, minFilter, wrapS, wrapT);
737 }
738
739 public static final TextureAttachment createColorTextureAttachment(final GL gl, final int internalFormat, final int width, final int height,
740 final int magFilter, final int minFilter, final int wrapS, final int wrapT) {
741 final int dataFormat, dataType;
742 final boolean alpha = hasAlpha(internalFormat);
743 if( gl.isGLES() ) {
744 dataFormat = alpha ? GL.GL_RGBA : GL.GL_RGB;
745 dataType = GL.GL_UNSIGNED_BYTE;
746 } else {
747 dataFormat = alpha ? GL.GL_BGRA : GL.GL_RGB;
748 dataType = alpha ? GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV : GL.GL_UNSIGNED_BYTE;
749 }
750 return createColorTextureAttachment(internalFormat, width, height, dataFormat, dataType, magFilter, minFilter, wrapS, wrapT);
751 }
752
753 /**
754 * Creates a color {@link TextureAttachment}, i.e. type {@link Type#COLOR_TEXTURE}.
755 *
756 * @param internalFormat internalFormat parameter to {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, long)}
757 * @param width texture width
758 * @param height texture height
759 * @param dataFormat format parameter to {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, long)}
760 * @param dataType type parameter to {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, long)}
761 * @param magFilter if > 0 value for {@link GL#GL_TEXTURE_MAG_FILTER}
762 * @param minFilter if > 0 value for {@link GL#GL_TEXTURE_MIN_FILTER}
763 * @param wrapS if > 0 value for {@link GL#GL_TEXTURE_WRAP_S}
764 * @param wrapT if > 0 value for {@link GL#GL_TEXTURE_WRAP_T}
765 * @return the created and uninitialized color {@link TextureAttachment}
766 */
767 public static final TextureAttachment createColorTextureAttachment(final int internalFormat, final int width, final int height, final int dataFormat, final int dataType,
768 final int magFilter, final int minFilter, final int wrapS, final int wrapT) {
769 return new TextureAttachment(Type.COLOR_TEXTURE, internalFormat, width, height, dataFormat, dataType,
770 magFilter, minFilter, wrapS, wrapT, 0 /* name */);
771 }
772
773 private static boolean hasAlpha(final int format) {
774 switch(format) {
775 case GL.GL_RGBA8:
776 case GL.GL_RGBA4:
777 case GL.GL_RGBA:
778 case GL.GL_BGRA:
779 case 4:
780 return true;
781 default:
782 return false;
783 }
784 }
785
786 private boolean initialized;
787 private boolean fullFBOSupport;
788 private boolean rgba8Avail;
789 private boolean depth24Avail;
790 private boolean depth32Avail;
791 private boolean stencil01Avail;
792 private boolean stencil04Avail;
793 private boolean stencil08Avail;
794 private boolean stencil16Avail;
795 private boolean packedDepthStencilAvail;
796 private int maxColorAttachments, maxSamples, maxTextureSize, maxRenderbufferSize;
797
798 private int width, height, samples;
799 private int vStatus;
800 private boolean ignoreStatus;
801 private int fbName;
802 private boolean bound;
803
804 private int colorbufferCount;
805 private int textureAttachmentCount;
806 private Colorbuffer[] colorbufferAttachments; // colorbuffer attachment points
807 private RenderAttachment depth, stencil; // depth and stencil maybe equal in case of packed-depth-stencil
808 private boolean modified; // size, sampleCount, or any attachment modified
809
810 private FBObject samplingSink; // MSAA sink
811 private Colorbuffer samplingColorSink;
812 private boolean samplingSinkDirty;
813
814 //
815 // ColorAttachment helper ..
816 //
817
818 private final void validateColorAttachmentPointRange(final int point) {
819 if(!initialized) {
820 throw new GLException("FBO not initialized");
821 }
822 if(maxColorAttachments != colorbufferAttachments.length) {
823 throw new InternalError(String.format("maxColorAttachments %d, array.length %d",
824 maxColorAttachments, colorbufferAttachments.length) );
825 }
826 if(0 > point || point >= maxColorAttachments) {
827 throw new IllegalArgumentException(String.format("attachment point out of range: %d, should be within [0..%d], %s",
828 point, maxColorAttachments-1, this.toString() ) );
829 }
830 }
831
832 private final void validateAddColorAttachment(final int point, final Colorbuffer ca) {
833 validateColorAttachmentPointRange(point);
834 if( null != colorbufferAttachments[point] ) {
835 throw new IllegalStateException(String.format("Cannot attach %s at %d, attachment point already in use by %s, %s",
836 ca.toString(), point, colorbufferAttachments[point].toString(), this.toString() ) );
837 }
838 }
839
840 private final void addColorAttachment(final int point, final Colorbuffer ca, final boolean validate) {
841 final Colorbuffer c = colorbufferAttachments[point];
842 if( validate ) {
843 validateColorAttachmentPointRange(point);
844 if( null == ca ) {
845 throw new IllegalArgumentException("Colorbuffer is null");
846 }
847 if( null != c ) {
848 throw new IllegalStateException(String.format("Cannot attach %s at %d, attachment point already in use by %s, %s",
849 ca.toString(), point, c.toString(), this.toString() ) );
850 }
851 }
852 colorbufferAttachments[point] = ca;
853 colorbufferCount++;
854 if( ca.isTextureAttachment() ) {
855 textureAttachmentCount++;
856 }
857 modified = true;
858 }
859
860 private final void removeColorAttachment(final int point, final Colorbuffer ca) {
861 validateColorAttachmentPointRange(point);
862 if( null == ca ) {
863 throw new IllegalArgumentException("Colorbuffer is null");
864 }
865 final Colorbuffer c = colorbufferAttachments[point];
866 if( c != ca ) {
867 throw new IllegalStateException(String.format("Cannot detach %s at %d, slot is holding other: %s, %s",
868 ca.toString(), point, c.toString(), this.toString() ) );
869 }
870 colorbufferAttachments[point] = null;
871 colorbufferCount--;
872 if( ca.isTextureAttachment() ) {
873 textureAttachmentCount--;
874 }
875 modified = true;
876 }
877
878 /**
879 * Return the {@link Colorbuffer} attachment at <code>attachmentPoint</code> if it is attached to this FBO, otherwise null.
880 *
881 * @see #attachColorbuffer(GL, boolean)
882 * @see #attachColorbuffer(GL, boolean)
883 * @see #attachTexture2D(GL, int, boolean, int, int, int, int)
884 * @see #attachTexture2D(GL, int, int, int, int, int, int, int, int)
885 */
886 public final Colorbuffer getColorbuffer(final int attachmentPoint) {
887 validateColorAttachmentPointRange(attachmentPoint);
888 return colorbufferAttachments[attachmentPoint];
889 }
890
891 /**
892 * Finds the passed {@link Colorbuffer} within the valid range of attachment points
893 * using <i>reference</i> comparison only.
894 * <p>
895 * Note: Slow. Implementation uses a logN array search to save resources, i.e. not using a HashMap.
896 * </p>
897 * @param ca the {@link Colorbuffer} to look for.
898 * @return -1 if the {@link Colorbuffer} could not be found, otherwise [0..{@link #getMaxColorAttachments()}-1]
899 */
900 public final int getColorbufferAttachmentPoint(final Colorbuffer ca) {
901 for(int i=0; i<colorbufferAttachments.length; i++) {
902 if( colorbufferAttachments[i] == ca ) {
903 return i;
904 }
905 }
906 return -1;
907 }
908
909 /**
910 * Returns the passed {@link Colorbuffer} if it is attached to this FBO, otherwise null.
911 * Implementation compares the <i>reference</i> only.
912 *
913 * <p>
914 * Note: Slow. Uses {@link #getColorbufferAttachmentPoint(Colorbuffer)} to determine it's attachment point
915 * to be used for {@link #getColorbuffer(int)}
916 * </p>
917 *
918 * @see #attachColorbuffer(GL, boolean)
919 * @see #attachColorbuffer(GL, boolean)
920 * @see #attachTexture2D(GL, int, boolean, int, int, int, int)
921 * @see #attachTexture2D(GL, int, int, int, int, int, int, int, int)
922 */
923 public final Colorbuffer getColorbuffer(final Colorbuffer ca) {
924 final int p = getColorbufferAttachmentPoint(ca);
925 return p>=0 ? getColorbuffer(p) : null;
926 }
927
928 /**
929 * Returns true if any attached {@link Colorbuffer} uses alpha,
930 * otherwise false.
931 */
932 public final boolean hasAttachmentUsingAlpha() {
933 final int caCount = getColorbufferCount();
934 boolean hasAlpha = false;
935 for(int i=0; i<caCount; i++) {
936 final Attachment ca = (Attachment)getColorbuffer(i);
937 if( null == ca ) {
938 break;
939 }
940 if( hasAlpha(ca.format) ) {
941 hasAlpha = true;
942 break;
943 }
944 }
945 return hasAlpha;
946 }
947
948 /**
949 * Creates an uninitialized FBObject instance.
950 * <p>
951 * Call {@link #init(GL, int, int, int)} .. etc to use it.
952 * </p>
953 */
954 public FBObject() {
955 this.initialized = false;
956
957 // TBD @ init
958 this.fullFBOSupport = false;
959 this.rgba8Avail = false;
960 this.depth24Avail = false;
961 this.depth32Avail = false;
962 this.stencil01Avail = false;
963 this.stencil04Avail = false;
964 this.stencil08Avail = false;
965 this.stencil16Avail = false;
966 this.packedDepthStencilAvail = false;
967 this.maxColorAttachments=-1;
968 this.maxSamples=-1;
969 this.maxTextureSize = 0;
970 this.maxRenderbufferSize = 0;
971
972 this.width = 0;
973 this.height = 0;
974 this.samples = 0;
975 this.vStatus = -1;
976 this.ignoreStatus = false;
977 this.fbName = 0;
978 this.bound = false;
979
980 this.colorbufferAttachments = null; // at init ..
981 this.colorbufferCount = 0;
982 this.textureAttachmentCount = 0;
983 this.depth = null;
984 this.stencil = null;
985 this.modified = true;
986
987 this.samplingSink = null;
988 this.samplingColorSink = null;
989 this.samplingSinkDirty = true;
990 }
991
992 /**
993 * Initializes this FBO's instance.
994 * <p>
995 * The sampling sink is not initializes, allowing manual assignment via {@link #setSamplingSink(FBObject)}
996 * if {@code newSamples > 0}.
997 * </p>
998 *
999 * <p>Leaves the FBO bound</p>
1000 *
1001 * @param gl the current GL context
1002 * @param newWidth the initial width, it's minimum is capped to 1
1003 * @param newHeight the initial height, it's minimum is capped to 1
1004 * @param newSamples if > 0, MSAA will be used, otherwise no multisampling. Will be capped to {@link #getMaxSamples()}.
1005 * @throws IllegalStateException if already initialized
1006 * @throws GLException in case of an error, i.e. size too big, etc ..
1007 */
1008 public void init(final GL gl, final int newWidth, final int newHeight, final int newSamples) throws IllegalStateException, GLException {
1009 if( initialized ) {
1010 throw new IllegalStateException("FBO already initialized");
1011 }
1012 if( !gl.hasBasicFBOSupport() ) {
1013 throw new GLException("FBO not supported w/ context: "+gl.getContext()+", "+this);
1014 }
1015 fullFBOSupport = gl.hasFullFBOSupport();
1016
1018 depth24Avail = fullFBOSupport || gl.isExtensionAvailable(GLExtensions.OES_depth24);
1019 depth32Avail = fullFBOSupport || gl.isExtensionAvailable(GLExtensions.OES_depth32);
1020 stencil01Avail = fullFBOSupport || gl.isExtensionAvailable(GLExtensions.OES_stencil1);
1021 stencil04Avail = fullFBOSupport || gl.isExtensionAvailable(GLExtensions.OES_stencil4);
1022 stencil08Avail = fullFBOSupport || gl.isExtensionAvailable(GLExtensions.OES_stencil8);
1023 stencil16Avail = fullFBOSupport;
1024
1025 packedDepthStencilAvail = fullFBOSupport ||
1028
1029 final boolean NV_fbo_color_attachments = gl.isExtensionAvailable(GLExtensions.NV_fbo_color_attachments);
1030
1031 final int val[] = new int[1];
1032
1033 checkPreGLError(gl);
1034
1035 int realMaxColorAttachments = 1;
1036 maxColorAttachments = 1;
1037 if( fullFBOSupport || NV_fbo_color_attachments ) {
1038 try {
1039 val[0] = 0;
1041 realMaxColorAttachments = 1 <= val[0] ? val[0] : 1; // cap minimum to 1
1042 } catch (final GLException gle) { gle.printStackTrace(); }
1043 }
1044 maxColorAttachments = realMaxColorAttachments <= 8 ? realMaxColorAttachments : 8; // cap to limit array size
1045
1046 colorbufferAttachments = new Colorbuffer[maxColorAttachments];
1047 colorbufferCount = 0;
1048 textureAttachmentCount = 0;
1049
1050 maxSamples = gl.getMaxRenderbufferSamples(); // if > 0 implies fullFBOSupport
1052 final int _maxTextureSize = val[0];
1053 if( 0 < USER_MAX_TEXTURE_SIZE ) {
1054 maxTextureSize = USER_MAX_TEXTURE_SIZE;
1055 } else {
1056 maxTextureSize = _maxTextureSize;
1057 }
1059 maxRenderbufferSize = val[0];
1060
1061 this.width = 0 < newWidth ? newWidth : 1;
1062 this.height = 0 < newHeight ? newHeight : 1;
1063 this.samples = newSamples <= maxSamples ? newSamples : maxSamples;
1064
1065 if(DEBUG) {
1066 System.err.println("FBObject.init() START: "+width+"x"+height+", "+newSamples+" -> "+this.samples+" samples");
1067 System.err.println("fullFBOSupport: "+fullFBOSupport);
1068 System.err.println("maxColorAttachments: "+maxColorAttachments+"/"+realMaxColorAttachments+" [capped/real]");
1069 System.err.println("maxSamples: "+maxSamples);
1070 System.err.println("maxTextureSize: "+_maxTextureSize+" -> "+maxTextureSize);
1071 System.err.println("maxRenderbufferSize: "+maxRenderbufferSize);
1072 System.err.println("rgba8: "+rgba8Avail);
1073 System.err.println("depth24: "+depth24Avail);
1074 System.err.println("depth32: "+depth32Avail);
1075 System.err.println("stencil01: "+stencil01Avail);
1076 System.err.println("stencil04: "+stencil04Avail);
1077 System.err.println("stencil08: "+stencil08Avail);
1078 System.err.println("stencil16: "+stencil16Avail);
1079 System.err.println("packedDepthStencil: "+packedDepthStencilAvail);
1080 System.err.println("NV_fbo_color_attachments: "+NV_fbo_color_attachments);
1081 System.err.println(gl.getContext().getGLVersion());
1082 System.err.println(JoglVersion.getGLStrings(gl, null, false).toString());
1083 }
1084
1085 checkPreGLError(gl);
1086
1087 if( width > maxRenderbufferSize || height > maxRenderbufferSize ) {
1088 throw new GLException("Size "+width+"x"+height+" exceeds on of the maxima renderbuffer size "+maxRenderbufferSize+": \n\t"+this);
1089 }
1090
1091 modified = true;
1092 samplingSinkDirty = true;
1093
1094 // generate fbo ..
1095 gl.glGenFramebuffers(1, val, 0);
1096 fbName = val[0];
1097 if(0 == fbName) {
1098 throw new GLException("null framebuffer");
1099 }
1100
1101 // bind fbo ..
1103 checkNoError(gl, gl.glGetError(), "FBObject Init.bindFB"); // throws GLException if error
1104 if(!gl.glIsFramebuffer(fbName)) {
1105 checkNoError(gl, GL.GL_INVALID_VALUE, "FBObject Init.isFB"); // throws GLException
1106 }
1107 bound = true;
1108 initialized = true;
1109
1110 vStatus = GL.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; // always incomplete w/o attachments!
1111 if(DEBUG) {
1112 System.err.println("FBObject.init() END: "+this);
1113 ExceptionUtils.dumpStack(System.err);
1114 }
1115 }
1116
1117 /**
1118 * Resets this FBO's instance.
1119 * <p>
1120 * In case the new parameters are compatible with the current ones
1121 * no action will be performed and method returns immediately.<br>
1122 * Otherwise all attachments will be recreated
1123 * to match the new given parameters.
1124 * </p>
1125 * <p>
1126 * {@link #resetSamplingSink(GL)} is being issued immediately
1127 * to match the new configuration.
1128 * </p>
1129 *
1130 * <p>Leaves the FBO bound state untouched</p>
1131 *
1132 * @param gl the current GL context
1133 * @param newWidth the new width, it's minimum is capped to 1
1134 * @param newHeight the new height, it's minimum is capped to 1
1135 * @param newSamples if > 0, MSAA will be used, otherwise no multisampling. Will be capped to {@link #getMaxSamples()}.
1136 * @return {@code true} if this instance has been modified, otherwise {@code false}.
1137 * @throws IllegalStateException if not initialized via {@link #init(GL, int, int, int)}.
1138 * @throws GLException in case of an error, i.e. size too big, etc ..
1139 */
1140 public final boolean reset(final GL gl, int newWidth, int newHeight, int newSamples) throws GLException, IllegalStateException {
1141 if( !initialized ) {
1142 throw new IllegalStateException("FBO not initialized");
1143 }
1144
1145 newSamples = newSamples <= maxSamples ? newSamples : maxSamples; // clamp
1146
1147 if( newWidth != width || newHeight != height || newSamples != samples ) {
1148 if( 0 >= newWidth ) { newWidth = 1; }
1149 if( 0 >= newHeight ) { newHeight = 1; }
1150 if( textureAttachmentCount > 0 && ( newWidth > 2 + maxTextureSize || newHeight > 2 + maxTextureSize ) ) {
1151 throw new GLException("Size "+newWidth+"x"+newHeight+" exceeds on of the maximum texture size "+maxTextureSize+": \n\t"+this);
1152 }
1153 if( newWidth > maxRenderbufferSize || newHeight > maxRenderbufferSize ) {
1154 throw new GLException("Size "+newWidth+"x"+newHeight+" exceeds on of the maxima renderbuffer size "+maxRenderbufferSize+": \n\t"+this);
1155 }
1156
1157 if(DEBUG) {
1158 System.err.println("FBObject.reset - START - "+width+"x"+height+", "+samples+" -> "+newWidth+"x"+newHeight+", "+newSamples+"; "+this);
1159 }
1160
1161 final boolean wasBound = isBound();
1162
1163 final int sampleCountChange;
1164 if( 0 < samples && 0 < newSamples || 0 == samples && 0 == newSamples ) {
1165 sampleCountChange = 0; // keep MSAA settings
1166 } else if( 0 == samples && 0 < newSamples ) {
1167 sampleCountChange = 1; // add MSAA
1168 } else if( 0 < samples && 0 == newSamples ) {
1169 sampleCountChange = -1; // remove MSAA
1170 } else {
1171 throw new IllegalArgumentException("Error in sampleCount change: "+samples+" -> "+newSamples);
1172 }
1173 width = newWidth;
1174 height = newHeight;
1175 samples = newSamples;
1176
1177 modified = true;
1178 samplingSinkDirty = true;
1179
1180 detachAllImpl(gl, true, true, sampleCountChange);
1182
1183 if(!wasBound) {
1184 unbind(gl);
1185 }
1186
1187 if(DEBUG) {
1188 System.err.println("FBObject.reset - END - wasBound, "+wasBound+", "+this);
1189 }
1190 return true;
1191 } else {
1192 return false;
1193 }
1194 }
1195
1196 /**
1197 * Simply resets this instance's size only, w/o validation.
1198 *
1199 * <p>Leaves the FBO bound</p>
1200 *
1201 * @param gl the current GL context
1202 * @param newWidth the new width, it's minimum is capped to 1
1203 * @param newHeight the new height, it's minimum is capped to 1
1204 */
1205 private final void resetSizeImpl(final GL gl, final int newWidth, final int newHeight) {
1206 if(DEBUG) {
1207 System.err.println("FBObject.resetSize - START - "+width+"x"+height+", "+samples+" -> "+newWidth+"x"+newHeight);
1208 }
1209
1210 final int sampleCountChange = 0; // keep MSAA settings
1211 width = newWidth;
1212 height = newHeight;
1213
1214 modified = true;
1215 samplingSinkDirty = true;
1216
1217 detachAllImpl(gl, true, true, sampleCountChange);
1218
1219 if(DEBUG) {
1220 System.err.println("FBObject.resetSize - END - "+this);
1221 }
1222 }
1223
1224 private void validateAttachmentSize(final Attachment a) {
1225 final int aWidth = a.getWidth();
1226 final int aHeight = a.getHeight();
1227
1228 if( a instanceof TextureAttachment && ( aWidth > 2 + maxTextureSize || aHeight > 2 + maxTextureSize ) ) {
1229 throw new GLException("Size "+aWidth+"x"+aHeight+" of "+a+" exceeds on of the maximum texture size "+maxTextureSize+": \n\t"+this);
1230 }
1231 if( aWidth > maxRenderbufferSize || aHeight > maxRenderbufferSize ) {
1232 throw new GLException("Size "+aWidth+"x"+aHeight+" of "+a+" exceeds on of the maxima renderbuffer size "+maxRenderbufferSize+": \n\t"+this);
1233 }
1234 }
1235
1236 /**
1237 * Writes the internal format of the attachments to the given GLCapabilities object.
1238 * @param caps the destination for format bits
1239 */
1240 public final void formatToGLCapabilities(final GLCapabilities caps) {
1241 caps.setSampleBuffers(samples > 0);
1242 caps.setNumSamples(samples);
1243 caps.setDepthBits(0);
1244 caps.setStencilBits(0);
1245
1246 final Colorbuffer cb = samples > 0 ? getSamplingSink() : getColorbuffer(0);
1247 if(null != cb) {
1248 cb.formatToGLCapabilities(caps, rgba8Avail);
1249 }
1250 if(null != depth) {
1251 depth.formatToGLCapabilities(caps, rgba8Avail);
1252 }
1253 if(null != stencil && stencil != depth) {
1254 stencil.formatToGLCapabilities(caps, rgba8Avail);
1255 }
1256 }
1257
1258 /**
1259 * Note that the status may reflect an incomplete state during transition of attachments.
1260 * @return The FB status. {@link GL.GL_FRAMEBUFFER_COMPLETE} if ok, otherwise return GL FBO error state or -1
1261 * @see #validateStatus()
1262 */
1263 public final int getStatus() {
1264 return vStatus;
1265 }
1266
1267 /** return the {@link #getStatus()} as a string. */
1268 public final String getStatusString() {
1269 return getStatusString(vStatus);
1270 }
1271
1272 public static final String getStatusString(final int fbStatus) {
1273 switch(fbStatus) {
1274 case -1:
1275 return "NOT A FBO";
1276
1278 return "OK";
1279
1281 return("FBO incomplete attachment\n");
1283 return("FBO missing attachment");
1285 return("FBO attached images must have same dimensions");
1287 return("FBO attached images must have same format");
1289 return("FBO missing draw buffer");
1291 return("FBO missing read buffer");
1293 return("FBO missing multisample buffer");
1295 return("FBO missing layer targets");
1296
1298 return("Unsupported FBO format");
1300 return("FBO undefined");
1301
1302 case 0:
1303 return("FBO implementation fault");
1304 default:
1305 return("FBO incomplete, implementation ERROR "+toHexString(fbStatus));
1306 }
1307 }
1308
1309 /**
1310 * The status may even be valid if incomplete during transition of attachments.
1311 * @see #getStatus()
1312 */
1313 public final boolean isStatusValid() {
1314 switch(vStatus) {
1316 return true;
1317
1326 if(0 == colorbufferCount || null == depth) {
1327 // we are in transition
1328 return true;
1329 }
1330
1333
1334 case 0:
1335 default:
1336 if(DEBUG) {
1337 System.err.println("Framebuffer " + fbName + " is incomplete, status = " + toHexString(vStatus) +
1338 " : " + getStatusString(vStatus));
1339 }
1340 return false;
1341 }
1342 }
1343
1344 private static int checkPreGLError(final GL gl) {
1345 final int glerr = gl.glGetError();
1346 if(DEBUG && GL.GL_NO_ERROR != glerr) {
1347 System.err.println("Pre-existing GL error: "+toHexString(glerr));
1348 ExceptionUtils.dumpStack(System.err);
1349 }
1350 return glerr;
1351 }
1352
1353 private final boolean checkNoError(final GL gl, final int err, final String exceptionMessage) throws GLException {
1354 if(GL.GL_NO_ERROR != err) {
1355 if(null != gl) {
1356 destroy(gl);
1357 }
1358 if(null != exceptionMessage) {
1359 throw new GLException(exceptionMessage+" GL Error "+toHexString(err)+" of "+this.toString());
1360 }
1361 return false;
1362 }
1363 return true;
1364 }
1365
1366 private final void checkInitialized() throws GLException {
1367 if(!initialized) {
1368 throw new GLException("FBO not initialized, call init(GL) first.");
1369 }
1370 }
1371
1372 /**
1373 * Attaches a {@link Colorbuffer}, i.e. {@link TextureAttachment}, to this FBO's instance at the given attachment point,
1374 * selecting the texture data type and format automatically.
1375 *
1376 * <p>Using default min/mag filter {@link GL#GL_NEAREST} and default wrapS/wrapT {@link GL#GL_CLAMP_TO_EDGE}.</p>
1377 *
1378 * <p>Leaves the FBO bound.</p>
1379 *
1380 * @param gl the current GL context
1381 * @param attachmentPoint the color attachment point ranging from [0..{@link #getMaxColorAttachments()}-1]
1382 * @param alpha set to <code>true</code> if you request alpha channel, otherwise <code>false</code>;
1383 * @return TextureAttachment instance describing the new attached texture colorbuffer if bound and configured successfully, otherwise GLException is thrown
1384 * @throws GLException in case the texture colorbuffer couldn't be allocated or MSAA has been chosen
1385 * @see #createColorTextureAttachment(GLProfile, boolean, int, int)
1386 */
1387 public final TextureAttachment attachTexture2D(final GL gl, final int attachmentPoint, final boolean alpha) throws GLException {
1388 return attachColorbuffer(gl, attachmentPoint,
1389 createColorTextureAttachment(gl, alpha, width, height)).getTextureAttachment();
1390 }
1391
1392 /**
1393 * Attaches a {@link Colorbuffer}, i.e. {@link TextureAttachment}, to this FBO's instance at the given attachment point,
1394 * selecting the texture data type and format automatically.
1395 *
1396 * <p>Leaves the FBO bound.</p>
1397 *
1398 * @param gl the current GL context
1399 * @param attachmentPoint the color attachment point ranging from [0..{@link #getMaxColorAttachments()}-1]
1400 * @param alpha set to <code>true</code> if you request alpha channel, otherwise <code>false</code>;
1401 * @param magFilter if > 0 value for {@link GL#GL_TEXTURE_MAG_FILTER}
1402 * @param minFilter if > 0 value for {@link GL#GL_TEXTURE_MIN_FILTER}
1403 * @param wrapS if > 0 value for {@link GL#GL_TEXTURE_WRAP_S}
1404 * @param wrapT if > 0 value for {@link GL#GL_TEXTURE_WRAP_T}
1405 * @return TextureAttachment instance describing the new attached texture colorbuffer if bound and configured successfully, otherwise GLException is thrown
1406 * @throws GLException in case the texture colorbuffer couldn't be allocated or MSAA has been chosen
1407 * @see #createColorTextureAttachment(GLProfile, boolean, int, int, int, int, int, int)
1408 */
1409 public final TextureAttachment attachTexture2D(final GL gl, final int attachmentPoint, final boolean alpha, final int magFilter, final int minFilter, final int wrapS, final int wrapT) throws GLException {
1410 return attachColorbuffer(gl, attachmentPoint,
1411 createColorTextureAttachment(gl, alpha, width, height, magFilter, minFilter, wrapS, wrapT)).getTextureAttachment();
1412 }
1413
1414 /**
1415 * Attaches a {@link Colorbuffer}, i.e. {@link TextureAttachment}, to this FBO's instance at the given attachment point.
1416 *
1417 * <p>Leaves the FBO bound.</p>
1418 *
1419 * @param gl the current GL context
1420 * @param attachmentPoint the color attachment point ranging from [0..{@link #getMaxColorAttachments()}-1]
1421 * @param internalFormat internalFormat parameter to {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, long)}
1422 * @param dataFormat format parameter to {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, long)}
1423 * @param dataType type parameter to {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, long)}
1424 * @param magFilter if > 0 value for {@link GL#GL_TEXTURE_MAG_FILTER}
1425 * @param minFilter if > 0 value for {@link GL#GL_TEXTURE_MIN_FILTER}
1426 * @param wrapS if > 0 value for {@link GL#GL_TEXTURE_WRAP_S}
1427 * @param wrapT if > 0 value for {@link GL#GL_TEXTURE_WRAP_T}
1428 * @return TextureAttachment instance describing the new attached texture colorbuffer if bound and configured successfully, otherwise GLException is thrown
1429 * @throws GLException in case the texture colorbuffer couldn't be allocated or MSAA has been chosen
1430 * @see #createColorTextureAttachment(int, int, int, int, int, int, int, int, int)
1431 */
1432 public final TextureAttachment attachTexture2D(final GL gl, final int attachmentPoint,
1433 final int internalFormat, final int dataFormat, final int dataType,
1434 final int magFilter, final int minFilter, final int wrapS, final int wrapT) throws GLException {
1435 return attachColorbuffer(gl, attachmentPoint,
1436 createColorTextureAttachment(internalFormat, width, height, dataFormat, dataType, magFilter, minFilter, wrapS, wrapT)).getTextureAttachment();
1437 }
1438
1439 /**
1440 * Creates a {@link ColorAttachment}, selecting the format automatically.
1441 * <p>
1442 * For GLES3, sampling-sink {@link Colorbuffer} format <b>must be equal</b> w/ the sampling-source {@link Colorbuffer}.
1443 * Implementation aligns w/ {@link #createColorTextureAttachment(GLProfile, boolean, int, int, int, int, int, int)}
1444 * and is enforced via {@link #sampleSinkExFormatMismatch(GL)}.
1445 * </p>
1446 *
1447 * @param alpha set to <code>true</code> if you request alpha channel, otherwise <code>false</code>;
1448 * @return uninitialized ColorAttachment instance describing the new attached colorbuffer
1449 */
1450 public final ColorAttachment createColorAttachment(final boolean alpha) {
1451 final int internalFormat;
1452
1453 if( rgba8Avail ) {
1454 internalFormat = alpha ? GL.GL_RGBA8 : GL.GL_RGB8 ;
1455 } else {
1456 internalFormat = alpha ? GL.GL_RGBA4 : GL.GL_RGB565;
1457 }
1458 return createColorAttachment(internalFormat, samples, width, height);
1459 }
1460
1461 /**
1462 * Creates a {@link ColorAttachment}, selecting the format automatically.
1463 * <p>
1464 * For GLES3, sampling-sink {@link Colorbuffer} format <b>must be equal</b> w/ the sampling-source {@link Colorbuffer}.
1465 * Implementation aligns w/ {@link #createColorTextureAttachment(GLProfile, boolean, int, int, int, int, int, int)}
1466 * and is enforced via {@link #sampleSinkExFormatMismatch(GL)}.
1467 * </p>
1468 *
1469 * @param alpha set to <code>true</code> if you request alpha channel, otherwise <code>false</code>;
1470 * @return uninitialized ColorAttachment instance describing the new attached colorbuffer
1471 */
1472 public static final ColorAttachment createColorAttachment(final int internalFormat, final int samples, final int width, final int height) {
1473 return new ColorAttachment(internalFormat, samples, width, height, 0 /* name not yet determined */);
1474 }
1475
1476 public static final RenderAttachment createRenderAttachment(final Type type, final int internalFormat, final int samples, final int width, final int height) {
1477 return new RenderAttachment(type, internalFormat, samples, width, height, 0 /* name not yet determined */);
1478 }
1479
1480 /**
1481 * Attaches a newly created and {@link Colorbuffer#initialize(GL) initialized} {@link Colorbuffer}, i.e. a {@link ColorAttachment},
1482 * at the given attachment point.
1483 * <p>
1484 * The {@link ColorAttachment} is created using {@code alpha} if {@code true} and current {@code sample count} and {@code size}.
1485 * </p>
1486 *
1487 * <p>Leaves the FBO bound.</p>
1488 *
1489 * @param gl the current GL context
1490 * @param attachmentPoint the color attachment point ranging from [0..{@link #getMaxColorAttachments()}-1]
1491 * @param alpha set to <code>true</code> if you request alpha channel, otherwise <code>false</code>;
1492 * @return ColorAttachment instance describing the new attached colorbuffer if bound and configured successfully, otherwise GLException is thrown
1493 * @throws GLException in case the colorbuffer couldn't be allocated
1494 * @see #createColorAttachment(boolean)
1495 */
1496 public final ColorAttachment attachColorbuffer(final GL gl, final int attachmentPoint, final boolean alpha) throws GLException {
1497 return attachColorbuffer(gl, attachmentPoint, createColorAttachment(alpha)).getColorAttachment();
1498 }
1499
1500 /**
1501 * Attaches a newly created and {@link Colorbuffer#initialize(GL) initialized} {@link Colorbuffer}, i.e. a {@link ColorAttachment},
1502 * at the given attachment point.
1503 * <p>
1504 * The {@link ColorAttachment} is created using the given {@code internalFormat} and current {@code sample count} and {@code size}.
1505 * </p>
1506 *
1507 * <p>Leaves the FBO bound.</p>
1508 *
1509 * @param gl the current GL context
1510 * @param attachmentPoint the color attachment point ranging from [0..{@link #getMaxColorAttachments()}-1]
1511 * @param internalFormat usually {@link GL#GL_RGBA4}, {@link GL#GL_RGB5_A1}, {@link GL#GL_RGB565}, {@link GL#GL_RGB8} or {@link GL#GL_RGBA8}
1512 * @return ColorAttachment instance describing the new attached colorbuffer if bound and configured successfully, otherwise GLException is thrown
1513 * @throws GLException in case the colorbuffer couldn't be allocated
1514 * @throws IllegalArgumentException if <code>internalFormat</code> doesn't reflect a colorbuffer
1515 */
1516 public final ColorAttachment attachColorbuffer(final GL gl, final int attachmentPoint, final int internalFormat) throws GLException, IllegalArgumentException {
1517 final Attachment.Type atype = Attachment.Type.determine(internalFormat);
1518 if( Attachment.Type.COLOR != atype ) {
1519 throw new IllegalArgumentException("colorformat invalid: "+toHexString(internalFormat)+", "+this);
1520 }
1521
1522 return attachColorbuffer(gl, attachmentPoint, createColorAttachment(internalFormat, samples, width, height)).getColorAttachment();
1523 }
1524
1525 /**
1526 * Attaches a {@link Colorbuffer} at the given attachment point
1527 * and {@link Colorbuffer#initialize(GL) initializes} it, if not done yet.
1528 * <p>
1529 * {@link Colorbuffer} may be a {@link ColorAttachment} or {@link TextureAttachment}.
1530 * </p>
1531 * <p>
1532 * If {@link Colorbuffer} is a {@link TextureAttachment} and is uninitialized, i.e. it's texture name is <code>zero</code>,
1533 * a new texture name is generated and setup w/ the texture parameter.<br/>
1534 * Otherwise, i.e. texture name is not <code>zero</code>, the passed TextureAttachment <code>texA</code> is
1535 * considered complete and assumed matching this FBO requirement. A GL error may occur is the latter is untrue.
1536 * </p>
1537 *
1538 * <p>Leaves the FBO bound.</p>
1539 *
1540 * @param gl
1541 * @param attachmentPoint the color attachment point ranging from [0..{@link #getMaxColorAttachments()}-1]
1542 * @param colbuf the to be attached {@link Colorbuffer}
1543 * @return given {@link Colorbuffer} instance if bound and configured successfully, otherwise GLException is thrown
1544 * @throws GLException in case the colorbuffer couldn't be allocated or MSAA has been chosen in case of a {@link TextureAttachment}
1545 */
1546 public final Colorbuffer attachColorbuffer(final GL gl, final int attachmentPoint, final Colorbuffer colbuf) throws GLException {
1547 bind(gl);
1548 return attachColorbufferImpl(gl, attachmentPoint, colbuf);
1549 }
1550
1551 private final Colorbuffer attachColorbufferImpl(final GL gl, final int attachmentPoint, final Colorbuffer colbuf) throws GLException {
1552 validateAddColorAttachment(attachmentPoint, colbuf);
1553 validateAttachmentSize((Attachment)colbuf);
1554
1555 final boolean initializedColorbuf = colbuf.initialize(gl);
1556 addColorAttachment(attachmentPoint, colbuf, false);
1557
1558 if( colbuf.isTextureAttachment() ) {
1559 final TextureAttachment texA = colbuf.getTextureAttachment();
1560 if( samples > 0 ) {
1561 removeColorAttachment(attachmentPoint, texA);
1562 if( initializedColorbuf ) {
1563 texA.free(gl);
1564 }
1565 throw new GLException("Texture2D not supported w/ MSAA. If you have enabled MSAA with exisiting texture attachments, you may want to detach them via detachAllTexturebuffer(gl).");
1566 }
1567
1568 // Set up the color buffer for use as a renderable texture:
1569 gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER,
1570 GL.GL_COLOR_ATTACHMENT0 + attachmentPoint,
1571 GL.GL_TEXTURE_2D, texA.getName(), 0);
1572
1573 if(!ignoreStatus) {
1574 updateStatus(gl);
1575 if( !isStatusValid() ) {
1576 detachColorbuffer(gl, attachmentPoint, true);
1577 throw new GLException("attachTexture2D "+texA+" at "+attachmentPoint+" failed: "+getStatusString()+", "+this);
1578 }
1579 }
1580 } else {
1581 final ColorAttachment colA = colbuf.getColorAttachment();
1582
1583 // Attach the color buffer
1584 gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER,
1585 GL.GL_COLOR_ATTACHMENT0 + attachmentPoint,
1586 GL.GL_RENDERBUFFER, colA.getName());
1587
1588 if(!ignoreStatus) {
1589 updateStatus(gl);
1590 if( !isStatusValid() ) {
1591 detachColorbuffer(gl, attachmentPoint, true);
1592 throw new GLException("attachColorbuffer "+colA+" at "+attachmentPoint+" failed: "+getStatusString()+", "+this);
1593 }
1594 }
1595 }
1596 if(DEBUG) {
1597 System.err.println("FBObject.attachColorbuffer.X: [attachmentPoint "+attachmentPoint+", colbuf "+colbuf+"]: "+this);
1598 }
1599 return colbuf;
1600 }
1601
1602 private final int getDepthIFormat(final int reqBits) {
1603 if( 32 <= reqBits && depth32Avail ) {
1604 return GL.GL_DEPTH_COMPONENT32;
1605 } else if( 24 <= reqBits && ( depth24Avail || depth32Avail ) ) {
1606 if( depth24Avail ) {
1607 return GL.GL_DEPTH_COMPONENT24;
1608 } else {
1609 return GL.GL_DEPTH_COMPONENT32;
1610 }
1611 } else {
1612 return GL.GL_DEPTH_COMPONENT16;
1613 }
1614 }
1615 private final int getStencilIFormat(final int reqBits) {
1616 if( 16 <= reqBits && stencil16Avail ) {
1617 return GL2GL3.GL_STENCIL_INDEX16;
1618 } else if( 8 <= reqBits && ( stencil08Avail || stencil16Avail ) ) {
1619 if( stencil08Avail ) {
1620 return GL.GL_STENCIL_INDEX8;
1621 } else {
1622 return GL2GL3.GL_STENCIL_INDEX16;
1623 }
1624 } else if( 4 <= reqBits && ( stencil04Avail || stencil08Avail || stencil16Avail ) ) {
1625 if( stencil04Avail ) {
1626 return GL.GL_STENCIL_INDEX4;
1627 } else if( stencil08Avail ) {
1628 return GL.GL_STENCIL_INDEX8;
1629 } else {
1630 return GL2GL3.GL_STENCIL_INDEX16;
1631 }
1632 } else if( 1 <= reqBits && ( stencil01Avail || stencil04Avail || stencil08Avail || stencil16Avail ) ) {
1633 if( stencil01Avail ) {
1634 return GL.GL_STENCIL_INDEX1;
1635 } else if( stencil04Avail ) {
1636 return GL.GL_STENCIL_INDEX4;
1637 } else if( stencil08Avail ) {
1638 return GL.GL_STENCIL_INDEX8;
1639 } else {
1640 return GL2GL3.GL_STENCIL_INDEX16;
1641 }
1642 } else {
1643 throw new GLException("stencil buffer n/a");
1644 }
1645 }
1646
1647 /** Request default bit count for depth- or stencil buffer (depth 24 bits, stencil 8 bits), value {@value} */
1648 public static final int DEFAULT_BITS = 0;
1649
1650 /**
1651 * Request current context drawable's <i>requested</i>
1652 * {@link GLCapabilitiesImmutable#getDepthBits() depth-} or {@link GLCapabilitiesImmutable#getStencilBits() stencil-}bits; value {@value} */
1653 public static final int REQUESTED_BITS = -1;
1654
1655 /**
1656 * Request current context drawable's <i>chosen</i>
1657 * {@link GLCapabilitiesImmutable#getDepthBits() depth-} or {@link GLCapabilitiesImmutable#getStencilBits() stencil-}bits; value {@value} */
1658 public static final int CHOSEN_BITS = -2;
1659
1660 /** Request maximum bit count for depth- or stencil buffer (depth 32 bits, stencil 16 bits), value {@value} */
1661 public static final int MAXIMUM_BITS = -3;
1662
1663
1664 /**
1665 * Attaches one depth, stencil or packed-depth-stencil buffer to this FBO's instance,
1666 * selecting the internalFormat automatically.
1667 * <p>
1668 * Stencil and depth buffer can be attached only once.
1669 * </p>
1670 * <p>
1671 * In case the bit-count is not supported,
1672 * the next available one is chosen, i.e. next higher (preferred) or lower bit-count.
1673 * </p>
1674 * <p>
1675 * Use {@link #getDepthAttachment()} and/or {@link #getStencilAttachment()} to retrieve details
1676 * about the attached buffer. The details cannot be returned, since it's possible 2 buffers
1677 * are being created, depth and stencil.
1678 * </p>
1679 *
1680 * <p>Leaves the FBO bound.</p>
1681 *
1682 * @param gl
1683 * @param atype either {@link Type#DEPTH}, {@link Type#STENCIL} or {@link Type#DEPTH_STENCIL}
1684 * @param reqBits desired bits for depth or stencil,
1685 * may use generic values {@link #DEFAULT_BITS}, {@link #REQUESTED_BITS}, {@link #CHOSEN_BITS} or {@link #MAXIMUM_BITS}.
1686 * @throws GLException in case the renderbuffer couldn't be allocated or one is already attached.
1687 * @throws IllegalArgumentException
1688 * @see #getDepthAttachment()
1689 * @see #getStencilAttachment()
1690 */
1691 public final void attachRenderbuffer(final GL gl, final Attachment.Type atype, final int reqBits) throws GLException, IllegalArgumentException {
1692 final int reqDepth, reqStencil;
1693 if( MAXIMUM_BITS > reqBits ) {
1694 throw new IllegalArgumentException("reqBits out of range, shall be >= "+MAXIMUM_BITS);
1695 } else if( MAXIMUM_BITS == reqBits ) {
1696 reqDepth = 32;
1697 reqStencil = 16;
1698 } else if( CHOSEN_BITS == reqBits ) {
1700 reqDepth = caps.getDepthBits();
1701 reqStencil = caps.getStencilBits();
1702 } else if( REQUESTED_BITS == reqBits ) {
1704 reqDepth = caps.getDepthBits();
1705 reqStencil = caps.getStencilBits();
1706 } else if( DEFAULT_BITS == reqBits ) {
1707 reqDepth = 24;
1708 reqStencil = 8;
1709 } else {
1710 reqDepth = reqBits;
1711 reqStencil = reqBits;
1712 }
1713 final int internalFormat;
1714 int internalStencilFormat = -1;
1715
1716 switch ( atype ) {
1717 case DEPTH:
1718 internalFormat = getDepthIFormat(reqDepth);
1719 break;
1720
1721 case STENCIL:
1722 internalFormat = getStencilIFormat(reqStencil);
1723 break;
1724
1725 case DEPTH_STENCIL:
1726 if( packedDepthStencilAvail ) {
1727 internalFormat = GL.GL_DEPTH24_STENCIL8;
1728 } else {
1729 internalFormat = getDepthIFormat(reqDepth);
1730 internalStencilFormat = getStencilIFormat(reqStencil);
1731 }
1732 break;
1733 default:
1734 throw new IllegalArgumentException("only depth/stencil types allowed, was "+atype+", "+this);
1735 }
1736 attachRenderbufferImpl(gl, atype, internalFormat);
1737
1738 if(0<=internalStencilFormat) {
1739 attachRenderbufferImpl(gl, Attachment.Type.STENCIL, internalStencilFormat);
1740 }
1741 }
1742
1743 /**
1744 * Attaches one depth, stencil or packed-depth-stencil buffer to this FBO's instance,
1745 * depending on the <code>internalFormat</code>.
1746 * <p>
1747 * Stencil and depth buffer can be attached only once.
1748 * </p>
1749 * <p>
1750 * Use {@link #getDepthAttachment()} and/or {@link #getStencilAttachment()} to retrieve details
1751 * about the attached buffer. The details cannot be returned, since it's possible 2 buffers
1752 * are being created, depth and stencil.
1753 * </p>
1754 *
1755 * <p>Leaves the FBO bound.</p>
1756 *
1757 * @param gl the current GL context
1758 * @param internalFormat {@link GL#GL_DEPTH_COMPONENT16}, {@link GL#GL_DEPTH_COMPONENT24}, {@link GL#GL_DEPTH_COMPONENT32},
1759 * {@link GL#GL_STENCIL_INDEX1}, {@link GL#GL_STENCIL_INDEX4}, {@link GL#GL_STENCIL_INDEX8}
1760 * or {@link GL#GL_DEPTH24_STENCIL8}
1761 * @throws GLException in case the renderbuffer couldn't be allocated or one is already attached.
1762 * @throws IllegalArgumentException
1763 * @see #getDepthAttachment()
1764 * @see #getStencilAttachment()
1765 */
1766 public final void attachRenderbuffer(final GL gl, final int internalFormat) throws GLException, IllegalArgumentException {
1767 final Attachment.Type atype = Attachment.Type.determine(internalFormat);
1768 if( Attachment.Type.DEPTH != atype && Attachment.Type.STENCIL != atype && Attachment.Type.DEPTH_STENCIL != atype ) {
1769 throw new IllegalArgumentException("renderformat invalid: "+toHexString(internalFormat)+", "+this);
1770 }
1771 attachRenderbufferImpl(gl, atype, internalFormat);
1772 }
1773
1774 protected final void attachRenderbufferImpl(final GL gl, final Attachment.Type atype, final int internalFormat) throws GLException {
1775 if( null != depth && ( Attachment.Type.DEPTH == atype || Attachment.Type.DEPTH_STENCIL == atype ) ) {
1776 throw new GLException("FBO depth buffer already attached (rb "+depth+"), type is "+atype+", "+toHexString(internalFormat)+", "+this);
1777 }
1778 if( null != stencil && ( Attachment.Type.STENCIL== atype || Attachment.Type.DEPTH_STENCIL == atype ) ) {
1779 throw new GLException("FBO stencil buffer already attached (rb "+stencil+"), type is "+atype+", "+toHexString(internalFormat)+", "+this);
1780 }
1781 bind(gl);
1782
1783 attachRenderbufferImpl2(gl, atype, internalFormat);
1784 }
1785
1786 private final void attachRenderbufferImpl2(final GL gl, final Attachment.Type atype, final int internalFormat) throws GLException {
1787 // atype and current depth and stencil instance are already validated in 'attachRenderbufferImpl(..)'
1788 if( Attachment.Type.DEPTH == atype ) {
1789 if(null == depth) {
1790 depth = createRenderAttachment(Type.DEPTH, internalFormat, samples, width, height);
1791 } else {
1792 depth.setSize(width, height);
1793 depth.setSamples(samples);
1794 }
1795 validateAttachmentSize(depth);
1796 depth.initialize(gl);
1797 } else if( Attachment.Type.STENCIL == atype ) {
1798 if(null == stencil) {
1799 stencil = createRenderAttachment(Type.STENCIL, internalFormat, samples, width, height);
1800 } else {
1801 stencil.setSize(width, height);
1802 stencil.setSamples(samples);
1803 }
1804 validateAttachmentSize(stencil);
1805 stencil.initialize(gl);
1806 } else if( Attachment.Type.DEPTH_STENCIL == atype ) {
1807 if(null == depth) {
1808 if(null != stencil) {
1809 throw new InternalError("XXX: DEPTH_STENCIL, depth was null, stencil not: "+this.toString());
1810 }
1811 depth = createRenderAttachment(Type.DEPTH_STENCIL, internalFormat, samples, width, height);
1812 } else {
1813 depth.setSize(width, height);
1814 depth.setSamples(samples);
1815 }
1816 validateAttachmentSize(depth);
1817 depth.initialize(gl);
1818 // DEPTH_STENCIL shares buffer w/ depth and stencil
1819 stencil = depth;
1820 }
1821
1822 // Attach the buffer
1823 if( Attachment.Type.DEPTH == atype ) {
1824 gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, GL.GL_RENDERBUFFER, depth.getName());
1825 } else if( Attachment.Type.STENCIL == atype ) {
1826 gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_STENCIL_ATTACHMENT, GL.GL_RENDERBUFFER, stencil.getName());
1827 } else if( Attachment.Type.DEPTH_STENCIL == atype ) {
1828 gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, GL.GL_RENDERBUFFER, depth.getName());
1829 gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_STENCIL_ATTACHMENT, GL.GL_RENDERBUFFER, stencil.getName());
1830 }
1831
1832 modified = true;
1833
1834 if(!ignoreStatus) {
1835 updateStatus(gl);
1836 if( !isStatusValid() ) {
1837 detachRenderbuffer(gl, atype, true);
1838 throw new GLException("renderbuffer [attachmentType "+atype+", iformat "+toHexString(internalFormat)+"] failed: "+this.getStatusString()+", "+this.toString());
1839 }
1840 }
1841
1842 if(DEBUG) {
1843 System.err.println("FBObject.attachRenderbuffer.X: [attachmentType "+atype+", iformat "+toHexString(internalFormat)+"]: "+this);
1844 }
1845 }
1846
1847 /**
1848 * Detaches a {@link Colorbuffer}, i.e. {@link ColorAttachment} or {@link TextureAttachment}.
1849 * <p>Leaves the FBO bound!</p>
1850 *
1851 * @param gl
1852 * @param attachmentPoint
1853 * @param dispose true if the Colorbuffer shall be disposed
1854 * @return the detached Colorbuffer
1855 * @throws IllegalArgumentException
1856 */
1857 public final Colorbuffer detachColorbuffer(final GL gl, final int attachmentPoint, final boolean dispose) throws IllegalArgumentException {
1858 bind(gl);
1859
1860 final Colorbuffer res = detachColorbufferImpl(gl, attachmentPoint, dispose ? DetachAction.DISPOSE : DetachAction.NONE, 0);
1861 if(null == res) {
1862 throw new IllegalArgumentException("ColorAttachment at "+attachmentPoint+", not attached, "+this);
1863 }
1864 if(DEBUG) {
1865 System.err.println("FBObject.detachColorbuffer.X: [attachmentPoint "+attachmentPoint+", dispose "+dispose+"]: "+res+", "+this);
1866 }
1867 return res;
1868 }
1869
1870 private final Colorbuffer detachColorbufferImpl(final GL gl, final int attachmentPoint, final DetachAction detachAction, final int sampleCountChange) {
1871 final Colorbuffer colbufOld = colorbufferAttachments[attachmentPoint]; // shortcut, don't validate here
1872
1873 if(null == colbufOld) {
1874 return null;
1875 }
1876
1877 removeColorAttachment(attachmentPoint, colbufOld);
1878
1879 if( colbufOld.isTextureAttachment() ) {
1880 final TextureAttachment texA = colbufOld.getTextureAttachment();
1881 if( 0 != texA.getName() ) {
1882 gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER,
1883 GL.GL_COLOR_ATTACHMENT0 + attachmentPoint,
1884 GL.GL_TEXTURE_2D, 0, 0);
1885 gl.glBindTexture(GL.GL_TEXTURE_2D, 0);
1886 switch(detachAction) {
1887 case DISPOSE:
1888 case RECREATE:
1889 texA.free(gl);
1890 break;
1891 default:
1892 }
1893 }
1894 if(DetachAction.RECREATE == detachAction) {
1895 final Colorbuffer colbufNew;
1896 if( 0 < sampleCountChange ) {
1897 // switch to MSAA: TextureAttachment -> ColorAttachment
1898 colbufNew = createColorAttachment(hasAlpha(texA.format));
1899 } else {
1900 // keep MSAA settings
1901 texA.setSize(width, height);
1902 colbufNew = texA;
1903 }
1904 attachColorbufferImpl(gl, attachmentPoint, colbufNew);
1905 }
1906 } else {
1907 final ColorAttachment colA = colbufOld.getColorAttachment();
1908 if( 0 != colA.getName() ) {
1909 gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER,
1910 GL.GL_COLOR_ATTACHMENT0+attachmentPoint,
1911 GL.GL_RENDERBUFFER, 0);
1912 switch(detachAction) {
1913 case DISPOSE:
1914 case RECREATE:
1915 colA.free(gl);
1916 break;
1917 default:
1918 }
1919 }
1920 if(DetachAction.RECREATE == detachAction) {
1921 final Colorbuffer colbufNew;
1922 if( 0 <= sampleCountChange || null == samplingColorSink ) {
1923 // keep ColorAttachment,
1924 // including 'switch to non-MSAA' if no samplingColorSink is available
1925 // to determine whether a TextureAttachment or ColorAttachment is desired!
1926 colA.setSize(width, height);
1927 colA.setSamples(samples);
1928 colbufNew = colA;
1929 } else {
1930 // switch to non MSAA
1931 if( samplingColorSink.isTextureAttachment() ) {
1932 final TextureAttachment samplingTextureSink = samplingColorSink.getTextureAttachment();
1933 colbufNew = createColorTextureAttachment(samplingTextureSink.format, width, height,
1934 samplingTextureSink.dataFormat, samplingTextureSink.dataType,
1935 samplingTextureSink.magFilter, samplingTextureSink.minFilter,
1936 samplingTextureSink.wrapS, samplingTextureSink.wrapT);
1937 } else {
1938 colbufNew = createColorAttachment(samplingColorSink.getFormat(), 0, width, height);
1939 }
1940 }
1941 attachColorbuffer(gl, attachmentPoint, colbufNew);
1942 }
1943 }
1944 return colbufOld;
1945 }
1946
1947 private final void freeAllColorbufferImpl(final GL gl) {
1948 for(int i=0; i<maxColorAttachments; i++) {
1949 final Colorbuffer colbuf = colorbufferAttachments[i]; // shortcut, don't validate here
1950
1951 if(null == colbuf) {
1952 return;
1953 }
1954
1955 if( colbuf.isTextureAttachment() ) {
1956 final TextureAttachment texA = colbuf.getTextureAttachment();
1957 if( 0 != texA.getName() ) {
1958 gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER,
1959 GL.GL_COLOR_ATTACHMENT0 + i,
1960 GL.GL_TEXTURE_2D, 0, 0);
1961 gl.glBindTexture(GL.GL_TEXTURE_2D, 0);
1962 }
1963 texA.free(gl);
1964 } else {
1965 final ColorAttachment colA = colbuf.getColorAttachment();
1966 if( 0 != colA.getName() ) {
1967 gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER,
1968 GL.GL_COLOR_ATTACHMENT0 + i,
1969 GL.GL_RENDERBUFFER, 0);
1970 }
1971 colA.free(gl);
1972 }
1973 }
1974 }
1975
1976 /**
1977 *
1978 * @param gl
1979 * @param dispose true if the Colorbuffer shall be disposed
1980 * @param reqAType {@link Type#DEPTH}, {@link Type#DEPTH} or {@link Type#DEPTH_STENCIL}
1981 */
1982 public final void detachRenderbuffer(final GL gl, final Attachment.Type atype, final boolean dispose) throws IllegalArgumentException {
1983 bind(gl);
1984 final RenderAttachment res = detachRenderbufferImpl(gl, atype, dispose ? DetachAction.DISPOSE : DetachAction.NONE);
1985 if(null == res) {
1986 throw new IllegalArgumentException("RenderAttachment type "+atype+", not attached, "+this);
1987 }
1988 if(DEBUG) {
1989 System.err.println("FBObject.detachRenderbuffer.X: [attachmentType "+atype+", dispose "+dispose+"]: "+this);
1990 }
1991 }
1992
1993 public final boolean isDepthStencilPackedFormat() {
1994 final boolean res = null != depth && null != stencil &&
1995 depth.format == stencil.format ;
1996 if(res) {
1997 if(depth.getName() != stencil.getName() ) {
1998 throw new InternalError("depth/stencil packed format not sharing: depth "+depth+", stencil "+stencil);
1999 }
2000 if(depth != stencil) {
2001 throw new InternalError("depth/stencil packed format not a shared reference: depth "+depth+", stencil "+stencil);
2002 }
2003 }
2004 return res;
2005 }
2006
2007 private final RenderAttachment detachRenderbufferImpl(final GL gl, Attachment.Type atype, final DetachAction detachAction) throws IllegalArgumentException {
2008 switch ( atype ) {
2009 case DEPTH:
2010 case STENCIL:
2011 case DEPTH_STENCIL:
2012 break;
2013 default:
2014 throw new IllegalArgumentException("only depth/stencil types allowed, was "+atype+", "+this);
2015 }
2016 if( null == depth && null == stencil ) {
2017 return null; // nop
2018 }
2019 final boolean packed = isDepthStencilPackedFormat();
2020 if( packed ) {
2021 // Note: DEPTH_STENCIL shares buffer w/ depth and stencil
2022 atype = Attachment.Type.DEPTH_STENCIL;
2023 }
2024 final RenderAttachment renderOld;
2025 switch ( atype ) {
2026 case DEPTH:
2027 renderOld = depth;
2028 if( null != renderOld ) {
2029 final int format = renderOld.format;
2030 if( 0 != renderOld.getName() ) {
2031 gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, GL.GL_RENDERBUFFER, 0);
2032 switch(detachAction) {
2033 case DISPOSE:
2034 case RECREATE:
2035 renderOld.free(gl);
2036 break;
2037 default:
2038 }
2039 }
2040 if(DetachAction.RECREATE == detachAction) {
2041 attachRenderbufferImpl2(gl, atype, format);
2042 } else {
2043 depth = null;
2044 }
2045 }
2046 break;
2047 case STENCIL:
2048 renderOld = stencil;
2049 if( null != renderOld ) {
2050 final int format = renderOld.format;
2051 if(0 != renderOld.getName()) {
2052 gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_STENCIL_ATTACHMENT, GL.GL_RENDERBUFFER, 0);
2053 switch(detachAction) {
2054 case DISPOSE:
2055 case RECREATE:
2056 renderOld.free(gl);
2057 break;
2058 default:
2059 }
2060 }
2061 if(DetachAction.RECREATE == detachAction) {
2062 attachRenderbufferImpl2(gl, atype, format);
2063 } else {
2064 stencil = null;
2065 }
2066 }
2067 break;
2068 case DEPTH_STENCIL:
2069 renderOld = depth;
2070 if( null != renderOld ) {
2071 final int format = renderOld.format;
2072 if(0 != renderOld.getName()) {
2073 gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, GL.GL_RENDERBUFFER, 0);
2074 if(packed) {
2075 gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_STENCIL_ATTACHMENT, GL.GL_RENDERBUFFER, 0);
2076 }
2077 switch(detachAction) {
2078 case DISPOSE:
2079 case RECREATE:
2080 renderOld.free(gl);
2081 break;
2082 default:
2083 }
2084 }
2085 if(DetachAction.RECREATE == detachAction) {
2086 attachRenderbufferImpl2(gl, packed ? Attachment.Type.DEPTH_STENCIL : Attachment.Type.DEPTH, format);
2087 } else {
2088 depth = null;
2089 if(packed) {
2090 stencil = null;
2091 }
2092 }
2093 }
2094 if( !packed && null != stencil ) {
2095 final int format = stencil.format;
2096 if(0 != stencil.getName()) {
2097 gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_STENCIL_ATTACHMENT, GL.GL_RENDERBUFFER, 0);
2098 switch(detachAction) {
2099 case DISPOSE:
2100 case RECREATE:
2101 stencil.free(gl);
2102 break;
2103 default:
2104 }
2105 }
2106 if(DetachAction.RECREATE == detachAction) {
2107 attachRenderbufferImpl2(gl, Attachment.Type.STENCIL, format);
2108 } else {
2109 stencil = null;
2110 }
2111 }
2112 break;
2113 default:
2114 throw new InternalError("XXX"); // handled by caller
2115 }
2116 modified = true;
2117 return renderOld;
2118 }
2119
2120 private final void freeAllRenderbufferImpl(final GL gl) throws IllegalArgumentException {
2121 // Note: DEPTH_STENCIL shares buffer w/ depth and stencil
2122 final boolean packed = isDepthStencilPackedFormat();
2123 if( null != depth ) {
2124 if(0 != depth.getName()) {
2125 gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, GL.GL_RENDERBUFFER, 0);
2126 if(packed) {
2127 gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_STENCIL_ATTACHMENT, GL.GL_RENDERBUFFER, 0);
2128 }
2129 depth.free(gl);
2130 }
2131 }
2132 if( !packed && null != stencil ) {
2133 if(0 != stencil.getName()) {
2134 gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_STENCIL_ATTACHMENT, GL.GL_RENDERBUFFER, 0);
2135 stencil.free(gl);
2136 }
2137 }
2138 }
2139
2140 /**
2141 * Detaches all {@link ColorAttachment}s, {@link TextureAttachment}s and {@link RenderAttachment}s
2142 * and disposes them.
2143 * <p>Leaves the FBO bound, if initialized!</p>
2144 * <p>
2145 * An attached sampling sink texture will be detached as well, see {@link #getSamplingTextureSink()}.
2146 * </p>
2147 * @param gl the current GL context
2148 */
2149 public final void detachAll(final GL gl) {
2150 if(null != samplingSink) {
2151 samplingSink.detachAll(gl);
2152 }
2153 detachAllImpl(gl, true/* detachNonColorbuffer */, false /* recreate */, 0);
2154 }
2155
2156 /**
2157 * Detaches all {@link ColorAttachment}s and {@link TextureAttachment}s
2158 * and disposes them.
2159 * <p>Leaves the FBO bound, if initialized!</p>
2160 * <p>
2161 * An attached sampling sink texture will be detached as well, see {@link #getSamplingTextureSink()}.
2162 * </p>
2163 * @param gl the current GL context
2164 */
2165 public final void detachAllColorbuffer(final GL gl) {
2166 if(null != samplingSink) {
2167 samplingSink.detachAllColorbuffer(gl);
2168 }
2169 detachAllImpl(gl, false/* detachNonColorbuffer */, false /* recreate */, 0);
2170 }
2171
2172 /**
2173 * Detaches all {@link TextureAttachment}s and disposes them.
2174 * <p>Leaves the FBO bound, if initialized!</p>
2175 * <p>
2176 * An attached sampling sink texture will be detached as well, see {@link #getSamplingTextureSink()}.
2177 * </p>
2178 * @param gl the current GL context
2179 */
2180 public final void detachAllTexturebuffer(final GL gl) {
2181 if( !isInitialized() ) {
2182 return;
2183 }
2184 if(null != samplingSink) {
2185 samplingSink.detachAllTexturebuffer(gl);
2186 }
2187 bind(gl);
2188 for(int i=0; i<maxColorAttachments; i++) {
2189 if( colorbufferAttachments[i].isTextureAttachment() ) {
2190 detachColorbufferImpl(gl, i, DetachAction.DISPOSE, 0);
2191 }
2192 }
2193 if(DEBUG) {
2194 System.err.println("FBObject.detachAllTexturebuffer.X: "+this);
2195 }
2196 }
2197
2198 public final void detachAllRenderbuffer(final GL gl) {
2199 if( !isInitialized() ) {
2200 return;
2201 }
2202 if(null != samplingSink) {
2203 samplingSink.detachAllRenderbuffer(gl);
2204 }
2205 bind(gl);
2206 detachRenderbufferImpl(gl, Attachment.Type.DEPTH_STENCIL, DetachAction.DISPOSE);
2207 }
2208
2209 private final void detachAllImpl(final GL gl, final boolean detachNonColorbuffer, final boolean recreate, final int sampleCountChange) {
2210 if( !isInitialized() ) {
2211 return;
2212 }
2213 ignoreStatus = recreate; // ignore status on single calls only if recreate -> reset
2214 try {
2215 bind(gl);
2216 if(FBOResizeQuirk) {
2217 if(detachNonColorbuffer && recreate) {
2218 // free all colorbuffer & renderbuffer 1st
2219 freeAllColorbufferImpl(gl);
2220 freeAllRenderbufferImpl(gl);
2221 }
2222 }
2223 for(int i=0; i<maxColorAttachments; i++) {
2224 detachColorbufferImpl(gl, i, recreate ? DetachAction.RECREATE : DetachAction.DISPOSE, sampleCountChange);
2225 }
2226 if( !recreate && colorbufferCount>0 ) {
2227 throw new InternalError("Non zero ColorAttachments "+this);
2228 }
2229
2230 if(detachNonColorbuffer) {
2231 detachRenderbufferImpl(gl, Attachment.Type.DEPTH_STENCIL, recreate ? DetachAction.RECREATE : DetachAction.DISPOSE);
2232 }
2233 if(ignoreStatus) { // post validate
2234 /* if(true) {
2235 throw new GLException("Simulating bug 617, reset FBO failure");
2236 } */
2237 updateStatus(gl);
2238 if(!isStatusValid()) {
2239 throw new GLException("detachAllImpl failed: "+getStatusString()+", "+this);
2240 }
2241 }
2242 } finally {
2243 ignoreStatus = false;
2244 }
2245 if(DEBUG) {
2246 System.err.println("FBObject.detachAll.X: [resetNonColorbuffer "+detachNonColorbuffer+", recreate "+recreate+"]: "+this);
2247 }
2248 }
2249
2250 /**
2251 * @param gl the current GL context
2252 */
2253 public final void destroy(final GL gl) {
2254 if(!initialized) {
2255 return;
2256 }
2257 if(DEBUG) {
2258 System.err.println("FBObject.destroy.0: "+this);
2259 // Thread.dumpStack();
2260 }
2261 if( null != samplingSink && samplingSink.isInitialized() ) {
2262 samplingSink.destroy(gl);
2263 }
2264
2265 detachAllImpl(gl, true /* detachNonColorbuffer */, false /* recreate */, 0);
2266
2267 // cache FB names, preset exposed to zero,
2268 // braking ties w/ GL/GLContext link to getReadFramebuffer()/getWriteFramebuffer()
2269 final int fb_cache = fbName;
2270 fbName = 0;
2271
2272 final int name[] = new int[1];
2273 if(0!=fb_cache) {
2274 name[0] = fb_cache;
2275 gl.glDeleteFramebuffers(1, name, 0);
2276 }
2277 initialized = false;
2278 bound = false;
2279 if(DEBUG) {
2280 System.err.println("FBObject.destroy.X: "+this);
2281 }
2282 }
2283
2284 private final boolean sampleSinkSizeMismatch() {
2285 return samplingSink.getWidth() != width || samplingSink.getHeight() != height ;
2286 }
2287 private final boolean sampleSinkDepthStencilMismatch() {
2288 if ( ( null != depth && ( null == samplingSink.depth || depth.format != samplingSink.depth.format ) )
2289 ||
2290 ( null == depth && null != samplingSink.depth )
2291 ) {
2292 return true;
2293 }
2294
2295 if ( ( null != stencil && ( null == samplingSink.stencil || stencil.format != samplingSink.stencil.format ) )
2296 ||
2297 ( null == stencil && null != samplingSink.stencil )
2298 ) {
2299 return true;
2300 }
2301
2302 return false;
2303 }
2304 /**
2305 * For GLES3, sampling-sink {@link Colorbuffer} <i>internal format</i> <b>must be equal</b> w/ the sampling-source {@link Colorbuffer}.
2306 * Implementation aligns w/ {@link #createColorTextureAttachment(GLProfile, boolean, int, int, int, int, int, int)}
2307 * and {@link #createColorAttachment(boolean)}.
2308 */
2309 private final boolean sampleSinkExFormatMismatch(final GL gl) {
2310 if( null != samplingColorSink && getColorbufferCount() > 0 && gl.isGL2ES3() ) {
2311 final Attachment ca = (Attachment)getColorbuffer(0); // should be at attachment-point 0
2312 // We cannot comply w/ attachment's format other than attachment point 0!
2313 // return ( null != ca && ca.format != samplingColorSink.getFormat() ) ||
2314 // hasAlpha(samplingColorSink.getFormat()) != hasAttachmentUsingAlpha();
2315 return null != ca && ca.format != samplingColorSink.getFormat();
2316 }
2317 return false;
2318 }
2319
2320 /**
2321 * Manually validates the MSAA sampling sink, if used.
2322 * <p>
2323 * If MSAA is being used and no sampling sink is attached via {@link #setSamplingSink(FBObject)}
2324 * a new sampling sink is being created.
2325 * </p>
2326 * <p>
2327 * If the sampling sink size or attributes differs from the source, its attachments are reset
2328 * to match the source.
2329 * </p>
2330 * <p>
2331 * Automatically called by {@link #reset(GL, int, int, int, boolean)}
2332 * and {@link #syncSamplingSink(GL)}.
2333 * </p>
2334 * <p>
2335 * It is recommended to call this method after initializing the FBO and attaching renderbuffer etc for the 1st time
2336 * if access to sampling sink resources is required.
2337 * </p>
2338 *
2339 * <p>Leaves the FBO bound state untouched</p>
2340 *
2341 * @param gl the current GL context
2342 * @return {@code true} if this instance has been modified, otherwise {@code false}.
2343 * @throws GLException in case of an error, i.e. size too big, etc ..
2344 */
2345 public final boolean resetSamplingSink(final GL gl) throws GLException {
2346 if(DEBUG) {
2347 System.err.println("FBObject.resetSamplingSink.0");
2348 ExceptionUtils.dumpStack(System.err);
2349 }
2350
2351 if( 0 == samples ) {
2352 final boolean modifiedInstance;
2353 // MSAA off
2354 if( null != samplingSink ) {
2355 // cleanup
2356 if( samplingSink.initialized ) {
2357 samplingSink.detachAll(gl);
2358 }
2359 samplingSink = null;
2360 samplingColorSink = null;
2361 modifiedInstance = true;
2362 } else {
2363 modifiedInstance = false;
2364 }
2365 this.modified = false;
2366 if(DEBUG) {
2367 System.err.println("FBObject.resetSamplingSink.X1: zero samples, mod "+modifiedInstance+"\n\tTHIS "+this);
2368 }
2369 return modifiedInstance;
2370 }
2371
2372 boolean modifiedInstance = false;
2373
2374 if( null == samplingSink ) {
2375 samplingSink = new FBObject();
2376 samplingSink.init(gl, width, height, 0);
2377 samplingColorSink = null;
2378 modifiedInstance = true;
2379 } else if( !samplingSink.initialized ) {
2380 throw new InternalError("InitState Mismatch: samplingSink set, but not initialized "+samplingSink);
2381 } else if( null == samplingColorSink || 0 == samplingColorSink.getName() ) {
2382 throw new InternalError("InitState Mismatch: samplingColorSink set, but not initialized "+samplingColorSink+", "+samplingSink);
2383 }
2384
2385 if(DEBUG) {
2386 System.err.println("FBObject.resetSamplingSink.1: mod "+modifiedInstance+"\n\tTHIS "+this+",\n\tSINK "+samplingSink);
2387 }
2388 boolean sampleSinkExFormatMismatch = sampleSinkExFormatMismatch(gl);
2389 boolean sampleSinkSizeMismatch = sampleSinkSizeMismatch();
2390 boolean sampleSinkDepthStencilMismatch = sampleSinkDepthStencilMismatch();
2391
2392 if( modifiedInstance ) {
2393 // samplingColorSink == null
2394 // must match size, format and colorbuffer do not exist yet
2395 if( sampleSinkExFormatMismatch || sampleSinkSizeMismatch ) {
2396 throw new InternalError("InitState Mismatch: Matching exFormat "+!sampleSinkExFormatMismatch+
2397 ", size "+!sampleSinkSizeMismatch +", "+this);
2398 }
2399 } else {
2400 // samplingColorSink != null
2401 if(!sampleSinkExFormatMismatch && !sampleSinkSizeMismatch && !sampleSinkDepthStencilMismatch) {
2402 if(DEBUG) {
2403 System.err.println("FBObject.resetSamplingSink.X2: Matching: exFormat "+!sampleSinkExFormatMismatch+
2404 ", size "+!sampleSinkSizeMismatch +", depthStencil "+!sampleSinkDepthStencilMismatch+
2405 ", mod "+modifiedInstance);
2406 }
2407 // all properties match ..
2408 samplingSink.modified = false;
2409 this.modified = false;
2410 return modifiedInstance;
2411 }
2412 }
2413
2414 final boolean wasBound;
2415 if( isBound() ) {
2416 markUnbound(); // automatic GL unbind by sampleSink binding
2417 wasBound = true;
2418 } else {
2419 wasBound = false;
2420 }
2421
2422 if(DEBUG) {
2423 System.err.println("FBObject.resetSamplingSink.2: wasBound "+wasBound+", matching: exFormat "+!sampleSinkExFormatMismatch+
2424 ", size "+!sampleSinkSizeMismatch +", depthStencil "+!sampleSinkDepthStencilMismatch);
2425 }
2426
2427 modifiedInstance = true;
2428
2429 if( sampleSinkDepthStencilMismatch ) { // includes 1st init
2430 samplingSink.detachAllRenderbuffer(gl);
2431 }
2432
2433 final boolean samplingColorSinkShallBeTA = null == samplingColorSink || samplingColorSink.isTextureAttachment();
2434
2435 if( sampleSinkExFormatMismatch ) {
2436 samplingSink.detachAllColorbuffer(gl);
2437 samplingColorSink = null;
2438 } else if( sampleSinkSizeMismatch ) {
2439 samplingSink.resetSizeImpl(gl, width, height);
2440 samplingColorSink = samplingSink.getColorbuffer(0);
2441 }
2442
2443 if( null == samplingColorSink ) { // sampleSinkFormatMismatch || 1st init
2444 final Colorbuffer cb0 = getColorbuffer(0); // align with colorbuffer at attachment-point 0
2445 if( null != cb0 ) {
2446 // match pre-existing format
2447 if( samplingColorSinkShallBeTA ) {
2448 samplingColorSink = createColorTextureAttachment(gl, cb0.getFormat(), width, height,
2451 } else {
2452 samplingColorSink = createColorAttachment(cb0.getFormat(), 0, width, height);
2453 }
2454 samplingSink.attachColorbuffer(gl, 0, samplingColorSink);
2455 } else {
2456 // match default format
2457 final boolean hasAlpha = hasAttachmentUsingAlpha();
2458 if( samplingColorSinkShallBeTA ) {
2459 samplingColorSink = samplingSink.attachTexture2D(gl, 0, hasAlpha);
2460 } else {
2461 samplingColorSink = samplingSink.attachColorbuffer(gl, 0, hasAlpha);
2462 }
2463 }
2464 }
2465
2466 if( sampleSinkDepthStencilMismatch ) { // includes 1st init
2467 samplingSink.attachRenderbuffer(gl, depth.format);
2468 if( null != stencil && !isDepthStencilPackedFormat() ) {
2469 samplingSink.attachRenderbuffer(gl, stencil.format);
2470 }
2471 }
2472
2473 sampleSinkExFormatMismatch = sampleSinkExFormatMismatch(gl);
2474 sampleSinkSizeMismatch = sampleSinkSizeMismatch();
2475 sampleSinkDepthStencilMismatch = sampleSinkDepthStencilMismatch();
2476 if(sampleSinkExFormatMismatch || sampleSinkSizeMismatch || sampleSinkDepthStencilMismatch) {
2477 throw new InternalError("Samples sink mismatch after reset: \n\tTHIS "+this+",\n\t SINK "+samplingSink+
2478 "\n\t Mismatch. Matching: exFormat "+!sampleSinkExFormatMismatch+
2479 ", size "+!sampleSinkSizeMismatch +", depthStencil "+!sampleSinkDepthStencilMismatch);
2480 }
2481
2482 samplingSink.modified = false;
2483 samplingSink.unbind(gl);
2484 this.modified = false;
2485
2486 if(wasBound) {
2487 bind(gl);
2488 }
2489
2490 if(DEBUG) {
2491 System.err.println("FBObject.resetSamplingSink.XX: END mod "+modifiedInstance+"\n\tTHIS "+this+",\n\tSINK "+samplingSink+
2492 "\n\t Matching: exFormat "+!sampleSinkExFormatMismatch+
2493 ", size "+!sampleSinkSizeMismatch +", depthStencil "+!sampleSinkDepthStencilMismatch);
2494 }
2495 return modifiedInstance;
2496 }
2497
2498 /**
2499 * Setting this FBO sampling sink.
2500 * @param newSamplingSink the new and initialized FBO sampling sink to use, or null to remove current sampling sink
2501 * @return the previous sampling sink or null if none was attached
2502 * @throws GLException if this FBO doesn't use MSAA or the given sink uses MSAA itself
2503 * @throws IllegalStateException if the {@code newSamplingSink} is not null and not initialized
2504 */
2505 public FBObject setSamplingSink(final FBObject newSamplingSink) throws IllegalStateException, GLException {
2506 final FBObject prev = samplingSink;
2507 if( null == newSamplingSink) {
2508 samplingSink = null;
2509 samplingColorSink = null;
2510 } else if( samples > 0 ) {
2511 if( !newSamplingSink.isInitialized() ) {
2512 throw new IllegalStateException("SamplingSink not initialized: "+newSamplingSink);
2513 }
2514 if( newSamplingSink.getNumSamples() > 0 ) {
2515 throw new GLException("SamplingSink FBO cannot use MSAA itself: "+newSamplingSink);
2516 }
2517 samplingSink = newSamplingSink;
2518 samplingColorSink = newSamplingSink.getColorbuffer(0);
2519 } else {
2520 throw new GLException("Setting SamplingSink for non MSAA FBO not allowed: "+this);
2521 }
2522 modified = true;
2523 samplingSinkDirty = true;
2524 return prev;
2525 }
2526
2527 /**
2528 * Bind this FBO, i.e. bind write framebuffer to {@link #getWriteFramebuffer()}.
2529 *
2530 * <p>
2531 * If multisampling is used, it sets the read framebuffer to the sampling sink {@link #getWriteFramebuffer()}.
2532 * </p>
2533 * <p>
2534 * In case you have attached more than one color buffer,
2535 * you may want to setup {@link GL2ES3#glDrawBuffers(int, int[], int)}.
2536 * </p>
2537 * @param gl the current GL context
2538 * @throws GLException
2539 */
2540 public final void bind(final GL gl) throws GLException {
2541 if(!bound || fbName != gl.getBoundFramebuffer(GL.GL_FRAMEBUFFER)) {
2542 checkInitialized();
2543 if( fullFBOSupport ) {
2544 gl.glBindFramebuffer(GL.GL_DRAW_FRAMEBUFFER, getWriteFramebuffer()); // this fb, msaa or normal
2545 gl.glBindFramebuffer(GL.GL_READ_FRAMEBUFFER, getReadFramebuffer()); // msaa: sampling sink, normal: this fb
2546 } else {
2547 gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, getWriteFramebuffer()); // normal: read/write
2548 }
2549 bound = true;
2550 samplingSinkDirty = true;
2551 }
2552 }
2553
2554 /**
2555 * Unbind this FBO, i.e. bind read and write framebuffer to default, see {@link GLBase#getDefaultDrawFramebuffer()}.
2556 *
2557 * <p>If full FBO is supported, sets the read and write framebuffer individually to default, hence not disturbing
2558 * an optional operating MSAA FBO, see {@link GLBase#getDefaultReadFramebuffer()} and {@link GLBase#getDefaultDrawFramebuffer()}</p>
2559 *
2560 * @param gl the current GL context
2561 * @throws GLException
2562 */
2563 public final void unbind(final GL gl) throws GLException {
2564 if(bound) {
2565 if(fullFBOSupport) {
2566 // default read/draw buffers, may utilize GLContext/GLDrawable override of
2567 // GLContext.getDefaultDrawFramebuffer() and GLContext.getDefaultReadFramebuffer()
2568 gl.glBindFramebuffer(GL.GL_DRAW_FRAMEBUFFER, 0);
2569 gl.glBindFramebuffer(GL.GL_READ_FRAMEBUFFER, 0);
2570 } else {
2571 gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0); // default draw buffer
2572 }
2573 bound = false;
2574 }
2575 }
2576
2577 /**
2578 * Method simply marks this FBO unbound w/o interfering w/ the bound framebuffer as perfomed by {@link #unbind(GL)}.
2579 * <p>
2580 * Only use this method if a subsequent {@link #unbind(GL)}, {@link #use(GL, TextureAttachment)} or {@link #bind(GL)}
2581 * follows on <i>any</i> FBO.
2582 * </p>
2583 */
2584 public final void markUnbound() {
2585 bound = false;
2586 }
2587
2588 /**
2589 * Returns <code>true</code> if framebuffer object is bound via {@link #bind(GL)}, otherwise <code>false</code>.
2590 * <p>
2591 * Method verifies the bound state via {@link GL#getBoundFramebuffer(int)}.
2592 * </p>
2593 * @param gl the current GL context
2594 */
2595 public final boolean isBound(final GL gl) {
2596 bound = bound && fbName == gl.getBoundFramebuffer(GL.GL_FRAMEBUFFER) ;
2597 return bound;
2598 }
2599
2600 /** Returns <code>true</code> if framebuffer object is bound via {@link #bind(GL)}, otherwise <code>false</code>. */
2601 public final boolean isBound() { return bound; }
2602
2603 /**
2604 * If multisampling is being used and flagged dirty by a previous call of {@link #bind(GL)} or after initialization,
2605 * the msaa-buffers are sampled to it's sink {@link #getSamplingTextureSink()}.
2606 * <p>
2607 * Method also resets the sampling sink configuration via {@link #resetSamplingSink(GL)} if used and required.
2608 * </p>
2609 * <p>
2610 * Method is called automatically by {@link #use(GL, TextureAttachment)}.
2611 * </p>
2612 * <p>
2613 * Method always resets the framebuffer binding to default in the end.
2614 * If full FBO is supported, sets the read and write framebuffer individually to default after sampling, hence not disturbing
2615 * an optional operating MSAA FBO, see {@link GLBase#getDefaultReadFramebuffer()} and {@link GLBase#getDefaultDrawFramebuffer()}
2616 * </p>
2617 * <p>
2618 * In case you use this FBO w/o the {@link GLFBODrawable} and intend to employ {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer) glReadPixels(..)}
2619 * you may want to call {@link GL#glBindFramebuffer(int, int) glBindFramebuffer}({@link GL2ES3#GL_READ_FRAMEBUFFER}, {@link #getReadFramebuffer()});
2620 * </p>
2621 * <p>Leaves the FBO unbound.</p>
2622 *
2623 * @param gl the current GL context
2624 * @param ta {@link TextureAttachment} to use, prev. attached w/ {@link #attachTexture2D(GL, int, boolean, int, int, int, int) attachTexture2D(..)}
2625 * @throws IllegalArgumentException
2626 */
2627 public final void syncSamplingSink(final GL gl) {
2628 markUnbound();
2629 if(samples>0 && samplingSinkDirty) { // implies fullFBOSupport
2630 samplingSinkDirty = false;
2631 if( isModified() ) {
2633 }
2634 final boolean checkError = DEBUG || GLContext.DEBUG_GL;
2635 if( checkError ) {
2636 checkPreGLError(gl);
2637 }
2638 gl.glBindFramebuffer(GL.GL_READ_FRAMEBUFFER, fbName); // read from this MSAA fb
2639 gl.glBindFramebuffer(GL.GL_DRAW_FRAMEBUFFER, samplingSink.getWriteFramebuffer()); // write to sampling sink
2640 ((GL2ES3)gl).glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, // since MSAA is supported, casting to GL2ES3 is OK
2642 if( checkError ) {
2643 checkNoError(null, gl.glGetError(), "FBObject syncSampleSink"); // throws GLException if error
2644 }
2645 } else {
2646 modified = false;
2647 }
2648 if(fullFBOSupport) {
2649 // default read/draw buffers, may utilize GLContext/GLDrawable override of
2650 // GLContext.getDefaultDrawFramebuffer() and GLContext.getDefaultReadFramebuffer()
2653 } else {
2654 gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0); // default draw buffer
2655 }
2656 }
2657
2658 /**
2659 * {@link #syncSamplingSink(GL) Synchronize the sampling sink} and bind the given {@link TextureAttachment}, if not <code>null</code>.
2660 *
2661 * <p>If using a {@link TextureAttachment} and multiple texture units, ensure you call {@link GL#glActiveTexture(int)} first!</p>
2662 *
2663 * <p>{@link #syncSamplingSink(GL)} is being called</p>
2664 *
2665 * <p>Leaves the FBO unbound!</p>
2666 *
2667 * @param gl the current GL context
2668 * @param ta {@link TextureAttachment} to use, prev. attached w/ {@link #attachTexture2D(GL, int, boolean, int, int, int, int) attachTexture2D(..)},
2669 * may be <code>null</code> in case no {@link TextureAttachment} is used.
2670 * @throws IllegalArgumentException
2671 */
2672 public final void use(final GL gl, final TextureAttachment ta) throws IllegalArgumentException {
2673 syncSamplingSink(gl);
2674 if( null != ta ) {
2675 gl.glBindTexture(GL.GL_TEXTURE_2D, ta.getName()); // use it ..
2676 }
2677 }
2678
2679 /**
2680 * Unbind texture, ie bind 'non' texture 0
2681 *
2682 * <p>Leaves the FBO unbound.</p>
2683 */
2684 public final void unuse(final GL gl) {
2685 unbind(gl);
2686 gl.glBindTexture(GL.GL_TEXTURE_2D, 0); // don't use it
2687 }
2688
2689 /** @see GL#hasFullFBOSupport() */
2690 public final boolean hasFullFBOSupport() throws GLException { checkInitialized(); return this.fullFBOSupport; }
2691
2692 /**
2693 * Returns <code>true</code> if renderbuffer accepts internal format {@link GL#GL_RGB8} and {@link GL#GL_RGBA8}, otherwise <code>false</code>.
2694 * @throws GLException if {@link #init(GL)} hasn't been called.
2695 */
2696 public final boolean supportsRGBA8() throws GLException { checkInitialized(); return rgba8Avail; }
2697
2698 /**
2699 * Returns <code>true</code> if {@link GL#GL_DEPTH_COMPONENT16}, {@link GL#GL_DEPTH_COMPONENT24} or {@link GL#GL_DEPTH_COMPONENT32} is supported, otherwise <code>false</code>.
2700 * @param bits 16, 24 or 32 bits
2701 * @throws GLException if {@link #init(GL)} hasn't been called.
2702 */
2703 public final boolean supportsDepth(final int bits) throws GLException {
2704 checkInitialized();
2705 switch(bits) {
2706 case 16: return true;
2707 case 24: return depth24Avail;
2708 case 32: return depth32Avail;
2709 default: return false;
2710 }
2711 }
2712
2713 /**
2714 * Returns <code>true</code> if {@link GL#GL_STENCIL_INDEX1}, {@link GL#GL_STENCIL_INDEX4}, {@link GL#GL_STENCIL_INDEX8} or {@link GL2GL3#GL_STENCIL_INDEX16} is supported, otherwise <code>false</code>.
2715 * @param bits 1, 4, 8 or 16 bits
2716 * @throws GLException if {@link #init(GL)} hasn't been called.
2717 */
2718 public final boolean supportsStencil(final int bits) throws GLException {
2719 checkInitialized();
2720 switch(bits) {
2721 case 1: return stencil01Avail;
2722 case 4: return stencil04Avail;
2723 case 8: return stencil08Avail;
2724 case 16: return stencil16Avail;
2725 default: return false;
2726 }
2727 }
2728
2729 /**
2730 * Returns <code>true</code> if {@link GL#GL_DEPTH24_STENCIL8} is supported, otherwise <code>false</code>.
2731 * @throws GLException if {@link #init(GL)} hasn't been called.
2732 */
2733 public final boolean supportsPackedDepthStencil() throws GLException { checkInitialized(); return packedDepthStencilAvail; }
2734
2735 /**
2736 * Returns the maximum number of colorbuffer attachments.
2737 * @throws GLException if {@link #init(GL)} hasn't been called.
2738 */
2739 public final int getMaxColorAttachments() throws GLException { checkInitialized(); return maxColorAttachments; }
2740
2741 public final int getMaxTextureSize() throws GLException { checkInitialized(); return this.maxTextureSize; }
2742 public final int getMaxRenderbufferSize() throws GLException { checkInitialized(); return this.maxRenderbufferSize; }
2743
2744 /** @see GL#getMaxRenderbufferSamples() */
2745 public final int getMaxSamples() throws GLException { checkInitialized(); return this.maxSamples; }
2746
2747 /**
2748 * Returns <code>true</code> if this instance has been initialized with {@link #reset(GL, int, int)}
2749 * or {@link #reset(GL, int, int, int, boolean)}, otherwise <code>false</code>
2750 */
2751 public final boolean isInitialized() { return initialized; }
2752 /** Returns the width */
2753 public final int getWidth() { return width; }
2754 /** Returns the height */
2755 public final int getHeight() { return height; }
2756 /** Returns the number of samples for multisampling (MSAA). zero if no multisampling is used. */
2757 public final int getNumSamples() { return samples; }
2758 /** Returns the framebuffer name to render to. */
2759 public final int getWriteFramebuffer() { return fbName; }
2760 /** Returns the framebuffer name to read from. Depending on multisampling, this may be a different framebuffer. */
2761 public final int getReadFramebuffer() {
2762 return 0 < samples ? ( null != samplingSink ? samplingSink.getReadFramebuffer() : 0 ) : fbName;
2763 }
2764
2765 public final int getDefaultDrawBuffer() { return GL.GL_COLOR_ATTACHMENT0; }
2766
2767 public final int getDefaultReadBuffer() { return GL.GL_COLOR_ATTACHMENT0; }
2768
2769 /** Return the number of attached {@link Colorbuffer}s */
2770 public final int getColorbufferCount() { return colorbufferCount; }
2771 /** Return the number of attached {@link TextureAttachment}s */
2772 public final int getTextureAttachmentCount() { return textureAttachmentCount; }
2773 /** Return the stencil {@link RenderAttachment} attachment, if exist. Maybe share the same {@link Attachment#getName()} as {@link #getDepthAttachment()}, if packed depth-stencil is being used. */
2774 public final RenderAttachment getStencilAttachment() { return stencil; }
2775 /** Return the depth {@link RenderAttachment} attachment. Maybe share the same {@link Attachment#getName()} as {@link #getStencilAttachment()}, if packed depth-stencil is being used. */
2776 public final RenderAttachment getDepthAttachment() { return depth; }
2777
2778 /** Return the complete multisampling {@link FBObject} sink, if using multisampling. */
2779 public final FBObject getSamplingSinkFBO() { return samplingSink; }
2780
2781 /** Return the multisampling {@link Colorbuffer} sink, if using multisampling. */
2782 public final Colorbuffer getSamplingSink() { return samplingColorSink; }
2783
2784 /**
2785 * Returns <code>true</code> if the multisampling colorbuffer (msaa-buffer)
2786 * has been flagged dirty by a previous call of {@link #bind(GL)},
2787 * otherwise <code>false</code>.
2788 */
2789 public final boolean isSamplingBufferDirty() { return samplingSinkDirty; }
2790
2791 /**
2792 * Returns <code>true</code> if size, sample-count or any attachment of this instance
2793 * or its {@link #getSamplingSink() sampling-sink} has been modified since last {@link #syncSamplingSink(GL) sync},
2794 * {@link #use(GL, TextureAttachment) use}, {@link #reset(GL, int, int, int) reset}
2795 * or {@link #resetSamplingSink(GL) resetSamplingSink}.
2796 * <p>
2797 * Otherwise method returns <code>false</code>.
2798 * </p>
2799 */
2800 public final boolean isModified() { return modified || ( null != samplingSink && samplingSink.modified ); }
2801
2802 int objectHashCode() { return super.hashCode(); }
2803
2804 @Override
2805 public final String toString() {
2806 final String caps = null != colorbufferAttachments ? Arrays.asList(colorbufferAttachments).toString() : null ;
2807 return "FBO[name r/w "+fbName+"/"+getReadFramebuffer()+", init "+initialized+", bound "+bound+", size "+width+"x"+height+
2808 ", samples "+samples+"/"+maxSamples+", modified "+modified+"/"+isModified()+", depth "+depth+", stencil "+stencil+
2809 ", colorbuffer attachments: "+colorbufferCount+"/"+maxColorAttachments+", with "+textureAttachmentCount+" textures"+
2810 ": "+caps+", msaa["+samplingColorSink+", hasSink "+(null != samplingSink)+
2811 ", dirty "+samplingSinkDirty+"], state "+getStatusString()+", obj "+toHexString(objectHashCode())+"]";
2812 }
2813
2814 private final void updateStatus(final GL gl) {
2815 if( 0 == fbName ) {
2816 vStatus = -1;
2817 } else {
2818 vStatus = gl.glCheckFramebufferStatus(GL.GL_FRAMEBUFFER);
2819 }
2820 }
2821}
void setRedBits(final int redBits)
Sets the number of bits requested for the color buffer's red component.
void setGreenBits(final int greenBits)
Sets the number of bits requested for the color buffer's green component.
void setBlueBits(final int blueBits)
Sets the number of bits requested for the color buffer's blue component.
void setAlphaBits(final int alphaBits)
Sets the number of bits requested for the color buffer's alpha component.
Common super class of all FBO attachments.
Definition: FBObject.java:125
final int format
immutable the internal format
Definition: FBObject.java:187
abstract boolean initialize(final GL gl)
Initializes the attachment and set it's parameter, if uninitialized, i.e.
final void setStorage(final GL gl)
Accessor to call StorageDefinition#setStorage(GL, Attachment) within initialize(GL) for implementatio...
Definition: FBObject.java:213
final void formatToGLCapabilities(final GLCapabilities caps, final boolean rgba8Avail)
Writes the internal format to the given GLCapabilities object.
Definition: FBObject.java:220
void setStorageDefinition(final StorageDefinition sd)
Override implementation default StorageDefinition.
Definition: FBObject.java:208
final int getName()
buffer name [1..max], maybe a texture or renderbuffer name, depending on type.
Definition: FBObject.java:302
final Type type
immutable type [COLOR, DEPTH, STENCIL, COLOR_TEXTURE, DEPTH_TEXTURE, STENCIL_TEXTURE ]
Definition: FBObject.java:184
final int getFormat()
immutable internal format of attachment
Definition: FBObject.java:293
static Type getType(final int attachmentPoint, final int maxColorAttachments)
Definition: FBObject.java:374
Attachment(final Type type, final int iFormat, final int width, final int height, final int name)
Definition: FBObject.java:196
abstract void free(final GL gl)
Releases the attachment if initialized, i.e.
final int getHeight()
height of attachment
Definition: FBObject.java:298
final int getWidth()
width of attachment
Definition: FBObject.java:296
boolean equals(final Object o)
Definition: FBObject.java:338
Color render buffer FBO attachment
Definition: FBObject.java:510
ColorAttachment(final int iFormat, final int samples, final int width, final int height, final int name)
Definition: FBObject.java:511
final ColorAttachment getColorAttachment()
Casts this object to a ColorAttachment reference, see isTextureAttachment().
Definition: FBObject.java:519
final TextureAttachment getTextureAttachment()
Casts this object to a TextureAttachment reference, see isTextureAttachment().
Definition: FBObject.java:517
final boolean isTextureAttachment()
Returns true if instance is of type TextureAttachment and false if instance is of type ColorAttachmen...
Definition: FBObject.java:515
Other renderbuffer attachment which maybe a colorbuffer, depth or stencil.
Definition: FBObject.java:390
boolean initialize(final GL gl)
Initializes the attachment and set it's parameter, if uninitialized, i.e.
Definition: FBObject.java:452
final int getSamples()
number of samples, or zero for no multisampling
Definition: FBObject.java:408
void free(final GL gl)
Releases the attachment if initialized, i.e.
Definition: FBObject.java:491
RenderAttachment(final Type type, final int iFormat, final int samples, final int width, final int height, final int name)
Definition: FBObject.java:401
TextureAttachment(final Type type, final int iFormat, final int width, final int height, final int dataFormat, final int dataType, final int magFilter, final int minFilter, final int wrapS, final int wrapT, final int name)
Definition: FBObject.java:540
final ColorAttachment getColorAttachment()
Casts this object to a ColorAttachment reference, see isTextureAttachment().
Definition: FBObject.java:641
final boolean isTextureAttachment()
Returns true if instance is of type TextureAttachment and false if instance is of type ColorAttachmen...
Definition: FBObject.java:637
final TextureAttachment getTextureAttachment()
Casts this object to a TextureAttachment reference, see isTextureAttachment().
Definition: FBObject.java:639
void free(final GL gl)
Releases the color buffer if initialized, i.e.
Definition: FBObject.java:625
boolean initialize(final GL gl)
Initializes the texture and set it's parameter, if uninitialized, i.e.
Definition: FBObject.java:568
final int dataFormat
details of the texture setup
Definition: FBObject.java:525
Core utility class simplifying usage of framebuffer objects (FBO) with all GLProfiles.
Definition: FBObject.java:53
final void attachRenderbufferImpl(final GL gl, final Attachment.Type atype, final int internalFormat)
Definition: FBObject.java:1774
final boolean isInitialized()
Returns true if this instance has been initialized with reset(GL, int, int) or reset(GL,...
Definition: FBObject.java:2751
final void detachAllRenderbuffer(final GL gl)
Definition: FBObject.java:2198
static final TextureAttachment createColorTextureAttachment(final int internalFormat, final int width, final int height, final int dataFormat, final int dataType, final int magFilter, final int minFilter, final int wrapS, final int wrapT)
Creates a color TextureAttachment, i.e.
Definition: FBObject.java:767
static final String getStatusString(final int fbStatus)
Definition: FBObject.java:1272
final void attachRenderbuffer(final GL gl, final Attachment.Type atype, final int reqBits)
Attaches one depth, stencil or packed-depth-stencil buffer to this FBO's instance,...
Definition: FBObject.java:1691
final void bind(final GL gl)
Bind this FBO, i.e.
Definition: FBObject.java:2540
final TextureAttachment attachTexture2D(final GL gl, final int attachmentPoint, final boolean alpha)
Attaches a Colorbuffer, i.e.
Definition: FBObject.java:1387
final int getReadFramebuffer()
Returns the framebuffer name to read from.
Definition: FBObject.java:2761
static final TextureAttachment createColorTextureAttachment(final GL gl, final boolean alpha, final int width, final int height, final int magFilter, final int minFilter, final int wrapS, final int wrapT)
Creates a color TextureAttachment, i.e.
Definition: FBObject.java:718
final int getWriteFramebuffer()
Returns the framebuffer name to render to.
Definition: FBObject.java:2759
static final int REQUESTED_BITS
Request current context drawable's requested depth- or stencil-bits; value {@value}.
Definition: FBObject.java:1653
final boolean supportsStencil(final int bits)
Returns true if GL#GL_STENCIL_INDEX1, GL#GL_STENCIL_INDEX4, GL#GL_STENCIL_INDEX8 or GL2GL3#GL_STENCIL...
Definition: FBObject.java:2718
final Colorbuffer attachColorbuffer(final GL gl, final int attachmentPoint, final Colorbuffer colbuf)
Attaches a Colorbuffer at the given attachment point and initializes it, if not done yet.
Definition: FBObject.java:1546
final boolean supportsRGBA8()
Returns true if renderbuffer accepts internal format GL#GL_RGB8 and GL#GL_RGBA8, otherwise false.
Definition: FBObject.java:2696
static final boolean DEBUG
Definition: FBObject.java:54
static final TextureAttachment createColorTextureAttachment(final GL gl, final int internalFormat, final int width, final int height, final int magFilter, final int minFilter, final int wrapS, final int wrapT)
Definition: FBObject.java:739
final void formatToGLCapabilities(final GLCapabilities caps)
Writes the internal format of the attachments to the given GLCapabilities object.
Definition: FBObject.java:1240
static final TextureAttachment createColorTextureAttachment(final GL gl, final boolean alpha, final int width, final int height)
Creates a color TextureAttachment, i.e.
Definition: FBObject.java:669
final String getStatusString()
return the getStatus() as a string.
Definition: FBObject.java:1268
final int getNumSamples()
Returns the number of samples for multisampling (MSAA).
Definition: FBObject.java:2757
final boolean hasAttachmentUsingAlpha()
Returns true if any attached Colorbuffer uses alpha, otherwise false.
Definition: FBObject.java:932
final RenderAttachment getDepthAttachment()
Return the depth RenderAttachment attachment.
Definition: FBObject.java:2776
final TextureAttachment attachTexture2D(final GL gl, final int attachmentPoint, final boolean alpha, final int magFilter, final int minFilter, final int wrapS, final int wrapT)
Attaches a Colorbuffer, i.e.
Definition: FBObject.java:1409
static final int MAXIMUM_BITS
Request maximum bit count for depth- or stencil buffer (depth 32 bits, stencil 16 bits),...
Definition: FBObject.java:1661
final int getWidth()
Returns the width.
Definition: FBObject.java:2753
final void detachAllColorbuffer(final GL gl)
Detaches all ColorAttachments and TextureAttachments and disposes them.
Definition: FBObject.java:2165
FBObject setSamplingSink(final FBObject newSamplingSink)
Setting this FBO sampling sink.
Definition: FBObject.java:2505
final boolean isStatusValid()
The status may even be valid if incomplete during transition of attachments.
Definition: FBObject.java:1313
static final RenderAttachment createRenderAttachment(final Type type, final int internalFormat, final int samples, final int width, final int height)
Definition: FBObject.java:1476
final boolean supportsPackedDepthStencil()
Returns true if GL#GL_DEPTH24_STENCIL8 is supported, otherwise false.
Definition: FBObject.java:2733
final int getDefaultReadBuffer()
Definition: FBObject.java:2767
final boolean isModified()
Returns true if size, sample-count or any attachment of this instance or its sampling-sink has been m...
Definition: FBObject.java:2800
final ColorAttachment createColorAttachment(final boolean alpha)
Creates a ColorAttachment, selecting the format automatically.
Definition: FBObject.java:1450
final void destroy(final GL gl)
Definition: FBObject.java:2253
final Colorbuffer detachColorbuffer(final GL gl, final int attachmentPoint, final boolean dispose)
Detaches a Colorbuffer, i.e.
Definition: FBObject.java:1857
final int getMaxColorAttachments()
Returns the maximum number of colorbuffer attachments.
Definition: FBObject.java:2739
final void attachRenderbuffer(final GL gl, final int internalFormat)
Attaches one depth, stencil or packed-depth-stencil buffer to this FBO's instance,...
Definition: FBObject.java:1766
final int getHeight()
Returns the height.
Definition: FBObject.java:2755
final RenderAttachment getStencilAttachment()
Return the stencil RenderAttachment attachment, if exist.
Definition: FBObject.java:2774
final int getDefaultDrawBuffer()
Definition: FBObject.java:2765
final void syncSamplingSink(final GL gl)
If multisampling is being used and flagged dirty by a previous call of bind(GL) or after initializati...
Definition: FBObject.java:2627
final boolean isSamplingBufferDirty()
Returns true if the multisampling colorbuffer (msaa-buffer) has been flagged dirty by a previous call...
Definition: FBObject.java:2789
final boolean isDepthStencilPackedFormat()
Definition: FBObject.java:1993
final void unuse(final GL gl)
Unbind texture, ie bind 'non' texture 0.
Definition: FBObject.java:2684
final void use(final GL gl, final TextureAttachment ta)
Synchronize the sampling sink and bind the given TextureAttachment, if not null.
Definition: FBObject.java:2672
final void markUnbound()
Method simply marks this FBO unbound w/o interfering w/ the bound framebuffer as perfomed by unbind(G...
Definition: FBObject.java:2584
final TextureAttachment attachTexture2D(final GL gl, final int attachmentPoint, final int internalFormat, final int dataFormat, final int dataType, final int magFilter, final int minFilter, final int wrapS, final int wrapT)
Attaches a Colorbuffer, i.e.
Definition: FBObject.java:1432
final void detachRenderbuffer(final GL gl, final Attachment.Type atype, final boolean dispose)
Definition: FBObject.java:1982
final Colorbuffer getSamplingSink()
Return the multisampling Colorbuffer sink, if using multisampling.
Definition: FBObject.java:2782
static final int DEFAULT_BITS
Request default bit count for depth- or stencil buffer (depth 24 bits, stencil 8 bits),...
Definition: FBObject.java:1648
static final ColorAttachment createColorAttachment(final int internalFormat, final int samples, final int width, final int height)
Creates a ColorAttachment, selecting the format automatically.
Definition: FBObject.java:1472
final boolean hasFullFBOSupport()
Definition: FBObject.java:2690
final boolean resetSamplingSink(final GL gl)
Manually validates the MSAA sampling sink, if used.
Definition: FBObject.java:2345
final ColorAttachment attachColorbuffer(final GL gl, final int attachmentPoint, final boolean alpha)
Attaches a newly created and initialized Colorbuffer, i.e.
Definition: FBObject.java:1496
final Colorbuffer getColorbuffer(final Colorbuffer ca)
Returns the passed Colorbuffer if it is attached to this FBO, otherwise null.
Definition: FBObject.java:923
final boolean supportsDepth(final int bits)
Returns true if GL#GL_DEPTH_COMPONENT16, GL#GL_DEPTH_COMPONENT24 or GL#GL_DEPTH_COMPONENT32 is suppor...
Definition: FBObject.java:2703
FBObject()
Creates an uninitialized FBObject instance.
Definition: FBObject.java:954
final boolean isBound(final GL gl)
Returns true if framebuffer object is bound via bind(GL), otherwise false.
Definition: FBObject.java:2595
final void detachAll(final GL gl)
Detaches all ColorAttachments, TextureAttachments and RenderAttachments and disposes them.
Definition: FBObject.java:2149
final int getColorbufferAttachmentPoint(final Colorbuffer ca)
Finds the passed Colorbuffer within the valid range of attachment points using reference comparison o...
Definition: FBObject.java:900
final int getTextureAttachmentCount()
Return the number of attached TextureAttachments.
Definition: FBObject.java:2772
final int getColorbufferCount()
Return the number of attached Colorbuffers.
Definition: FBObject.java:2770
final ColorAttachment attachColorbuffer(final GL gl, final int attachmentPoint, final int internalFormat)
Attaches a newly created and initialized Colorbuffer, i.e.
Definition: FBObject.java:1516
final void unbind(final GL gl)
Unbind this FBO, i.e.
Definition: FBObject.java:2563
final boolean isBound()
Returns true if framebuffer object is bound via bind(GL), otherwise false.
Definition: FBObject.java:2601
final boolean reset(final GL gl, int newWidth, int newHeight, int newSamples)
Resets this FBO's instance.
Definition: FBObject.java:1140
final int getMaxRenderbufferSize()
Definition: FBObject.java:2742
static final int CHOSEN_BITS
Request current context drawable's chosen depth- or stencil-bits; value {@value}.
Definition: FBObject.java:1658
final int getStatus()
Note that the status may reflect an incomplete state during transition of attachments.
Definition: FBObject.java:1263
void init(final GL gl, final int newWidth, final int newHeight, final int newSamples)
Initializes this FBO's instance.
Definition: FBObject.java:1008
final FBObject getSamplingSinkFBO()
Return the complete multisampling FBObject sink, if using multisampling.
Definition: FBObject.java:2779
final Colorbuffer getColorbuffer(final int attachmentPoint)
Return the Colorbuffer attachment at attachmentPoint if it is attached to this FBO,...
Definition: FBObject.java:886
final void detachAllTexturebuffer(final GL gl)
Detaches all TextureAttachments and disposes them.
Definition: FBObject.java:2180
Specifies a set of OpenGL capabilities.
void setStencilBits(final int stencilBits)
Sets the number of bits requested for the stencil buffer.
void setNumSamples(final int numSamples)
If sample buffers are enabled, indicates the number of buffers to be allocated.
void setSampleBuffers(final boolean enable)
Defaults to false.
void setDepthBits(final int depthBits)
Sets the number of bits requested for the depth buffer.
Abstraction for an OpenGL rendering context.
Definition: GLContext.java:74
abstract GLDrawable getGLDrawable()
Returns the write-drawable this context uses for framebuffer operations.
static final boolean DEBUG_GL
Reflects property jogl.debug.DebugGL.
Definition: GLContext.java:107
final String getGLVersion()
Returns a valid OpenGL version string, ie
Definition: GLContext.java:769
A generic exception for OpenGL errors used throughout the binding as a substitute for RuntimeExceptio...
Class holding OpenGL extension strings, commonly used by JOGL's implementation.
static final String NV_fbo_color_attachments
static final String OES_stencil8
static final String OES_depth24
static final String OES_depth32
static final String EXT_packed_depth_stencil
static final String OES_packed_depth_stencil
static final String OES_stencil4
static final String OES_stencil1
static final String OES_rgb8_rgba8
static StringBuilder getGLStrings(final GL gl, final StringBuilder sb)
static Type determine(final int format)
Returns COLOR, DEPTH, STENCIL or DEPTH_STENCIL.
Definition: FBObject.java:133
Interface abstraction to allow custom definitions of Attachment's storage.
Definition: FBObject.java:162
void setStorage(final GL gl, final Attachment a)
Set or create the Attachment's storage after generating its name and binding it to the target.
Generic color buffer FBO attachment, either of type ColorAttachment or TextureAttachment.
Definition: FBObject.java:70
int getFormat()
internal format of colorbuffer
int getWidth()
width of colorbuffer
boolean initialize(final GL gl)
Initializes the color buffer and set it's parameter, if uninitialized, i.e.
TextureAttachment getTextureAttachment()
Casts this object to a TextureAttachment reference, see isTextureAttachment().
void formatToGLCapabilities(final GLCapabilities caps, final boolean rgba8Avail)
Writes the internal format to the given GLCapabilities object.
void free(final GL gl)
Releases the color buffer if initialized, i.e.
int getHeight()
height of colorbuffer
boolean isTextureAttachment()
Returns true if instance is of type TextureAttachment and false if instance is of type ColorAttachmen...
int getName()
colorbuffer name [1..max]
ColorAttachment getColorAttachment()
Casts this object to a ColorAttachment reference, see isTextureAttachment().
static final int GL_MAX_COLOR_ATTACHMENTS
GL_ES_VERSION_3_0, GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_EXT_draw_buffers,...
Definition: GL2ES2.java:494
static final int GL_FRAMEBUFFER_UNDEFINED
GL_ES_VERSION_3_0, GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_OES_surfaceless_context Alias for: G...
Definition: GL2ES3.java:66
static final int GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER
GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_EXT_framebuffer_object Alias for: GL_FRAMEBUFFER_INCOMP...
Definition: GL2GL3.java:251
static final int GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER
GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_EXT_framebuffer_object Alias for: GL_FRAMEBUFFER_INCOMP...
Definition: GL2GL3.java:439
static final int GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS
GL_ES_VERSION_3_2, GL_VERSION_3_2, GL_NV_geometry_program4, GL_EXT_geometry_shader4,...
Definition: GL3ES3.java:258
boolean hasBasicFBOSupport()
Returns true if basic FBO support is available, otherwise false.
boolean isGLES()
Indicates whether this GL object conforms to one of the OpenGL ES profiles, see isGLES1(),...
int getMaxRenderbufferSamples()
Returns the maximum number of FBO RENDERBUFFER samples if full FBO is supported, otherwise false.
int getBoundFramebuffer(int target)
Return the framebuffer name bound to this context, see GL#glBindFramebuffer(int, int).
boolean isGL2ES3()
Indicates whether this GL object conforms to a either a GL2GL3 or GL3ES3 compatible profile.
boolean isExtensionAvailable(String glExtensionName)
Returns true if the specified OpenGL extension can be used successfully through this GL instance give...
GLContext getContext()
Returns the GLContext associated which this GL object.
boolean isGLES3()
Indicates whether this GL object conforms to the OpenGL ES ≥ 3.0 profile.
boolean hasFullFBOSupport()
Returns true if full FBO support is available, otherwise false.
Specifies an immutable set of OpenGL capabilities.
int getDepthBits()
Returns the number of depth buffer bits.
int getStencilBits()
Returns the number of stencil buffer bits.
GLCapabilitiesImmutable getChosenGLCapabilities()
Fetches the GLCapabilitiesImmutable corresponding to the chosen OpenGL capabilities (pixel format / v...
GLCapabilitiesImmutable getRequestedGLCapabilities()
Fetches the GLCapabilitiesImmutable corresponding to the user requested OpenGL capabilities (pixel fo...
void glFramebufferTexture2D(int target, int attachment, int textarget, int texture, int level)
Entry point to C language function: void {@native glFramebufferTexture2D}(GLenum target,...
static final int GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
GL_ES_VERSION_2_0, GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_EXT_framebuffer_object,...
Definition: GL.java:38
static final int GL_TEXTURE_MAG_FILTER
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_TEXTURE_MAG_FILTER" w...
Definition: GL.java:197
static final int GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
GL_ES_VERSION_2_0, GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_OES_framebuffer_object,...
Definition: GL.java:655
static final int GL_READ_FRAMEBUFFER
GL_ES_VERSION_3_0, GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_EXT_framebuffer_blit,...
Definition: GL.java:336
static final int GL_RGBA4
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_EXT_texture, GL_OES_framebuffer_object, GL_OES_required_interna...
Definition: GL.java:171
void glGetIntegerv(int pname, IntBuffer data)
Entry point to C language function: void {@native glGetIntegerv}(GLenum pname, GLint * data) Part ...
static final int GL_RGB8
GL_ES_VERSION_3_0, GL_VERSION_1_1, GL_EXT_texture, GL_OES_rgb8_rgba8, GL_OES_required_internalformat ...
Definition: GL.java:479
static final int GL_BGRA
GL_VERSION_1_2, GL_IMG_read_format, GL_APPLE_texture_format_BGRA8888, GL_EXT_texture_format_BGRA8888,...
Definition: GL.java:404
static final int GL_INVALID_VALUE
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_INVALID_VALUE" with e...
Definition: GL.java:794
static final int GL_RGB
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_RGB" with expression ...
Definition: GL.java:374
static final int GL_TEXTURE_2D
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_TEXTURE_2D" with expr...
Definition: GL.java:491
static final int GL_TEXTURE_WRAP_S
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_TEXTURE_WRAP_S" with ...
Definition: GL.java:485
void glDeleteTextures(int n, IntBuffer textures)
Entry point to C language function: void {@native glDeleteTextures}(GLsizei n, const GLuint * textur...
void glBindTexture(int target, int texture)
Entry point to C language function: void {@native glBindTexture}(GLenum target, GLuint texture) Pa...
void glGenTextures(int n, IntBuffer textures)
Entry point to C language function: void {@native glGenTextures}(GLsizei n, GLuint * textures) Par...
int glCheckFramebufferStatus(int target)
Entry point to C language function: GLenum {@native glCheckFramebufferStatus}(GLenum target) Part ...
static final int GL_STENCIL_INDEX8
GL_ES_VERSION_2_0, GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_EXT_framebuffer_object,...
Definition: GL.java:665
static final int GL_RGB565
GL_ARB_ES2_compatibility, GL_ES_VERSION_2_0, GL_VERSION_4_1, GL_OES_framebuffer_object,...
Definition: GL.java:457
void glDeleteRenderbuffers(int n, IntBuffer renderbuffers)
Entry point to C language function: void {@native glDeleteRenderbuffers}(GLsizei n,...
void glRenderbufferStorage(int target, int internalformat, int width, int height)
Entry point to C language function: void {@native glRenderbufferStorage}(GLenum target,...
static final int GL_NO_ERROR
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_NO_ERROR" with expres...
Definition: GL.java:481
static final int GL_MAX_RENDERBUFFER_SIZE
GL_ES_VERSION_2_0, GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_OES_framebuffer_object,...
Definition: GL.java:321
int glGetError()
Entry point to C language function: GLenum {@native glGetError}() Part of GL_ES_VERSION_2_0,...
void glGenFramebuffers(int n, IntBuffer framebuffers)
Entry point to C language function: void {@native glGenFramebuffers}(GLsizei n, GLuint * framebuffer...
static final int GL_STENCIL_INDEX4
GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_EXT_framebuffer_object, GL_OES_stencil4 Alias for: GL_S...
Definition: GL.java:736
static final int GL_RENDERBUFFER
GL_ES_VERSION_2_0, GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_EXT_framebuffer_object,...
Definition: GL.java:718
void glDeleteFramebuffers(int n, IntBuffer framebuffers)
Entry point to C language function: void {@native glDeleteFramebuffers}(GLsizei n,...
static final int GL_TEXTURE_MIN_FILTER
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_TEXTURE_MIN_FILTER" w...
Definition: GL.java:372
static final int GL_COLOR_BUFFER_BIT
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_COLOR_BUFFER_BIT" wit...
Definition: GL.java:390
static final int GL_RGBA8
GL_ES_VERSION_3_0, GL_VERSION_1_1, GL_OES_rgb8_rgba8, GL_OES_required_internalformat,...
Definition: GL.java:279
boolean glIsFramebuffer(int framebuffer)
Entry point to C language function: GLboolean {@native glIsFramebuffer}(GLuint framebuffer) Part o...
void glFramebufferRenderbuffer(int target, int attachment, int renderbuffertarget, int renderbuffer)
Entry point to C language function: void {@native glFramebufferRenderbuffer}(GLenum target,...
static final int GL_DEPTH_COMPONENT32
GL_VERSION_1_4, GL_ARB_depth_texture, GL_SGIX_depth_texture, GL_OES_depth32 Alias for: GL_DEPTH_COMPO...
Definition: GL.java:678
static final int GL_COLOR_ATTACHMENT0
GL_ES_VERSION_2_0, GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_NV_draw_buffers, GL_OES_framebuffer_...
Definition: GL.java:349
static final int GL_TEXTURE_WRAP_T
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_TEXTURE_WRAP_T" with ...
Definition: GL.java:489
void glTexParameteri(int target, int pname, int param)
Entry point to C language function: void {@native glTexParameteri}(GLenum target,...
static final int GL_FRAMEBUFFER_COMPLETE
GL_ES_VERSION_2_0, GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_EXT_framebuffer_object,...
Definition: GL.java:605
static final int GL_FRAMEBUFFER_INCOMPLETE_FORMATS
Part of GL_EXT_framebuffer_object; GL_ES_VERSION_2_0; GL_OES_framebuffer_object
Definition: GL.java:1281
static final int GL_STENCIL_INDEX1
GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_EXT_framebuffer_object, GL_OES_stencil1 Alias for: GL_S...
Definition: GL.java:268
void glBindFramebuffer(int target, int framebuffer)
Entry point to C language function: void {@native glBindFramebuffer}(GLenum target,...
static final int GL_NEAREST
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_NEAREST" with express...
Definition: GL.java:715
static final int GL_DEPTH_COMPONENT16
GL_ES_VERSION_2_0, GL_VERSION_1_4, GL_ARB_depth_texture, GL_OES_framebuffer_object,...
Definition: GL.java:254
static final int GL_RGBA
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_RGBA" with expression...
Definition: GL.java:150
static final int GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
GL_ES_VERSION_2_0, GL_EXT_framebuffer_object, GL_OES_framebuffer_object Alias for: GL_FRAMEBUFFER_INC...
Definition: GL.java:202
static final int GL_FRAMEBUFFER_UNSUPPORTED
GL_ES_VERSION_2_0, GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_EXT_framebuffer_object,...
Definition: GL.java:686
static final int GL_MAX_TEXTURE_SIZE
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_MAX_TEXTURE_SIZE" wit...
Definition: GL.java:244
void glRenderbufferStorageMultisample(int target, int samples, int internalformat, int width, int height)
Entry point to C language function: void {@native glRenderbufferStorageMultisample}(GLenum target,...
void glTexImage2D(int target, int level, int internalformat, int width, int height, int border, int format, int type, Buffer pixels)
Entry point to C language function: void {@native glTexImage2D}(GLenum target, GLint level,...
static final int GL_DRAW_FRAMEBUFFER
GL_ES_VERSION_3_0, GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_NV_framebuffer_blit,...
Definition: GL.java:306
static final int GL_DEPTH_COMPONENT24
GL_ES_VERSION_3_0, GL_VERSION_1_4, GL_ARB_depth_texture, GL_OES_depth24, GL_SGIX_depth_texture Alias ...
Definition: GL.java:694
static final int GL_CLAMP_TO_EDGE
GL_ES_VERSION_2_0, GL_VERSION_1_2, GL_VERSION_ES_1_0, GL_SGIS_texture_edge_clamp Alias for: GL_CLAMP_...
Definition: GL.java:775
static final int GL_DEPTH_ATTACHMENT
GL_ES_VERSION_2_0, GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_EXT_framebuffer_object,...
Definition: GL.java:297
static final int GL_UNSIGNED_BYTE
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_VERSION_1_0, GL_VERSION_ES_1_0 Define "GL_UNSIGNED_BYTE" with e...
Definition: GL.java:284
static final int GL_DEPTH24_STENCIL8
GL_ES_VERSION_3_0, GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_EXT_packed_depth_stencil,...
Definition: GL.java:222
static final int GL_STENCIL_ATTACHMENT
GL_ES_VERSION_2_0, GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_EXT_framebuffer_object,...
Definition: GL.java:792
static final int GL_FRAMEBUFFER
GL_ES_VERSION_2_0, GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_OES_framebuffer_object,...
Definition: GL.java:630
static final int GL_RGB5_A1
GL_ES_VERSION_2_0, GL_VERSION_1_1, GL_OES_framebuffer_object, GL_OES_required_internalformat,...
Definition: GL.java:103
static final int GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE
GL_ES_VERSION_3_0, GL_ARB_framebuffer_object, GL_VERSION_3_0, GL_IMG_multisampled_render_to_texture,...
Definition: GL.java:228