protected static List<GLCapabilitiesImmutable> getAvailableCapabilities( X11GLXDrawableFactory factory, AbstractGraphicsDevice device) { X11GLXDrawableFactory.SharedResource sharedResource = factory.getOrCreateSharedResource(device); if (null == sharedResource) { throw new GLException("Shared resource for device n/a: " + device); } final X11GraphicsScreen sharedScreen = (X11GraphicsScreen) sharedResource.getScreen(); final boolean isMultisampleAvailable = factory.isGLXMultisampleAvailable(sharedScreen.getDevice()); final X11GLXDrawable sharedDrawable = (X11GLXDrawable) sharedResource.getDrawable(); final GLCapabilitiesImmutable capsChosen = sharedDrawable.getChosenGLCapabilities(); final GLProfile glp = capsChosen.getGLProfile(); List<GLCapabilitiesImmutable> availableCaps = null; if (sharedResource.isGLXVersionGreaterEqualOneThree()) { availableCaps = getAvailableGLCapabilitiesFBConfig(sharedScreen, glp, isMultisampleAvailable); } if (null == availableCaps || availableCaps.isEmpty()) { availableCaps = getAvailableGLCapabilitiesXVisual(sharedScreen, glp, isMultisampleAvailable); } if (null != availableCaps && availableCaps.size() > 1) { Collections.sort(availableCaps, XVisualIDComparator); } return availableCaps; }
public final void swapBuffers() throws GLException { GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) surface.getGraphicsConfiguration().getChosenCapabilities(); if (caps.getDoubleBuffered()) { if (!surface.surfaceSwap()) { int lockRes = lockSurface(); // it's recursive, so it's ok within [makeCurrent .. release] if (NativeSurface.LOCK_SURFACE_NOT_READY == lockRes) { return; } try { if (NativeSurface.LOCK_SURFACE_CHANGED == lockRes) { updateHandle(); } swapBuffersImpl(); } finally { unlockSurface(); } } } else { GLContext ctx = GLContext.getCurrent(); if (null != ctx && ctx.getGLDrawable() == this) { ctx.getGL().glFinish(); } } surface.surfaceUpdated(this, surface, System.currentTimeMillis()); }
@Override protected final GLDrawableImpl createOffscreenDrawableImpl(NativeSurface target) { if (target == null) { throw new IllegalArgumentException("Null target"); } AbstractGraphicsConfiguration config = target.getGraphicsConfiguration(); GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); if (!caps.isPBuffer()) { return new X11PixmapGLXDrawable(this, target); } // PBuffer GLDrawable Creation GLDrawableImpl pbufferDrawable; AbstractGraphicsDevice device = config.getScreen().getDevice(); /** * Due to the ATI Bug https://bugzilla.mozilla.org/show_bug.cgi?id=486277, we need to have a * context current on the same Display to create a PBuffer. The dummy context shall also use the * same Display, since switching Display in this regard is another ATI bug. */ SharedResource sr = (SharedResource) sharedResourceRunner.getOrCreateShared(device); if (null != sr && sr.isGLXVendorATI() && null == GLContext.getCurrent()) { sr.getContext().makeCurrent(); try { pbufferDrawable = new X11PbufferGLXDrawable(this, target); } finally { sr.getContext().release(); } } else { pbufferDrawable = new X11PbufferGLXDrawable(this, target); } return pbufferDrawable; }
@Override public synchronized void setVisibleActionPost(boolean visible, boolean nativeWindowCreated) { long t0; if (Window.DEBUG_IMPLEMENTATION) { t0 = System.nanoTime(); System.err.println( "GLWindow.setVisibleActionPost(" + visible + ", " + nativeWindowCreated + ") " + WindowImpl.getThreadName() + ", start"); } else { t0 = 0; } if (null == drawable && visible && 0 != window.getWindowHandle() && 0 < getWidth() * getHeight()) { if ((null != context)) { throw new InternalError( "GLWindow.LifecycleHook.setVisiblePost: " + WindowImpl.getThreadName() + " - Null drawable, but valid context - " + GLWindow.this); } final NativeSurface ns; { final NativeSurface wrapped_ns = window.getWrappedSurface(); ns = null != wrapped_ns ? wrapped_ns : window; } final GLCapabilitiesImmutable glCaps = (GLCapabilitiesImmutable) ns.getGraphicsConfiguration().getChosenCapabilities(); if (null == factory) { factory = GLDrawableFactory.getFactory(glCaps.getGLProfile()); } drawable = (GLDrawableImpl) factory.createGLDrawable(ns); drawable.setRealized(true); if (!GLWindow.this.pushGLEventListenerState()) { context = (GLContextImpl) drawable.createContext(sharedContext); context.setContextCreationFlags(additionalCtxCreationFlags); } } if (Window.DEBUG_IMPLEMENTATION) { System.err.println( "GLWindow.setVisibleActionPost(" + visible + ", " + nativeWindowCreated + ") " + WindowImpl.getThreadName() + ", fin: dt " + (System.nanoTime() - t0) / 1e6 + "ms"); } }
@Override public synchronized void setVisibleActionPost(boolean visible, boolean nativeWindowCreated) { long t0; if (Window.DEBUG_IMPLEMENTATION) { t0 = System.nanoTime(); System.err.println( "GLWindow.setVisibleActionPost(" + visible + ", " + nativeWindowCreated + ") " + WindowImpl.getThreadName() + ", start"); } else { t0 = 0; } /* if (nativeWindowCreated && null != context) { throw new GLException("InternalError: Native Windows has been just created, but context wasn't destroyed (is not null)"); } */ if (null == context && visible && 0 != window.getWindowHandle() && 0 < getWidth() * getHeight()) { NativeWindow nw; if (window.getWrappedWindow() != null) { nw = NativeWindowFactory.getNativeWindow( window.getWrappedWindow(), window.getPrivateGraphicsConfiguration()); } else { nw = window; } GLCapabilitiesImmutable glCaps = (GLCapabilitiesImmutable) nw.getGraphicsConfiguration().getChosenCapabilities(); if (null == factory) { factory = GLDrawableFactory.getFactory(glCaps.getGLProfile()); } if (null == drawable) { drawable = (GLDrawableImpl) factory.createGLDrawable(nw); } drawable.setRealized(true); context = (GLContextImpl) drawable.createContext(sharedContext); context.setContextCreationFlags(additionalCtxCreationFlags); } if (Window.DEBUG_IMPLEMENTATION) { System.err.println( "GLWindow.setVisibleActionPost(" + visible + ", " + nativeWindowCreated + ") " + WindowImpl.getThreadName() + ", fin: dt " + (System.nanoTime() - t0) / 1e6 + "ms"); } }
@Override protected GLDrawableImpl createOffscreenDrawableImpl(NativeSurface target) { if (target == null) { throw new IllegalArgumentException("Null target"); } AbstractGraphicsConfiguration config = target.getGraphicsConfiguration(); GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); if (!caps.isPBuffer()) { throw new GLException("Non pbuffer not yet implemented"); } // PBuffer GLDrawable Creation return new EGLPbufferDrawable(this, EGLWrappedSurface.get(target)); }
protected static void mapStaticGLESVersion( AbstractGraphicsDevice device, GLCapabilitiesImmutable caps) { final GLProfile glp = caps.getGLProfile(); final int[] reqMajorCTP = new int[2]; GLContext.getRequestMajorAndCompat(glp, reqMajorCTP); if (glp.isGLES() && reqMajorCTP[0] >= 2) { reqMajorCTP[1] |= GLContext.CTX_IMPL_ES2_COMPAT | GLContext.CTX_IMPL_FBO; } if (!caps.getHardwareAccelerated()) { reqMajorCTP[1] |= GLContext.CTX_IMPL_ACCEL_SOFT; } mapCurrentAvailableGLVersionImpl(device, reqMajorCTP[0], 0, reqMajorCTP[1]); }
private static List<GLCapabilitiesImmutable> getAvailableEGLConfigs( EGLGraphicsDevice eglDisplay, GLCapabilitiesImmutable caps) { final IntBuffer numConfigs = Buffers.newDirectIntBuffer(1); if (!EGL.eglGetConfigs(eglDisplay.getHandle(), null, 0, numConfigs)) { throw new GLException( "EGLDrawableFactory.getAvailableEGLConfigs: Get maxConfigs (eglGetConfigs) call failed, error " + EGLContext.toHexString(EGL.eglGetError())); } if (0 < numConfigs.get(0)) { final PointerBuffer configs = PointerBuffer.allocateDirect(numConfigs.get(0)); final IntBuffer attrs = EGLGraphicsConfiguration.GLCapabilities2AttribList(caps); final int winattrmask = GLGraphicsConfigurationUtil.getExclusiveWinAttributeBits(caps); if (EGL.eglChooseConfig( eglDisplay.getHandle(), attrs, configs, configs.capacity(), numConfigs) && numConfigs.get(0) > 0) { return EGLGraphicsConfigurationFactory.eglConfigs2GLCaps( eglDisplay, caps.getGLProfile(), configs, numConfigs.get(0), winattrmask, false /* forceTransparentFlag */); } } return new ArrayList<GLCapabilitiesImmutable>(0); }
/** * @param capsRequested * @param absScreen * @param eglConfigID {@link EGL#EGL_CONFIG_ID} for which the config is being created for. * @return * @throws GLException if invalid EGL display. */ public static EGLGraphicsConfiguration create( GLCapabilitiesImmutable capsRequested, AbstractGraphicsScreen absScreen, int eglConfigID) { final AbstractGraphicsDevice absDevice = absScreen.getDevice(); if (null == absDevice || !(absDevice instanceof EGLGraphicsDevice)) { throw new GLException("GraphicsDevice must be a valid EGLGraphicsDevice"); } final long dpy = absDevice.getHandle(); if (dpy == EGL.EGL_NO_DISPLAY) { throw new GLException("Invalid EGL display: " + absDevice); } final long cfg = EGLConfigId2EGLConfig(dpy, eglConfigID); if (0 < cfg) { final GLRendererQuirks defaultQuirks = GLRendererQuirks.getStickyDeviceQuirks( GLDrawableFactory.getEGLFactory().getDefaultDevice()); final int winattrmask = GLGraphicsConfigurationUtil.getExclusiveWinAttributeBits(capsRequested); final EGLGLCapabilities caps = EGLConfig2Capabilities( defaultQuirks, (EGLGraphicsDevice) absDevice, capsRequested.getGLProfile(), cfg, winattrmask, false); return new EGLGraphicsConfiguration( absScreen, caps, capsRequested, new DefaultGLCapabilitiesChooser()); } return null; }
protected void swapBuffers() { DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); if (caps.isOnscreen()) { if (isNSContext) { if (!CGL.flushBuffer(contextHandle)) { throw new GLException("Error swapping buffers (NS)"); } } else { if (CGL.kCGLNoError != CGL.CGLFlushDrawable(contextHandle)) { throw new GLException("Error swapping buffers (CGL)"); } } } }
@Override public GLAutoDrawable createGLAutoDrawable( final QuitAdapter quitAdapter, final GLCapabilitiesImmutable caps, final int width, final int height) throws InterruptedException, InvocationTargetException { final GLAutoDrawable glad; if (caps.isOnscreen()) { final Frame frame = new Frame("Gears AWT Test"); Assert.assertNotNull(frame); final GLCanvas glCanvas = new GLCanvas(caps); Assert.assertNotNull(glCanvas); final Dimension glc_sz = new Dimension(width, height); glCanvas.setMinimumSize(glc_sz); glCanvas.setPreferredSize(glc_sz); glCanvas.setSize(glc_sz); glad = glCanvas; new AWTWindowAdapter(new TraceWindowAdapter(quitAdapter), glCanvas).addTo(frame); frame.setLayout(new BorderLayout()); frame.add(glCanvas, BorderLayout.CENTER); javax.swing.SwingUtilities.invokeAndWait( new Runnable() { public void run() { frame.pack(); frame.setVisible(true); } }); } else { final GLDrawableFactory factory = GLDrawableFactory.getFactory(caps.getGLProfile()); glad = factory.createOffscreenAutoDrawable(null, caps, null, width, height); Assert.assertNotNull(glad); } return glad; }
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; if (useTexture) { texFormat = caps.getAlphaBits() > 0 ? EGL.EGL_TEXTURE_RGBA : EGL.EGL_TEXTURE_RGB; } else { texFormat = EGL.EGL_NO_TEXTURE; } if (DEBUG) { System.out.println("Pbuffer config: " + config); } final IntBuffer attrs = EGLGraphicsConfiguration.CreatePBufferSurfaceAttribList(width, height, texFormat); final long surf = EGL.eglCreatePbufferSurface(eglDevice.getHandle(), config.getNativeConfig(), attrs); if (EGL.EGL_NO_SURFACE == surf) { 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)); } return surf; }
static X11GLXGraphicsConfiguration chooseGraphicsConfigurationStatic( GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsReq, GLCapabilitiesChooser chooser, X11GraphicsScreen x11Screen) { if (x11Screen == null) { throw new IllegalArgumentException("AbstractGraphicsScreen is null"); } if (capsChosen == null) { capsChosen = new GLCapabilities(null); } X11GraphicsDevice x11Device = (X11GraphicsDevice) x11Screen.getDevice(); X11GLXDrawableFactory factory = (X11GLXDrawableFactory) GLDrawableFactory.getDesktopFactory(); capsChosen = GLGraphicsConfigurationUtil.fixGLCapabilities( capsChosen, factory.canCreateGLPbuffer(x11Device)); boolean usePBuffer = capsChosen.isPBuffer(); X11GLXGraphicsConfiguration res = null; if (factory.isGLXVersionGreaterEqualOneThree(x11Device)) { res = chooseGraphicsConfigurationFBConfig(capsChosen, capsReq, chooser, x11Screen); } if (null == res) { if (usePBuffer) { throw new GLException( "Error: Couldn't create X11GLXGraphicsConfiguration based on FBConfig for " + capsChosen); } res = chooseGraphicsConfigurationXVisual(capsChosen, capsReq, chooser, x11Screen); } if (null == res) { throw new GLException( "Error: Couldn't create X11GLXGraphicsConfiguration based on FBConfig and XVisual for " + capsChosen); } if (DEBUG) { System.err.println( "X11GLXGraphicsConfiguration.chooseGraphicsConfigurationStatic(" + x11Screen + "," + capsChosen + "): " + res); } return res; }
private static X11GLXGraphicsConfiguration chooseGraphicsConfigurationXVisual( GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsReq, GLCapabilitiesChooser chooser, X11GraphicsScreen x11Screen) { if (chooser == null) { chooser = new DefaultGLCapabilitiesChooser(); } GLProfile glProfile = capsChosen.getGLProfile(); final int winattrmask = GLGraphicsConfigurationUtil.getWinAttributeBits( capsChosen.isOnscreen(), false /* pbuffer */); ArrayList availableCaps = new ArrayList(); int recommendedIndex = -1; AbstractGraphicsDevice absDevice = x11Screen.getDevice(); long display = absDevice.getHandle(); int screen = x11Screen.getIndex(); final X11GLXDrawableFactory factory = (X11GLXDrawableFactory) GLDrawableFactory.getDesktopFactory(); final boolean isMultisampleAvailable = factory.isGLXMultisampleAvailable(absDevice); int[] attribs = X11GLXGraphicsConfiguration.GLCapabilities2AttribList( capsChosen, false, isMultisampleAvailable, display, screen); // 1st choice: get GLCapabilities based on users GLCapabilities setting recommendedIndex as // preferred choice XVisualInfo recommendedVis = GLX.glXChooseVisual(display, screen, attribs, 0); if (DEBUG) { System.err.print("glXChooseVisual recommended "); if (recommendedVis == null) { System.err.println("null visual"); } else { System.err.println("visual id " + toHexString(recommendedVis.getVisualid())); } } // 2nd choice: get all GLCapabilities available, preferred recommendedIndex might be available // if 1st choice was successful int[] count = new int[1]; XVisualInfo template = XVisualInfo.create(); template.setScreen(screen); XVisualInfo[] infos = X11Lib.XGetVisualInfo(display, X11Lib.VisualScreenMask, template, count, 0); if (infos == null || infos.length < 1) { throw new GLException("Error while enumerating available XVisualInfos"); } for (int i = 0; i < infos.length; i++) { if (!X11GLXGraphicsConfiguration.XVisualInfo2GLCapabilities( availableCaps, glProfile, display, infos[i], winattrmask, isMultisampleAvailable)) { if (DEBUG) { System.err.println( "X11GLXGraphicsConfiguration.chooseGraphicsConfigurationXVisual: XVisual invalid: (" + x11Screen + "): fbcfg: " + toHexString(infos[i].getVisualid())); } } else { // Attempt to find the visual chosenIndex by glXChooseVisual, if not translucent if (capsChosen.isBackgroundOpaque() && recommendedVis != null && recommendedVis.getVisualid() == infos[i].getVisualid()) { recommendedIndex = availableCaps.size() - 1; } } } int chosenIndex = chooseCapabilities(chooser, capsChosen, availableCaps, recommendedIndex); if (0 > chosenIndex) { if (DEBUG) { System.err.println( "X11GLXGraphicsConfiguration.chooseGraphicsConfigurationXVisual: failed, return null"); Thread.dumpStack(); } return null; } X11GLCapabilities chosenCaps = (X11GLCapabilities) availableCaps.get(chosenIndex); return new X11GLXGraphicsConfiguration(x11Screen, chosenCaps, capsReq, chooser); }
private static X11GLXGraphicsConfiguration chooseGraphicsConfigurationFBConfig( GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsReq, GLCapabilitiesChooser chooser, X11GraphicsScreen x11Screen) { int recommendedIndex = -1; PointerBuffer fbcfgsL = null; GLProfile glProfile = capsChosen.getGLProfile(); boolean onscreen = capsChosen.isOnscreen(); boolean usePBuffer = capsChosen.isPBuffer(); // Utilizing FBConfig // AbstractGraphicsDevice absDevice = x11Screen.getDevice(); long display = absDevice.getHandle(); int screen = x11Screen.getIndex(); final X11GLXDrawableFactory factory = (X11GLXDrawableFactory) GLDrawableFactory.getDesktopFactory(); final boolean isMultisampleAvailable = factory.isGLXMultisampleAvailable(absDevice); int[] attribs = X11GLXGraphicsConfiguration.GLCapabilities2AttribList( capsChosen, true, isMultisampleAvailable, display, screen); int[] count = {-1}; ArrayList /*<X11GLCapabilities>*/ availableCaps = new ArrayList(); final int winattrmask = GLGraphicsConfigurationUtil.getWinAttributeBits(onscreen, usePBuffer); // 1st choice: get GLCapabilities based on users GLCapabilities setting recommendedIndex as // preferred choice fbcfgsL = GLX.glXChooseFBConfig(display, screen, attribs, 0, count, 0); if (fbcfgsL != null && fbcfgsL.limit() > 0) { for (int i = 0; i < fbcfgsL.limit(); i++) { if (!X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities( availableCaps, glProfile, display, fbcfgsL.get(i), winattrmask, isMultisampleAvailable)) { if (DEBUG) { System.err.println( "X11GLXGraphicsConfiguration.chooseGraphicsConfigurationFBConfig: FBConfig invalid (1): (" + x11Screen + "," + capsChosen + "): fbcfg: " + toHexString(fbcfgsL.get(i))); } } } if (availableCaps.size() > 0) { recommendedIndex = capsChosen.isBackgroundOpaque() ? 0 : -1; // only use recommended idx if not translucent if (DEBUG) { System.err.println( "glXChooseFBConfig recommended fbcfg " + toHexString(fbcfgsL.get(0)) + ", idx " + recommendedIndex); System.err.println("user caps " + capsChosen); System.err.println("fbcfg caps " + availableCaps.get(0)); } } else if (DEBUG) { System.err.println( "glXChooseFBConfig no caps for recommended fbcfg " + toHexString(fbcfgsL.get(0))); System.err.println("user caps " + capsChosen); } } // 2nd choice: get all GLCapabilities available, no preferred recommendedIndex available if (0 == availableCaps.size()) { // reset .. recommendedIndex = -1; fbcfgsL = GLX.glXChooseFBConfig(display, screen, null, 0, count, 0); if (fbcfgsL == null || fbcfgsL.limit() <= 0) { if (DEBUG) { System.err.println( "X11GLXGraphicsConfiguration.chooseGraphicsConfigurationFBConfig: Failed glXChooseFBConfig (" + x11Screen + "," + capsChosen + "): " + fbcfgsL + ", " + count[0]); } return null; } for (int i = 0; i < fbcfgsL.limit(); i++) { if (!X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities( availableCaps, glProfile, display, fbcfgsL.get(i), winattrmask, isMultisampleAvailable)) { if (DEBUG) { System.err.println( "X11GLXGraphicsConfiguration.chooseGraphicsConfigurationFBConfig: FBConfig invalid (2): (" + x11Screen + "): fbcfg: " + toHexString(fbcfgsL.get(i))); } } } } int chosenIndex = chooseCapabilities(chooser, capsChosen, availableCaps, recommendedIndex); if (0 > chosenIndex) { if (DEBUG) { System.err.println( "X11GLXGraphicsConfiguration.chooseGraphicsConfigurationFBConfig: failed, return null"); Thread.dumpStack(); } return null; } X11GLCapabilities chosenCaps = (X11GLCapabilities) availableCaps.get(chosenIndex); return new X11GLXGraphicsConfiguration(x11Screen, chosenCaps, capsReq, chooser); }
/** * Creates and initializes an appropriate OpenGl Context (NS). Should only be called by {@link * makeCurrentImpl()}. */ protected boolean create(boolean pbuffer, boolean floatingPoint) { MacOSXCGLContext other = (MacOSXCGLContext) GLContextShareSet.getShareContext(this); long share = 0; if (other != null) { if (!other.isNSContext()) { throw new GLException("GLContextShareSet is not a NS Context"); } share = other.getHandle(); if (share == 0) { throw new GLException("GLContextShareSet returned a NULL OpenGL context"); } } MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); GLCapabilitiesImmutable capabilitiesRequested = (GLCapabilitiesImmutable) config.getRequestedCapabilities(); GLProfile glProfile = capabilitiesRequested.getGLProfile(); if (glProfile.isGL3()) { throw new GLException( "GL3 profile currently not supported on MacOSX, due to the lack of a OpenGL 3.1 implementation"); } // HACK .. bring in OnScreen/PBuffer selection to the DrawableFactory !! GLCapabilities capabilities = (GLCapabilities) capabilitiesRequested.cloneMutable(); capabilities.setPBuffer(pbuffer); capabilities.setPbufferFloatingPointBuffers(floatingPoint); long pixelFormat = MacOSXCGLGraphicsConfiguration.GLCapabilities2NSPixelFormat(capabilities); if (pixelFormat == 0) { throw new GLException("Unable to allocate pixel format with requested GLCapabilities"); } config.setChosenPixelFormat(pixelFormat); try { int[] viewNotReady = new int[1]; // Try to allocate a context with this contextHandle = CGL.createContext(share, drawable.getHandle(), pixelFormat, viewNotReady, 0); if (contextHandle == 0) { if (viewNotReady[0] == 1) { if (DEBUG) { System.err.println("!!! View not ready for " + getClass().getName()); } // View not ready at the window system level -- this is OK return false; } throw new GLException("Error creating NSOpenGLContext with requested pixel format"); } if (!pbuffer && !capabilities.isBackgroundOpaque()) { // Set the context opacity CGL.setContextOpacity(contextHandle, 0); } GLCapabilitiesImmutable caps = MacOSXCGLGraphicsConfiguration.NSPixelFormat2GLCapabilities(glProfile, pixelFormat); config.setChosenCapabilities(caps); } finally { CGL.deletePixelFormat(pixelFormat); } if (!CGL.makeCurrentContext(contextHandle)) { throw new GLException("Error making Context (NS) current"); } isNSContext = true; setGLFunctionAvailability(true, 0, 0, CTX_PROFILE_COMPAT | CTX_OPTION_ANY); GLContextShareSet.contextCreated(this); return true; }
private void createPbuffer() { final MutableSurface ms = (MutableSurface) getNativeSurface(); final DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) ms.getGraphicsConfiguration(); final GLCapabilitiesImmutable capabilities = (GLCapabilitiesImmutable) config.getChosenCapabilities(); final GLProfile glProfile = capabilities.getGLProfile(); MacOSXCGLDrawableFactory.SharedResource sr = ((MacOSXCGLDrawableFactory) factory) .getOrCreateOSXSharedResource(config.getScreen().getDevice()); if (DEBUG) { System.out.println(getThreadName() + ": Pbuffer config: " + config); if (null != sr) { System.out.println("Pbuffer NPOT Texure avail: " + sr.isNPOTTextureAvailable()); System.out.println("Pbuffer RECT Texture avail: " + sr.isRECTTextureAvailable()); } else { System.out.println("Pbuffer no sr, no RECT/NPOT Texture avail"); } } if (capabilities.getPbufferRenderToTextureRectangle() && null != sr && sr.isRECTTextureAvailable()) { pBufferTexTarget = GL2GL3.GL_TEXTURE_RECTANGLE; } else { pBufferTexTarget = GL.GL_TEXTURE_2D; } if (GL2GL3.GL_TEXTURE_RECTANGLE == pBufferTexTarget || (null != sr && sr.isNPOTTextureAvailable())) { pBufferTexWidth = getWidth(); pBufferTexHeight = getHeight(); } else { pBufferTexWidth = GLBuffers.getNextPowerOf2(getWidth()); pBufferTexHeight = GLBuffers.getNextPowerOf2(getHeight()); } int internalFormat = GL.GL_RGBA; if (capabilities.getPbufferFloatingPointBuffers()) { if (!glProfile.isGL2GL3() || null == sr || sr.isAppleFloatPixelsAvailable()) { throw new GLException("Floating-point support (GL_APPLE_float_pixels) not available"); } switch (capabilities.getRedBits()) { case 16: internalFormat = GL2.GL_RGBA_FLOAT16_APPLE; break; case 32: internalFormat = GL2.GL_RGBA_FLOAT32_APPLE; break; default: throw new GLException("Invalid floating-point bit depth (only 16 and 32 supported)"); } } final long pBuffer = impl.create(pBufferTexTarget, internalFormat, getWidth(), getHeight()); if (DEBUG) { System.err.println( "MacOSXPbufferCGLDrawable tex: target " + toHexString(pBufferTexTarget) + ", pbufferSize " + getWidth() + "x" + getHeight() + ", texSize " + pBufferTexWidth + "x" + pBufferTexHeight + ", internal-fmt " + toHexString(internalFormat)); System.err.println("MacOSXPbufferCGLDrawable pBuffer: " + toHexString(pBuffer)); // Thread.dumpStack(); } if (pBuffer == 0) { throw new GLException("pbuffer creation error: CGL.createPBuffer() failed"); } ms.setSurfaceHandle(pBuffer); }
public static IntBuffer GLCapabilities2AttribList(GLCapabilitiesImmutable caps) { final IntBuffer attrs = Buffers.newDirectIntBuffer(32); int idx = 0; attrs.put(idx++, EGL.EGL_SURFACE_TYPE); final int surfaceType; if (caps.isOnscreen()) { surfaceType = EGL.EGL_WINDOW_BIT; } else if (caps.isFBO()) { surfaceType = EGL.EGL_PBUFFER_BIT; // native replacement! } else if (caps.isPBuffer()) { surfaceType = EGL.EGL_PBUFFER_BIT; } else if (caps.isBitmap()) { surfaceType = EGL.EGL_PIXMAP_BIT; } else { throw new GLException("no surface type set in caps: " + caps); } attrs.put(idx++, surfaceType); attrs.put(idx++, EGL.EGL_RED_SIZE); attrs.put(idx++, caps.getRedBits()); attrs.put(idx++, EGL.EGL_GREEN_SIZE); attrs.put(idx++, caps.getGreenBits()); attrs.put(idx++, EGL.EGL_BLUE_SIZE); attrs.put(idx++, caps.getBlueBits()); if (caps.getAlphaBits() > 0) { attrs.put(idx++, EGL.EGL_ALPHA_SIZE); attrs.put(idx++, caps.getAlphaBits()); } if (caps.getStencilBits() > 0) { attrs.put(idx++, EGL.EGL_STENCIL_SIZE); attrs.put(idx++, caps.getStencilBits()); } attrs.put(idx++, EGL.EGL_DEPTH_SIZE); attrs.put(idx++, caps.getDepthBits()); if (caps.getSampleBuffers()) { if (caps.getSampleExtension().equals(GLGraphicsConfigurationUtil.NV_coverage_sample)) { attrs.put(idx++, EGLExt.EGL_COVERAGE_BUFFERS_NV); attrs.put(idx++, 1); attrs.put(idx++, EGLExt.EGL_COVERAGE_SAMPLES_NV); attrs.put(idx++, caps.getNumSamples()); } else { // try default .. attrs.put(idx++, EGL.EGL_SAMPLE_BUFFERS); attrs.put(idx++, 1); attrs.put(idx++, EGL.EGL_SAMPLES); attrs.put(idx++, caps.getNumSamples()); } } attrs.put(idx++, EGL.EGL_TRANSPARENT_TYPE); attrs.put(idx++, caps.isBackgroundOpaque() ? EGL.EGL_NONE : EGL.EGL_TRANSPARENT_TYPE); // 22 if (!caps.isBackgroundOpaque()) { attrs.put(idx++, EGL.EGL_TRANSPARENT_RED_VALUE); attrs.put( idx++, caps.getTransparentRedValue() >= 0 ? caps.getTransparentRedValue() : EGL.EGL_DONT_CARE); attrs.put(idx++, EGL.EGL_TRANSPARENT_GREEN_VALUE); attrs.put( idx++, caps.getTransparentGreenValue() >= 0 ? caps.getTransparentGreenValue() : EGL.EGL_DONT_CARE); attrs.put(idx++, EGL.EGL_TRANSPARENT_BLUE_VALUE); attrs.put( idx++, caps.getTransparentBlueValue() >= 0 ? caps.getTransparentBlueValue() : EGL.EGL_DONT_CARE); /** * Not define in EGL attrs.put(idx++, EGL.EGL_TRANSPARENT_ALPHA_VALUE; attrs.put(idx++, * caps.getTransparentAlphaValue()>=0?caps.getTransparentAlphaValue():EGL.EGL_DONT_CARE; */ } // 28 attrs.put(idx++, EGL.EGL_RENDERABLE_TYPE); if (caps.getGLProfile().usesNativeGLES1()) { attrs.put(idx++, EGL.EGL_OPENGL_ES_BIT); } else if (caps.getGLProfile().usesNativeGLES2()) { attrs.put(idx++, EGL.EGL_OPENGL_ES2_BIT); } else if (caps.getGLProfile().usesNativeGLES3()) { if (GLRendererQuirks.existStickyDeviceQuirk( GLDrawableFactory.getEGLFactory().getDefaultDevice(), GLRendererQuirks.GLES3ViaEGLES2Config)) { attrs.put(idx++, EGL.EGL_OPENGL_ES2_BIT); } else { attrs.put(idx++, EGLExt.EGL_OPENGL_ES3_BIT_KHR); } } else { attrs.put(idx++, EGL.EGL_OPENGL_BIT); } // 30 attrs.put(idx++, EGL.EGL_NONE); return attrs; }
/** Display all informations about the currently activated OpenGL mode. */ @SuppressWarnings("nls") private void displayOpenGLStatusInfo() { final GLCapabilitiesImmutable activeCaps = getChosenGLCapabilities(); doubleBuffered = activeCaps.getDoubleBuffered(); if (activeCaps.getHardwareAccelerated()) { LOGGER.debug("OpenGL Hardware acceleration active"); } else { LOGGER.warn("OpenGL Hardware acceleration inactive"); } LOGGER.debug("Active Samples: " + Integer.toString(activeCaps.getNumSamples())); if (activeCaps.getGLProfile().isGLES1()) { LOGGER.debug("OpenGL ES 1.x supported"); } else { LOGGER.debug("OpenGL ES 1.x not supported"); } if (activeCaps.getGLProfile().isGLES2()) { LOGGER.debug("OpenGL ES 2.x supported"); } else { LOGGER.debug("OpenGL ES 2.x not supported"); } if (activeCaps.getGLProfile().isGL2()) { LOGGER.debug("OpenGL 1.x, 2.x, 3.0 supported"); } else { LOGGER.debug("OpenGL 1.x, 2.x, 3.0 not supported"); } if (activeCaps.getGLProfile().isGL3()) { LOGGER.debug("OpenGL 3.x supported"); } else { LOGGER.debug("OpenGL 3.x not supported"); } if (activeCaps.getGLProfile().isGL4()) { LOGGER.debug("OpenGL 4.x supported"); } else { LOGGER.debug("OpenGL 4.x not supported"); } if (activeCaps.getGLProfile().isGL2GL3()) { LOGGER.debug("OpenGL 2.x, 3.x supported"); } else { LOGGER.debug("OpenGL 2.x, 3.x not supported"); } if (activeCaps.getGLProfile().isGL2ES1()) { LOGGER.debug("OpenGL 1.x, 2.x, 3.0 and OpenGL ES 1.x supported"); } else { LOGGER.debug("OpenGL 1.x, 2.x, 3.0 and OpenGL ES 1.x not supported"); } if (activeCaps.getGLProfile().isGL2ES2()) { LOGGER.debug("OpenGL 1.x, 2.x, 3.0 and OpenGL ES 2.x supported"); } else { LOGGER.debug("OpenGL 1.x, 2.x, 3.0 and OpenGL ES 2.x not supported"); } if (activeCaps.getGLProfile().hasGLSL()) { LOGGER.debug("OpenGL shader language supported"); } else { LOGGER.debug("OpenGL shader language not supported"); } if (activeCaps.getGLProfile().usesNativeGLES()) { LOGGER.debug("OpenGL ES native supported"); } else { LOGGER.debug("OpenGL ES native not supported"); } if (activeCaps.getGLProfile().usesNativeGLES1()) { LOGGER.debug("OpenGL ES 1.x native supported"); } else { LOGGER.debug("OpenGL ES 1.x native not supported"); } if (activeCaps.getGLProfile().usesNativeGLES2()) { LOGGER.debug("OpenGL ES 2.x native supported"); } else { LOGGER.debug("OpenGL ES 2.x native not supported"); } }
/** * 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 } }
void doTest(final GLCapabilitiesImmutable reqGLCaps, final GLEventListener demo) throws InterruptedException { System.out.println("Requested GL Caps: " + reqGLCaps); final GLDrawableFactory factory = GLDrawableFactory.getFactory(reqGLCaps.getGLProfile()); final GLCapabilitiesImmutable expGLCaps = GLGraphicsConfigurationUtil.fixGLCapabilities(reqGLCaps, factory, null); System.out.println("Expected GL Caps: " + expGLCaps); // // Create native OpenGL resources .. XGL/WGL/CGL .. // equivalent to GLAutoDrawable methods: setVisible(true) // final GLOffscreenAutoDrawable glad = factory.createOffscreenAutoDrawable( null, reqGLCaps, null, widthStep * szStep, heightStep * szStep); Assert.assertNotNull(glad); System.out.println( "Drawable Pre-GL(0): " + glad.getClass().getName() + ", " + glad.getNativeSurface().getClass().getName()); Assert.assertTrue(glad.isRealized()); // Check caps of NativeWindow config w/o GL final CapabilitiesImmutable chosenCaps = glad.getChosenGLCapabilities(); System.out.println("Drawable Caps Pre_GL : " + chosenCaps); Assert.assertNotNull(chosenCaps); Assert.assertTrue(chosenCaps.getGreenBits() > 4); Assert.assertTrue(chosenCaps.getBlueBits() > 4); Assert.assertTrue(chosenCaps.getRedBits() > 4); glad.display(); // force native context creation // Check caps of GLDrawable after realization final GLCapabilitiesImmutable chosenGLCaps = glad.getChosenGLCapabilities(); System.out.println("Chosen GL CTX (1): " + glad.getContext().getGLVersion()); System.out.println("Chosen GL Caps(1): " + chosenGLCaps); System.out.println( "Chosen GL Caps(2): " + glad.getNativeSurface().getGraphicsConfiguration().getChosenCapabilities()); Assert.assertNotNull(chosenGLCaps); Assert.assertTrue(chosenGLCaps.getGreenBits() > 4); Assert.assertTrue(chosenGLCaps.getBlueBits() > 4); Assert.assertTrue(chosenGLCaps.getRedBits() > 4); Assert.assertTrue(chosenGLCaps.getDepthBits() > 4); Assert.assertEquals(expGLCaps.isOnscreen(), chosenGLCaps.isOnscreen()); Assert.assertEquals(expGLCaps.isFBO(), chosenGLCaps.isFBO()); Assert.assertEquals(expGLCaps.isPBuffer(), chosenGLCaps.isPBuffer()); Assert.assertEquals(expGLCaps.isBitmap(), chosenGLCaps.isBitmap()); /** * Single/Double buffer cannot be checked since result may vary .. if(chosenGLCaps.isOnscreen() * || chosenGLCaps.isFBO()) { // dbl buffer may be disabled w/ offscreen pbuffer and bitmap * Assert.assertEquals(expGLCaps.getDoubleBuffered(), chosenGLCaps.getDoubleBuffered()); } */ glad.addGLEventListener(demo); final SnapshotGLEventListener snapshotGLEventListener = new SnapshotGLEventListener(); glad.addGLEventListener(snapshotGLEventListener); glad.display(); // initial resize/display // 1 - szStep = 2 Assert.assertTrue( "Size not reached: Expected " + (widthStep * szStep) + "x" + (heightStep * szStep) + ", Is " + glad.getSurfaceWidth() + "x" + glad.getSurfaceHeight(), AWTRobotUtil.waitForSize(glad, widthStep * szStep, heightStep * szStep)); snapshotGLEventListener.setMakeSnapshot(); glad.display(); // 2, 3 (resize + display) szStep = 1; glad.setSurfaceSize(widthStep * szStep, heightStep * szStep); Assert.assertTrue( "Size not reached: Expected " + (widthStep * szStep) + "x" + (heightStep * szStep) + ", Is " + glad.getSurfaceWidth() + "x" + glad.getSurfaceHeight(), AWTRobotUtil.waitForSize(glad, widthStep * szStep, heightStep * szStep)); snapshotGLEventListener.setMakeSnapshot(); glad.display(); // 4, 5 (resize + display) szStep = 4; glad.setSurfaceSize(widthStep * szStep, heightStep * szStep); Assert.assertTrue( "Size not reached: Expected " + (widthStep * szStep) + "x" + (heightStep * szStep) + ", Is " + glad.getSurfaceWidth() + "x" + glad.getSurfaceHeight(), AWTRobotUtil.waitForSize(glad, widthStep * szStep, heightStep * szStep)); snapshotGLEventListener.setMakeSnapshot(); glad.display(); Thread.sleep(50); glad.destroy(); System.out.println("Fin Drawable: " + glad); }
@Override public void test( final GLCapabilitiesImmutable caps, final boolean useSwingDoubleBuffer, final boolean skipGLOrientationVerticalFlip) { if (skipGLOrientationVerticalFlip || useSwingDoubleBuffer) { return; // NOP } final AWTGLReadBufferUtil awtGLReadBufferUtil = new AWTGLReadBufferUtil(caps.getGLProfile(), false); final Frame frame = new Frame(); final Dimension d = new Dimension(320, 240); final GLCanvas glad = createGLCanvas(caps, d); final TextRendererGLEL textRendererGLEL = new TextRendererGLEL(); final SnapshotGLELAWT snapshotGLEL = doSnapshot ? new SnapshotGLELAWT(textRendererGLEL, awtGLReadBufferUtil) : null; try { javax.swing.SwingUtilities.invokeAndWait( new Runnable() { public void run() { frame.setLocation(64, 64); frame.setLayout(new BorderLayout()); // final JPanel panel = new JPanel(); // panel.setLayout(new BorderLayout()); // panel.setDoubleBuffered(useSwingDoubleBuffer); // frame.getContentPane().add(panel); final GearsES2 gears = new GearsES2(1); gears.setVerbose(false); glad.addGLEventListener(gears); glad.addGLEventListener(textRendererGLEL); if (doSnapshot) { glad.addGLEventListener(snapshotGLEL); } // panel.add(glad); frame.add(glad, BorderLayout.CENTER); frame.pack(); frame.setVisible(true); } }); } catch (Throwable throwable) { throwable.printStackTrace(); Assume.assumeNoException(throwable); } glad.display(); // trigger initialization to get chosen-caps! final Dimension size0 = frame.getSize(); final Dimension size1 = new Dimension(size0.width + 100, size0.height + 100); final Dimension size2 = new Dimension(size0.width - 100, size0.height - 100); try { for (int i = 0; i < 3; i++) { final String str = "Frame# " + textRendererGLEL.frameNo + ", user #" + (i + 1); System.err.println(str); if (keyFrame) { waitForKey(str); } textRendererGLEL.userCounter = i + 1; glad.display(); } try { Thread.sleep(duration); } catch (InterruptedException e) { } javax.swing.SwingUtilities.invokeAndWait( new Runnable() { public void run() { frame.setSize(size1); frame.validate(); } }); try { Thread.sleep(duration); } catch (InterruptedException e) { } javax.swing.SwingUtilities.invokeAndWait( new Runnable() { public void run() { frame.setSize(size2); frame.validate(); } }); try { Thread.sleep(duration); } catch (InterruptedException e) { } javax.swing.SwingUtilities.invokeAndWait( new Runnable() { public void run() { frame.setSize(size0); frame.validate(); } }); try { Thread.sleep(duration); } catch (InterruptedException e) { } if (doSnapshot) { glad.disposeGLEventListener(snapshotGLEL, true /* remove */); } final Animator anim = new Animator(glad); anim.start(); try { Thread.sleep(2 * duration); } catch (InterruptedException e) { } anim.stop(); } catch (Exception e1) { e1.printStackTrace(); } try { SwingUtilities.invokeAndWait( new Runnable() { public void run() { frame.dispose(); } }); } catch (Exception e1) { e1.printStackTrace(); } }
/** * Takes a snapshot of the drawable's current front framebuffer. Example filenames: * * <pre> * TestGLDrawableAutoDelegateOnOffscrnCapsNEWT.testES2OffScreenFBOSglBuf____-n0001-msaa0-GLES2_-sw-fbobject-Bdbl-Frgb__Irgb_-S00_default-0400x0300.png * TestGLDrawableAutoDelegateOnOffscrnCapsNEWT.testES2OffScreenPbufferDblBuf-n0003-msaa0-GLES2_-sw-pbuffer_-Bdbl-Frgb__Irgb_-S00_default-0200x0150.png * TestGLDrawableAutoDelegateOnOffscrnCapsNEWT.testGL2OffScreenPbufferSglBuf-n0003-msaa0-GL2___-hw-pbuffer_-Bone-Frgb__Irgb_-S00_default-0200x0150.png * </pre> * * @param sn sequential number * @param postSNDetail optional detail to be added to the filename after <code>sn</code> * @param gl the current GL context object. It's read drawable is being used as the pixel source * and to gather some details which will end up in the filename. * @param readBufferUtil the {@link GLReadBufferUtil} to be used to read the pixels for the * screenshot. * @param fileSuffix Optional file suffix without a <i>dot</i> defining the file type, i.e. <code> * "png"</code>. If <code>null</code> the <code>"png"</code> as defined in {@link * TextureIO#PNG} is being used. * @param destPath Optional platform dependent file path. It shall use {@link File#separatorChar} * as is directory separator. It shall not end with a directory separator, {@link * File#separatorChar}. If <code>null</code> the current working directory is being used. */ public void snapshot( int sn, String postSNDetail, GL gl, GLReadBufferUtil readBufferUtil, String fileSuffix, String destPath) { if (null == fileSuffix) { fileSuffix = TextureIO.PNG; } final int maxSimpleTestNameLen = getMaxTestNameLen() + getClass().getSimpleName().length() + 1; final String simpleTestName = this.getSimpleTestName("."); final String filenameBaseName; { final GLDrawable drawable = gl.getContext().getGLReadDrawable(); final GLCapabilitiesImmutable caps = drawable.getChosenGLCapabilities(); final String accel = caps.getHardwareAccelerated() ? "hw" : "sw"; final String scrnm; if (caps.isOnscreen()) { scrnm = "onscreen"; } else if (caps.isFBO()) { scrnm = "fbobject"; } else if (caps.isPBuffer()) { scrnm = "pbuffer_"; } else if (caps.isBitmap()) { scrnm = "bitmap__"; } else { scrnm = "unknown_"; } final String dblb = caps.getDoubleBuffered() ? "dbl" : "one"; final String F_pfmt = readBufferUtil.hasAlpha() ? "rgba" : "rgb_"; final String pfmt = caps.getAlphaBits() > 0 ? "rgba" : "rgb_"; final int samples = caps.getNumSamples(); final String aaext = caps.getSampleExtension(); postSNDetail = null != postSNDetail ? "-" + postSNDetail : ""; filenameBaseName = String.format( "%-" + maxSimpleTestNameLen + "s-n%04d%s-%-6s-%s-%s-B%s-F%s_I%s-S%02d_%s-%04dx%04d.%s", simpleTestName, sn, postSNDetail, drawable.getGLProfile().getName(), accel, scrnm, dblb, F_pfmt, pfmt, samples, aaext, drawable.getWidth(), drawable.getHeight(), fileSuffix) .replace(' ', '_'); } final String filename = null != destPath ? destPath + File.separator + filenameBaseName : filenameBaseName; System.err.println( Thread.currentThread().getName() + ": ** screenshot: " + filename + ", maxTestNameLen " + maxSimpleTestNameLen + ", <" + simpleTestName + ">"); gl.glFinish(); // just make sure rendering finished .. if (readBufferUtil.readPixels(gl, false)) { readBufferUtil.write(new File(filename)); } }