Jogamp
Bug 1020 - First MSAA FBO frame on a mac osx nvidia card not antialiased
[jogl.git] / src / jogl / classes / jogamp / opengl / GLFBODrawableImpl.java
1 package jogamp.opengl;
2
3 import javax.media.nativewindow.NativeSurface;
4 import javax.media.nativewindow.NativeWindowException;
5 import javax.media.nativewindow.ProxySurface;
6 import javax.media.nativewindow.UpstreamSurfaceHook;
7 import javax.media.opengl.GL;
8 import javax.media.opengl.GLCapabilities;
9 import javax.media.opengl.GLCapabilitiesImmutable;
10 import javax.media.opengl.GLContext;
11 import javax.media.opengl.GLException;
12 import javax.media.opengl.GLFBODrawable;
13
14 import com.jogamp.common.util.PropertyAccess;
15 import com.jogamp.common.util.VersionUtil;
16 import com.jogamp.nativewindow.MutableGraphicsConfiguration;
17 import com.jogamp.opengl.FBObject;
18 import com.jogamp.opengl.FBObject.Attachment;
19 import com.jogamp.opengl.FBObject.Colorbuffer;
20 import com.jogamp.opengl.FBObject.TextureAttachment;
21 import com.jogamp.opengl.JoglVersion;
22
23 /**
24  * {@link FBObject} offscreen GLDrawable implementation, i.e. {@link GLFBODrawable}.
25  * <p>
26  * It utilizes the context lifecycle hook {@link #contextRealized(GLContext, boolean)}
27  * to initialize the {@link FBObject} instance.
28  * </p>
29  * <p>
30  * It utilizes the context current hook {@link #contextMadeCurrent(GLContext, boolean) contextMadeCurrent(context, true)}
31  * to {@link FBObject#bind(GL) bind} the FBO.
32  * </p>
33  * See {@link GLFBODrawable} for double buffering details.
34  *
35  * @see GLDrawableImpl#contextRealized(GLContext, boolean)
36  * @see GLDrawableImpl#contextMadeCurrent(GLContext, boolean)
37  * @see GLDrawableImpl#getDefaultDrawFramebuffer()
38  * @see GLDrawableImpl#getDefaultReadFramebuffer()
39  */
40 public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable {
41     protected static final boolean DEBUG;
42     protected static final boolean DEBUG_SWAP;
43
44     static {
45         Debug.initSingleton();
46         DEBUG = GLDrawableImpl.DEBUG || Debug.debug("FBObject");
47         DEBUG_SWAP = DEBUG || PropertyAccess.isPropertyDefined("jogl.debug.FBObject.Swap", true);
48     }
49
50     private final GLDrawableImpl parent;
51     private GLCapabilitiesImmutable origParentChosenCaps;
52
53     private boolean initialized;
54     private int fboModeBits;
55     private int texUnit;
56     private int samples;
57     private boolean fboResetQuirk;
58
59     private FBObject[] fbos;
60     private int fboIBack;  // points to GL_BACK buffer
61     private int fboIFront; // points to GL_FRONT buffer
62     private int pendingFBOReset = -1;
63     /** Indicates whether the FBO is bound. */
64     private boolean fboBound;
65     /** Indicates whether the FBO is swapped, resets to false after makeCurrent -> contextMadeCurrent. */
66     private boolean fboSwapped;
67
68     /** dump fboResetQuirk info only once pre ClassLoader and only in DEBUG mode */
69     private static volatile boolean resetQuirkInfoDumped = false;
70
71     /** number of FBOs for double buffering. TODO: Possible to configure! */
72     private static final int bufferCount = 2;
73
74     // private DoubleBufferMode doubleBufferMode; // TODO: Add or remove TEXTURE (only) DoubleBufferMode support
75
76     private SwapBufferContext swapBufferContext;
77
78     public static interface SwapBufferContext {
79         public void swapBuffers(boolean doubleBuffered);
80     }
81
82     /**
83      * @param factory
84      * @param parent
85      * @param surface
86      * @param fboCaps the requested FBO capabilities
87      * @param textureUnit
88      */
89     protected GLFBODrawableImpl(final GLDrawableFactoryImpl factory, final GLDrawableImpl parent, final NativeSurface surface,
90                                 final GLCapabilitiesImmutable fboCaps, final int textureUnit) {
91         super(factory, surface, fboCaps, false);
92         this.initialized = false;
93         this.fboModeBits = FBOMODE_USE_TEXTURE | FBOMODE_USE_DEPTH;
94
95         this.parent = parent;
96         this.origParentChosenCaps = getChosenGLCapabilities(); // just to avoid null, will be reset at initialize(..)
97         this.texUnit = textureUnit;
98         this.samples = fboCaps.getNumSamples();
99         fboResetQuirk = false;
100
101         // default .. // TODO: Add or remove TEXTURE (only) DoubleBufferMode support
102         // this.doubleBufferMode = ( samples > 0 || fboCaps.getDoubleBuffered() ) ? DoubleBufferMode.FBO : DoubleBufferMode.NONE ;
103
104         this.swapBufferContext = null;
105     }
106
107     private final void initialize(final boolean realize, final GL gl) {
108         if( !initialized && !realize ) {
109             if( DEBUG ) {
110                 System.err.println("GLFBODrawableImpl.initialize(): WARNING - Already unrealized!");
111                 Thread.dumpStack();
112             }
113             return; // NOP, no exception for de-init twice or no init!
114         }
115         if( initialized == realize ) {
116             throw new IllegalStateException("initialize already in state "+realize+": "+this);
117         }
118         if(realize) {
119             final GLCapabilities chosenFBOCaps = (GLCapabilities) getChosenGLCapabilities(); // cloned at setRealized(true)
120
121             final int maxSamples = gl.getMaxRenderbufferSamples();
122             {
123                 final int newSamples = samples <= maxSamples ? samples : maxSamples;
124                 if(DEBUG) {
125                     System.err.println("GLFBODrawableImpl.initialize(): samples "+samples+" -> "+newSamples+"/"+maxSamples);
126                 }
127                 samples = newSamples;
128             }
129
130             final int fbosN;
131             if(samples > 0) {
132                 fbosN = 1;
133             } else if( chosenFBOCaps.getDoubleBuffered() ) {
134                 fbosN = bufferCount;
135             } else {
136                 fbosN = 1;
137             }
138
139             fbos = new FBObject[fbosN];
140             fboIBack = 0;                // head
141             fboIFront = fbos.length - 1; // tail
142
143             final boolean useTexture = 0 != ( FBOMODE_USE_TEXTURE & fboModeBits );
144             final boolean useDepth   = 0 != ( FBOMODE_USE_DEPTH   & fboModeBits );
145             final boolean useStencil = chosenFBOCaps.getStencilBits() > 0;
146             final boolean useAlpha = chosenFBOCaps.getAlphaBits() > 0;
147             final int width = getSurfaceWidth();
148             final int height = getSurfaceHeight();
149
150             for(int i=0; i<fbosN; i++) {
151                 fbos[i] = new FBObject();
152                 fbos[i].reset(gl, width, height, samples, false);
153                 if(fbos[i].getNumSamples() != samples) {
154                     throw new InternalError("Sample number mismatch: "+samples+", fbos["+i+"] "+fbos[i]);
155                 }
156                 if(samples > 0 || !useTexture) {
157                     fbos[i].attachColorbuffer(gl, 0, useAlpha);
158                 } else {
159                     fbos[i].attachTexture2D(gl, 0, useAlpha);
160                 }
161                 if( useStencil ) {
162                     if( useDepth ) {
163                         fbos[i].attachRenderbuffer(gl, Attachment.Type.DEPTH_STENCIL, 24);
164                     } else {
165                         fbos[i].attachRenderbuffer(gl, Attachment.Type.STENCIL, 24);
166                     }
167                 } else if( useDepth ) {
168                     fbos[i].attachRenderbuffer(gl, Attachment.Type.DEPTH, 24);
169                 }
170                 if(samples > 0) {
171                     final FBObject ssink = new FBObject();
172                     {
173                         ssink.reset(gl, width, height);
174                         if( !useTexture ) {
175                             ssink.attachColorbuffer(gl, 0, useAlpha);
176                         } else {
177                             ssink.attachTexture2D(gl, 0, useAlpha);
178                         }
179                         if( useStencil ) {
180                             if( useDepth ) {
181                                 ssink.attachRenderbuffer(gl, Attachment.Type.DEPTH_STENCIL, 24);
182                             } else {
183                                 ssink.attachRenderbuffer(gl, Attachment.Type.STENCIL, 24);
184                             }
185                         } else if( useDepth ) {
186                             ssink.attachRenderbuffer(gl, Attachment.Type.DEPTH, 24);
187                         }
188                     }
189                     fbos[i].setSamplingSink(ssink);
190                     fbos[i].resetSamplingSink(gl); // validate
191                 }
192                 // Clear the framebuffer allowing defined state not exposing previous content.
193                 // Also remedy for Bug 1020, i.e. OSX/Nvidia's FBO needs to be cleared before blitting,
194                 // otherwise first MSAA frame lacks antialiasing.
195                 fbos[i].bind(gl);
196                 if( useDepth ) {
197                     gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
198                 } else {
199                     gl.glClear(GL.GL_COLOR_BUFFER_BIT);
200                 }
201             }
202             fbos[fbosN-1].unbind(gl);
203             fbos[0].formatToGLCapabilities(chosenFBOCaps);
204             chosenFBOCaps.setDoubleBuffered( chosenFBOCaps.getDoubleBuffered() || samples > 0 );
205         } else {
206             for(int i=0; i<fbos.length; i++) {
207                 fbos[i].destroy(gl);
208             }
209             fbos=null;
210         }
211         fboBound = false;
212         fboSwapped = false;
213         pendingFBOReset = -1;
214         initialized = realize;
215
216         if(DEBUG) {
217             System.err.println("GLFBODrawableImpl.initialize("+realize+"): "+this);
218             Thread.dumpStack();
219         }
220     }
221
222     public final void setSwapBufferContext(final SwapBufferContext sbc) {
223         swapBufferContext = sbc;
224     }
225
226     private final void reset(final GL gl, final int idx, final int width, final int height, final int samples, final int alphaBits, final int stencilBits) {
227         if( !fboResetQuirk ) {
228             try {
229                 fbos[idx].reset(gl, width, height, samples, false);
230                 if(fbos[idx].getNumSamples() != samples) {
231                     throw new InternalError("Sample number mismatch: "+samples+", fbos["+idx+"] "+fbos[idx]);
232                 }
233                 return;
234             } catch (final GLException e) {
235                 fboResetQuirk = true;
236                 if(DEBUG) {
237                     if(!resetQuirkInfoDumped) {
238                         resetQuirkInfoDumped = true;
239                         System.err.println("GLFBODrawable: FBO Reset failed: "+e.getMessage());
240                         System.err.println("GLFBODrawable: Enabling FBOResetQuirk, due to GL driver bug.");
241                         final JoglVersion joglVersion = JoglVersion.getInstance();
242                         if(DEBUG) {
243                             System.err.println(VersionUtil.getPlatformInfo());
244                             System.err.println(joglVersion.toString());
245                             System.err.println(JoglVersion.getGLInfo(gl, null));
246                         } else {
247                             System.err.println(joglVersion.getBriefOSGLBuildInfo(gl, null));
248                         }
249                         e.printStackTrace();
250                     }
251                 }
252                 // 'fallthrough' intended
253             }
254         }
255         // resetQuirk fallback
256         fbos[idx].destroy(gl);
257         fbos[idx] = new FBObject();
258         fbos[idx].reset(gl, getSurfaceWidth(), getSurfaceHeight(), samples, false);
259         if(fbos[idx].getNumSamples() != samples) {
260             throw new InternalError("Sample number mismatch: "+samples+", fbos["+idx+"] "+fbos[idx]);
261         }
262         if(samples > 0) {
263             fbos[idx].attachColorbuffer(gl, 0, alphaBits>0);
264         } else {
265             fbos[idx].attachTexture2D(gl, 0, alphaBits>0);
266         }
267         if( stencilBits > 0 ) {
268             fbos[idx].attachRenderbuffer(gl, Attachment.Type.DEPTH_STENCIL, 24);
269         } else {
270             fbos[idx].attachRenderbuffer(gl, Attachment.Type.DEPTH, 24);
271         }
272     }
273
274     private final void reset(final GL gl, int newSamples) throws GLException {
275         if(!initialized) {
276             // NOP if not yet initializes
277             return;
278         }
279
280         final GLContext curContext = GLContext.getCurrent();
281         final GLContext ourContext = gl.getContext();
282         final boolean ctxSwitch = null != curContext && curContext != ourContext;
283         if(DEBUG) {
284             System.err.println("GLFBODrawableImpl.reset(newSamples "+newSamples+"): BEGIN - ctxSwitch "+ctxSwitch+", "+this);
285             Thread.dumpStack();
286         }
287         Throwable tFBO = null;
288         Throwable tGL = null;
289         ourContext.makeCurrent();
290         gl.glFinish(); // sync GL command stream
291         fboBound = false; // clear bound-flag immediatly, caused by contextMadeCurrent(..) - otherwise we would swap @ release
292         fboSwapped = false;
293         try {
294             final int maxSamples = gl.getMaxRenderbufferSamples();
295             newSamples = newSamples <= maxSamples ? newSamples : maxSamples;
296
297             if(0==samples && 0<newSamples || 0<samples && 0==newSamples) {
298                 // MSAA on/off switch
299                 if(DEBUG) {
300                     System.err.println("GLFBODrawableImpl.reset(): samples [on/off] reconfig: "+samples+" -> "+newSamples+"/"+maxSamples);
301                 }
302                 initialize(false, gl);
303                 samples = newSamples;
304                 initialize(true, gl);
305             } else {
306                 if(DEBUG) {
307                     System.err.println("GLFBODrawableImpl.reset(): simple reconfig: "+samples+" -> "+newSamples+"/"+maxSamples);
308                 }
309                 final int nWidth = getSurfaceWidth();
310                 final int nHeight = getSurfaceHeight();
311                 samples = newSamples;
312                 pendingFBOReset = ( 1 < fbos.length ) ? fboIFront : -1; // pending-front reset only w/ double buffering (or zero samples)
313                 final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) surface.getGraphicsConfiguration().getChosenCapabilities();
314                 for(int i=0; i<fbos.length; i++) {
315                     if( pendingFBOReset != i ) {
316                         reset(gl, i, nWidth, nHeight, samples, caps.getAlphaBits(), caps.getStencilBits());
317                     }
318                 }
319                 final GLCapabilities fboCapsNative = (GLCapabilities) surface.getGraphicsConfiguration().getChosenCapabilities();
320                 fbos[0].formatToGLCapabilities(fboCapsNative);
321             }
322         } catch (final Throwable t) {
323             tFBO = t;
324         } finally {
325             try {
326                 ourContext.release();
327                 if(ctxSwitch) {
328                     curContext.makeCurrent();
329                 }
330             } catch (final Throwable t) {
331                 tGL = t;
332             }
333         }
334         if(null != tFBO) {
335             throw GLException.newGLException(tFBO);
336         }
337         if(null != tGL) {
338             throw GLException.newGLException(tGL);
339         }
340         if(DEBUG) {
341             System.err.println("GLFBODrawableImpl.reset(newSamples "+newSamples+"): END "+this);
342         }
343     }
344
345     //
346     // GLDrawable
347     //
348
349     @Override
350     public final GLContext createContext(final GLContext shareWith) {
351         final GLContext ctx = parent.createContext(shareWith);
352         ctx.setGLDrawable(this, false);
353         return ctx;
354     }
355
356     //
357     // GLDrawableImpl
358     //
359
360     @Override
361     public final GLDynamicLookupHelper getGLDynamicLookupHelper() {
362         return parent.getGLDynamicLookupHelper();
363     }
364
365     @Override
366     protected final int getDefaultDrawFramebuffer() { return initialized ? fbos[fboIBack].getWriteFramebuffer() : 0; }
367
368     @Override
369     protected final int getDefaultReadFramebuffer() { return initialized ? fbos[fboIFront].getReadFramebuffer() : 0; }
370
371     @Override
372     protected final int getDefaultReadBuffer(final GL gl, final boolean hasDedicatedDrawableRead) {
373         return initialized ? fbos[fboIFront].getDefaultReadBuffer() : GL.GL_COLOR_ATTACHMENT0 ;
374     }
375
376     @Override
377     protected final void setRealizedImpl() {
378         final MutableGraphicsConfiguration msConfig = (MutableGraphicsConfiguration) surface.getGraphicsConfiguration();
379         if(realized) {
380             parent.setRealized(true);
381             origParentChosenCaps = (GLCapabilitiesImmutable) msConfig.getChosenCapabilities();
382             final GLCapabilities chosenFBOCaps = (GLCapabilities) origParentChosenCaps.cloneMutable(); // incl. <Type>GLCapabilities, e.g. X11GLCapabilities
383             chosenFBOCaps.copyFrom(getRequestedGLCapabilities()); // copy user values
384             msConfig.setChosenCapabilities(chosenFBOCaps);
385         } else {
386             msConfig.setChosenCapabilities(origParentChosenCaps);
387             parent.setRealized(false);
388         }
389     }
390
391     @Override
392     protected void associateContext(final GLContext glc, final boolean bound) {
393         initialize(bound, glc.getGL());
394     }
395
396     @Override
397     protected final void contextMadeCurrent(final GLContext glc, final boolean current) {
398         final GL gl = glc.getGL();
399         if(current) {
400             if( !initialized ) {
401                 throw new GLException("Not initialized: "+this);
402             }
403             fbos[fboIBack].bind(gl);
404             fboBound = true;
405             fboSwapped = false;
406         } else if( fboBound && !fboSwapped ) {
407             swapFBOImpl(glc);
408             swapFBOImplPost(glc);
409             fboBound=false;
410             fboSwapped=true;
411             if(DEBUG_SWAP) {
412                 System.err.println("Post FBO swap(@release): done");
413             }
414         }
415     }
416
417     @Override
418     protected void swapBuffersImpl(final boolean doubleBuffered) {
419         final GLContext ctx = GLContext.getCurrent();
420         boolean doPostSwap;
421         if( null != ctx && ctx.getGLDrawable() == this && fboBound ) {
422             swapFBOImpl(ctx);
423             doPostSwap = true;
424             fboSwapped = true;
425             if(DEBUG_SWAP) {
426                 System.err.println("Post FBO swap(@swap): done");
427             }
428         } else {
429             doPostSwap = false;
430         }
431         if( null != swapBufferContext ) {
432             swapBufferContext.swapBuffers(doubleBuffered);
433         }
434         if(doPostSwap) {
435             swapFBOImplPost(ctx);
436         }
437     }
438
439     private final void swapFBOImplPost(final GLContext glc) {
440         // Safely reset the previous front FBO - after completing propagating swap
441         if(0 <= pendingFBOReset) {
442             final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) surface.getGraphicsConfiguration().getChosenCapabilities();
443             reset(glc.getGL(), pendingFBOReset, getSurfaceWidth(), getSurfaceHeight(), samples, caps.getAlphaBits(), caps.getStencilBits());
444             pendingFBOReset = -1;
445         }
446     }
447
448     private final void swapFBOImpl(final GLContext glc) {
449         final GL gl = glc.getGL();
450         fbos[fboIBack].markUnbound(); // fast path, use(gl,..) is called below
451
452         if(DEBUG) {
453             final int _fboIFront = ( fboIFront + 1 ) % fbos.length;
454             if(_fboIFront != fboIBack) { throw new InternalError("XXX: "+_fboIFront+"!="+fboIBack); }
455         }
456         fboIFront = fboIBack;
457         fboIBack  = ( fboIBack  + 1 ) % fbos.length;
458
459         final Colorbuffer colorbuffer = samples > 0 ? fbos[fboIFront].getSamplingSink() : fbos[fboIFront].getColorbuffer(0);
460         if(null == colorbuffer) {
461             throw new GLException("Front colorbuffer is null: samples "+samples+", "+this);
462         }
463         final TextureAttachment texAttachment;
464         if( colorbuffer.isTextureAttachment() ) {
465             texAttachment = colorbuffer.getTextureAttachment();
466             gl.glActiveTexture(GL.GL_TEXTURE0 + texUnit);
467         } else {
468             texAttachment = null;
469         }
470         fbos[fboIFront].use(gl, texAttachment);
471
472         /* Included in above use command:
473                 gl.glBindFramebuffer(GL2GL3.GL_DRAW_FRAMEBUFFER, fbos[fboIBack].getDrawFramebuffer());
474                 gl.glBindFramebuffer(GL2GL3.GL_READ_FRAMEBUFFER, fbos[fboIFront].getReadFramebuffer());
475         } */
476
477         if(DEBUG_SWAP) {
478             System.err.println("Post FBO swap(X): fboI back "+fboIBack+", front "+fboIFront+", num "+fbos.length);
479         }
480     }
481
482     //
483     // GLFBODrawable
484     //
485
486     @Override
487     public final boolean isInitialized() {
488         return initialized;
489     }
490
491     @Override
492     public final void setFBOMode(final int modeBits) throws IllegalStateException {
493         if( isInitialized() ) {
494             throw new IllegalStateException("Already initialized: "+this);
495         }
496         this.fboModeBits = modeBits;
497     }
498
499     @Override
500     public final int getFBOMode() {
501         return fboModeBits;
502     }
503
504     @Override
505     public final void resetSize(final GL gl) throws GLException {
506         reset(gl, samples);
507     }
508
509     @Override
510     public final int getTextureUnit() { return texUnit; }
511
512     @Override
513     public final void setTextureUnit(final int u) { texUnit = u; }
514
515     @Override
516     public final int getNumSamples() { return samples; }
517
518     @Override
519     public void setNumSamples(final GL gl, final int newSamples) throws GLException {
520         if(samples != newSamples) {
521             reset(gl, newSamples);
522         }
523     }
524
525     @Override
526     public final int setNumBuffers(final int bufferCount) throws GLException {
527         // FIXME: Implement
528         return bufferCount;
529     }
530
531     @Override
532     public final int getNumBuffers() {
533         return bufferCount;
534     }
535
536     /** // TODO: Add or remove TEXTURE (only) DoubleBufferMode support
537     @Override
538     public final DoubleBufferMode getDoubleBufferMode() {
539         return doubleBufferMode;
540     }
541
542     @Override
543     public final void setDoubleBufferMode(DoubleBufferMode mode) throws GLException {
544         if(initialized) {
545             throw new GLException("Not allowed past initialization: "+this);
546         }
547         final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) surface.getGraphicsConfiguration().getChosenCapabilities();
548         if(0 == samples && caps.getDoubleBuffered() && DoubleBufferMode.NONE != mode) {
549             doubleBufferMode = mode;
550         }
551     } */
552
553     @Override
554     public FBObject getFBObject(final int bufferName) throws IllegalArgumentException {
555         if(!initialized) {
556             return null;
557         }
558         final FBObject res;
559         switch(bufferName) {
560             case GL.GL_FRONT:
561                 if( samples > 0 ) {
562                     res = fbos[0].getSamplingSinkFBO();
563                 } else {
564                     res = fbos[fboIFront];
565                 }
566                 break;
567             case GL.GL_BACK:
568                 res = fbos[fboIBack];
569                 break;
570             default:
571                 throw new IllegalArgumentException(illegalBufferName+toHexString(bufferName));
572         }
573         return res;
574     }
575
576     @Override
577     public final Colorbuffer getColorbuffer(final int bufferName) throws IllegalArgumentException {
578         if(!initialized) {
579             return null;
580         }
581         final Colorbuffer res;
582         switch(bufferName) {
583             case GL.GL_FRONT:
584                 if( samples > 0 ) {
585                     res = fbos[0].getSamplingSink();
586                 } else {
587                     res = fbos[fboIFront].getColorbuffer(0);
588                 }
589                 break;
590             case GL.GL_BACK:
591                 if( samples > 0 ) {
592                     throw new IllegalArgumentException("Cannot access GL_BACK buffer of MSAA FBO: "+this);
593                 } else {
594                     res = fbos[fboIBack].getColorbuffer(0);
595                 }
596                 break;
597             default:
598                 throw new IllegalArgumentException(illegalBufferName+toHexString(bufferName));
599         }
600         return res;
601     }
602     private static final String illegalBufferName = "Only GL_FRONT and GL_BACK buffer are allowed, passed ";
603
604     @Override
605     public String toString() {
606         return getClass().getSimpleName()+"[Initialized "+initialized+", realized "+isRealized()+", texUnit "+texUnit+", samples "+samples+
607                 ",\n\tFactory   "+getFactory()+
608                 ",\n\tHandle    "+toHexString(getHandle())+
609                 ",\n\tCaps      "+surface.getGraphicsConfiguration().getChosenCapabilities()+
610                 ",\n\tfboI back "+fboIBack+", front "+fboIFront+", num "+(initialized ? fbos.length : 0)+
611                 ",\n\tFBO front read "+getDefaultReadFramebuffer()+", "+getFBObject(GL.GL_FRONT)+
612                 ",\n\tFBO back  write "+getDefaultDrawFramebuffer()+", "+getFBObject(GL.GL_BACK)+
613                 ",\n\tSurface   "+surface+
614                 "]";
615     }
616
617     public static class ResizeableImpl extends GLFBODrawableImpl implements GLFBODrawable.Resizeable {
618         protected ResizeableImpl(final GLDrawableFactoryImpl factory, final GLDrawableImpl parent, final ProxySurface surface,
619                                  final GLCapabilitiesImmutable fboCaps, final int textureUnit) {
620             super(factory, parent, surface, fboCaps, textureUnit);
621         }
622
623         @Override
624         public final void setSurfaceSize(final GLContext context, final int newWidth, final int newHeight) throws NativeWindowException, GLException {
625             if(DEBUG) {
626                 System.err.println("GLFBODrawableImpl.ResizeableImpl setSize: ("+getThreadName()+"): "+newWidth+"x"+newHeight+" - surfaceHandle 0x"+Long.toHexString(getNativeSurface().getSurfaceHandle()));
627             }
628             final int lockRes = lockSurface();
629             if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) {
630                 throw new NativeWindowException("Could not lock surface: "+this);
631             }
632             try {
633                 // propagate new size
634                 final ProxySurface ps = (ProxySurface) getNativeSurface();
635                 final UpstreamSurfaceHook ush = ps.getUpstreamSurfaceHook();
636                 if(ush instanceof UpstreamSurfaceHook.MutableSize) {
637                     ((UpstreamSurfaceHook.MutableSize)ush).setSurfaceSize(newWidth, newHeight);
638                 } else {
639                     throw new InternalError("GLFBODrawableImpl.ResizableImpl's ProxySurface doesn't hold a UpstreamSurfaceHookMutableSize but "+ush.getClass().getName()+", "+ps+", ush");
640                 }
641                 if( null != context && context.isCreated() ) {
642                     resetSize(context.getGL());
643                 }
644             } finally {
645                 unlockSurface();
646             }
647         }
648     }
649 }
http://JogAmp.org git info: FAQ, tutorial and man pages.