aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java')
-rw-r--r--src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java593
1 files changed, 593 insertions, 0 deletions
diff --git a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java
new file mode 100644
index 000000000..6f5fa3eed
--- /dev/null
+++ b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java
@@ -0,0 +1,593 @@
+package jogamp.opengl;
+
+import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.NativeWindowException;
+import javax.media.nativewindow.ProxySurface;
+import javax.media.nativewindow.UpstreamSurfaceHook;
+import javax.media.opengl.GL;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLCapabilitiesImmutable;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLFBODrawable;
+
+import com.jogamp.common.util.VersionUtil;
+import com.jogamp.nativewindow.MutableGraphicsConfiguration;
+import com.jogamp.opengl.FBObject;
+import com.jogamp.opengl.FBObject.Attachment;
+import com.jogamp.opengl.FBObject.Colorbuffer;
+import com.jogamp.opengl.FBObject.TextureAttachment;
+import com.jogamp.opengl.JoglVersion;
+
+/**
+ * {@link FBObject} offscreen GLDrawable implementation, i.e. {@link GLFBODrawable}.
+ * <p>
+ * It utilizes the context lifecycle hook {@link #contextRealized(GLContext, boolean)}
+ * to initialize the {@link FBObject} instance.
+ * </p>
+ * <p>
+ * It utilizes the context current hook {@link #contextMadeCurrent(GLContext, boolean) contextMadeCurrent(context, true)}
+ * to {@link FBObject#bind(GL) bind} the FBO.
+ * </p>
+ * See {@link GLFBODrawable} for double buffering details.
+ *
+ * @see GLDrawableImpl#contextRealized(GLContext, boolean)
+ * @see GLDrawableImpl#contextMadeCurrent(GLContext, boolean)
+ * @see GLDrawableImpl#getDefaultDrawFramebuffer()
+ * @see GLDrawableImpl#getDefaultReadFramebuffer()
+ */
+public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable {
+ protected static final boolean DEBUG;
+ protected static final boolean DEBUG_SWAP;
+
+ static {
+ Debug.initSingleton();
+ DEBUG = GLDrawableImpl.DEBUG || Debug.debug("FBObject");
+ DEBUG_SWAP = DEBUG || Debug.isPropertyDefined("jogl.debug.FBObject.Swap", true);
+ }
+
+ private final GLDrawableImpl parent;
+ private GLCapabilitiesImmutable origParentChosenCaps;
+
+ private boolean initialized;
+ private int texUnit;
+ private int samples;
+ private boolean fboResetQuirk;
+
+ private FBObject[] fbos;
+ private int fboIBack; // points to GL_BACK buffer
+ private int fboIFront; // points to GL_FRONT buffer
+ private int pendingFBOReset = -1;
+ /** Indicated whether the FBO is bound. */
+ private boolean fboBound;
+ /** Indicated whether the FBO is swapped, resets to false after makeCurrent -> contextMadeCurrent. */
+ private boolean fboSwapped;
+
+ /** dump fboResetQuirk info only once pre ClassLoader and only in DEBUG mode */
+ private static volatile boolean resetQuirkInfoDumped = false;
+
+ /** number of FBOs for double buffering. TODO: Possible to configure! */
+ private static final int bufferCount = 2;
+
+ // private DoubleBufferMode doubleBufferMode; // TODO: Add or remove TEXTURE (only) DoubleBufferMode support
+
+ private SwapBufferContext swapBufferContext;
+
+ public static interface SwapBufferContext {
+ public void swapBuffers(boolean doubleBuffered);
+ }
+
+ /**
+ * @param factory
+ * @param parent
+ * @param surface
+ * @param fboCaps the requested FBO capabilities
+ * @param textureUnit
+ */
+ protected GLFBODrawableImpl(GLDrawableFactoryImpl factory, GLDrawableImpl parent, NativeSurface surface,
+ GLCapabilitiesImmutable fboCaps, int textureUnit) {
+ super(factory, surface, fboCaps, false);
+ this.initialized = false;
+
+ this.parent = parent;
+ this.origParentChosenCaps = getChosenGLCapabilities(); // just to avoid null, will be reset at initialize(..)
+ this.texUnit = textureUnit;
+ this.samples = fboCaps.getNumSamples();
+ fboResetQuirk = false;
+
+ // default .. // TODO: Add or remove TEXTURE (only) DoubleBufferMode support
+ // this.doubleBufferMode = ( samples > 0 || fboCaps.getDoubleBuffered() ) ? DoubleBufferMode.FBO : DoubleBufferMode.NONE ;
+
+ this.swapBufferContext = null;
+ }
+
+ private final void initialize(boolean realize, GL gl) {
+ if( !initialized && !realize ) {
+ if( DEBUG ) {
+ System.err.println("GLFBODrawableImpl.initialize(): WARNING - Already unrealized!");
+ Thread.dumpStack();
+ }
+ return; // NOP, no exception for de-init twice or no init!
+ }
+ if( initialized == realize ) {
+ throw new IllegalStateException("initialize already in state "+realize+": "+this);
+ }
+ if(realize) {
+ final GLCapabilities chosenFBOCaps = (GLCapabilities) getChosenGLCapabilities(); // cloned at setRealized(true)
+
+ final int maxSamples = gl.getMaxRenderbufferSamples();
+ {
+ final int newSamples = samples <= maxSamples ? samples : maxSamples;
+ if(DEBUG) {
+ System.err.println("GLFBODrawableImpl.initialize(): samples "+samples+" -> "+newSamples+"/"+maxSamples);
+ }
+ samples = newSamples;
+ }
+
+ final int fbosN;
+ if(samples > 0) {
+ fbosN = 1;
+ } else if( chosenFBOCaps.getDoubleBuffered() ) {
+ fbosN = bufferCount;
+ } else {
+ fbosN = 1;
+ }
+
+ fbos = new FBObject[fbosN];
+ fboIBack = 0; // head
+ fboIFront = fbos.length - 1; // tail
+
+ for(int i=0; i<fbosN; i++) {
+ fbos[i] = new FBObject();
+ fbos[i].reset(gl, getWidth(), getHeight(), samples, false);
+ if(fbos[i].getNumSamples() != samples) {
+ throw new InternalError("Sample number mismatch: "+samples+", fbos["+i+"] "+fbos[i]);
+ }
+ if(samples > 0) {
+ fbos[i].attachColorbuffer(gl, 0, chosenFBOCaps.getAlphaBits()>0);
+ } else {
+ fbos[i].attachTexture2D(gl, 0, chosenFBOCaps.getAlphaBits()>0);
+ }
+ if( chosenFBOCaps.getStencilBits() > 0 ) {
+ fbos[i].attachRenderbuffer(gl, Attachment.Type.DEPTH_STENCIL, 24);
+ } else {
+ fbos[i].attachRenderbuffer(gl, Attachment.Type.DEPTH, 24);
+ }
+ }
+ fbos[fboIFront].resetSamplingSink(gl);
+
+ fbos[0].formatToGLCapabilities(chosenFBOCaps);
+ chosenFBOCaps.setDoubleBuffered( chosenFBOCaps.getDoubleBuffered() || samples > 0 );
+ } else {
+ for(int i=0; i<fbos.length; i++) {
+ fbos[i].destroy(gl);
+ }
+ fbos=null;
+ }
+ fboBound = false;
+ fboSwapped = false;
+ pendingFBOReset = -1;
+ initialized = realize;
+
+ if(DEBUG) {
+ System.err.println("GLFBODrawableImpl.initialize("+realize+"): "+this);
+ Thread.dumpStack();
+ }
+ }
+
+ public final void setSwapBufferContext(SwapBufferContext sbc) {
+ swapBufferContext = sbc;
+ }
+
+ private final void reset(GL gl, int idx, int width, int height, int samples, int alphaBits, int stencilBits) {
+ if( !fboResetQuirk ) {
+ try {
+ fbos[idx].reset(gl, width, height, samples, false);
+ if(fbos[idx].getNumSamples() != samples) {
+ throw new InternalError("Sample number mismatch: "+samples+", fbos["+idx+"] "+fbos[idx]);
+ }
+ return;
+ } catch (GLException e) {
+ fboResetQuirk = true;
+ if(DEBUG) {
+ if(!resetQuirkInfoDumped) {
+ resetQuirkInfoDumped = true;
+ System.err.println("GLFBODrawable: FBO Reset failed: "+e.getMessage());
+ System.err.println("GLFBODrawable: Enabling FBOResetQuirk, due to GL driver bug.");
+ final JoglVersion joglVersion = JoglVersion.getInstance();
+ if(DEBUG) {
+ System.err.println(VersionUtil.getPlatformInfo());
+ System.err.println(joglVersion.toString());
+ System.err.println(JoglVersion.getGLInfo(gl, null));
+ } else {
+ System.err.println(joglVersion.getBriefOSGLBuildInfo(gl, null));
+ }
+ e.printStackTrace();
+ }
+ }
+ // 'fallthrough' intended
+ }
+ }
+ // resetQuirk fallback
+ fbos[idx].destroy(gl);
+ fbos[idx] = new FBObject();
+ fbos[idx].reset(gl, getWidth(), getHeight(), samples, false);
+ if(fbos[idx].getNumSamples() != samples) {
+ throw new InternalError("Sample number mismatch: "+samples+", fbos["+idx+"] "+fbos[idx]);
+ }
+ if(samples > 0) {
+ fbos[idx].attachColorbuffer(gl, 0, alphaBits>0);
+ } else {
+ fbos[idx].attachTexture2D(gl, 0, alphaBits>0);
+ }
+ if( stencilBits > 0 ) {
+ fbos[idx].attachRenderbuffer(gl, Attachment.Type.DEPTH_STENCIL, 24);
+ } else {
+ fbos[idx].attachRenderbuffer(gl, Attachment.Type.DEPTH, 24);
+ }
+ }
+
+ private final void reset(GL gl, int newSamples) throws GLException {
+ if(!initialized) {
+ // NOP if not yet initializes
+ return;
+ }
+
+ final GLContext curContext = GLContext.getCurrent();
+ final GLContext ourContext = gl.getContext();
+ final boolean ctxSwitch = null != curContext && curContext != ourContext;
+ if(DEBUG) {
+ System.err.println("GLFBODrawableImpl.reset(newSamples "+newSamples+"): BEGIN - ctxSwitch "+ctxSwitch+", "+this);
+ Thread.dumpStack();
+ }
+ Throwable tFBO = null;
+ Throwable tGL = null;
+ ourContext.makeCurrent();
+ gl.glFinish(); // sync GL command stream
+ fboBound = false; // clear bound-flag immediatly, caused by contextMadeCurrent(..) - otherwise we would swap @ release
+ fboSwapped = false;
+ try {
+ final int maxSamples = gl.getMaxRenderbufferSamples();
+ newSamples = newSamples <= maxSamples ? newSamples : maxSamples;
+
+ if(0==samples && 0<newSamples || 0<samples && 0==newSamples) {
+ // MSAA on/off switch
+ if(DEBUG) {
+ System.err.println("GLFBODrawableImpl.reset(): samples [on/off] reconfig: "+samples+" -> "+newSamples+"/"+maxSamples);
+ }
+ initialize(false, gl);
+ samples = newSamples;
+ initialize(true, gl);
+ } else {
+ if(DEBUG) {
+ System.err.println("GLFBODrawableImpl.reset(): simple reconfig: "+samples+" -> "+newSamples+"/"+maxSamples);
+ }
+ final int nWidth = getWidth();
+ final int nHeight = getHeight();
+ samples = newSamples;
+ pendingFBOReset = ( 1 < fbos.length ) ? fboIFront : -1; // pending-front reset only w/ double buffering (or zero samples)
+ final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) surface.getGraphicsConfiguration().getChosenCapabilities();
+ for(int i=0; i<fbos.length; i++) {
+ if( pendingFBOReset != i ) {
+ reset(gl, i, nWidth, nHeight, samples, caps.getAlphaBits(), caps.getStencilBits());
+ }
+ }
+ final GLCapabilities fboCapsNative = (GLCapabilities) surface.getGraphicsConfiguration().getChosenCapabilities();
+ fbos[0].formatToGLCapabilities(fboCapsNative);
+ }
+ } catch (Throwable t) {
+ tFBO = t;
+ } finally {
+ try {
+ ourContext.release();
+ if(ctxSwitch) {
+ curContext.makeCurrent();
+ }
+ } catch (Throwable t) {
+ tGL = t;
+ }
+ }
+ if(null != tFBO) {
+ throw new GLException("GLFBODrawableImpl.reset(..) FBObject.reset(..) exception", tFBO);
+ }
+ if(null != tGL) {
+ throw new GLException("GLFBODrawableImpl.reset(..) GLContext.release() exception", tGL);
+ }
+ if(DEBUG) {
+ System.err.println("GLFBODrawableImpl.reset(newSamples "+newSamples+"): END "+this);
+ }
+ }
+
+ //
+ // GLDrawable
+ //
+
+ @Override
+ public final GLContext createContext(GLContext shareWith) {
+ final GLContext ctx = parent.createContext(shareWith);
+ ctx.setGLDrawable(this, false);
+ return ctx;
+ }
+
+ //
+ // GLDrawableImpl
+ //
+
+ @Override
+ public final GLDynamicLookupHelper getGLDynamicLookupHelper() {
+ return parent.getGLDynamicLookupHelper();
+ }
+
+ @Override
+ protected final int getDefaultDrawFramebuffer() { return initialized ? fbos[fboIBack].getWriteFramebuffer() : 0; }
+
+ @Override
+ protected final int getDefaultReadFramebuffer() { return initialized ? fbos[fboIFront].getReadFramebuffer() : 0; }
+
+ @Override
+ protected final int getDefaultReadBuffer(GL gl, boolean hasDedicatedDrawableRead) {
+ return initialized ? fbos[fboIFront].getDefaultReadBuffer() : GL.GL_COLOR_ATTACHMENT0 ;
+ }
+
+ @Override
+ protected final void setRealizedImpl() {
+ final MutableGraphicsConfiguration msConfig = (MutableGraphicsConfiguration) surface.getGraphicsConfiguration();
+ if(realized) {
+ parent.setRealized(true);
+ origParentChosenCaps = (GLCapabilitiesImmutable) msConfig.getChosenCapabilities();
+ final GLCapabilities chosenFBOCaps = (GLCapabilities) origParentChosenCaps.cloneMutable();
+ chosenFBOCaps.copyFrom(getRequestedGLCapabilities());
+ msConfig.setChosenCapabilities(chosenFBOCaps);
+ } else {
+ msConfig.setChosenCapabilities(origParentChosenCaps);
+ parent.setRealized(false);
+ }
+ }
+
+ @Override
+ protected void associateContext(GLContext glc, boolean bound) {
+ initialize(bound, glc.getGL());
+ }
+
+ @Override
+ protected final void contextMadeCurrent(GLContext glc, boolean current) {
+ final GL gl = glc.getGL();
+ if(current) {
+ if( !initialized ) {
+ throw new GLException("Not initialized: "+this);
+ }
+ fbos[fboIBack].bind(gl);
+ fboBound = true;
+ fboSwapped = false;
+ } else if( fboBound && !fboSwapped ) {
+ swapFBOImpl(glc);
+ swapFBOImplPost(glc);
+ fboBound=false;
+ fboSwapped=true;
+ if(DEBUG_SWAP) {
+ System.err.println("Post FBO swap(@release): done");
+ }
+ }
+ }
+
+ @Override
+ protected void swapBuffersImpl(boolean doubleBuffered) {
+ final GLContext ctx = GLContext.getCurrent();
+ boolean doPostSwap;
+ if( null != ctx && ctx.getGLDrawable() == this && fboBound ) {
+ swapFBOImpl(ctx);
+ doPostSwap = true;
+ fboSwapped = true;
+ if(DEBUG_SWAP) {
+ System.err.println("Post FBO swap(@swap): done");
+ }
+ } else {
+ doPostSwap = false;
+ }
+ if( null != swapBufferContext ) {
+ swapBufferContext.swapBuffers(doubleBuffered);
+ }
+ if(doPostSwap) {
+ swapFBOImplPost(ctx);
+ }
+ }
+
+ private final void swapFBOImplPost(GLContext glc) {
+ // Safely reset the previous front FBO - after completing propagating swap
+ if(0 <= pendingFBOReset) {
+ final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) surface.getGraphicsConfiguration().getChosenCapabilities();
+ reset(glc.getGL(), pendingFBOReset, getWidth(), getHeight(), samples, caps.getAlphaBits(), caps.getStencilBits());
+ pendingFBOReset = -1;
+ }
+ }
+
+ private final void swapFBOImpl(GLContext glc) {
+ final GL gl = glc.getGL();
+ fbos[fboIBack].markUnbound(); // fast path, use(gl,..) is called below
+
+ if(DEBUG) {
+ int _fboIFront = ( fboIFront + 1 ) % fbos.length;
+ if(_fboIFront != fboIBack) { throw new InternalError("XXX: "+_fboIFront+"!="+fboIBack); }
+ }
+ fboIFront = fboIBack;
+ fboIBack = ( fboIBack + 1 ) % fbos.length;
+
+ final Colorbuffer colorbuffer = samples > 0 ? fbos[fboIFront].getSamplingSink() : fbos[fboIFront].getColorbuffer(0);
+ final TextureAttachment texAttachment;
+ if(colorbuffer instanceof TextureAttachment) {
+ texAttachment = (TextureAttachment) colorbuffer;
+ } else {
+ if(null == colorbuffer) {
+ throw new GLException("Front colorbuffer is null: samples "+samples+", "+this);
+ } else {
+ throw new GLException("Front colorbuffer is not a texture: "+colorbuffer.getClass().getName()+": samples "+samples+", "+colorbuffer+", "+this);
+ }
+ }
+ gl.glActiveTexture(GL.GL_TEXTURE0 + texUnit);
+ fbos[fboIFront].use(gl, texAttachment);
+
+ /* Included in above use command:
+ gl.glBindFramebuffer(GL2GL3.GL_DRAW_FRAMEBUFFER, fbos[fboIBack].getDrawFramebuffer());
+ gl.glBindFramebuffer(GL2GL3.GL_READ_FRAMEBUFFER, fbos[fboIFront].getReadFramebuffer());
+ } */
+
+ if(DEBUG_SWAP) {
+ System.err.println("Post FBO swap(X): fboI back "+fboIBack+", front "+fboIFront+", num "+fbos.length);
+ }
+ }
+
+ //
+ // GLFBODrawable
+ //
+
+ @Override
+ public final boolean isInitialized() {
+ return initialized;
+ }
+
+ @Override
+ public final void resetSize(GL gl) throws GLException {
+ reset(gl, samples);
+ }
+
+ @Override
+ public final int getTextureUnit() { return texUnit; }
+
+ @Override
+ public final void setTextureUnit(int u) { texUnit = u; }
+
+ @Override
+ public final int getNumSamples() { return samples; }
+
+ @Override
+ public void setNumSamples(GL gl, int newSamples) throws GLException {
+ if(samples != newSamples) {
+ reset(gl, newSamples);
+ }
+ }
+
+ @Override
+ public final int setNumBuffers(int bufferCount) throws GLException {
+ // FIXME: Implement
+ return bufferCount;
+ }
+
+ @Override
+ public final int getNumBuffers() {
+ return bufferCount;
+ }
+
+ /** // TODO: Add or remove TEXTURE (only) DoubleBufferMode support
+ @Override
+ public final DoubleBufferMode getDoubleBufferMode() {
+ return doubleBufferMode;
+ }
+
+ @Override
+ public final void setDoubleBufferMode(DoubleBufferMode mode) throws GLException {
+ if(initialized) {
+ throw new GLException("Not allowed past initialization: "+this);
+ }
+ final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) surface.getGraphicsConfiguration().getChosenCapabilities();
+ if(0 == samples && caps.getDoubleBuffered() && DoubleBufferMode.NONE != mode) {
+ doubleBufferMode = mode;
+ }
+ } */
+
+ @Override
+ public FBObject getFBObject(int bufferName) throws IllegalArgumentException {
+ if(!initialized) {
+ return null;
+ }
+ final FBObject res;
+ switch(bufferName) {
+ case GL.GL_FRONT:
+ if( samples > 0 ) {
+ res = fbos[0].getSamplingSinkFBO();
+ } else {
+ res = fbos[fboIFront];
+ }
+ break;
+ case GL.GL_BACK:
+ res = fbos[fboIBack];
+ break;
+ default:
+ throw new IllegalArgumentException(illegalBufferName+toHexString(bufferName));
+ }
+ return res;
+ }
+
+ @Override
+ public final TextureAttachment getTextureBuffer(int bufferName) throws IllegalArgumentException {
+ if(!initialized) {
+ return null;
+ }
+ final TextureAttachment res;
+ switch(bufferName) {
+ case GL.GL_FRONT:
+ if( samples > 0 ) {
+ res = fbos[0].getSamplingSink();
+ } else {
+ res = (TextureAttachment) fbos[fboIFront].getColorbuffer(0);
+ }
+ break;
+ case GL.GL_BACK:
+ if( samples > 0 ) {
+ throw new IllegalArgumentException("Cannot access GL_BACK buffer of MSAA FBO: "+this);
+ } else {
+ res = (TextureAttachment) fbos[fboIBack].getColorbuffer(0);
+ }
+ break;
+ default:
+ throw new IllegalArgumentException(illegalBufferName+toHexString(bufferName));
+ }
+ return res;
+ }
+ private static final String illegalBufferName = "Only GL_FRONT and GL_BACK buffer are allowed, passed ";
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName()+"[Initialized "+initialized+", realized "+isRealized()+", texUnit "+texUnit+", samples "+samples+
+ ",\n\tFactory "+getFactory()+
+ ",\n\tHandle "+toHexString(getHandle())+
+ ",\n\tCaps "+surface.getGraphicsConfiguration().getChosenCapabilities()+
+ ",\n\tfboI back "+fboIBack+", front "+fboIFront+", num "+(initialized ? fbos.length : 0)+
+ ",\n\tFBO front read "+getDefaultReadFramebuffer()+", "+getFBObject(GL.GL_FRONT)+
+ ",\n\tFBO back write "+getDefaultDrawFramebuffer()+", "+getFBObject(GL.GL_BACK)+
+ ",\n\tSurface "+surface+
+ "]";
+ }
+
+ public static class ResizeableImpl extends GLFBODrawableImpl implements GLFBODrawable.Resizeable {
+ protected ResizeableImpl(GLDrawableFactoryImpl factory, GLDrawableImpl parent, ProxySurface surface,
+ GLCapabilitiesImmutable fboCaps, int textureUnit) {
+ super(factory, parent, surface, fboCaps, textureUnit);
+ }
+
+ @Override
+ public final void setSize(GLContext context, int newWidth, int newHeight) throws NativeWindowException, GLException {
+ if(DEBUG) {
+ System.err.println("GLFBODrawableImpl.ResizeableImpl setSize: ("+getThreadName()+"): "+newWidth+"x"+newHeight+" - surfaceHandle 0x"+Long.toHexString(getNativeSurface().getSurfaceHandle()));
+ }
+ int lockRes = lockSurface();
+ if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) {
+ throw new NativeWindowException("Could not lock surface: "+this);
+ }
+ try {
+ // propagate new size
+ final ProxySurface ps = (ProxySurface) getNativeSurface();
+ final UpstreamSurfaceHook ush = ps.getUpstreamSurfaceHook();
+ if(ush instanceof UpstreamSurfaceHook.MutableSize) {
+ ((UpstreamSurfaceHook.MutableSize)ush).setSize(newWidth, newHeight);
+ } else {
+ throw new InternalError("GLFBODrawableImpl.ResizableImpl's ProxySurface doesn't hold a UpstreamSurfaceHookMutableSize but "+ush.getClass().getName()+", "+ps+", ush");
+ }
+ if( null != context && context.isCreated() ) {
+ resetSize(context.getGL());
+ }
+ } finally {
+ unlockSurface();
+ }
+ }
+ }
+}