diff options
author | Sven Gothel <[email protected]> | 2012-09-15 16:54:52 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2012-09-15 16:54:52 +0200 |
commit | 4dd44b985fe0541be3a3bcd9045d201ed3ca2cc5 (patch) | |
tree | e14c927a1da9f089297aa291dcd69f2f39b4f15e /src/nativewindow/classes | |
parent | 9036376b7806a5fc61590bf49404eb71830de92f (diff) |
Seamless Integration of an FBObject based GLFBODrawable as GLOffscreenAutoDrawable.FBO and as an OffscreenLayerSurface's drawable (OSX) - Fix Bugs 569 and 599
Summary:
=========
The new FBObject based GLFBODrawable implementation allows the seamless utilization of
FBO offscreen rendering in single buffer, double buffer and MSAA mode.
The GLFBODrawable uses a parent drawable based on a
dummy surface to allow a GLOffscreenAutoDrawable.FBO creation
or a mutable surface supporting an existing offscreen layer surface (OSX CALayer).
Offscreen GLDrawable's and GLOffscreenAutoDrawable's can be selected via the
GLCapabilities. If simply !onscreen is selected in the caps instance w/o enabling FBO, PBuffer or Bitmap,
the factory will automatically choose regarding availability:
FBO > PBuffer > Bitmap
Double buffering is supported in MSAA more (intrinsic) and explicit in non MSAA.
It is preferred when delivering resources (texture id's or framebuffer names)
to a shared GLContext.
This is demonstrated in (emulates our OSX CALayer implementation):
TestFBOOffThreadSharedContextMix2DemosES2NEWT,
TestFBOOnThreadSharedContext1DemoES2NEWT
and with the OSX JAWT OffscreenLayerSurface itself. FBO is the preferred choice.
+++
Offscreen drawables can be resized while maintaining a bound GLContext (e.g. w/ GLAutoDrawable).
Previously both, drawable and context, needed to be destroyed and recreated at offscreen resize.
Common implementation in GLDrawableHelper is used in the implementations
(NEWT's GLWindow, AWT GLCanvas, SWT GLCanvas).
+++
Tested:
=======
Manually run all unit tests on:
- Linux x86_64 NVidia/AMD/Mesa3d(ES)
- OSX x86_64 NVidia
- Windows x86_64 NVidia
- Android arm Mali-400/Tegra-2
No regressions.
Disclaimer:
===========
This feature is committed almost in one patch.
Both previous commits were introducing / fixing the capabilities behavior:
90d45928186f2be99999461cfe45f76a783cc961
9036376b7806a5fc61590bf49404eb71830de92f
I have to appologize for the huge size and impact (files and platforms) of this commit
however, I could not find a better way to inject this feature in one sane piece.
NativeWindow Details:
=====================
Complete decoupling of platform impl. detail of surfaces
implementing ProxySurface. Used to generalize dummy surfaces and EGL surfaces
on top of a native platform surface.
- ProxySurface.UpstreamSurfaceHook -> UpstreamSurfaceHook
- abstract class ProxySurface -> interface ProxySurface + ProxySurfaceImpl
- Misc. implementations
JOGL Details:
=====================
FBOObject: API Change / Simplification & Usability
- Removed reference counter to remove complexity, allow user to choose.
- Add 'dispose' flag for detachColorbuffer(..), allowing to keep attachment alive
- Fix equals operation of Attachment
- Check pre-exising GL errors
- Interface Colobuffer gets lifecycle methods
- Add static factory methods to create Attachments w/o FBObject instance
- Reset:
- Clip min size to 1
- Keep alive samplingSink, i.e. don't issue resetMSAATexture2DSink(..).
It gets called at syncFramebuffer()/use(..) later on before actual usage.
This allows the consumer to utilize the GL_FRONT buffer until (e.g.) swap.
- misc bugfixes
GLOffscreenAutoDrawable: API Change
- Reloc and interfacing
- class com.jogamp.opengl.OffscreenAutoDrawable -> javax.media.opengl.*
interfaces GLOffscreenAutoDrawable extends GLAutoDrawable
GLOffscreenAutoDrawable.FBO extends GLOffscreenAutoDrawable, GLFBODrawable
- Added general implementation and FBO specialization
- Replacing GLPBuffer (deprecated) .. usable for any offscreen GLDrawable via factory
GLAutoDrawable:
- Add 'GLDrawable getDelegatedDrawable()'
- Refine documentation of setContext(..), remove disclaimer and fixme tags
GLDrawableFactory:
- Refine API doc and it's selection mechanism for offscreen.
- Add createOffscreenDrawable(..)
- Add createOffscreenAutoDrawable(..)
- Add canCreateFBO(..)
- Mark createGLPbuffer(..) deprectated
Mark GLPBuffer deprecated
New: GLFBODrawable extends GLDrawable
GLCanvas (AWT and SWT): Add offscreen resize support w/o GLContext recreation
GLAutoDrawableBase .. GLWindow:
- Add offscreen resize support w/o GLContext recreation
- Remove double swapBuffer call
-
GLBase/GLContext:
- Add:
- boolean hasBasicFBOSupport()
- boolean hasFullFBOSupport()
- int getMaxRenderbufferSamples()
- boolean isTextureFormatBGRA8888Available()
GLContext: Fix version detection and hasGLSL()
- Version detection in setGLFunctionAvailability(..)
- Query GL_VERSION ASAP and parse it and compare w/ given major/minor
- Use parsed version if valid and lower than given _or_ given is invalid.
- Use validated version for caching (procaddr, ..), version number, etc.
- Fix hasGLSL()
Since 'isGL2ES2()' is true if 'isGL2()'
and the latter simply alows GL 1.*, we confine the result to a GL >= 2.0
on desktops. FIXME: May consider GL 1.5 w/ extensions.
- return isGL2ES2();
+ return isGLES2() ||
+ isGL3() ||
+ isGL2() && ctxMajorVersion>1 ;
GLDrawableImpl:
- Add 'associateContext(GLContext, boolean)' allowing impl.
to have a (weak) reference list of bound context.
This is was pulled up from the OSX specific drawable impl.
- swapBuffersImpl() -> swapBuffersImpl(boolean doubleBuffered)
and call it regardless of single buffering.
This is required to propagate this event to impl. properly,
i.e. FBODrawable requires a swap notification.
- Clarify 'contextMadeCurrent(..)' protocol
GLDrawableHelper:
- Add resize and recreate offscreen drawable util method
- Simplify required init/reshape calls for GLEventListener
-
GLGraphicsConfigurationUtil:
- fixWinAttribBitsAndHwAccel: Reflect sharede context hw-accel bits
- OSX has no offscreen bitmap, use pbuffer
- use proper offscreen auto selection if offscreen and no modes are set
EGL Context/Drawable/DrawableFactory: Abstract native platform code out of base classes
- Use EGLWrappedSurface w/ UpstreamSurfaceHook to handle upstream (X11, WGL, ..)
lifecycle - in case the EGL resource is hooked up on it.
Invisible dummy surfaces: All platforms
- size is now reduced to 64x64 and decoupled of actual generic mutable size
- fix device lifecycle, no more leaks
+++
OSX
====
Enable support for GLFBODrawableImpl in offscreen CALayer mode
- NSOpenGLImpl: hooks to calayer native code
- calayer code:
- allows pbuffer and texures (FBO)
- decouple size and draw calls avoiding flickering
- enable auto resize of calayer tree
MacOSXCGLContext:
- NSOpenGLImpl:
- Fix false pbuffer 'usage', validate the pointer
- If !pbuffer, copy other window mode bits of caps
-
MacOSXCGLGraphicsConfiguration:
- Only assume pbuffer if !onscreen
- Remove reference of native pixelformat pointer
Native code:
- use 'respondsToSelector:' query before calling 'new' methods
avoiding an error message where unsuported (prev. OSX versions)
- if monitor refresh-rate is queried 0, set to default 60hz
- add missing NSAutoreleasePool decoration
+++
Android / NEWT:
===============
Issue setVisible(..) w/o wait, i.e. queue on EDT,
@Android surfaceChanged() callback. Otherwise we could deadlock:
setVisible(..) -> EDT -> setVisibleImpl(..) -> 'GL-display'.
the latter may may cause havoc while Android-EDT is blocked [until it's return].
Diffstat (limited to 'src/nativewindow/classes')
17 files changed, 920 insertions, 325 deletions
diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookMutableSize.java b/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookMutableSize.java new file mode 100644 index 000000000..22c95f3dd --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookMutableSize.java @@ -0,0 +1,39 @@ +package com.jogamp.nativewindow; + +import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.UpstreamSurfaceHook; + +public class DelegatedUpstreamSurfaceHookMutableSize extends UpstreamSurfaceHookMutableSize { + final UpstreamSurfaceHook upstream; + + /** + * @param upstream optional upstream UpstreamSurfaceHook used for {@link #create(ProxySurface)} and {@link #destroy(ProxySurface)}. + * @param width initial width + * @param height initial height + */ + public DelegatedUpstreamSurfaceHookMutableSize(UpstreamSurfaceHook upstream, int width, int height) { + super(width, height); + this.upstream = upstream; + } + + @Override + public final void create(ProxySurface s) { + if(null != upstream) { + upstream.create(s); + } + } + + @Override + public final void destroy(ProxySurface s) { + if(null != upstream) { + upstream.destroy(s); + } + } + + @Override + public String toString() { + return getClass().getSimpleName()+"[ "+ width + "x" + height + ", " + upstream + "]"; + } + +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookWithSurfaceSize.java b/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookWithSurfaceSize.java new file mode 100644 index 000000000..85e24582c --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/DelegatedUpstreamSurfaceHookWithSurfaceSize.java @@ -0,0 +1,54 @@ +package com.jogamp.nativewindow; + +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.UpstreamSurfaceHook; + +public class DelegatedUpstreamSurfaceHookWithSurfaceSize implements UpstreamSurfaceHook { + final UpstreamSurfaceHook upstream; + final NativeSurface surface; + + /** + * @param upstream optional upstream UpstreamSurfaceHook used for {@link #create(ProxySurface)} and {@link #destroy(ProxySurface)}. + * @param surface mandatory {@link NativeSurface} used for {@link #getWidth(ProxySurface)} and {@link #getHeight(ProxySurface)} + */ + public DelegatedUpstreamSurfaceHookWithSurfaceSize(UpstreamSurfaceHook upstream, NativeSurface surface) { + this.upstream = upstream; + this.surface = surface; + if(null == surface) { + throw new IllegalArgumentException("given surface is null"); + } + } + + @Override + public final void create(ProxySurface s) { + if(null != upstream) { + upstream.create(s); + } + } + + @Override + public final void destroy(ProxySurface s) { + if(null != upstream) { + upstream.destroy(s); + } + } + + @Override + public final int getWidth(ProxySurface s) { + return surface.getWidth(); + } + + @Override + public final int getHeight(ProxySurface s) { + return surface.getHeight(); + } + + @Override + public String toString() { + final String us_s = null != surface ? ( surface.getClass().getName() + ": 0x" + Long.toHexString(surface.getSurfaceHandle()) + " " +surface.getWidth() + "x" + surface.getHeight() ) : "nil"; + return getClass().getSimpleName()+"["+upstream+", "+us_s+"]"; + } + +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/UpstreamSurfaceHookMutableSize.java b/src/nativewindow/classes/com/jogamp/nativewindow/UpstreamSurfaceHookMutableSize.java new file mode 100644 index 000000000..29c540ac4 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/UpstreamSurfaceHookMutableSize.java @@ -0,0 +1,45 @@ +package com.jogamp.nativewindow; + +import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.UpstreamSurfaceHook; + +public class UpstreamSurfaceHookMutableSize implements UpstreamSurfaceHook.MutableSize { + int width, height; + + /** + * @param width initial width + * @param height initial height + */ + public UpstreamSurfaceHookMutableSize(int width, int height) { + this.width = width; + this.height = height; + } + + @Override + public final void setSize(int width, int height) { + this.width = width; + this.height = height; + } + + @Override + public final int getWidth(ProxySurface s) { + return width; + } + + @Override + public final int getHeight(ProxySurface s) { + return height; + } + @Override + public void create(ProxySurface s) { /* nop */ } + + @Override + public void destroy(ProxySurface s) { /* nop */ } + + @Override + public String toString() { + return getClass().getSimpleName()+"[ "+ width + "x" + height + "]"; + } + +} + diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java index d4b927cf1..a62d08ccf 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java @@ -39,12 +39,14 @@ package com.jogamp.nativewindow.awt; import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; +import com.jogamp.nativewindow.MutableGraphicsConfiguration; import java.awt.Component; import java.awt.Container; import java.applet.Applet; import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.CapabilitiesImmutable; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; @@ -110,21 +112,6 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, this.offscreenSurfaceLayer = 0; } - @Override - public void setShallUseOffscreenLayer(boolean v) { - shallUseOffscreenLayer = v; - } - - @Override - public final boolean getShallUseOffscreenLayer() { - return shallUseOffscreenLayer; - } - - @Override - public final boolean isOffscreenLayerSurfaceEnabled() { - return isOffscreenLayerSurface; - } - protected synchronized void invalidate() { invalidateNative(); jawt = null; @@ -136,26 +123,29 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, } protected abstract void invalidateNative(); - protected final void updateBounds(JAWT_Rectangle jawtBounds) { - if(DEBUG) { - final Rectangle jb = new Rectangle(jawtBounds.getX(), jawtBounds.getY(), jawtBounds.getWidth(), jawtBounds.getHeight()); - if(!bounds.equals(jb)) { + protected final boolean updateBounds(JAWT_Rectangle jawtBounds) { + final Rectangle jb = new Rectangle(jawtBounds.getX(), jawtBounds.getY(), jawtBounds.getWidth(), jawtBounds.getHeight()); + final boolean changed = !bounds.equals(jb); + + if(changed) { + if(DEBUG) { System.err.println("JAWTWindow.updateBounds: "+bounds+" -> "+jb); Thread.dumpStack(); } + bounds.setX(jawtBounds.getX()); + bounds.setY(jawtBounds.getY()); + bounds.setWidth(jawtBounds.getWidth()); + bounds.setHeight(jawtBounds.getHeight()); + + if(component instanceof Container) { + java.awt.Insets contInsets = ((Container)component).getInsets(); + insets.setLeftWidth(contInsets.left); + insets.setRightWidth(contInsets.right); + insets.setTopHeight(contInsets.top); + insets.setBottomHeight(contInsets.bottom); + } } - bounds.setX(jawtBounds.getX()); - bounds.setY(jawtBounds.getY()); - bounds.setWidth(jawtBounds.getWidth()); - bounds.setHeight(jawtBounds.getHeight()); - - if(component instanceof Container) { - java.awt.Insets contInsets = ((Container)component).getInsets(); - insets.setLeftWidth(contInsets.left); - insets.setRightWidth(contInsets.right); - insets.setTopHeight(contInsets.top); - insets.setBottomHeight(contInsets.bottom); - } + return changed; } /** @return the JAWT_DrawingSurfaceInfo's (JAWT_Rectangle) bounds, updated with lock */ @@ -181,9 +171,29 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, return jawt; } - /** - * {@inheritDoc} - */ + // + // OffscreenLayerOption + // + + @Override + public void setShallUseOffscreenLayer(boolean v) { + shallUseOffscreenLayer = v; + } + + @Override + public final boolean getShallUseOffscreenLayer() { + return shallUseOffscreenLayer; + } + + @Override + public final boolean isOffscreenLayerSurfaceEnabled() { + return isOffscreenLayerSurface; + } + + // + // OffscreenLayerSurface + // + @Override public final void attachSurfaceLayer(final long layerHandle) throws NativeWindowException { if( !isOffscreenLayerSurfaceEnabled() ) { @@ -205,9 +215,6 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, } protected abstract void attachSurfaceLayerImpl(final long layerHandle); - /** - * {@inheritDoc} - */ @Override public final void detachSurfaceLayer() throws NativeWindowException { if( !isOffscreenLayerSurfaceEnabled() ) { @@ -232,11 +239,21 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, } protected abstract void detachSurfaceLayerImpl(final long layerHandle); + protected final long getAttachedSurfaceLayer() { + return offscreenSurfaceLayer; + } + @Override public final boolean isSurfaceLayerAttached() { return 0 != offscreenSurfaceLayer; } + @Override + public final void setChosenCapabilities(CapabilitiesImmutable caps) { + ((MutableGraphicsConfiguration)getGraphicsConfiguration()).setChosenCapabilities(caps); + getPrivateGraphicsConfiguration().setChosenCapabilities(caps); + } + // // SurfaceUpdateListener // @@ -381,7 +398,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, public final AbstractGraphicsConfiguration getGraphicsConfiguration() { return config.getNativeGraphicsConfiguration(); } - + @Override public final long getDisplayHandle() { return getGraphicsConfiguration().getScreen().getDevice().getHandle(); @@ -393,13 +410,13 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, } @Override - public int getWidth() { + public final int getWidth() { return component.getWidth(); } @Override - public int getHeight() { - return component.getHeight(); + public final int getHeight() { + return component.getHeight(); } // diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java b/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java index 40042ec81..b824350ff 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java @@ -67,8 +67,8 @@ public class EGLGraphicsDevice extends DefaultGraphicsDevice implements Cloneabl * Note that this is not an open connection, ie no native display handle exist. * This constructor exist to setup a default device connection/unit.<br> */ - public EGLGraphicsDevice(String connection, int unitID) { - super(NativeWindowFactory.TYPE_EGL, connection, unitID); + public EGLGraphicsDevice() { + super(NativeWindowFactory.TYPE_EGL, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); this.nativeDisplayID[0] = 0 ; // EGL.EGL_DEFAULT_DISPLAY this.eglLifecycleCallback = null; } diff --git a/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java b/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java index cec7d4ec3..27462ae70 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java +++ b/src/nativewindow/classes/javax/media/nativewindow/NativeSurface.java @@ -124,8 +124,11 @@ public interface NativeSurface extends SurfaceUpdatedListener { /** * Provide a mechanism to utilize custom (pre-) swap surface * code. This method is called before the render toolkit (e.g. JOGL) - * swaps the buffer/surface. The implementation may itself apply the swapping, + * swaps the buffer/surface if double buffering is enabled. + * <p> + * The implementation may itself apply the swapping, * in which case true shall be returned. + * </p> * * @return true if this method completed swapping the surface, * otherwise false, in which case eg the GLDrawable diff --git a/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java b/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java index f7dbc6c27..f9800109c 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java +++ b/src/nativewindow/classes/javax/media/nativewindow/OffscreenLayerSurface.java @@ -50,4 +50,7 @@ public interface OffscreenLayerSurface { /** Returns true if a surface layer is attached, otherwise false. */ public boolean isSurfaceLayerAttached(); + /** Sets the capabilities of this instance, allowing upstream API's to refine it, i.e. OpenGL related settings. */ + public void setChosenCapabilities(CapabilitiesImmutable caps); + } diff --git a/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java b/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java index 7fc9789c2..395fdc818 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java +++ b/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java @@ -1,5 +1,5 @@ /** - * Copyright 2010 JogAmp Community. All rights reserved. + * Copyright 2012 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: @@ -29,242 +29,82 @@ package javax.media.nativewindow; import jogamp.nativewindow.Debug; -import jogamp.nativewindow.SurfaceUpdatedHelper; -import com.jogamp.common.util.locks.LockFactory; -import com.jogamp.common.util.locks.RecursiveLock; - -public abstract class ProxySurface implements NativeSurface, MutableSurface { +/** + * Provides a mutable {@link NativeSurface}, i.e. {@link MutableSurface}, while allowing an + * {@link UpstreamSurfaceHook} to influence the lifecycle and information. + * + * @see UpstreamSurfaceHook + * @see MutableSurface + * @see NativeSurface + */ +public interface ProxySurface extends MutableSurface { public static final boolean DEBUG = Debug.debug("ProxySurface"); /** - * Implementation specific bitvalue stating the upstream's {@link AbstractGraphicsDevice} is owned by this {@link ProxySurface}. - * @see #setImplBitfield(int) - * @see #getImplBitfield() + * Implementation specific bit-value stating this {@link ProxySurface} owns the upstream's surface handle + * @see #addUpstreamOptionBits(int) + * @see #getUpstreamOptionBits() */ - public static final int OWN_DEVICE = 1 << 7; + public static final int OPT_PROXY_OWNS_UPSTREAM_SURFACE = 1 << 6; + + /** + * Implementation specific bit-value stating this {@link ProxySurface} owns the upstream's {@link AbstractGraphicsDevice}. + * @see #addUpstreamOptionBits(int) + * @see #getUpstreamOptionBits() + */ + public static final int OPT_PROXY_OWNS_UPSTREAM_DEVICE = 1 << 7; /** * Implementation specific bitvalue stating the upstream's {@link NativeSurface} is an invisible window, i.e. maybe incomplete. - * @see #setImplBitfield(int) - * @see #getImplBitfield() + * @see #addUpstreamOptionBits(int) + * @see #getUpstreamOptionBits() */ - public static final int INVISIBLE_WINDOW = 1 << 8; + public static final int OPT_UPSTREAM_WINDOW_INVISIBLE = 1 << 8; - /** Interface allowing upstream caller to pass lifecycle actions and size info to a {@link ProxySurface} instance. */ - public interface UpstreamSurfaceHook { - /** called within {@link ProxySurface#createNotify()} within lock, before using surface. */ - public void create(ProxySurface s); - /** called within {@link ProxySurface#destroyNotify()} within lock, before clearing fields. */ - public void destroy(ProxySurface s); + /** Allow redefining the AbstractGraphicsConfiguration */ + public void setGraphicsConfiguration(AbstractGraphicsConfiguration cfg); - /** Returns the width of the upstream surface */ - public int getWidth(ProxySurface s); - /** Returns the height of the upstream surface */ - public int getHeight(ProxySurface s); - } + /** Returns the set {@link UpstreamSurfaceHook}, or null if not set. */ + public UpstreamSurfaceHook getUpstreamSurfaceHook(); - private final SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper(); - private final AbstractGraphicsConfiguration config; // control access due to delegation - private final UpstreamSurfaceHook upstream; - public final int initialWidth; - public final int initialHeight; - private long surfaceHandle_old; - protected RecursiveLock surfaceLock = LockFactory.createRecursiveLock(); - protected long displayHandle; - protected int scrnIndex; - protected int implBitfield; - /** - * @param cfg the {@link AbstractGraphicsConfiguration} to be used - * @param initialWidth the initial width - * @param initialHeight the initial height + * Sets the {@link UpstreamSurfaceHook} and returns the previous value. */ - protected ProxySurface(AbstractGraphicsConfiguration cfg, int initialWidth, int initialHeight, UpstreamSurfaceHook upstream) { - if(null == cfg) { - throw new IllegalArgumentException("null config"); - } - this.config = cfg; - this.upstream = upstream; - this.initialWidth = initialWidth; - this.initialHeight = initialHeight; - this.displayHandle=config.getNativeGraphicsConfiguration().getScreen().getDevice().getHandle(); - this.surfaceHandle_old = 0; - this.implBitfield = 0; - } - - public final UpstreamSurfaceHook getUpstreamSurfaceHook() { return upstream; } + public void setUpstreamSurfaceHook(UpstreamSurfaceHook hook); + + /** + * Enables or disables the {@link UpstreamSurfaceHook} lifecycle functions + * {@link UpstreamSurfaceHook#create(ProxySurface)} and {@link UpstreamSurfaceHook#destroy(ProxySurface)}. + * <p> + * Use this for small code blocks where the native resources shall not change, + * i.e. resizing a derived (OpenGL) drawable. + * </p> + */ + public void enableUpstreamSurfaceHookLifecycle(boolean enable); /** - * If a valid {@link UpstreamSurfaceHook} instance is passed in the - * {@link ProxySurface#ProxySurface(AbstractGraphicsConfiguration, int, int, UpstreamSurfaceHook) constructor}, * {@link UpstreamSurfaceHook#create(ProxySurface)} is being issued and the proxy surface/window handles shall be set. */ - public void createNotify() { - if(null != upstream) { - upstream.create(this); - } - this.displayHandle=config.getNativeGraphicsConfiguration().getScreen().getDevice().getHandle(); - this.surfaceHandle_old = 0; - } + public void createNotify(); /** - * If a valid {@link UpstreamSurfaceHook} instance is passed in the - * {@link ProxySurface#ProxySurface(AbstractGraphicsConfiguration, int, int, UpstreamSurfaceHook) constructor}, - * {@link UpstreamSurfaceHook#destroy(ProxySurface)} is being issued and all fields are cleared. + * {@link UpstreamSurfaceHook#destroy(ProxySurface)} is being issued and all proxy surface/window handles shall be cleared. */ - public void destroyNotify() { - if(null != upstream) { - upstream.destroy(this); - invalidateImpl(); - } - this.displayHandle = 0; - this.surfaceHandle_old = 0; - } + public void destroyNotify(); - /** - * Must be overridden by implementations allowing having a {@link UpstreamSurfaceHook} being passed. - * @see #destroyNotify() - */ - protected void invalidateImpl() { - throw new InternalError("UpstreamSurfaceHook given, but required method not implemented."); - } + public StringBuilder getUpstreamOptionBits(StringBuilder sink); + public int getUpstreamOptionBits(); - @Override - public final long getDisplayHandle() { - return displayHandle; - } - - protected final AbstractGraphicsConfiguration getPrivateGraphicsConfiguration() { - return config; - } - - @Override - public final AbstractGraphicsConfiguration getGraphicsConfiguration() { - return config.getNativeGraphicsConfiguration(); - } - - @Override - public final int getScreenIndex() { - return getGraphicsConfiguration().getScreen().getIndex(); - } - - @Override - public abstract long getSurfaceHandle(); - - @Override - public abstract void setSurfaceHandle(long surfaceHandle); + /** Returns <code>true</code> if the give bit-mask <code>v</code> is set in this instance upstream-option-bits, otherwise <code>false</code>.*/ + public boolean containsUpstreamOptionBits(int v); - @Override - public final int getWidth() { - if(null != upstream) { - return upstream.getWidth(this); - } - return initialWidth; - } - - @Override - public final int getHeight() { - if(null != upstream) { - return upstream.getHeight(this); - } - return initialHeight; - } - - @Override - public boolean surfaceSwap() { - return false; - } - - @Override - public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { - surfaceUpdatedHelper.addSurfaceUpdatedListener(l); - } - - @Override - public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException { - surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l); - } - - @Override - public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { - surfaceUpdatedHelper.removeSurfaceUpdatedListener(l); - } - - @Override - public void surfaceUpdated(Object updater, NativeSurface ns, long when) { - surfaceUpdatedHelper.surfaceUpdated(updater, ns, when); - } - - @Override - public int lockSurface() throws NativeWindowException, RuntimeException { - surfaceLock.lock(); - int res = surfaceLock.getHoldCount() == 1 ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ? - - if ( LOCK_SURFACE_NOT_READY == res ) { - try { - final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); - adevice.lock(); - try { - res = lockSurfaceImpl(); - if(LOCK_SUCCESS == res && surfaceHandle_old != getSurfaceHandle()) { - res = LOCK_SURFACE_CHANGED; - if(DEBUG) { - System.err.println("ProxySurface: surface change 0x"+Long.toHexString(surfaceHandle_old)+" -> 0x"+Long.toHexString(getSurfaceHandle())); - // Thread.dumpStack(); - } - } - } finally { - if (LOCK_SURFACE_NOT_READY >= res) { - adevice.unlock(); - } - } - } finally { - if (LOCK_SURFACE_NOT_READY >= res) { - surfaceLock.unlock(); - } - } - } - return res; - } - - @Override - public final void unlockSurface() { - surfaceLock.validateLocked(); - surfaceHandle_old = getSurfaceHandle(); - - if (surfaceLock.getHoldCount() == 1) { - final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); - try { - unlockSurfaceImpl(); - } finally { - adevice.unlock(); - } - } - surfaceLock.unlock(); - } - - protected abstract int lockSurfaceImpl(); - - protected abstract void unlockSurfaceImpl() ; - - public final void validateSurfaceLocked() { - surfaceLock.validateLocked(); - } - - @Override - public final boolean isSurfaceLockedByOtherThread() { - return surfaceLock.isLockedByOtherThread(); - } - - @Override - public final Thread getSurfaceLockOwner() { - return surfaceLock.getOwner(); - } + /** Add the given bit-mask to this instance upstream-option-bits using bit-or w/ <code>v</code>.*/ + public void addUpstreamOptionBits(int v); - @Override - public abstract String toString(); + /** Clear the given bit-mask from this instance upstream-option-bits using bit-and w/ <code>~v</code>*/ + public void clearUpstreamOptionBits(int v); - public int getImplBitfield() { return implBitfield; } - public void setImplBitfield(int v) { implBitfield=v; } + public StringBuilder toString(StringBuilder sink); + public String toString(); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/UpstreamSurfaceHook.java b/src/nativewindow/classes/javax/media/nativewindow/UpstreamSurfaceHook.java new file mode 100644 index 000000000..6fe2e5364 --- /dev/null +++ b/src/nativewindow/classes/javax/media/nativewindow/UpstreamSurfaceHook.java @@ -0,0 +1,52 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package javax.media.nativewindow; + +/** + * Interface allowing upstream caller to pass lifecycle actions and size info + * to a {@link ProxySurface} instance. + */ +public interface UpstreamSurfaceHook { + /** called within {@link ProxySurface#createNotify()} within lock, before using surface. */ + public void create(ProxySurface s); + /** called within {@link ProxySurface#destroyNotify()} within lock, before clearing fields. */ + public void destroy(ProxySurface s); + + /** Returns the width of the upstream surface, used if {@link ProxySurface#UPSTREAM_PROVIDES_SIZE} is set. */ + public int getWidth(ProxySurface s); + /** Returns the height of the upstream surface, used if {@link ProxySurface#UPSTREAM_PROVIDES_SIZE} is set. */ + public int getHeight(ProxySurface s); + + /** + * {@link UpstreamSurfaceHook} w/ mutable size, allowing it's {@link ProxySurface} user to resize. + */ + public interface MutableSize extends UpstreamSurfaceHook { + public void setSize(int width, int height); + } +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java b/src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java new file mode 100644 index 000000000..63f56cbae --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java @@ -0,0 +1,326 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package jogamp.nativewindow; + +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.SurfaceUpdatedListener; +import javax.media.nativewindow.UpstreamSurfaceHook; + + +import com.jogamp.common.util.locks.LockFactory; +import com.jogamp.common.util.locks.RecursiveLock; + +public abstract class ProxySurfaceImpl implements ProxySurface { + private final SurfaceUpdatedHelper surfaceUpdatedHelper = new SurfaceUpdatedHelper(); + protected long displayHandle; // convenient ref of config.screen.device.handle + private AbstractGraphicsConfiguration config; // control access due to delegation + private UpstreamSurfaceHook upstream; + private long surfaceHandle_old; + private RecursiveLock surfaceLock = LockFactory.createRecursiveLock(); + private int implBitfield; + private boolean upstreamSurfaceHookLifecycleEnabled; + + /** + * @param cfg the {@link AbstractGraphicsConfiguration} to be used + * @param upstream the {@link UpstreamSurfaceHook} to be used + * @param ownsDevice <code>true</code> if this {@link ProxySurface} instance + * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice}, + * otherwise <code>false</code>. Owning the device implies closing it at {@link #destroyNotify()}. + */ + protected ProxySurfaceImpl(AbstractGraphicsConfiguration cfg, UpstreamSurfaceHook upstream, boolean ownsDevice) { + if(null == cfg) { + throw new IllegalArgumentException("null AbstractGraphicsConfiguration"); + } + if(null == upstream) { + throw new IllegalArgumentException("null UpstreamSurfaceHook"); + } + this.config = cfg; + this.displayHandle=config.getNativeGraphicsConfiguration().getScreen().getDevice().getHandle(); + this.upstream = upstream; + this.surfaceHandle_old = 0; + this.implBitfield = 0; + this.upstreamSurfaceHookLifecycleEnabled = true; + if(ownsDevice) { + addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); + } + } + + @Override + public final UpstreamSurfaceHook getUpstreamSurfaceHook() { return upstream; } + + @Override + public void setUpstreamSurfaceHook(UpstreamSurfaceHook hook) { + if(null == hook) { + throw new IllegalArgumentException("null UpstreamSurfaceHook"); + } + upstream = hook; + } + + @Override + public final void enableUpstreamSurfaceHookLifecycle(boolean enable) { + upstreamSurfaceHookLifecycleEnabled = enable; + } + + @Override + public void createNotify() { + if(upstreamSurfaceHookLifecycleEnabled) { + upstream.create(this); + } + this.displayHandle=config.getNativeGraphicsConfiguration().getScreen().getDevice().getHandle(); + this.surfaceHandle_old = 0; + } + + @Override + public void destroyNotify() { + if(upstreamSurfaceHookLifecycleEnabled) { + upstream.destroy(this); + if( containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ) ) { + final AbstractGraphicsDevice aDevice = getGraphicsConfiguration().getScreen().getDevice(); + aDevice.close(); + clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); + } + invalidateImpl(); + } + this.displayHandle = 0; + this.surfaceHandle_old = 0; + } + + /** + * Must be overridden by implementations allowing having a {@link UpstreamSurfaceHook} being passed. + * @see #destroyNotify() + */ + protected void invalidateImpl() { + throw new InternalError("UpstreamSurfaceHook given, but required method not implemented."); + } + + @Override + public final long getDisplayHandle() { + return displayHandle; + } + + protected final AbstractGraphicsConfiguration getPrivateGraphicsConfiguration() { + return config; + } + + @Override + public final AbstractGraphicsConfiguration getGraphicsConfiguration() { + return config.getNativeGraphicsConfiguration(); + } + + @Override + public final void setGraphicsConfiguration(AbstractGraphicsConfiguration cfg) { + config = cfg; + } + + @Override + public final int getScreenIndex() { + return getGraphicsConfiguration().getScreen().getIndex(); + } + + @Override + public abstract long getSurfaceHandle(); + + @Override + public abstract void setSurfaceHandle(long surfaceHandle); + + @Override + public final int getWidth() { + return upstream.getWidth(this); + } + + @Override + public final int getHeight() { + return upstream.getHeight(this); + } + + @Override + public boolean surfaceSwap() { + return false; + } + + @Override + public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { + surfaceUpdatedHelper.addSurfaceUpdatedListener(l); + } + + @Override + public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException { + surfaceUpdatedHelper.addSurfaceUpdatedListener(index, l); + } + + @Override + public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { + surfaceUpdatedHelper.removeSurfaceUpdatedListener(l); + } + + @Override + public void surfaceUpdated(Object updater, NativeSurface ns, long when) { + surfaceUpdatedHelper.surfaceUpdated(updater, ns, when); + } + + @Override + public int lockSurface() throws NativeWindowException, RuntimeException { + surfaceLock.lock(); + int res = surfaceLock.getHoldCount() == 1 ? LOCK_SURFACE_NOT_READY : LOCK_SUCCESS; // new lock ? + + if ( LOCK_SURFACE_NOT_READY == res ) { + try { + final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); + adevice.lock(); + try { + res = lockSurfaceImpl(); + if(LOCK_SUCCESS == res && surfaceHandle_old != getSurfaceHandle()) { + res = LOCK_SURFACE_CHANGED; + if(DEBUG) { + System.err.println("ProxySurfaceImpl: surface change 0x"+Long.toHexString(surfaceHandle_old)+" -> 0x"+Long.toHexString(getSurfaceHandle())); + // Thread.dumpStack(); + } + } + } finally { + if (LOCK_SURFACE_NOT_READY >= res) { + adevice.unlock(); + } + } + } finally { + if (LOCK_SURFACE_NOT_READY >= res) { + surfaceLock.unlock(); + } + } + } + return res; + } + + @Override + public final void unlockSurface() { + surfaceLock.validateLocked(); + surfaceHandle_old = getSurfaceHandle(); + + if (surfaceLock.getHoldCount() == 1) { + final AbstractGraphicsDevice adevice = getGraphicsConfiguration().getScreen().getDevice(); + try { + unlockSurfaceImpl(); + } finally { + adevice.unlock(); + } + } + surfaceLock.unlock(); + } + + protected abstract int lockSurfaceImpl(); + + protected abstract void unlockSurfaceImpl() ; + + public final void validateSurfaceLocked() { + surfaceLock.validateLocked(); + } + + @Override + public final boolean isSurfaceLockedByOtherThread() { + return surfaceLock.isLockedByOtherThread(); + } + + @Override + public final Thread getSurfaceLockOwner() { + return surfaceLock.getOwner(); + } + + public final StringBuilder getUpstreamOptionBits(StringBuilder sink) { + if(null == sink) { + sink = new StringBuilder(); + } + sink.append("UOB[ "); + if(0 == implBitfield) { + sink.append("]"); + return sink; + } + boolean needsOr = false; + if( 0 != ( implBitfield & OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) { + sink.append("OWNS_SURFACE"); + needsOr = true; + } + if( 0 != ( implBitfield & OPT_PROXY_OWNS_UPSTREAM_DEVICE ) ) { + if(needsOr) { + sink.append(" | "); + } + sink.append("OWNS_DEVICE"); + needsOr = true; + } + if( 0 != ( implBitfield & OPT_UPSTREAM_WINDOW_INVISIBLE ) ) { + if(needsOr) { + sink.append(" | "); + } + sink.append("WINDOW_INVISIBLE"); + needsOr = true; + } + sink.append(" ]"); + return sink; + } + + @Override + public final int getUpstreamOptionBits() { return implBitfield; } + + @Override + public final boolean containsUpstreamOptionBits(int v) { + return v == ( implBitfield & v ) ; + } + + @Override + public final void addUpstreamOptionBits(int v) { implBitfield |= v; } + + @Override + public final void clearUpstreamOptionBits(int v) { implBitfield &= ~v; } + + @Override + public StringBuilder toString(StringBuilder sink) { + if(null == sink) { + sink = new StringBuilder(); + } + sink.append(getUpstreamSurfaceHook()). + append(", displayHandle 0x" + Long.toHexString(getDisplayHandle())). + append(", surfaceHandle 0x" + Long.toHexString(getSurfaceHandle())). + append(", size " + getWidth() + "x" + getHeight()).append(", "); + getUpstreamOptionBits(sink); + sink.append(", surfaceLock "+surfaceLock); + return sink; + } + + @Override + public String toString() { + StringBuilder msg = new StringBuilder(); + msg.append(getClass().getSimpleName()).append("[ "); + toString(msg); + msg.append(" ]"); + return msg.toString(); + } + +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/WrappedSurface.java b/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java index b7f6ba45d..e544bc61a 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/WrappedSurface.java +++ b/src/nativewindow/classes/jogamp/nativewindow/WrappedSurface.java @@ -26,17 +26,46 @@ * or implied, of JogAmp Community. */ -package com.jogamp.nativewindow; +package jogamp.nativewindow; import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.UpstreamSurfaceHook; -public class WrappedSurface extends ProxySurface { - protected long surfaceHandle; +import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; - public WrappedSurface(AbstractGraphicsConfiguration cfg, long handle, int initialWidth, int initialHeight, UpstreamSurfaceHook upstream) { - super(cfg, initialWidth, initialHeight, upstream); - surfaceHandle=handle; +public class WrappedSurface extends ProxySurfaceImpl { + protected long surfaceHandle; + + /** + * Utilizes a {@link UpstreamSurfaceHook.MutableSize} to hold the size information, + * which is being passed to the {@link ProxySurface} instance. + * + * @param cfg the {@link AbstractGraphicsConfiguration} to be used + * @param handle the wrapped pre-existing native surface handle, maybe 0 if not yet determined + * @param initialWidth + * @param initialHeight + * @param ownsDevice <code>true</code> if this {@link ProxySurface} instance + * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice}, + * otherwise <code>false</code>. Owning the device implies closing it at {@link #destroyNotify()}. + */ + public WrappedSurface(AbstractGraphicsConfiguration cfg, long handle, int initialWidth, int initialHeight, boolean ownsDevice) { + super(cfg, new UpstreamSurfaceHookMutableSize(initialWidth, initialHeight), ownsDevice); + surfaceHandle=handle; + } + + /** + * @param cfg the {@link AbstractGraphicsConfiguration} to be used + * @param handle the wrapped pre-existing native surface handle, maybe 0 if not yet determined + * @param upstream the {@link UpstreamSurfaceHook} to be used + * @param ownsDevice <code>true</code> if this {@link ProxySurface} instance + * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice}, + * otherwise <code>false</code>. + */ + public WrappedSurface(AbstractGraphicsConfiguration cfg, long handle, UpstreamSurfaceHook upstream, boolean ownsDevice) { + super(cfg, upstream, ownsDevice); + surfaceHandle=handle; } @Override @@ -63,16 +92,4 @@ public class WrappedSurface extends ProxySurface { protected final void unlockSurfaceImpl() { } - @Override - public String toString() { - final UpstreamSurfaceHook ush = getUpstreamSurfaceHook(); - final String ush_s = null != ush ? ( ush.getClass().getName() + ": " + ush ) : "nil"; - - return "WrappedSurface[config " + getPrivateGraphicsConfiguration()+ - ", displayHandle 0x" + Long.toHexString(getDisplayHandle()) + - ", surfaceHandle 0x" + Long.toHexString(getSurfaceHandle()) + - ", size " + getWidth() + "x" + getHeight() + - ", surfaceLock "+surfaceLock+ - ", upstreamSurfaceHook "+ush_s+"]"; - } } diff --git a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java index e81d61e0f..5fd242247 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java +++ b/src/nativewindow/classes/jogamp/nativewindow/jawt/macosx/MacOSXJAWTWindow.java @@ -51,7 +51,6 @@ import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.MutableSurface; import javax.media.nativewindow.util.Point; -import com.jogamp.nativewindow.MutableGraphicsConfiguration; import com.jogamp.nativewindow.awt.JAWTWindow; import jogamp.nativewindow.jawt.JAWT; @@ -71,17 +70,18 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { } protected void invalidateNative() { - surfaceHandle=0; + offscreenSurfaceHandle=0; + offscreenSurfaceHandleSet=false; if(isOffscreenLayerSurfaceEnabled()) { if(0 != rootSurfaceLayerHandle) { OSXUtil.DestroyCALayer(rootSurfaceLayerHandle); rootSurfaceLayerHandle = 0; } - if(0 != drawable) { - OSXUtil.DestroyNSWindow(drawable); - drawable = 0; + if(0 != windowHandle) { + OSXUtil.DestroyNSWindow(windowHandle); } } + windowHandle=0; } protected void attachSurfaceLayerImpl(final long layerHandle) { @@ -92,8 +92,14 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { OSXUtil.RemoveCASublayer(rootSurfaceLayerHandle, layerHandle); } - public long getSurfaceHandle() { - return isOffscreenLayerSurfaceEnabled() ? surfaceHandle : super.getSurfaceHandle() ; + @Override + public final long getWindowHandle() { + return windowHandle; + } + + @Override + public final long getSurfaceHandle() { + return offscreenSurfaceHandleSet ? offscreenSurfaceHandle : drawable /* super.getSurfaceHandle() */ ; } public void setSurfaceHandle(long surfaceHandle) { @@ -103,7 +109,8 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { if(DEBUG) { System.err.println("MacOSXJAWTWindow.setSurfaceHandle(): 0x"+Long.toHexString(surfaceHandle)); } - this.surfaceHandle = surfaceHandle; + this.offscreenSurfaceHandle = surfaceHandle; + this.offscreenSurfaceHandleSet = true; } protected JAWT fetchJAWTImpl() throws NativeWindowException { @@ -167,6 +174,7 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { unlockSurfaceImpl(); return NativeWindow.LOCK_SURFACE_NOT_READY; } else { + windowHandle = OSXUtil.GetNSWindow(drawable); ret = NativeWindow.LOCK_SUCCESS; } } else { @@ -177,36 +185,46 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { * The actual surface/ca-layer shall be created/attached * by the upper framework (JOGL) since they require more information. */ + String errMsg = null; if(0 == drawable) { - drawable = OSXUtil.CreateNSWindow(0, 0, getBounds().getWidth(), getBounds().getHeight()); - if(0 == drawable) { - unlockSurfaceImpl(); - throw new NativeWindowException("Unable to created dummy NSWindow (layered case)"); + windowHandle = OSXUtil.CreateNSWindow(0, 0, 64, 64); + if(0 == windowHandle) { + errMsg = "Unable to create dummy NSWindow (layered case)"; + } else { + drawable = OSXUtil.GetNSView(windowHandle); + if(0 == drawable) { + errMsg = "Null NSView of NSWindow 0x"+Long.toHexString(windowHandle); + } + } + if(null == errMsg) { + // fix caps reflecting offscreen! (no GL available here ..) + Capabilities caps = (Capabilities) getGraphicsConfiguration().getChosenCapabilities().cloneMutable(); + caps.setOnscreen(false); + setChosenCapabilities(caps); } - // fix caps reflecting offscreen! - Capabilities caps = (Capabilities) getPrivateGraphicsConfiguration().getChosenCapabilities().cloneMutable(); - caps.setOnscreen(false); - getPrivateGraphicsConfiguration().setChosenCapabilities(caps); - caps = (Capabilities) getGraphicsConfiguration().getChosenCapabilities().cloneMutable(); - caps.setOnscreen(false); - ((MutableGraphicsConfiguration)getGraphicsConfiguration()).setChosenCapabilities(caps); } - if(0 == rootSurfaceLayerHandle) { - rootSurfaceLayerHandle = OSXUtil.CreateCALayer(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight()); - if(0 == rootSurfaceLayerHandle) { - OSXUtil.DestroyNSWindow(drawable); - drawable = 0; - unlockSurfaceImpl(); - throw new NativeWindowException("Could not create root CALayer: "+this); + if(null == errMsg) { + if(0 == rootSurfaceLayerHandle) { + rootSurfaceLayerHandle = OSXUtil.CreateCALayer(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight()); + if(0 == rootSurfaceLayerHandle) { + errMsg = "Could not create root CALayer"; + } else if(!SetJAWTRootSurfaceLayer0(dsi.getBuffer(), rootSurfaceLayerHandle)) { + errMsg = "Could not set JAWT rootSurfaceLayerHandle 0x"+Long.toHexString(rootSurfaceLayerHandle); + } } - if(!SetJAWTRootSurfaceLayer0(dsi.getBuffer(), rootSurfaceLayerHandle)) { + } + if(null != errMsg) { + if(0 != rootSurfaceLayerHandle) { OSXUtil.DestroyCALayer(rootSurfaceLayerHandle); rootSurfaceLayerHandle = 0; - OSXUtil.DestroyNSWindow(drawable); - drawable = 0; - unlockSurfaceImpl(); - throw new NativeWindowException("Could not set JAWT rootSurfaceLayerHandle: "+this); } + if(0 != windowHandle) { + OSXUtil.DestroyNSWindow(windowHandle); + windowHandle = 0; + } + drawable = 0; + unlockSurfaceImpl(); + throw new NativeWindowException(errMsg+": "+this); } ret = NativeWindow.LOCK_SUCCESS; } @@ -264,7 +282,9 @@ public class MacOSXJAWTWindow extends JAWTWindow implements MutableSurface { private long rootSurfaceLayerHandle = 0; // attached to the JAWT_SurfaceLayer - private long surfaceHandle = 0; + private long windowHandle = 0; + private long offscreenSurfaceHandle = 0; + private boolean offscreenSurfaceHandleSet = false; // Workaround for instance of 4796548 private boolean firstLock = true; diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXDummyUpstreamSurfaceHook.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXDummyUpstreamSurfaceHook.java new file mode 100644 index 000000000..de3206c0c --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXDummyUpstreamSurfaceHook.java @@ -0,0 +1,56 @@ +package jogamp.nativewindow.macosx; + +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.UpstreamSurfaceHook; + +import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; + +public class OSXDummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize { + long nsWindow; + + /** + * @param width the initial width as returned by {@link NativeSurface#getWidth()} via {@link UpstreamSurfaceHook#getWidth(ProxySurface)}, + * not the actual dummy surface width. + * The latter is platform specific and small + * @param height the initial height as returned by {@link NativeSurface#getHeight()} via {@link UpstreamSurfaceHook#getHeight(ProxySurface)}, + * not the actual dummy surface height, + * The latter is platform specific and small + */ + public OSXDummyUpstreamSurfaceHook(int width, int height) { + super(width, height); + nsWindow = 0; + } + + @Override + public final void create(ProxySurface s) { + if(0 == nsWindow && 0 == s.getSurfaceHandle()) { + nsWindow = OSXUtil.CreateNSWindow(0, 0, 64, 64); + if(0 == nsWindow) { + throw new NativeWindowException("Error NS window 0"); + } + long nsView = OSXUtil.GetNSView(nsWindow); + if(0 == nsView) { + throw new NativeWindowException("Error NS view 0"); + } + s.setSurfaceHandle(nsView); + s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + } + s.addUpstreamOptionBits(ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE); + } + + @Override + public final void destroy(ProxySurface s) { + if( s.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) { + if( 0 == nsWindow || 0 == s.getSurfaceHandle() ) { + throw new InternalError("Owns upstream surface, but no OSX view/window: "+s+", nsWindow 0x"+Long.toHexString(nsWindow)); + } + OSXUtil.DestroyNSWindow(nsWindow); + nsWindow = 0; + s.setSurfaceHandle(0); + s.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + } + } + +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java index 149ebdf4a..b7a83e133 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java @@ -72,6 +72,10 @@ public class OSXUtil { return isNSView0(object); } + public static boolean isNSWindow(long object) { + return isNSWindow0(object); + } + /** * In case the <code>windowOrView</code> is top-level, * you shall set <code>topLevel</code> to true where @@ -114,6 +118,9 @@ public class OSXUtil { public static long GetNSView(long nsWindow) { return GetNSView0(nsWindow); } + public static long GetNSWindow(long nsView) { + return GetNSWindow0(nsView); + } public static long CreateCALayer(int x, int y, int width, int height) { return CreateCALayer0(x, y, width, height); @@ -149,6 +156,11 @@ public class OSXUtil { return IsMainThread0(); } + /** Returns the screen refresh rate in Hz. If unavailable, returns 60Hz. */ + public static int GetScreenRefreshRate(int scrn_idx) { + return GetScreenRefreshRate0(scrn_idx); + } + /*** private static boolean isAWTEDTMainThreadInit = false; private static boolean isAWTEDTMainThread; @@ -172,15 +184,18 @@ public class OSXUtil { private static native boolean initIDs0(); private static native boolean isNSView0(long object); + private static native boolean isNSWindow0(long object); private static native Object GetLocationOnScreen0(long windowOrView, int src_x, int src_y); private static native Object GetInsets0(long windowOrView); private static native long CreateNSWindow0(int x, int y, int width, int height); private static native void DestroyNSWindow0(long nsWindow); private static native long GetNSView0(long nsWindow); + private static native long GetNSWindow0(long nsView); private static native long CreateCALayer0(int x, int y, int width, int height); private static native void AddCASublayer0(long rootCALayer, long subCALayer); private static native void RemoveCASublayer0(long rootCALayer, long subCALayer); private static native void DestroyCALayer0(long caLayer); private static native void RunOnMainThread0(boolean waitUntilDone, Runnable runnable); private static native boolean IsMainThread0(); + private static native int GetScreenRefreshRate0(int scrn_idx); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIDummyUpstreamSurfaceHook.java b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIDummyUpstreamSurfaceHook.java new file mode 100644 index 000000000..aa5f3dac5 --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIDummyUpstreamSurfaceHook.java @@ -0,0 +1,50 @@ +package jogamp.nativewindow.windows; + +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.UpstreamSurfaceHook; + +import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; + +public class GDIDummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize { + /** + * @param width the initial width as returned by {@link NativeSurface#getWidth()} via {@link UpstreamSurfaceHook#getWidth(ProxySurface)}, + * not the actual dummy surface width. + * The latter is platform specific and small + * @param height the initial height as returned by {@link NativeSurface#getHeight()} via {@link UpstreamSurfaceHook#getHeight(ProxySurface)}, + * not the actual dummy surface height, + * The latter is platform specific and small + */ + public GDIDummyUpstreamSurfaceHook(int width, int height) { + super(width, height); + } + + @Override + public final void create(ProxySurface s) { + final GDISurface ms = (GDISurface)s; + if(0 == ms.getWindowHandle()) { + final long windowHandle = GDIUtil.CreateDummyWindow(0, 0, 64, 64); + if(0 == windowHandle) { + throw new NativeWindowException("Error windowHandle 0, werr: "+GDI.GetLastError()); + } + ms.setWindowHandle(windowHandle); + ms.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + } + s.addUpstreamOptionBits(ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE); + } + + @Override + public final void destroy(ProxySurface s) { + final GDISurface ms = (GDISurface)s; + if( ms.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) { + if( 0 == ms.getWindowHandle() ) { + throw new InternalError("Owns upstream surface, but no GDI window: "+ms); + } + GDI.ShowWindow(ms.getWindowHandle(), GDI.SW_HIDE); + GDIUtil.DestroyDummyWindow(ms.getWindowHandle()); + ms.setWindowHandle(0); + ms.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + } + } +} diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java b/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java index e368aa6a1..3db2b5fc9 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDISurface.java @@ -29,9 +29,13 @@ package jogamp.nativewindow.windows; import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.ProxySurface; -import javax.media.nativewindow.ProxySurface.UpstreamSurfaceHook; +import javax.media.nativewindow.UpstreamSurfaceHook; + +import jogamp.nativewindow.ProxySurfaceImpl; +import jogamp.nativewindow.windows.GDI; /** @@ -40,12 +44,20 @@ import javax.media.nativewindow.ProxySurface.UpstreamSurfaceHook; * The latter will get and release the HDC. * The size via getWidth()/getHeight() is invalid. */ -public class GDISurface extends ProxySurface { +public class GDISurface extends ProxySurfaceImpl { protected long windowHandle; protected long surfaceHandle; - public GDISurface(AbstractGraphicsConfiguration cfg, long windowHandle, int initialWidth, int initialHeight, UpstreamSurfaceHook upstream) { - super(cfg, initialWidth, initialHeight, upstream); + /** + * @param cfg the {@link AbstractGraphicsConfiguration} to be used + * @param windowHandle the wrapped pre-existing native window handle, maybe 0 if not yet determined + * @param upstream the {@link UpstreamSurfaceHook} to be used + * @param ownsDevice <code>true</code> if this {@link ProxySurface} instance + * owns the {@link AbstractGraphicsConfiguration}'s {@link AbstractGraphicsDevice}, + * otherwise <code>false</code>. Owning the device implies closing it at {@link #destroyNotify()}. + */ + public GDISurface(AbstractGraphicsConfiguration cfg, long windowHandle, UpstreamSurfaceHook upstream, boolean ownsDevice) { + super(cfg, upstream, ownsDevice); this.windowHandle=windowHandle; this.surfaceHandle=0; } @@ -114,18 +126,4 @@ public class GDISurface extends ProxySurface { final public long getSurfaceHandle() { return surfaceHandle; } - - @Override - final public String toString() { - final UpstreamSurfaceHook ush = getUpstreamSurfaceHook(); - final String ush_s = null != ush ? ( ush.getClass().getName() + ": " + ush ) : "nil"; - return getClass().getSimpleName()+"[config "+getPrivateGraphicsConfiguration()+ - ", displayHandle 0x"+Long.toHexString(getDisplayHandle())+ - ", windowHandle 0x"+Long.toHexString(windowHandle)+ - ", surfaceHandle 0x"+Long.toHexString(getSurfaceHandle())+ - ", size "+getWidth()+"x"+getHeight()+ - ", surfaceLock "+surfaceLock+ - ", upstreamSurfaceHook "+ush_s+"]"; - } - } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java new file mode 100644 index 000000000..55a29dd5e --- /dev/null +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java @@ -0,0 +1,60 @@ +package jogamp.nativewindow.x11; + +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.UpstreamSurfaceHook; + +import jogamp.nativewindow.x11.X11Lib; + +import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; +import com.jogamp.nativewindow.x11.X11GraphicsConfiguration; +import com.jogamp.nativewindow.x11.X11GraphicsDevice; +import com.jogamp.nativewindow.x11.X11GraphicsScreen; + +public class X11DummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize { + /** + * @param width the initial width as returned by {@link NativeSurface#getWidth()} via {@link UpstreamSurfaceHook#getWidth(ProxySurface)}, + * not the actual dummy surface width. + * The latter is platform specific and small + * @param height the initial height as returned by {@link NativeSurface#getHeight()} via {@link UpstreamSurfaceHook#getHeight(ProxySurface)}, + * not the actual dummy surface height, + * The latter is platform specific and small + */ + public X11DummyUpstreamSurfaceHook(int width, int height) { + super(width, height); + } + + @Override + public final void create(ProxySurface s) { + final X11GraphicsConfiguration cfg = (X11GraphicsConfiguration) s.getGraphicsConfiguration(); + final X11GraphicsScreen screen = (X11GraphicsScreen) cfg.getScreen(); + final X11GraphicsDevice device = (X11GraphicsDevice) screen.getDevice(); + if(0 == device.getHandle()) { + device.open(); + s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); + } + if( 0 == s.getSurfaceHandle() ) { + final long windowHandle = X11Lib.CreateDummyWindow(device.getHandle(), screen.getIndex(), cfg.getXVisualID(), 64, 64); + if(0 == windowHandle) { + throw new NativeWindowException("Creating dummy window failed w/ "+cfg); + } + s.setSurfaceHandle(windowHandle); + s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + } + s.addUpstreamOptionBits(ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE); + } + + @Override + public final void destroy(ProxySurface s) { + if( s.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) { + final X11GraphicsDevice device = (X11GraphicsDevice) s.getGraphicsConfiguration().getScreen().getDevice(); + if( 0 == s.getSurfaceHandle() ) { + throw new InternalError("Owns upstream surface, but no X11 window: "+s); + } + X11Lib.DestroyDummyWindow(device.getHandle(), s.getSurfaceHandle()); + s.setSurfaceHandle(0); + s.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + } + } +} |