@Override public final void create(ProxySurface surface) { final String dbgPrefix; if (DEBUG) { dbgPrefix = getThreadName() + ": EGLUpstreamSurfaceHook.create( up " + upstreamSurface.getClass().getSimpleName() + " -> this " + 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(); } // 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(); } }
@Override public final synchronized void setRealized(boolean realizedArg) { if (realized != realizedArg) { if (DEBUG) { System.err.println( getThreadName() + ": setRealized: " + getClass().getSimpleName() + " " + realized + " -> " + realizedArg); } realized = realizedArg; AbstractGraphicsDevice aDevice = surface.getGraphicsConfiguration().getScreen().getDevice(); if (realizedArg) { if (surface instanceof ProxySurface) { ((ProxySurface) surface).createNotify(); } if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockSurface()) { throw new GLException( "GLDrawableImpl.setRealized(true): Surface not ready (lockSurface)"); } } else { aDevice.lock(); } try { if (realizedArg) { setRealizedImpl(); updateHandle(); } else { destroyHandle(); setRealizedImpl(); } } finally { if (realizedArg) { unlockSurface(); } else { aDevice.unlock(); if (surface instanceof ProxySurface) { ((ProxySurface) surface).destroyNotify(); } } } } else if (DEBUG) { System.err.println( getThreadName() + ": setRealized: " + getClass().getName() + " " + this.realized + " == " + realizedArg); } }
@Override public final void destroy(ProxySurface surface) { if (EGLDrawableFactory.DEBUG) { System.err.println( "EGLUpstreamSurfaceHook.destroy(" + surface.getClass().getSimpleName() + "): " + this); } surface.clearUpstreamOptionBits(ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE); if (upstreamSurface instanceof ProxySurface) { ((ProxySurface) upstreamSurface).destroyNotify(); } }
private final void evalUpstreamSurface(String dbgPrefix, ProxySurface surface) { // // evaluate nature of upstreamSurface, may create EGL instances if required // boolean isEGLSurfaceValid = true; // assume yes final EGLGraphicsDevice eglDevice; final AbstractGraphicsConfiguration aConfig; { final AbstractGraphicsConfiguration surfaceConfig = surface.getGraphicsConfiguration(); final AbstractGraphicsDevice surfaceDevice = null != surfaceConfig ? surfaceConfig.getScreen().getDevice() : null; if (DEBUG) { System.err.println( dbgPrefix + "SurfaceDevice: " + surfaceDevice.getClass().getSimpleName() + ", hash 0x" + Integer.toHexString(surfaceDevice.hashCode()) + ", " + surfaceDevice); System.err.println( dbgPrefix + "SurfaceConfig: " + surfaceConfig.getClass().getSimpleName() + ", hash 0x" + Integer.toHexString(surfaceConfig.hashCode()) + ", " + surfaceConfig); } final AbstractGraphicsConfiguration upstreamConfig = upstreamSurface.getGraphicsConfiguration(); final AbstractGraphicsDevice upstreamDevice = upstreamConfig.getScreen().getDevice(); if (DEBUG) { System.err.println( dbgPrefix + "UpstreamDevice: " + upstreamDevice.getClass().getSimpleName() + ", hash 0x" + Integer.toHexString(upstreamDevice.hashCode()) + ", " + upstreamDevice); System.err.println( dbgPrefix + "UpstreamConfig: " + upstreamConfig.getClass().getSimpleName() + ", hash 0x" + Integer.toHexString(upstreamConfig.hashCode()) + ", " + upstreamConfig); } if (surfaceDevice instanceof EGLGraphicsDevice) { eglDevice = (EGLGraphicsDevice) surfaceDevice; aConfig = surfaceConfig; if (DEBUG) { System.err.println( dbgPrefix + "Reusing this eglDevice: " + eglDevice + ", using this config " + aConfig.getClass().getSimpleName() + " " + aConfig); } if (EGL.EGL_NO_DISPLAY == eglDevice.getHandle()) { eglDevice.open(); isEGLSurfaceValid = false; surface.addUpstreamOptionBits(ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE); } } else if (upstreamDevice instanceof EGLGraphicsDevice) { eglDevice = (EGLGraphicsDevice) upstreamDevice; aConfig = upstreamConfig; if (DEBUG) { System.err.println( dbgPrefix + "Reusing upstream eglDevice: " + eglDevice + ", using upstream config " + aConfig.getClass().getSimpleName() + " " + aConfig); } if (EGL.EGL_NO_DISPLAY == eglDevice.getHandle()) { eglDevice.open(); isEGLSurfaceValid = false; surface.addUpstreamOptionBits(ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE); } } else { eglDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(upstreamSurface); eglDevice.open(); aConfig = upstreamConfig; 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 /* forceTransparencyFlag */); if (null == eglConfig) { throw new GLException("Couldn't create EGLGraphicsConfiguration from " + eglScreen); } else if (DEBUG) { System.err.println(dbgPrefix + "Chosen eglConfig: " + eglConfig); } isEGLSurfaceValid = false; } 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); } } }
/** * Moves all GLEventListenerState components to the given {@link GLAutoDrawable} from this * instance, while loosing {@link #isOwner() ownership}. * * <p>If the previous {@link GLAutoDrawable} was removed from a {@link GLAnimatorControl} by * previous {@link #moveFrom(GLAutoDrawable)}, the given {@link GLAutoDrawable} is added to the * cached {@link GLAnimatorControl}. This operation is skipped, if the given {@link * GLAutoDrawable} is already added to a {@link GLAnimatorControl} instance. * * <p>Note: After this operation, the GLEventListenerState reference should be released. * * @param a {@link GLAutoDrawable} destination to move GLEventListenerState components to * @throws GLException if the {@link GLAutoDrawable}'s configuration is incompatible, i.e. * different {@link GLCapabilitiesImmutable}. * @see #moveFrom(GLAutoDrawable) * @see #isOwner() */ public final void moveTo(GLAutoDrawable a) { final List<GLRunnable> aGLCmds = new ArrayList<GLRunnable>(); final int aSz = listenerCount(); final NativeSurface aSurface = a.getNativeSurface(); final MutableGraphicsConfiguration aCfg = (MutableGraphicsConfiguration) aSurface.getGraphicsConfiguration(); final GLCapabilitiesImmutable aCaps = (GLCapabilitiesImmutable) aCfg.getChosenCapabilities(); if (caps.getVisualID(VisualIDHolder.VIDType.INTRINSIC) != aCaps.getVisualID(VisualIDHolder.VIDType.INTRINSIC) || caps.getVisualID(VisualIDHolder.VIDType.NATIVE) != aCaps.getVisualID(VisualIDHolder.VIDType.NATIVE)) { throw new GLException( "Incompatible Capabilities - Prev-Holder: " + caps + ", New-Holder " + caps); } // Destroy and remove currently associated GLContext, if any (will be replaced) { final GLContext ctx = a.getContext(); if (null != ctx) { ctx.destroy(); } a.setContext(null); } final boolean aRealized = a.isRealized(); if (aRealized) { a.setRealized(false); } // Set new Screen and close previous one { if (DEBUG) { System.err.println( "XX0 NativeSurface: " + aSurface.getClass().getName() + ", " + aSurface); } final AbstractGraphicsScreen aScreen1 = aCfg.getScreen(); aCfg.setScreen(screen); aScreen1.getDevice().close(); System.err.println( "XXX NativeSurface: " + aSurface.getClass().getName() + ", " + aSurface); } // If using a ProxySurface w/ an upstream surface, set new Screen and close previous one on it { boolean upstreamSet = false; if (aSurface instanceof ProxySurface) { final ProxySurface aProxy = (ProxySurface) aSurface; final NativeSurface aUpSurface = aProxy.getUpstreamSurface(); if (null != aUpSurface) { final MutableGraphicsConfiguration aUpCfg = (MutableGraphicsConfiguration) aUpSurface.getGraphicsConfiguration(); final AbstractGraphicsScreen aUpScreen1 = aUpCfg.getScreen(); if (null != upstreamScreen) { System.err.println( "XX0 UpstreamSurface: " + aUpSurface.getClass().getName() + ", " + aUpSurface); aUpCfg.setScreen(upstreamScreen); aUpScreen1.getDevice().close(); upstreamSet = true; System.err.println( "XXX UpstreamSurface: " + aUpSurface.getClass().getName() + ", " + aUpSurface); } else { throw new GLException( "Incompatible Surface config - Has Upstream-Surface: Prev-Holder = false, New-Holder = true"); } } } if (!upstreamSet && null != upstreamScreen) { throw new GLException( "Incompatible Surface config - Has Upstream-Surface: Prev-Holder = true, New-Holder = false"); } } if (aRealized) { a.setRealized(true); } final boolean surfaceLocked = false; // NativeSurface.LOCK_SURFACE_NOT_READY < aSurface.lockSurface(); try { a.setContext(context); } finally { if (surfaceLocked) { aSurface.unlockSurface(); } } owner = false; // // Trigger GL-Viewport reset and reshape of all initialized GLEventListeners // aGLCmds.add(setViewport); for (int i = 0; i < aSz; i++) { if (listenersInit[i]) { aGLCmds.add(new ReshapeGLEventListener(listeners[i])); } } aGLCmds.add(glFinish); a.invoke(aRealized, aGLCmds); // only wait if already realized // add all cached GLEventListener to their destination and fix their init-state for (int i = 0; i < aSz; i++) { final GLEventListener l = listeners[i]; a.addGLEventListener(l); a.setGLEventListenerInitState(l, listenersInit[i]); listeners[i] = null; } if (null != anim && null == a.getAnimator()) { anim.add(a); // also handles ECT } }
/** * Moves all GLEventListenerState components from the given {@link GLAutoDrawable} to a newly * created instance. * * <p>Note that all components are removed from the {@link GLAutoDrawable}, i.e. the {@link * GLContext}, all {@link GLEventListener}. * * <p>If the {@link GLAutoDrawable} was added to a {@link GLAnimatorControl}, it is removed and * the {@link GLAnimatorControl} added to the GLEventListenerState. * * <p>The returned GLEventListenerState instance is the {@link #isOwner() owner of the * components}. * * @param a {@link GLAutoDrawable} source to move components from * @return new GLEventListenerState instance {@link #isOwner() owning} moved components. * @see #moveTo(GLAutoDrawable) */ public static GLEventListenerState moveFrom(GLAutoDrawable a) { final int aSz = a.getGLEventListenerCount(); // Create new AbstractGraphicsScreen w/ cloned AbstractGraphicsDevice for future GLAutoDrawable // allowing this AbstractGraphicsDevice to loose ownership -> not closing display/device! final NativeSurface aSurface = a.getNativeSurface(); final AbstractGraphicsConfiguration aCfg = aSurface.getGraphicsConfiguration(); final AbstractGraphicsScreen aScreen1 = aCfg.getScreen(); final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) aCfg.getChosenCapabilities(); final AbstractGraphicsScreen aScreen2 = cloneScreen(aScreen1); if (DEBUG) { System.err.println( "X00 NativeSurface: " + aSurface.getClass().getName() + ", " + aSurface); } aScreen1.getDevice().clearHandleOwner(); // don't close device handle final AbstractGraphicsScreen aUpScreen2; { AbstractGraphicsScreen _aUpScreen2 = null; if (aSurface instanceof ProxySurface) { final ProxySurface aProxy = (ProxySurface) aSurface; final NativeSurface aUpSurface = aProxy.getUpstreamSurface(); if (null != aUpSurface) { System.err.println( "X00 UpstreamSurface: " + aUpSurface.getClass().getName() + ", " + aUpSurface); } aProxy.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE); // don't close device handle if (null != aUpSurface) { final AbstractGraphicsScreen aUpScreen1 = aUpSurface.getGraphicsConfiguration().getScreen(); _aUpScreen2 = cloneScreen(aUpScreen1); if (null != aUpScreen1) { aUpScreen1.getDevice().clearHandleOwner(); // don't close device handle } System.err.println( "X0X NativeSurface: " + aSurface.getClass().getName() + ", " + aSurface); System.err.println( "X0X UpstreamSurface: " + aUpSurface.getClass().getName() + ", " + aUpSurface); } } aUpScreen2 = _aUpScreen2; } final GLAnimatorControl aAnim = a.getAnimator(); if (null != aAnim) { aAnim.remove(a); // also handles ECT } final GLEventListenerState glls = new GLEventListenerState(aUpScreen2, aScreen2, caps, a.getContext(), aSz, aAnim); // // remove and cache all GLEventListener and their init-state // for (int i = 0; i < aSz; i++) { final GLEventListener l = a.getGLEventListener(0); glls.listenersInit[i] = a.getGLEventListenerInitState(l); glls.listeners[i] = a.removeGLEventListener(l); } // // trigger glFinish to sync GL ctx // a.invoke(true, glFinish); a.setContext(null); return glls; }
private boolean mapAvailableEGLESConfig( AbstractGraphicsDevice adevice, int esProfile, boolean[] hasPBuffer, GLRendererQuirks[] rendererQuirks, int[] ctp) { final String profileString; switch (esProfile) { case 3: profileString = GLProfile.GLES3; break; case 2: profileString = GLProfile.GLES2; break; case 1: profileString = GLProfile.GLES1; break; default: throw new GLException("Invalid ES profile number " + esProfile); } if (!GLProfile.isAvailable(adevice, profileString)) { if (DEBUG) { System.err.println( "EGLDrawableFactory.mapAvailableEGLESConfig: " + profileString + " n/a on " + adevice); } return false; } final GLProfile glp = GLProfile.get(adevice, profileString); final GLDrawableFactoryImpl desktopFactory = (GLDrawableFactoryImpl) GLDrawableFactory.getDesktopFactory(); final boolean mapsADeviceToDefaultDevice = !QUERY_EGL_ES_NATIVE_TK || null == desktopFactory || adevice instanceof EGLGraphicsDevice; if (DEBUG) { System.err.println( "EGLDrawableFactory.mapAvailableEGLESConfig: " + profileString + " ( " + esProfile + " ), " + "defaultSharedResourceSet " + (null != defaultSharedResource) + ", mapsADeviceToDefaultDevice " + mapsADeviceToDefaultDevice + " (QUERY_EGL_ES_NATIVE_TK " + QUERY_EGL_ES_NATIVE_TK + ", hasDesktopFactory " + (null != desktopFactory) + ", isEGLGraphicsDevice " + (adevice instanceof EGLGraphicsDevice) + ")"); } EGLGraphicsDevice eglDevice = null; NativeSurface surface = null; ProxySurface upstreamSurface = null; // X11, GLX, .. boolean success = false; boolean deviceFromUpstreamSurface = false; try { final GLCapabilities reqCapsAny = new GLCapabilities(glp); reqCapsAny.setRedBits(5); reqCapsAny.setGreenBits(5); reqCapsAny.setBlueBits(5); reqCapsAny.setAlphaBits(0); reqCapsAny.setDoubleBuffered(false); if (mapsADeviceToDefaultDevice) { // In this branch, any non EGL device is mapped to EGL default shared resources (default // behavior). // Only one default shared resource instance is ever be created. final GLCapabilitiesImmutable reqCapsPBuffer = GLGraphicsConfigurationUtil.fixGLPBufferGLCapabilities(reqCapsAny); final List<GLCapabilitiesImmutable> availablePBufferCapsL = getAvailableEGLConfigs(defaultDevice, reqCapsPBuffer); hasPBuffer[0] = availablePBufferCapsL.size() > 0; // 1st case: adevice is not the EGL default device, map default shared resources if (adevice != defaultDevice) { if (null == defaultSharedResource) { return false; } switch (esProfile) { case 3: if (!defaultSharedResource.wasES3ContextCreated) { return false; } rendererQuirks[0] = defaultSharedResource.rendererQuirksES3ES2; ctp[0] = defaultSharedResource.ctpES3ES2; break; case 2: if (!defaultSharedResource.wasES2ContextCreated) { return false; } rendererQuirks[0] = defaultSharedResource.rendererQuirksES3ES2; ctp[0] = defaultSharedResource.ctpES3ES2; break; case 1: if (!defaultSharedResource.wasES1ContextCreated) { return false; } rendererQuirks[0] = defaultSharedResource.rendererQuirksES1; ctp[0] = defaultSharedResource.ctpES1; break; } EGLContext.mapStaticGLVersion(adevice, esProfile, 0, ctp[0]); return true; } // attempt to created the default shared resources .. eglDevice = defaultDevice; // reuse if (hasPBuffer[0]) { // 2nd case create defaultDevice shared resource using pbuffer surface surface = createDummySurfaceImpl( eglDevice, false, reqCapsPBuffer, reqCapsPBuffer, null, 64, 64); // egl pbuffer offscreen upstreamSurface = (ProxySurface) surface; upstreamSurface.createNotify(); deviceFromUpstreamSurface = false; } else { // 3rd case fake creation of defaultDevice shared resource, no pbuffer available final List<GLCapabilitiesImmutable> capsAnyL = getAvailableEGLConfigs(eglDevice, reqCapsAny); if (capsAnyL.size() > 0) { final GLCapabilitiesImmutable chosenCaps = capsAnyL.get(0); EGLContext.mapStaticGLESVersion(eglDevice, chosenCaps); success = true; } if (DEBUG) { System.err.println( "EGLDrawableFactory.mapAvailableEGLESConfig() no pbuffer config available, detected !pbuffer config: " + success); EGLGraphicsConfigurationFactory.printCaps("!PBufferCaps", capsAnyL, System.err); } } } else { // 4th case always creates a true mapping of given device to EGL surface = desktopFactory.createDummySurface( adevice, reqCapsAny, null, 64, 64); // X11, WGL, .. dummy window upstreamSurface = (surface instanceof ProxySurface) ? (ProxySurface) surface : null; if (null != upstreamSurface) { upstreamSurface.createNotify(); } eglDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(surface); deviceFromUpstreamSurface = true; hasPBuffer[0] = true; } if (null != surface) { final EGLDrawable drawable = (EGLDrawable) createOnscreenDrawableImpl( surface); // works w/ implicit pbuffer surface via proxy-hook drawable.setRealized(true); final EGLContext context = (EGLContext) drawable.createContext(null); if (null != context) { try { context.makeCurrent(); // could cause exception if (context.isCurrent()) { final String glVersion = context.getGL().glGetString(GL.GL_VERSION); if (null != glVersion) { context.mapCurrentAvailableGLVersion(eglDevice); if (eglDevice != adevice) { context.mapCurrentAvailableGLVersion(adevice); } rendererQuirks[0] = context.getRendererQuirks(); ctp[0] = context.getContextOptions(); success = true; } else { // Oops .. something is wrong if (DEBUG) { System.err.println( "EGLDrawableFactory.mapAvailableEGLESConfig: " + eglDevice + ", " + context.getGLVersion() + " - VERSION is null, dropping availability!"); } } } } catch (GLException gle) { if (DEBUG) { System.err.println( "EGLDrawableFactory.mapAvailableEGLESConfig: INFO: context create/makeCurrent failed"); gle.printStackTrace(); } } finally { context.destroy(); } } drawable.setRealized(false); } } catch (Throwable t) { if (DEBUG) { System.err.println("Catched Exception on thread " + getThreadName()); t.printStackTrace(); } success = false; } finally { if (eglDevice == defaultDevice) { if (null != upstreamSurface) { upstreamSurface.destroyNotify(); } } else if (deviceFromUpstreamSurface) { if (null != eglDevice) { eglDevice.close(); } if (null != upstreamSurface) { upstreamSurface.destroyNotify(); } } else { if (null != upstreamSurface) { upstreamSurface.destroyNotify(); } if (null != eglDevice) { eglDevice.close(); } } } return success; }