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/jogl/classes/jogamp/opengl/egl | |
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/jogl/classes/jogamp/opengl/egl')
13 files changed, 315 insertions, 267 deletions
diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLContext.java b/src/jogl/classes/jogamp/opengl/egl/EGLContext.java index 03d0d650f..06953a8e1 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLContext.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLContext.java @@ -282,12 +282,6 @@ public abstract class EGLContext extends GLContextImpl { return EGL.eglSwapInterval(drawable.getNativeSurface().getDisplayHandle(), interval); } - @Override - public abstract void bindPbufferToTexture(); - - @Override - public abstract void releasePbufferFromTexture(); - // // Accessible .. // diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java index 0dba4bb09..167eebf3a 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java @@ -36,7 +36,8 @@ package jogamp.opengl.egl; -import javax.media.nativewindow.MutableSurface; +import java.nio.IntBuffer; + import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.ProxySurface; @@ -46,10 +47,10 @@ import javax.media.opengl.GLException; import jogamp.opengl.GLDrawableImpl; import jogamp.opengl.GLDynamicLookupHelper; +import com.jogamp.common.nio.Buffers; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; public abstract class EGLDrawable extends GLDrawableImpl { - private boolean ownEGLSurface = false; // for destruction protected EGLDrawable(EGLDrawableFactory factory, NativeSurface component) throws GLException { super(factory, component, false); @@ -58,21 +59,14 @@ public abstract class EGLDrawable extends GLDrawableImpl { @Override public abstract GLContext createContext(GLContext shareWith); - protected abstract long createSurface(EGLGraphicsConfiguration config, long nativeSurfaceHandle); + protected abstract long createSurface(EGLGraphicsConfiguration config, int width, int height, long nativeSurfaceHandle); - private final void recreateSurface() { - final EGLGraphicsConfiguration eglConfig = (EGLGraphicsConfiguration) surface.getGraphicsConfiguration(); - final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) eglConfig.getScreen().getDevice(); - if(DEBUG) { - System.err.println(getThreadName() + ": createSurface using "+eglConfig); - } - if( EGL.EGL_NO_SURFACE != surface.getSurfaceHandle() ) { - EGL.eglDestroySurface(eglDevice.getHandle(), surface.getSurfaceHandle()); - } + private final long createEGLSurface() { + final EGLWrappedSurface eglws = (EGLWrappedSurface) surface; + final EGLGraphicsConfiguration eglConfig = (EGLGraphicsConfiguration) eglws.getGraphicsConfiguration(); + final NativeSurface upstreamSurface = eglws.getUpstreamSurface(); - final EGLUpstreamSurfaceHook upstreamHook = (EGLUpstreamSurfaceHook) ((ProxySurface)surface).getUpstreamSurfaceHook(); - final NativeSurface upstreamSurface = upstreamHook.getUpstreamSurface(); - long eglSurface = createSurface(eglConfig, upstreamSurface.getSurfaceHandle()); + long eglSurface = createSurface(eglConfig, eglws.getWidth(), eglws.getHeight(), upstreamSurface.getSurfaceHandle()); int eglError0; if (EGL.EGL_NO_SURFACE == eglSurface) { @@ -86,7 +80,7 @@ public abstract class EGLDrawable extends GLDrawableImpl { if(DEBUG) { System.err.println(getThreadName() + ": Info: Creation of window surface w/ surface handle failed: "+eglConfig+", error "+toHexString(eglError0)+", retry w/ windowHandle"); } - eglSurface = createSurface(eglConfig, nw.getWindowHandle()); + eglSurface = createSurface(eglConfig, eglws.getWidth(), eglws.getHeight(), nw.getWindowHandle()); if (EGL.EGL_NO_SURFACE == eglSurface) { eglError0 = EGL.eglGetError(); } @@ -99,34 +93,53 @@ public abstract class EGLDrawable extends GLDrawableImpl { if (EGL.EGL_NO_SURFACE == eglSurface) { throw new GLException("Creation of window surface failed: "+eglConfig+", "+surface+", error "+toHexString(eglError0)); } - if(DEBUG) { - System.err.println(getThreadName() + ": setSurface using component: handle "+toHexString(surface.getSurfaceHandle())+" -> "+toHexString(eglSurface)); + System.err.println(getThreadName() + ": createEGLSurface handle "+toHexString(eglSurface)); } - - ((MutableSurface)surface).setSurfaceHandle(eglSurface); + return eglSurface; } @Override protected final void updateHandle() { - if(ownEGLSurface) { - recreateSurface(); + final EGLWrappedSurface eglws = (EGLWrappedSurface) surface; + if(DEBUG) { + System.err.println(getThreadName() + ": updateHandle of "+eglws); + } + if( eglws.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) { + if( EGL.EGL_NO_SURFACE != eglws.getSurfaceHandle() ) { + throw new InternalError("Set surface but claimed to be invalid: "+eglws); + } + eglws.setSurfaceHandle( createEGLSurface() ); + } else if( EGL.EGL_NO_SURFACE == eglws.getSurfaceHandle() ) { + throw new InternalError("Nil surface but claimed to be valid: "+eglws); + } + } + + protected void destroyHandle() { + final EGLWrappedSurface eglws = (EGLWrappedSurface) surface; + if(DEBUG) { + System.err.println(getThreadName() + ": destroyHandle of "+eglws); + } + if( EGL.EGL_NO_SURFACE == eglws.getSurfaceHandle() ) { + throw new InternalError("Nil surface but claimed to be valid: "+eglws); + } + final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) eglws.getGraphicsConfiguration().getScreen().getDevice(); + if( eglws.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) { + EGL.eglDestroySurface(eglDevice.getHandle(), eglws.getSurfaceHandle()); + eglws.setSurfaceHandle(EGL.EGL_NO_SURFACE); } } - protected static boolean isValidEGLSurface(EGLGraphicsDevice eglDevice, NativeSurface surface) { - final long eglDisplayHandle = eglDevice.getHandle(); - if (EGL.EGL_NO_DISPLAY == eglDisplayHandle) { - throw new GLException("Invalid EGL display in EGLGraphicsDevice "+eglDevice); + protected static boolean isValidEGLSurface(long eglDisplayHandle, long surfaceHandle) { + if( 0 == surfaceHandle ) { + return false; } - boolean eglSurfaceValid = 0 != surface.getSurfaceHandle(); - if(eglSurfaceValid) { - int[] tmp = new int[1]; - eglSurfaceValid = EGL.eglQuerySurface(eglDisplayHandle, surface.getSurfaceHandle(), EGL.EGL_CONFIG_ID, tmp, 0); - if(!eglSurfaceValid) { - if(DEBUG) { - System.err.println(getThreadName() + ": EGLDrawable.isValidEGLSurface eglQuerySuface failed: "+toHexString(EGL.eglGetError())+", "+surface); - } + final IntBuffer val = Buffers.newDirectIntBuffer(1); + final boolean eglSurfaceValid = EGL.eglQuerySurface(eglDisplayHandle, surfaceHandle, EGL.EGL_CONFIG_ID, val); + if( !eglSurfaceValid ) { + final int eglErr = EGL.eglGetError(); + if(DEBUG) { + System.err.println(getThreadName() + ": EGLDrawable.isValidEGLSurface eglQuerySuface failed: error "+toHexString(eglErr)+", "+toHexString(surfaceHandle)); } } return eglSurfaceValid; @@ -134,55 +147,19 @@ public abstract class EGLDrawable extends GLDrawableImpl { @Override protected final void setRealizedImpl() { - final EGLGraphicsConfiguration eglConfig = (EGLGraphicsConfiguration) surface.getGraphicsConfiguration(); - final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) eglConfig.getScreen().getDevice(); - if (realized) { - final boolean eglSurfaceValid = isValidEGLSurface(eglDevice, surface); - if(eglSurfaceValid) { - // surface holds valid EGLSurface - if(DEBUG) { - System.err.println(getThreadName() + ": EGLDrawable.setRealizedImpl re-using component's EGLSurface: handle "+toHexString(surface.getSurfaceHandle())); - } - ownEGLSurface=false; - } else { - // EGLSurface is ours - subsequent updateHandle() will issue recreateSurface(); - // However .. let's validate the surface object first - if( ! (surface instanceof ProxySurface) ) { - throw new InternalError("surface not ProxySurface: "+surface.getClass().getName()+", "+surface); - } - final ProxySurface.UpstreamSurfaceHook upstreamHook = ((ProxySurface)surface).getUpstreamSurfaceHook(); - if( null == upstreamHook ) { - throw new InternalError("null upstreamHook of: "+surface); - } - if( ! (upstreamHook instanceof EGLUpstreamSurfaceHook) ) { - throw new InternalError("upstreamHook not EGLUpstreamSurfaceHook: Surface: "+surface.getClass().getName()+", "+surface+"; UpstreamHook: "+upstreamHook.getClass().getName()+", "+upstreamHook); - } - if( null == ((EGLUpstreamSurfaceHook)upstreamHook).getUpstreamSurface() ) { - throw new InternalError("null upstream surface"); - } - ownEGLSurface=true; - if(DEBUG) { - System.err.println(getThreadName() + ": EGLDrawable.setRealizedImpl owning EGLSurface"); - } - } - } else if (ownEGLSurface && surface.getSurfaceHandle() != EGL.EGL_NO_SURFACE) { - if(DEBUG) { - System.err.println(getThreadName() + ": EGLDrawable.setRealized(false): ownSurface "+ownEGLSurface+", "+eglDevice+", eglSurface: "+toHexString(surface.getSurfaceHandle())); - } - // Destroy the window surface - if (!EGL.eglDestroySurface(eglDevice.getHandle(), surface.getSurfaceHandle())) { - throw new GLException("Error destroying window surface (eglDestroySurface)"); - } - ((MutableSurface)surface).setSurfaceHandle(EGL.EGL_NO_SURFACE); + if(DEBUG) { + System.err.println(getThreadName() + ": EGLDrawable.setRealized("+realized+"): NOP - "+surface); } } @Override - protected final void swapBuffersImpl() { - final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) surface.getGraphicsConfiguration().getScreen().getDevice(); - // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers() - if(!EGL.eglSwapBuffers(eglDevice.getHandle(), surface.getSurfaceHandle())) { - throw new GLException("Error swapping buffers, eglError "+toHexString(EGL.eglGetError())+", "+this); + protected final void swapBuffersImpl(boolean doubleBuffered) { + if(doubleBuffered) { + final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) surface.getGraphicsConfiguration().getScreen().getDevice(); + // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers() + if(!EGL.eglSwapBuffers(eglDevice.getHandle(), surface.getSurfaceHandle())) { + throw new GLException("Error swapping buffers, eglError "+toHexString(EGL.eglGetError())+", "+this); + } } } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java index 292eb17c8..e98d69140 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java @@ -52,8 +52,7 @@ import javax.media.nativewindow.MutableSurface; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.ProxySurface; -import javax.media.nativewindow.ProxySurface.UpstreamSurfaceHook; -import javax.media.nativewindow.VisualIDHolder.VIDType; +import javax.media.nativewindow.UpstreamSurfaceHook; import javax.media.nativewindow.VisualIDHolder; import javax.media.opengl.GL; import javax.media.opengl.GLCapabilities; @@ -65,6 +64,7 @@ import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; +import jogamp.nativewindow.WrappedSurface; import jogamp.opengl.Debug; import jogamp.opengl.GLDrawableFactoryImpl; import jogamp.opengl.GLDrawableImpl; @@ -76,10 +76,11 @@ import com.jogamp.common.nio.Buffers; import com.jogamp.common.nio.PointerBuffer; import com.jogamp.common.os.Platform; import com.jogamp.common.util.ReflectionUtil; -import com.jogamp.nativewindow.WrappedSurface; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; public class EGLDrawableFactory extends GLDrawableFactoryImpl { + protected static final boolean DEBUG = GLDrawableFactoryImpl.DEBUG; + /* package */ static final boolean QUERY_EGL_ES = !Debug.isPropertyDefined("jogl.debug.EGLDrawableFactory.DontQuery", true); /* package */ static final boolean QUERY_EGL_ES_NATIVE_TK = Debug.isPropertyDefined("jogl.debug.EGLDrawableFactory.QueryNativeTK", true); @@ -112,7 +113,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { } catch (JogampRuntimeException jre) { /* n/a .. */ } } - defaultDevice = new EGLGraphicsDevice(AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); + defaultDevice = new EGLGraphicsDevice(); // FIXME: Probably need to move EGL from a static model // to a dynamic one, where there can be 2 instances @@ -310,6 +311,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { try { final GLCapabilities reqCapsAny = new GLCapabilities(glp); reqCapsAny.setRedBits(5); reqCapsAny.setGreenBits(5); reqCapsAny.setBlueBits(5); reqCapsAny.setAlphaBits(0); + reqCapsAny.setDoubleBuffered(false); final GLCapabilitiesImmutable reqCapsPBuffer = GLGraphicsConfigurationUtil.fixGLPBufferGLCapabilities(reqCapsAny); final List<GLCapabilitiesImmutable> availablePBufferCapsL = getAvailableEGLConfigs(sharedEGLDevice, reqCapsPBuffer); hasPBuffer[0] = availablePBufferCapsL.size() > 0; @@ -324,18 +326,20 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { } else { final List<GLCapabilitiesImmutable> capsAnyL = getAvailableEGLConfigs(eglDevice, reqCapsAny); if(capsAnyL.size() > 0) { - final GLCapabilitiesImmutable caps = capsAnyL.get(0); - EGLContext.mapStaticGLESVersion(eglDevice, caps); + final GLCapabilitiesImmutable chosenCaps = capsAnyL.get(0); + EGLContext.mapStaticGLESVersion(eglDevice, chosenCaps); if(eglDevice != adevice) { - EGLContext.mapStaticGLESVersion(adevice, caps); + EGLContext.mapStaticGLESVersion(adevice, chosenCaps); } + final EGLGraphicsDevice adeviceEGLDevice = new EGLGraphicsDevice(adevice.getHandle(), EGL.EGL_NO_DISPLAY, adevice.getConnection(), adevice.getUnitID(), null); + EGLContext.mapStaticGLESVersion(adeviceEGLDevice, chosenCaps); success = true; } if(DEBUG) { System.err.println("EGLDrawableFactory.isEGLContextAvailable() no pbuffer config available, detected !pbuffer config: "+success); EGLGraphicsConfigurationFactory.printCaps("!PBufferCaps", capsAnyL, System.err); } - } + } } else { surface = desktopFactory.createDummySurface(adevice, reqCapsAny, null, 64, 64); // X11, WGL, .. dummy window upstreamSurface = ( surface instanceof ProxySurface ) ? (ProxySurface)surface : null ; @@ -361,6 +365,8 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { if(eglDevice != adevice) { context.mapCurrentAvailableGLVersion(adevice); } + final EGLGraphicsDevice adeviceEGLDevice = new EGLGraphicsDevice(adevice.getHandle(), EGL.EGL_NO_DISPLAY, adevice.getConnection(), adevice.getUnitID(), null); + context.mapCurrentAvailableGLVersion(adeviceEGLDevice); success = true; } else { // Oops .. something is wrong @@ -538,70 +544,9 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { if (target == null) { throw new IllegalArgumentException("Null target"); } - return new EGLOnscreenDrawable(this, getEGLSurface(target)); + return new EGLOnscreenDrawable(this, EGLWrappedSurface.get(target)); } - protected static NativeSurface getEGLSurface(NativeSurface surface) { - AbstractGraphicsConfiguration aConfig = surface.getGraphicsConfiguration(); - AbstractGraphicsDevice aDevice = aConfig.getScreen().getDevice(); - if( aDevice instanceof EGLGraphicsDevice && aConfig instanceof EGLGraphicsConfiguration ) { - if(surface instanceof WrappedSurface) { - // already wrapped surface - no wrapped recursion - if(DEBUG) { - System.err.println(getThreadName() + ": getEGLSurface - already wrapped surface - use as-is: "+surface); - } - return surface; - } - if(EGLDrawable.isValidEGLSurface((EGLGraphicsDevice)aDevice, surface)) { - // already in native EGL format - if(DEBUG) { - System.err.println(getThreadName() + ": getEGLSurface - already valid EGL surface - use as-is: "+surface); - } - return surface; - } - } - // create EGL instance out of platform native types - final EGLGraphicsDevice eglDevice; - if( aDevice instanceof EGLGraphicsDevice ) { - eglDevice = (EGLGraphicsDevice) aDevice; - if(DEBUG) { - System.err.println(getThreadName() + ": getEGLSurface - Reusing eglDevice: "+eglDevice); - } - if(0 == eglDevice.getHandle()) { - eglDevice.open(); - } - } else { - eglDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(surface); - } - final AbstractGraphicsScreen eglScreen = new DefaultGraphicsScreen(eglDevice, aConfig.getScreen().getIndex()); - final GLCapabilitiesImmutable capsRequested = (GLCapabilitiesImmutable) aConfig.getRequestedCapabilities(); - final EGLGraphicsConfiguration eglConfig; - if( aConfig instanceof EGLGraphicsConfiguration ) { - // Config is already in EGL type - reuse .. - final EGLGLCapabilities capsChosen = (EGLGLCapabilities) aConfig.getChosenCapabilities(); - if( 0 == capsChosen.getEGLConfig() ) { - // 'refresh' the native EGLConfig handle - capsChosen.setEGLConfig(EGLGraphicsConfiguration.EGLConfigId2EGLConfig(eglDevice.getHandle(), capsChosen.getEGLConfigID())); - if( 0 == capsChosen.getEGLConfig() ) { - throw new GLException("Refreshing native EGLConfig handle failed with error "+EGLContext.toHexString(EGL.eglGetError())+": "+eglDevice+", "+capsChosen+" of "+aConfig); - } - } - eglConfig = new EGLGraphicsConfiguration(eglScreen, capsChosen, capsRequested, null); - if(DEBUG) { - System.err.println(getThreadName() + ": getEGLSurface - Reusing chosenCaps: "+eglConfig); - } - } else { - eglConfig = EGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic( - capsRequested, capsRequested, null, eglScreen, aConfig.getVisualID(VIDType.NATIVE), false); - - if (null == eglConfig) { - throw new GLException("Couldn't create EGLGraphicsConfiguration from "+eglScreen); - } else if(DEBUG) { - System.err.println(getThreadName() + ": getEGLSurface - Chosen eglConfig: "+eglConfig); - } - } - return new WrappedSurface(eglConfig, EGL.EGL_NO_SURFACE, surface.getWidth(), surface.getHeight(), new EGLUpstreamSurfaceHook(surface)); - } static String getThreadName() { return Thread.currentThread().getName(); } @Override @@ -615,7 +560,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { throw new GLException("Non pbuffer not yet implemented"); } // PBuffer GLDrawable Creation - return new EGLPbufferDrawable(this, getEGLSurface(target)); + return new EGLPbufferDrawable(this, EGLWrappedSurface.get(target)); } @Override @@ -628,20 +573,24 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { @Override protected ProxySurface createMutableSurfaceImpl(AbstractGraphicsDevice deviceReq, boolean createNewDevice, GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested, - GLCapabilitiesChooser chooser, int width, int height, UpstreamSurfaceHook lifecycleHook) { + GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstreamHook) { + final boolean ownDevice; final EGLGraphicsDevice device; - if(createNewDevice) { - final EGLGraphicsDevice eglDeviceReq = (EGLGraphicsDevice) deviceReq; - device = EGLDisplayUtil.eglCreateEGLGraphicsDevice(eglDeviceReq.getNativeDisplayID(), deviceReq.getConnection(), deviceReq.getUnitID()); + if(createNewDevice || ! ( deviceReq instanceof EGLGraphicsDevice ) ) { + final long nativeDisplayID = ( deviceReq instanceof EGLGraphicsDevice) ? + ( (EGLGraphicsDevice) deviceReq ).getNativeDisplayID() : deviceReq.getHandle() ; + device = EGLDisplayUtil.eglCreateEGLGraphicsDevice(nativeDisplayID, deviceReq.getConnection(), deviceReq.getUnitID()); + ownDevice = true; } else { device = (EGLGraphicsDevice) deviceReq; + ownDevice = false; } final DefaultGraphicsScreen screen = new DefaultGraphicsScreen(device, 0); final EGLGraphicsConfiguration config = EGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, screen, VisualIDHolder.VID_UNDEFINED, false); if(null == config) { throw new GLException("Choosing GraphicsConfiguration failed w/ "+capsChosen+" on "+screen); } - return new WrappedSurface(config, 0, width, height, lifecycleHook); + return new WrappedSurface(config, 0, upstreamHook, ownDevice); } @Override @@ -649,54 +598,9 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { GLCapabilitiesImmutable requestedCaps, GLCapabilitiesChooser chooser, int width, int height) { final GLCapabilitiesImmutable chosenCaps = GLGraphicsConfigurationUtil.fixDoubleBufferedGLCapabilities( - GLGraphicsConfigurationUtil.fixOffscreenGLCapabilities(requestedCaps, false, canCreateGLPbuffer(deviceReq)), - false); - return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser, width, height, dummySurfaceLifecycleHook); + GLGraphicsConfigurationUtil.fixOffscreenGLCapabilities(requestedCaps, false, canCreateGLPbuffer(deviceReq)), false); + return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser, new EGLDummyUpstreamSurfaceHook(width, height)); } - private static final ProxySurface.UpstreamSurfaceHook dummySurfaceLifecycleHook = new ProxySurface.UpstreamSurfaceHook() { - @Override - public final void create(ProxySurface s) { - if( EGL.EGL_NO_SURFACE == s.getSurfaceHandle() ) { - final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) s.getGraphicsConfiguration().getScreen().getDevice(); - if(0 == eglDevice.getHandle()) { - eglDevice.open(); - s.setImplBitfield(ProxySurface.OWN_DEVICE); - } - createPBufferSurfaceImpl(s, false); - if(DEBUG) { - System.err.println("EGLDrawableFactory.dummySurfaceLifecycleHook.create: "+s); - } - } - } - @Override - public final void destroy(ProxySurface s) { - if( EGL.EGL_NO_SURFACE != s.getSurfaceHandle() ) { - final EGLGraphicsConfiguration config = (EGLGraphicsConfiguration) s.getGraphicsConfiguration(); - final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) config.getScreen().getDevice(); - EGL.eglDestroySurface(eglDevice.getHandle(), s.getSurfaceHandle()); - s.setSurfaceHandle(EGL.EGL_NO_SURFACE); - if( 0 != ( ProxySurface.OWN_DEVICE & s.getImplBitfield() ) ) { - eglDevice.close(); - } - if(DEBUG) { - System.err.println("EGLDrawableFactory.dummySurfaceLifecycleHook.create: "+s); - } - } - } - @Override - public final int getWidth(ProxySurface s) { - return s.initialWidth; - } - @Override - public final int getHeight(ProxySurface s) { - return s.initialHeight; - } - @Override - public String toString() { - return "EGLSurfaceLifecycleHook[]"; - } - - }; /** * @param ms {@link MutableSurface} which dimensions and config are being used to create the pbuffer surface. @@ -705,7 +609,9 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { * @return the passed {@link MutableSurface} which now has the EGL pbuffer surface set as it's handle */ protected static MutableSurface createPBufferSurfaceImpl(MutableSurface ms, boolean useTexture) { - final EGLGraphicsConfiguration config = (EGLGraphicsConfiguration) ms.getGraphicsConfiguration(); + return null; + } + protected static long createPBufferSurfaceImpl(EGLGraphicsConfiguration config, int width, int height, boolean useTexture) { final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) config.getScreen().getDevice(); final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); final int texFormat; @@ -720,15 +626,14 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { System.out.println("Pbuffer config: " + config); } - final int[] attrs = EGLGraphicsConfiguration.CreatePBufferSurfaceAttribList(ms.getWidth(), ms.getHeight(), texFormat); + final int[] attrs = EGLGraphicsConfiguration.CreatePBufferSurfaceAttribList(width, height, texFormat); final long surf = EGL.eglCreatePbufferSurface(eglDevice.getHandle(), config.getNativeConfig(), attrs, 0); if (EGL.EGL_NO_SURFACE==surf) { - throw new GLException("Creation of window surface (eglCreatePbufferSurface) failed, dim "+ms.getWidth()+"x"+ms.getHeight()+", error 0x"+Integer.toHexString(EGL.eglGetError())); + throw new GLException("Creation of window surface (eglCreatePbufferSurface) failed, dim "+width+"x"+height+", "+eglDevice+", "+config+", error 0x"+Integer.toHexString(EGL.eglGetError())); } else if(DEBUG) { System.err.println("PBuffer setSurface result: eglSurface 0x"+Long.toHexString(surf)); } - ms.setSurfaceHandle(surf); - return ms; + return surf; } @Override @@ -737,7 +642,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { final EGLGraphicsDevice device = EGLDisplayUtil.eglCreateEGLGraphicsDevice(eglDeviceReq.getNativeDisplayID(), deviceReq.getConnection(), deviceReq.getUnitID()); final DefaultGraphicsScreen screen = new DefaultGraphicsScreen(device, screenIdx); final EGLGraphicsConfiguration cfg = EGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsRequested, capsRequested, chooser, screen, VisualIDHolder.VID_UNDEFINED, false); - return new WrappedSurface(cfg, windowHandle, 0, 0, upstream); + return new WrappedSurface(cfg, windowHandle, upstream, true); } @Override diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDummyUpstreamSurfaceHook.java b/src/jogl/classes/jogamp/opengl/egl/EGLDummyUpstreamSurfaceHook.java new file mode 100644 index 000000000..b172d4f35 --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDummyUpstreamSurfaceHook.java @@ -0,0 +1,49 @@ +package jogamp.opengl.egl; + +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.UpstreamSurfaceHook; + +import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; +import com.jogamp.nativewindow.egl.EGLGraphicsDevice; + +public class EGLDummyUpstreamSurfaceHook 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 EGLDummyUpstreamSurfaceHook(int width, int height) { + super(width, height); + } + + @Override + public final void create(ProxySurface s) { + final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) s.getGraphicsConfiguration().getScreen().getDevice(); + if(0 == eglDevice.getHandle()) { + eglDevice.open(); + s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); + } + if( EGL.EGL_NO_SURFACE == s.getSurfaceHandle() ) { + s.setSurfaceHandle( EGLDrawableFactory.createPBufferSurfaceImpl((EGLGraphicsConfiguration)s.getGraphicsConfiguration(), 64, 64, false) ); + 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 EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) s.getGraphicsConfiguration().getScreen().getDevice(); + if( EGL.EGL_NO_SURFACE == s.getSurfaceHandle() ) { + throw new InternalError("Owns upstream surface, but no EGL surface: "+s); + } + EGL.eglDestroySurface(eglDevice.getHandle(), s.getSurfaceHandle()); + s.setSurfaceHandle(EGL.EGL_NO_SURFACE); + s.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + } + } +} diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLExternalContext.java b/src/jogl/classes/jogamp/opengl/egl/EGLExternalContext.java index 585638d21..84bd705db 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLExternalContext.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLExternalContext.java @@ -79,15 +79,4 @@ public class EGLExternalContext extends EGLContext { @Override protected void destroyImpl() throws GLException { } - - @Override - public void bindPbufferToTexture() { - throw new GLException("Should not call this"); - } - - @Override - public void releasePbufferFromTexture() { - throw new GLException("Should not call this"); - } - } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLGLCapabilities.java b/src/jogl/classes/jogamp/opengl/egl/EGLGLCapabilities.java index e513a86cf..f857c6b5c 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLGLCapabilities.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLGLCapabilities.java @@ -57,8 +57,8 @@ public class EGLGLCapabilities extends GLCapabilities { this.eglcfg = eglcfg; this.eglcfgid = eglcfgid; if(!isCompatible(glp, renderableType)) { - throw new GLException("Incompatible "+glp+ - " with EGL-RenderableType["+renderableTypeToString(null, renderableType)+"]"); + throw new GLException("Requested GLProfile "+glp+ + " not compatible with EGL-RenderableType["+renderableTypeToString(null, renderableType)+"]"); } this.renderableType = renderableType; this.nativeVisualID = visualID; @@ -131,6 +131,7 @@ public class EGLGLCapabilities extends GLCapabilities { sink = new StringBuilder(); } boolean first=true; + sink.append("0x").append(Integer.toHexString(renderableType)).append(": "); if(0 != (renderableType & EGL.EGL_OPENGL_BIT)) { sink.append("GL"); first=false; } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java index 8ee98072f..7bf201238 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java @@ -211,6 +211,13 @@ public class EGLGraphicsConfiguration extends MutableGraphicsConfiguration imple if(null == glp) { glp = EGLGLCapabilities.getCompatible(device, rType); } + if(!EGLGLCapabilities.isCompatible(glp, rType)) { + if(DEBUG) { + System.err.println("config "+toHexString(config)+": Requested GLProfile "+glp+ + " not compatible with EGL-RenderableType["+EGLGLCapabilities.renderableTypeToString(null, rType)+"]"); + } + return null; + } caps = new EGLGLCapabilities(config, cfgID, visualID, glp, rType); } catch (GLException gle) { if(DEBUG) { @@ -288,7 +295,7 @@ public class EGLGraphicsConfiguration extends MutableGraphicsConfiguration imple return null; } - return (EGLGLCapabilities) GLGraphicsConfigurationUtil.setWinAttributeBits(caps, drawableTypeBits); + return (EGLGLCapabilities) GLGraphicsConfigurationUtil.fixWinAttribBitsAndHwAccel(device, drawableTypeBits, caps); } public static int[] GLCapabilities2AttribList(GLCapabilitiesImmutable caps) { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenContext.java b/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenContext.java index eae47fa92..325ad6142 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenContext.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenContext.java @@ -41,16 +41,5 @@ public class EGLOnscreenContext extends EGLContext { public EGLOnscreenContext(EGLOnscreenDrawable drawable, GLContext shareWith) { super(drawable, shareWith); } - - @Override - public void bindPbufferToTexture() { - throw new GLException("Should not call this"); - } - - @Override - public void releasePbufferFromTexture() { - throw new GLException("Should not call this"); - } - } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java index d54057775..6440cf1e5 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java @@ -54,8 +54,8 @@ public class EGLOnscreenDrawable extends EGLDrawable { } @Override - protected long createSurface(EGLGraphicsConfiguration config, long nativeSurfaceHandle) { + protected long createSurface(EGLGraphicsConfiguration config, int width, int height, long nativeSurfaceHandle) { return EGL.eglCreateWindowSurface(config.getScreen().getDevice().getHandle(), config.getNativeConfig(), nativeSurfaceHandle, null); - } + } } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferContext.java b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferContext.java index 7175d516f..bb9eeb892 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferContext.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferContext.java @@ -46,15 +46,5 @@ public class EGLPbufferContext extends EGLContext { public int getFloatingPointMode() { return 0; // FIXME ?? } - - @Override - public void bindPbufferToTexture() { - throw new GLException("Not yet implemented"); - } - - @Override - public void releasePbufferFromTexture() { - throw new GLException("Not yet implemented"); - } } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java index 4a36625bd..eb7e320c8 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java @@ -52,12 +52,8 @@ public class EGLPbufferDrawable extends EGLDrawable { } @Override - protected long createSurface(EGLGraphicsConfiguration config, long nativeSurfaceHandle) { - final MutableSurface ms = (MutableSurface)getNativeSurface(); - if(config != ms.getGraphicsConfiguration()) { - throw new InternalError("Not same: "+config.hashCode()+", "+ms.getGraphicsConfiguration()+": "+config+", "+ms.getGraphicsConfiguration()); - } - return EGLDrawableFactory.createPBufferSurfaceImpl(ms, useTexture).getSurfaceHandle(); + protected long createSurface(EGLGraphicsConfiguration config, int width, int height, long nativeSurfaceHandle) { + return EGLDrawableFactory.createPBufferSurfaceImpl(config, width, height, false); } @Override diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java b/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java index 42c6e100e..342c4c417 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java @@ -1,38 +1,163 @@ package jogamp.opengl.egl; +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.DefaultGraphicsScreen; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.UpstreamSurfaceHook; +import javax.media.nativewindow.VisualIDHolder.VIDType; +import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLException; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; -public class EGLUpstreamSurfaceHook implements ProxySurface.UpstreamSurfaceHook { +public class EGLUpstreamSurfaceHook implements UpstreamSurfaceHook.MutableSize { + protected static final boolean DEBUG = EGLDrawableFactory.DEBUG; private final NativeSurface upstreamSurface; + private final UpstreamSurfaceHook.MutableSize upstreamSurfaceHookMutableSize; public EGLUpstreamSurfaceHook(NativeSurface upstream) { upstreamSurface = upstream; + if(upstreamSurface instanceof ProxySurface) { + final UpstreamSurfaceHook ush = ((ProxySurface)upstreamSurface).getUpstreamSurfaceHook(); + if(ush instanceof UpstreamSurfaceHook.MutableSize) { + // offscreen NativeSurface w/ MutableSize (default) + upstreamSurfaceHookMutableSize = (UpstreamSurfaceHook.MutableSize) ush; + } else { + upstreamSurfaceHookMutableSize = null; + } + } else { + upstreamSurfaceHookMutableSize = null; + } } public final NativeSurface getUpstreamSurface() { return upstreamSurface; } + static String getThreadName() { return Thread.currentThread().getName(); } + + public final void setSize(int width, int height) { + if(null != upstreamSurfaceHookMutableSize) { + upstreamSurfaceHookMutableSize.setSize(width, height); + } + } + @Override public final void create(ProxySurface surface) { + final String dbgPrefix; + if(DEBUG) { + dbgPrefix = getThreadName() + ": EGLUpstreamSurfaceHook.create("+surface.getClass().getSimpleName()+"): "; + System.err.println(dbgPrefix+this); + } else { + dbgPrefix = null; + } + if(upstreamSurface instanceof ProxySurface) { + // propagate createNotify(..) so upstreamSurface will be created ((ProxySurface)upstreamSurface).createNotify(); - if(NativeSurface.LOCK_SURFACE_NOT_READY >= upstreamSurface.lockSurface()) { - throw new GLException("Could not lock: "+upstreamSurface); + } + + // lock upstreamSurface, so it can be used in case EGLDisplay is derived from it! + if(NativeSurface.LOCK_SURFACE_NOT_READY >= upstreamSurface.lockSurface()) { + throw new GLException("Could not lock: "+upstreamSurface); + } + try { + evalUpstreamSurface(dbgPrefix, surface); + } finally { + upstreamSurface.unlockSurface(); + } + } + + private final void evalUpstreamSurface(String dbgPrefix, ProxySurface surface) { + // + // evaluate nature of upstreamSurface, may create EGL instances if required + // + + boolean isEGLSurfaceValid = true; // assume yes + + final AbstractGraphicsConfiguration aConfig = upstreamSurface.getGraphicsConfiguration(); + final AbstractGraphicsDevice aDevice = aConfig.getScreen().getDevice(); + + final EGLGraphicsDevice eglDevice; + if( aDevice instanceof EGLGraphicsDevice ) { + eglDevice = (EGLGraphicsDevice) aDevice; + if(DEBUG) { + System.err.println(dbgPrefix+"Reusing eglDevice: "+eglDevice); + } + if(EGL.EGL_NO_DISPLAY == eglDevice.getHandle()) { + eglDevice.open(); + isEGLSurfaceValid = false; + surface.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); + } + } else { + eglDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(upstreamSurface); + isEGLSurfaceValid = false; + surface.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); + } + + final GLCapabilitiesImmutable capsRequested = (GLCapabilitiesImmutable) aConfig.getRequestedCapabilities(); + final EGLGraphicsConfiguration eglConfig; + if( aConfig instanceof EGLGraphicsConfiguration ) { + // Config is already in EGL type - reuse .. + final EGLGLCapabilities capsChosen = (EGLGLCapabilities) aConfig.getChosenCapabilities(); + if( !isEGLSurfaceValid || !EGLGraphicsConfiguration.isEGLConfigValid(eglDevice.getHandle(), capsChosen.getEGLConfig()) ) { + // 'refresh' the native EGLConfig handle + capsChosen.setEGLConfig(EGLGraphicsConfiguration.EGLConfigId2EGLConfig(eglDevice.getHandle(), capsChosen.getEGLConfigID())); + if( 0 == capsChosen.getEGLConfig() ) { + throw new GLException("Refreshing native EGLConfig handle failed with error "+EGLContext.toHexString(EGL.eglGetError())+": "+eglDevice+", "+capsChosen+" of "+aConfig); + } + final AbstractGraphicsScreen eglScreen = new DefaultGraphicsScreen(eglDevice, aConfig.getScreen().getIndex()); + eglConfig = new EGLGraphicsConfiguration(eglScreen, capsChosen, capsRequested, null); + if(DEBUG) { + System.err.println(dbgPrefix+"Refreshing eglConfig: "+eglConfig); + } + isEGLSurfaceValid = false; + } else { + eglConfig = (EGLGraphicsConfiguration) aConfig; + if(DEBUG) { + System.err.println(dbgPrefix+"Reusing eglConfig: "+eglConfig); + } + } + } else { + final AbstractGraphicsScreen eglScreen = new DefaultGraphicsScreen(eglDevice, aConfig.getScreen().getIndex()); + eglConfig = EGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic( + capsRequested, capsRequested, null, eglScreen, aConfig.getVisualID(VIDType.NATIVE), false); + + if (null == eglConfig) { + throw new GLException("Couldn't create EGLGraphicsConfiguration from "+eglScreen); + } else if(DEBUG) { + System.err.println(dbgPrefix+"Chosen eglConfig: "+eglConfig); } + isEGLSurfaceValid = false; } - final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) surface.getGraphicsConfiguration().getScreen().getDevice(); - eglDevice.open(); + surface.setGraphicsConfiguration(eglConfig); + + if(isEGLSurfaceValid) { + isEGLSurfaceValid = EGLDrawable.isValidEGLSurface(eglDevice.getHandle(), upstreamSurface.getSurfaceHandle()); + } + if(isEGLSurfaceValid) { + surface.setSurfaceHandle(upstreamSurface.getSurfaceHandle()); + surface.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + if(DEBUG) { + System.err.println(dbgPrefix+"Fin: Already valid EGL surface - use as-is: "+upstreamSurface); + } + } else { + surface.setSurfaceHandle(EGL.EGL_NO_SURFACE); + surface.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); // create/destroy in EGLDrawable + if(DEBUG) { + System.err.println(dbgPrefix+"Fin: EGL surface n/a - TBD: "+upstreamSurface); + } + } } @Override public final void destroy(ProxySurface surface) { - final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) surface.getGraphicsConfiguration().getScreen().getDevice(); - eglDevice.close(); + if(EGLDrawableFactory.DEBUG) { + System.err.println("EGLUpstreamSurfaceHook.destroy("+surface.getClass().getSimpleName()+"): "+this); + } + surface.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); if(upstreamSurface instanceof ProxySurface) { - upstreamSurface.unlockSurface(); ((ProxySurface)upstreamSurface).destroyNotify(); } } @@ -49,8 +174,8 @@ public class EGLUpstreamSurfaceHook implements ProxySurface.UpstreamSurfaceHook @Override public String toString() { - final String us_s = null != upstreamSurface ? ( upstreamSurface.getClass().getName() + ": " + upstreamSurface ) : "nil"; - return "EGLUpstreamSurfaceHook[upstream: "+us_s+"]"; + final String us_s = null != upstreamSurface ? ( upstreamSurface.getClass().getName() + ": 0x" + Long.toHexString(upstreamSurface.getSurfaceHandle()) ) : "nil"; + return "EGLUpstreamSurfaceHook[ "+ upstreamSurface.getWidth() + "x" + upstreamSurface.getHeight() + ", " + us_s+ "]"; } } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLWrappedSurface.java b/src/jogl/classes/jogamp/opengl/egl/EGLWrappedSurface.java new file mode 100644 index 000000000..b36303392 --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/egl/EGLWrappedSurface.java @@ -0,0 +1,26 @@ +package jogamp.opengl.egl; + +import javax.media.nativewindow.NativeSurface; + +import jogamp.nativewindow.WrappedSurface; + +public class EGLWrappedSurface extends WrappedSurface { + + public static EGLWrappedSurface get(NativeSurface surface) { + if(surface instanceof EGLWrappedSurface) { + return (EGLWrappedSurface)surface; + } + return new EGLWrappedSurface(surface); + } + + public EGLWrappedSurface(NativeSurface surface) { + super(surface.getGraphicsConfiguration(), EGL.EGL_NO_SURFACE, new EGLUpstreamSurfaceHook(surface), false /* tbd in UpstreamSurfaceHook */); + if(EGLDrawableFactory.DEBUG) { + System.err.println("EGLWrappedSurface.ctor(): "+this); + } + } + + public final NativeSurface getUpstreamSurface() { + return ((EGLUpstreamSurfaceHook)super.getUpstreamSurfaceHook()).getUpstreamSurface(); + } +} |