diff options
Diffstat (limited to 'src/jogl')
71 files changed, 2499 insertions, 1393 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/FBObject.java b/src/jogl/classes/com/jogamp/opengl/FBObject.java index 03693a688..ceebe5f45 100644 --- a/src/jogl/classes/com/jogamp/opengl/FBObject.java +++ b/src/jogl/classes/com/jogamp/opengl/FBObject.java @@ -44,6 +44,7 @@ import javax.media.opengl.GLProfile; import jogamp.opengl.Debug; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.util.PropertyAccess; import com.jogamp.opengl.FBObject.Attachment.Type; @@ -698,10 +699,7 @@ public class FBObject { final int magFilter, final int minFilter, final int wrapS, final int wrapT) { final int dataFormat, dataType; final boolean alpha = hasAlpha(internalFormat); - if( gl.isGLES3() ) { - dataFormat = alpha ? GL.GL_RGBA : GL.GL_RGB; - dataType = GL.GL_UNSIGNED_BYTE; - } else if( gl.isGLES() ) { + if( gl.isGLES() ) { dataFormat = alpha ? GL.GL_RGBA : GL.GL_RGB; dataType = GL.GL_UNSIGNED_BYTE; } else { @@ -1071,7 +1069,7 @@ public class FBObject { vStatus = GL.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; // always incomplete w/o attachments! if(DEBUG) { System.err.println("FBObject.init() END: "+this); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } @@ -1306,7 +1304,7 @@ public class FBObject { final int glerr = gl.glGetError(); if(DEBUG && GL.GL_NO_ERROR != glerr) { System.err.println("Pre-existing GL error: "+toHexString(glerr)); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return glerr; } @@ -1520,7 +1518,7 @@ public class FBObject { final TextureAttachment texA = colbuf.getTextureAttachment(); if( samples > 0 ) { removeColorAttachment(attachmentPoint, texA); - if(initializedColorbuf) { + if( initializedColorbuf ) { texA.free(gl); } throw new GLException("Texture2D not supported w/ MSAA. If you have enabled MSAA with exisiting texture attachments, you may want to detach them via detachAllTexturebuffer(gl)."); @@ -1533,9 +1531,9 @@ public class FBObject { if(!ignoreStatus) { updateStatus(gl); - if(!isStatusValid()) { + if( !isStatusValid() ) { detachColorbuffer(gl, attachmentPoint, true); - throw new GLException("attachTexture2D "+texA+" at "+attachmentPoint+" failed "+getStatusString()+", "+this); + throw new GLException("attachTexture2D "+texA+" at "+attachmentPoint+" failed: "+getStatusString()+", "+this); } } } else { @@ -1548,9 +1546,9 @@ public class FBObject { if(!ignoreStatus) { updateStatus(gl); - if(!isStatusValid()) { + if( !isStatusValid() ) { detachColorbuffer(gl, attachmentPoint, true); - throw new GLException("attachColorbuffer "+colA+" at "+attachmentPoint+" failed "+getStatusString()+", "+this); + throw new GLException("attachColorbuffer "+colA+" at "+attachmentPoint+" failed: "+getStatusString()+", "+this); } } } @@ -1796,7 +1794,7 @@ public class FBObject { updateStatus(gl); if( !isStatusValid() ) { detachRenderbuffer(gl, atype, true); - throw new GLException("renderbuffer [attachmentType "+atype+", iformat "+toHexString(internalFormat)+"] failed: "+this.getStatusString()+": "+this.toString()); + throw new GLException("renderbuffer [attachmentType "+atype+", iformat "+toHexString(internalFormat)+"] failed: "+this.getStatusString()+", "+this.toString()); } } @@ -2197,7 +2195,7 @@ public class FBObject { } */ updateStatus(gl); if(!isStatusValid()) { - throw new GLException("detachAllImpl failed "+getStatusString()+", "+this); + throw new GLException("detachAllImpl failed: "+getStatusString()+", "+this); } } } finally { @@ -2306,7 +2304,7 @@ public class FBObject { public final boolean resetSamplingSink(final GL gl) throws GLException { if(DEBUG) { System.err.println("FBObject.resetSamplingSink.0"); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } if( 0 == samples ) { diff --git a/src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java b/src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java index e4cd5c5d9..9b973c626 100644 --- a/src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java +++ b/src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java @@ -33,9 +33,8 @@ import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.opengl.GLCapabilitiesImmutable; import com.jogamp.common.os.Platform; - -import jogamp.opengl.egl.EGL; -import jogamp.opengl.egl.EGLExt; +import com.jogamp.opengl.egl.EGL; +import com.jogamp.opengl.egl.EGLExt; /** * GLRendererQuirks contains information of known bugs of various GL renderer. @@ -419,8 +418,36 @@ public class GLRendererQuirks { */ public static final int NoARBCreateContext = 21; + /** + * No support for ES or desktop GL >= 3.0 current context without surface, + * i.e. without a default framebuffer as read- and write drawables. + * <p> + * See <i>OpenGL spec 3.0, chapter 2.1 OpenGL Fundamentals, page 7</i> or<br> + * <i>OpenGL ES spec 3.0.2, chapter 2.1 OpenGL Fundamentals, page 6</i>: + * <pre> + * It is possible to use a GL context without a default framebuffer, in which case + * a framebuffer object must be used to perform all rendering. This is useful for + * applications neeting to perform offscreen rendering. + * </pre> + * </p> + * <p> + * The feature will be attempted at initialization and this quirk will be set if failing. + * </p> + * <p> + * Known drivers failing the specification: + * <ul> + * <li>GNU/Linux X11 Nvidia proprietary driver + * <ul> + * <li>GL_VERSION 4.4.0 NVIDIA 340.24</li> + * <li>Platform GNU/Linux X11</li> + * </ul></li> + * </ul> + * </p> + */ + public static final int NoSurfacelessCtx = 22; + /** Return the number of known quirks. */ - public static final int getCount() { return 22; } + public static final int getCount() { return 23; } private static final String[] _names = new String[] { "NoDoubleBufferedPBuffer", "NoDoubleBufferedBitmap", "NoSetSwapInterval", "NoOffscreenBitmap", "NoSetSwapIntervalPostRetarget", "GLSLBuggyDiscard", @@ -429,7 +456,7 @@ public class GLRendererQuirks { "NoFullFBOSupport", "GLSLNonCompliant", "GL4NeedsGL3Request", "GLSharedContextBuggy", "GLES3ViaEGLES2Config", "SingletonEGLDisplayOnly", "NoMultiSamplingBuffers", "BuggyColorRenderbuffer", "NoPBufferWithAccum", - "NeedSharedObjectSync", "NoARBCreateContext" + "NeedSharedObjectSync", "NoARBCreateContext", "NoSurfacelessCtx" }; private static final IdentityHashMap<String, GLRendererQuirks> stickyDeviceQuirks = new IdentityHashMap<String, GLRendererQuirks>(); diff --git a/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java b/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java index 1a8924c8f..4a08d2e1f 100644 --- a/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java +++ b/src/jogl/classes/com/jogamp/opengl/math/FloatUtil.java @@ -491,16 +491,18 @@ public final class FloatUtil { * @param zNear * @param zFar * @return given matrix for chaining + * @throws GLException with GL_INVALID_VALUE if zNear is <= 0, or zFar < 0, + * or if left == right, or bottom == top, or zNear == zFar. */ public static float[] makeFrustum(final float[] m, final int m_offset, final boolean initM, final float left, final float right, final float bottom, final float top, - final float zNear, final float zFar) { - if(zNear<=0.0f||zFar<0.0f) { + final float zNear, final float zFar) throws GLException { + if( zNear <= 0.0f || zFar < 0.0f ) { throw new GLException("GL_INVALID_VALUE: zNear and zFar must be positive, and zNear>0"); } - if(left==right || top==bottom) { - throw new GLException("GL_INVALID_VALUE: top,bottom and left,right must not be equal"); + if( left == right || top == bottom || zNear == zFar ) { + throw new GLException("GL_INVALID_VALUE: top,bottom and left,right and zNear,zFar must not be equal"); } if( initM ) { // m[m_offset+0+4*0] = 1f; @@ -563,9 +565,10 @@ public final class FloatUtil { * @param zNear * @param zFar * @return given matrix for chaining + * @throws GLException with GL_INVALID_VALUE if zNear is <= 0, or zFar < 0, or if zNear == zFar. */ public static float[] makePerspective(final float[] m, final int m_off, final boolean initM, - final float fovy_rad, final float aspect, final float zNear, final float zFar) { + final float fovy_rad, final float aspect, final float zNear, final float zFar) throws GLException { final float top = tan(fovy_rad/2f) * zNear; // use tangent of half-fov ! final float bottom = -1.0f * top; final float left = aspect * bottom; @@ -588,9 +591,10 @@ public final class FloatUtil { * @param zNear * @param zFar * @return given matrix for chaining + * @throws GLException with GL_INVALID_VALUE if zNear is <= 0, or zFar < 0, or if zNear == zFar. */ public static float[] makePerspective(final float[] m, final int m_offset, final boolean initM, - final FovHVHalves fovhv, final float zNear, final float zFar) { + final FovHVHalves fovhv, final float zNear, final float zFar) throws GLException { final FovHVHalves fovhvTan = fovhv.toTangents(); // use tangent of half-fov ! final float top = fovhvTan.top * zNear; final float bottom = -1.0f * fovhvTan.bottom * zNear; diff --git a/src/jogl/classes/com/jogamp/opengl/math/Matrix4.java b/src/jogl/classes/com/jogamp/opengl/math/Matrix4.java index 830f1a882..b86a26dd5 100644 --- a/src/jogl/classes/com/jogamp/opengl/math/Matrix4.java +++ b/src/jogl/classes/com/jogamp/opengl/math/Matrix4.java @@ -28,6 +28,7 @@ package com.jogamp.opengl.math; +import javax.media.opengl.GLException; import javax.media.opengl.fixedfunc.GLMatrixFunc; import com.jogamp.opengl.util.PMVMatrix; @@ -139,11 +140,28 @@ public class Matrix4 { multMatrix( FloatUtil.makeOrtho(mat4Tmp1, 0, true, left, right, bottom, top, zNear, zFar) ); } - public final void makeFrustum(final float left, final float right, final float bottom, final float top, final float zNear, final float zFar) { + /** + * @param left + * @param right + * @param bottom + * @param top + * @param zNear + * @param zFar + * @throws GLException with GL_INVALID_VALUE if zNear is <= 0, or zFar < 0, + * or if left == right, or bottom == top, or zNear == zFar. + */ + public final void makeFrustum(final float left, final float right, final float bottom, final float top, final float zNear, final float zFar) throws GLException { multMatrix( FloatUtil.makeFrustum(mat4Tmp1, 0, true, left, right, bottom, top, zNear, zFar) ); } - public final void makePerspective(final float fovy_rad, final float aspect, final float zNear, final float zFar) { + /** + * @param fovy_rad + * @param aspect + * @param zNear + * @param zFar + * @throws GLException with GL_INVALID_VALUE if zNear is <= 0, or zFar < 0, or if zNear == zFar. + */ + public final void makePerspective(final float fovy_rad, final float aspect, final float zNear, final float zFar) throws GLException { multMatrix( FloatUtil.makePerspective(mat4Tmp1, 0, true, fovy_rad, aspect, zNear, zFar) ); } diff --git a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java index 5f2db20bd..3bd013a1a 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java +++ b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java @@ -39,6 +39,8 @@ import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; +import com.jogamp.common.ExceptionUtils; + /** * Base implementation of GLAnimatorControl<br> * <p> @@ -625,7 +627,7 @@ public abstract class AnimatorBase implements GLAnimatorControl { " - " + getThreadName()); System.err.println(" - "+toString()); if(nok) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } return res; diff --git a/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java b/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java index 54d40f285..1bd428c10 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java +++ b/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java @@ -45,6 +45,8 @@ import java.util.TimerTask; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLException; +import com.jogamp.common.ExceptionUtils; + /** * An Animator subclass which attempts to achieve a target * frames-per-second rate to avoid using all CPU time. The target FPS @@ -392,7 +394,7 @@ public class FPSAnimator extends AnimatorBase { if( null != task ) { if( DEBUG ) { System.err.println("FPSAnimator.resume() Ops: !pauseIssued, but task != null: "+toString()); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } task.cancel(); task = null; diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java b/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java index d4ab4e4f4..b8088bd16 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java +++ b/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java @@ -372,29 +372,29 @@ public class GLBuffers extends Buffers { int skipImages = 0; if (pack) { - alignment = glGetInteger(gl, GL.GL_PACK_ALIGNMENT, tmp); + alignment = glGetInteger(gl, GL.GL_PACK_ALIGNMENT, tmp); // es2, es3, gl3 if( gl.isGL2ES3() ) { - rowLength = glGetInteger(gl, GL2ES3.GL_PACK_ROW_LENGTH, tmp); - skipRows = glGetInteger(gl, GL2ES3.GL_PACK_SKIP_ROWS, tmp); - skipPixels = glGetInteger(gl, GL2ES3.GL_PACK_SKIP_PIXELS, tmp); - if (depth > 1 && gl.isGL2GL3() && gl.getContext().getGLVersionNumber().compareTo(GLContext.Version120) >= 0 ) { - imageHeight = glGetInteger(gl, GL2GL3.GL_PACK_IMAGE_HEIGHT, tmp); - skipImages = glGetInteger(gl, GL2GL3.GL_PACK_SKIP_IMAGES, tmp); + rowLength = glGetInteger(gl, GL2ES3.GL_PACK_ROW_LENGTH, tmp); // es3, gl3 + skipRows = glGetInteger(gl, GL2ES3.GL_PACK_SKIP_ROWS, tmp); // es3, gl3 + skipPixels = glGetInteger(gl, GL2ES3.GL_PACK_SKIP_PIXELS, tmp); // es3, gl3 + if (depth > 1 && gl.isGL2GL3() && gl.getContext().getGLVersionNumber().compareTo(GLContext.Version1_2) >= 0 ) { + imageHeight = glGetInteger(gl, GL2GL3.GL_PACK_IMAGE_HEIGHT, tmp); // gl3, GL_VERSION_1_2 + skipImages = glGetInteger(gl, GL2GL3.GL_PACK_SKIP_IMAGES, tmp); // gl3, GL_VERSION_1_2 } } } else { - alignment = glGetInteger(gl, GL.GL_UNPACK_ALIGNMENT, tmp); + alignment = glGetInteger(gl, GL.GL_UNPACK_ALIGNMENT, tmp); // es2, es3, gl3 if( gl.isGL2ES3() ) { - rowLength = glGetInteger(gl, GL2ES2.GL_UNPACK_ROW_LENGTH, tmp); - skipRows = glGetInteger(gl, GL2ES2.GL_UNPACK_SKIP_ROWS, tmp); - skipPixels = glGetInteger(gl, GL2ES2.GL_UNPACK_SKIP_PIXELS, tmp); + rowLength = glGetInteger(gl, GL2ES2.GL_UNPACK_ROW_LENGTH, tmp); // es3, gl3 + skipRows = glGetInteger(gl, GL2ES2.GL_UNPACK_SKIP_ROWS, tmp); // es3, gl3 + skipPixels = glGetInteger(gl, GL2ES2.GL_UNPACK_SKIP_PIXELS, tmp); // es3, gl3 if( depth > 1 && ( gl.isGL3ES3() || - ( gl.isGL2GL3() && gl.getContext().getGLVersionNumber().compareTo(GLContext.Version120) >= 0 ) + ( gl.isGL2GL3() && gl.getContext().getGLVersionNumber().compareTo(GLContext.Version1_2) >= 0 ) ) ) { - imageHeight = glGetInteger(gl, GL2ES3.GL_UNPACK_IMAGE_HEIGHT, tmp); - skipImages = glGetInteger(gl, GL2ES3.GL_UNPACK_SKIP_IMAGES, tmp); + imageHeight = glGetInteger(gl, GL2ES3.GL_UNPACK_IMAGE_HEIGHT, tmp);// es3, gl3, GL_VERSION_1_2 + skipImages = glGetInteger(gl, GL2ES3.GL_UNPACK_SKIP_IMAGES, tmp); // es3, gl3, GL_VERSION_1_2 } } } diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLPixelBuffer.java b/src/jogl/classes/com/jogamp/opengl/util/GLPixelBuffer.java index a09321d75..00bbd6ce7 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/GLPixelBuffer.java +++ b/src/jogl/classes/com/jogamp/opengl/util/GLPixelBuffer.java @@ -58,41 +58,100 @@ public class GLPixelBuffer { /** Allow {@link GL2ES3#GL_PACK_ROW_LENGTH}, or {@link GL2ES2#GL_UNPACK_ROW_LENGTH}. */ boolean getAllowRowStride(); - /** Called first to determine {@link GLPixelAttributes}. */ - GLPixelAttributes getAttributes(GL gl, int componentCount); + /** + * Returns RGB[A] {@link GLPixelAttributes} matching {@link GL}, {@code componentCount} and {@code pack}. + * + * @param gl the corresponding current {@link GL} context object + * @param componentCount RGBA component count, i.e. 1 (luminance, alpha or red), 3 (RGB) or 4 (RGBA) + * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}. + * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}. + */ + GLPixelAttributes getAttributes(GL gl, int componentCount, boolean pack); + + /** + * Returns the host {@link PixelFormat.Composition} matching {@link GL} and {@code componentCount} + * if required by implementation, otherwise {@code null}. + * + * @param glp the corresponding current {@link GL} context object + * @param componentCount RGBA component count, i.e. 1 (luminance, alpha or red), 3 (RGB) or 4 (RGBA) + */ + PixelFormat.Composition getHostPixelComp(final GLProfile glp, final int componentCount); /** * Allocates a new {@link GLPixelBuffer} object. * <p> - * Being called to gather the initial {@link GLPixelBuffer}, - * or a new replacement {@link GLPixelBuffer} if {@link GLPixelBuffer#requiresNewBuffer(GL, int, int, int)}. - * </p> - * <p> * The minimum required {@link Buffer#remaining() remaining} byte size equals to <code>minByteSize</code>, if > 0, * otherwise utilize {@link GLBuffers#sizeof(GL, int[], int, int, int, int, int, boolean)} * to calculate it. * </p> * - * @param gl the corresponding current GL context object - * @param pixelAttributes the desired {@link GLPixelAttributes} + * @param gl the corresponding current {@link GL} context object + * @param hostPixComp host {@link PixelFormat pixel format}, i.e. of the source or sink depending on {@code pack}, + * e.g. fetched via {@link #getHostPixelComp(GLProfile, int)}. + * If {@code null}, {@code pixelAttributes} instance maybe used or an exception is thrown, + * depending on implementation semantics. + * @param pixelAttributes the desired {@link GLPixelAttributes}, e.g. fetched via {@link #getAttributes(GL, int, boolean)} + * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}. + * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}. * @param width in pixels * @param height in pixels * @param depth in pixels - * @param pack true for read mode GPU -> CPU, otherwise false for write mode CPU -> GPU * @param minByteSize if > 0, the pre-calculated minimum byte-size for the resulting buffer, otherwise ignore. + * @see #getHostPixelComp(GLProfile, int) + * @see #getAttributes(GL, int, boolean) */ - GLPixelBuffer allocate(GL gl, GLPixelAttributes pixelAttributes, int width, int height, int depth, boolean pack, int minByteSize); + GLPixelBuffer allocate(GL gl, PixelFormat.Composition hostPixComp, GLPixelAttributes pixelAttributes, + boolean pack, int width, int height, int depth, int minByteSize); } /** Single {@link GLPixelBuffer} provider. */ public static interface SingletonGLPixelBufferProvider extends GLPixelBufferProvider { - /** Return the last {@link #allocate(GL, GLPixelAttributes, int, int, int, boolean, int) allocated} {@link GLPixelBuffer} w/ {@link GLPixelAttributes#componentCount}. */ - GLPixelBuffer getSingleBuffer(GLPixelAttributes pixelAttributes); /** - * Initializes the single {@link GLPixelBuffer} w/ a given size, if not yet {@link #allocate(GL, GLPixelAttributes, int, int, int, boolean, int) allocated}. + * {@inheritDoc} + * <p> + * Being called to gather the initial {@link GLPixelBuffer}, + * or a new replacement {@link GLPixelBuffer} if {@link GLPixelBuffer#requiresNewBuffer(GL, int, int, int)}. + * </p> + */ + @Override + GLPixelBuffer allocate(GL gl, PixelFormat.Composition hostPixComp, GLPixelAttributes pixelAttributes, + boolean pack, int width, int height, int depth, int minByteSize); + + /** + * Return the last {@link #allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int) allocated} {@link GLPixelBuffer} + * matching the given parameter. + * <p> + * May return {@code null} if none has been allocated yet. + * </p> + * <p> + * Returned {@link GLPixelBuffer} may be {@link GLPixelBuffer#isValid() invalid}. + * </p> + * @param hostPixComp host {@link PixelFormat pixel format}, i.e. of the source or sink depending on {@code pack}, + * e.g. fetched via {@link #getHostPixelComp(GLProfile, int)}. + * If {@code null}, {@code pixelAttributes} instance maybe used or an exception is thrown, + * depending on implementation semantics. + * @param pixelAttributes the desired {@link GLPixelAttributes}, e.g. fetched via {@link #getAttributes(GL, int, boolean)} + * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}. + * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}. + */ + GLPixelBuffer getSingleBuffer(PixelFormat.Composition hostPixelComp, GLPixelAttributes pixelAttributes, boolean pack); + /** + * Initializes the single {@link GLPixelBuffer} w/ a given size, + * if not yet {@link #allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int) allocated}. + * + * @param glp + * @param componentCount RGBA component count, i.e. 1 (luminance, alpha or red), 3 (RGB) or 4 (RGBA) + * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}. + * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}. + * @param width + * @param height + * @param depth * @return the newly initialized single {@link GLPixelBuffer}, or null if already allocated. */ - GLPixelBuffer initSingleton(int componentCount, int width, int height, int depth, boolean pack); + GLPixelBuffer initSingleton(GLProfile glp, int componentCount, boolean pack, int width, int height, int depth); + + /** Dispose all resources.*/ + void dispose(); } public static class DefaultGLPixelBufferProvider implements GLPixelBufferProvider { @@ -110,36 +169,24 @@ public class GLPixelBuffer { public boolean getAllowRowStride() { return allowRowStride; } @Override - public GLPixelAttributes getAttributes(final GL gl, final int componentCount) { - final GLContext ctx = gl.getContext(); - final int dFormat, dType; - - if( 1 == componentCount ) { - if( gl.isGL3ES3() ) { - // RED is supported on ES3 and >= GL3 [core]; ALPHA is deprecated on core - dFormat = GL2ES2.GL_RED; - } else { - // ALPHA is supported on ES2 and GL2, i.e. <= GL3 [core] or compatibility - dFormat = GL.GL_ALPHA; - } - dType = GL.GL_UNSIGNED_BYTE; - } else if( 3 == componentCount ) { - dFormat = GL.GL_RGB; - dType = GL.GL_UNSIGNED_BYTE; - } else if( 4 == componentCount ) { - final int _dFormat = ctx.getDefaultPixelDataFormat(); - final int dComps = GLBuffers.componentCount(_dFormat); - if( dComps == componentCount ) { - dFormat = _dFormat; - dType = ctx.getDefaultPixelDataType(); - } else { - dFormat = GL.GL_RGBA; - dType = GL.GL_UNSIGNED_BYTE; - } - } else { + public GLPixelAttributes getAttributes(final GL gl, final int componentCount, final boolean pack) { + final GLPixelAttributes res = GLPixelAttributes.convert(gl, componentCount, pack); + if( null == res ) { throw new GLException("Unsupported componentCount "+componentCount+", contact maintainer to enhance"); + } else { + return res; } - return new GLPixelAttributes(componentCount, dFormat, dType); + } + + /** + * {@inheritDoc} + * <p> + * Returns {@code null}! + * </p> + */ + @Override + public PixelFormat.Composition getHostPixelComp(final GLProfile glp, final int componentCount) { + return null; } /** @@ -149,13 +196,15 @@ public class GLPixelBuffer { * </p> */ @Override - public GLPixelBuffer allocate(final GL gl, final GLPixelAttributes pixelAttributes, final int width, final int height, final int depth, final boolean pack, final int minByteSize) { + public GLPixelBuffer allocate(final GL gl, final PixelFormat.Composition hostPixComp, final GLPixelAttributes pixelAttributes, + final boolean pack, final int width, final int height, final int depth, final int minByteSize) { + // unused: hostPixComp if( minByteSize > 0 ) { - return new GLPixelBuffer(pixelAttributes, width, height, depth, pack, Buffers.newDirectByteBuffer(minByteSize), getAllowRowStride()); + return new GLPixelBuffer(pixelAttributes, pack, width, height, depth, Buffers.newDirectByteBuffer(minByteSize), getAllowRowStride()); } else { final int[] tmp = { 0 }; - final int byteSize = GLBuffers.sizeof(gl, tmp, pixelAttributes.bytesPerPixel, width, height, depth, pack); - return new GLPixelBuffer(pixelAttributes, width, height, depth, pack, Buffers.newDirectByteBuffer(byteSize), getAllowRowStride()); + final int byteSize = GLBuffers.sizeof(gl, tmp, pixelAttributes.pfmt.comp.bytesPerPixel(), width, height, depth, pack); + return new GLPixelBuffer(pixelAttributes, pack, width, height, depth, Buffers.newDirectByteBuffer(byteSize), getAllowRowStride()); } } } @@ -163,74 +212,190 @@ public class GLPixelBuffer { /** * Default {@link GLPixelBufferProvider} with {@link GLPixelBufferProvider#getAllowRowStride()} == <code>false</code>, * utilizing best match for {@link GLPixelAttributes} - * and {@link GLPixelBufferProvider#allocate(GL, GLPixelAttributes, int, int, int, boolean, int) allocating} a {@link ByteBuffer}. + * and {@link GLPixelBufferProvider#allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int) allocating} a {@link ByteBuffer}. */ public static final GLPixelBufferProvider defaultProviderNoRowStride = new DefaultGLPixelBufferProvider(false); /** * Default {@link GLPixelBufferProvider} with {@link GLPixelBufferProvider#getAllowRowStride()} == <code>true</code>, * utilizing best match for {@link GLPixelAttributes} - * and {@link GLPixelBufferProvider#allocate(GL, GLPixelAttributes, int, int, int, boolean, int) allocating} a {@link ByteBuffer}. + * and {@link GLPixelBufferProvider#allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int) allocating} a {@link ByteBuffer}. */ public static final GLPixelBufferProvider defaultProviderWithRowStride = new DefaultGLPixelBufferProvider(true); /** Pixel attributes. */ public static class GLPixelAttributes { /** Undefined instance of {@link GLPixelAttributes}, having componentCount:=0, format:=0 and type:= 0. */ - public static final GLPixelAttributes UNDEF = new GLPixelAttributes(0, 0, 0, false); - - /** Pixel <i>source</i> component count, i.e. number of meaningful components. */ - public final int componentCount; - /** The OpenGL pixel data format */ - public final int format; - /** The OpenGL pixel data type */ - public final int type; - /** The OpenGL pixel size in bytes */ - public final int bytesPerPixel; + public static final GLPixelAttributes UNDEF = new GLPixelAttributes(null, PixelFormat.LUMINANCE, 0, 0, true, false); /** - * Deriving {@link #componentCount} via GL <code>dataFormat</code>, i.e. {@link GLBuffers#componentCount(int)} if > 0. - * @param dataFormat GL data format - * @param dataType GL data type + * Returns the matching {@link PixelFormat} for the given GL format and type if exists, + * otherwise returns <code>null</code>. */ - public GLPixelAttributes(final int dataFormat, final int dataType) { - this(0 < dataFormat ? GLBuffers.componentCount(dataFormat) : 0, dataFormat, dataType); + public static final PixelFormat getPixelFormat(final int glFormat, final int glDataType) { + PixelFormat pixFmt = null; + + switch(glFormat) { + case GL.GL_ALPHA: + case GL.GL_LUMINANCE: + case GL2ES2.GL_RED: + pixFmt = PixelFormat.LUMINANCE; + break; + case GL.GL_RGB: + switch(glDataType) { + case GL2GL3.GL_UNSIGNED_SHORT_5_6_5_REV: + pixFmt = PixelFormat.RGB565; + break; + case GL.GL_UNSIGNED_SHORT_5_6_5: + pixFmt = PixelFormat.BGR565; + break; + case GL.GL_UNSIGNED_BYTE: + pixFmt = PixelFormat.RGB888; + break; + } + break; + case GL.GL_RGBA: + switch(glDataType) { + case GL2GL3.GL_UNSIGNED_SHORT_1_5_5_5_REV: + pixFmt = PixelFormat.RGBA5551; + break; + case GL.GL_UNSIGNED_SHORT_5_5_5_1: + pixFmt = PixelFormat.ABGR1555; + break; + case GL.GL_UNSIGNED_BYTE: + pixFmt = PixelFormat.RGBA8888; + break; + case GL2GL3.GL_UNSIGNED_INT_8_8_8_8: + pixFmt = PixelFormat.ABGR8888; + break; + } + break; + case GL2GL3.GL_BGR: + if( GL.GL_UNSIGNED_BYTE == glDataType ) { + pixFmt = PixelFormat.BGR888; + } + break; + case GL.GL_BGRA: + switch(glDataType) { + case GL2GL3.GL_UNSIGNED_INT_8_8_8_8: + pixFmt = PixelFormat.ARGB8888; + break; + case GL.GL_UNSIGNED_BYTE: + pixFmt = PixelFormat.BGRA8888; + break; + } + break; + } + return pixFmt; } + /** - * Using user specified source {@link #componentCount}. - * @param componentCount source component count - * @param dataFormat GL data format - * @param dataType GL data type + * Returns the matching {@link GLPixelAttributes} for the given byte sized RGBA {@code componentCount} and {@link GL} if exists, + * otherwise returns {@code null}. + * + * @param gl the corresponding current {@link GL} context object + * @param componentCount RGBA component count, i.e. 1 (luminance, alpha or red), 3 (RGB) or 4 (RGBA) + * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}. + * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}. */ - public GLPixelAttributes(final int componentCount, final int dataFormat, final int dataType) { - this(componentCount, dataFormat, dataType, true); + public static GLPixelAttributes convert(final GL gl, final int componentCount, final boolean pack) { + final int dFormat, dType; + final boolean glesReadMode = pack && gl.isGLES(); + + if( 1 == componentCount && !glesReadMode ) { + if( gl.isGL3ES3() ) { + // RED is supported on ES3 and >= GL3 [core]; ALPHA is deprecated on core + dFormat = GL2ES2.GL_RED; + } else { + // ALPHA is supported on ES2 and GL2, i.e. <= GL3 [core] or compatibility + dFormat = GL.GL_ALPHA; + } + dType = GL.GL_UNSIGNED_BYTE; + } else if( 3 == componentCount && !glesReadMode ) { + dFormat = GL.GL_RGB; + dType = GL.GL_UNSIGNED_BYTE; + } else if( 4 == componentCount || glesReadMode ) { + final GLContext ctx = gl.getContext(); + final int _dFormat = ctx.getDefaultPixelDataFormat(); + final int dComps = GLBuffers.componentCount(_dFormat); + if( dComps == componentCount || 4 == dComps ) { // accept if desired component count or 4 components + dFormat = _dFormat; + dType = ctx.getDefaultPixelDataType(); + } else { + dFormat = GL.GL_RGBA; + dType = GL.GL_UNSIGNED_BYTE; + } + } else { + return null; + } + return new GLPixelAttributes(dFormat, dType); } /** - * Returns the matching {@link GLPixelAttributes} for the given {@link PixelFormat} and {@link GLProfile} if exists, - * otherwise returns <code>null</code>. + * Returns the matching {@link GLPixelAttributes} for the given {@link GLProfile}, {@link PixelFormat} and {@code pack} if exists, + * otherwise returns {@code null}. + * @param glp the corresponding {@link GLProfile} + * @param pixFmt the to be matched {@link PixelFormat pixel format} + * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}. + * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}. */ - public static final GLPixelAttributes convert(final PixelFormat pixFmt, final GLProfile glp) { + public static final GLPixelAttributes convert(final GLProfile glp, final PixelFormat pixFmt, final boolean pack) { + final int[] df = new int[1]; + final int[] dt = new int[1]; + convert(glp, pixFmt, pack, df, dt); + if( 0 != df[0] ) { + return new GLPixelAttributes(null, pixFmt, df[0], dt[0], true /* not used */, true); + } + return null; + } + private static final int convert(final GLProfile glp, final PixelFormat pixFmt, final boolean pack, + final int[] dfRes, final int[] dtRes) { + final boolean glesReadMode = pack && glp.isGLES(); int df = 0; // format int dt = GL.GL_UNSIGNED_BYTE; // data type switch(pixFmt) { case LUMINANCE: - if( glp.isGL3ES3() ) { - // RED is supported on ES3 and >= GL3 [core]; ALPHA/LUMINANCE is deprecated on core - df = GL2ES2.GL_RED; - } else { - // ALPHA/LUMINANCE is supported on ES2 and GL2, i.e. <= GL3 [core] or compatibility - df = GL.GL_LUMINANCE; + if( !glesReadMode ) { + if( glp.isGL3ES3() ) { + // RED is supported on ES3 and >= GL3 [core]; ALPHA/LUMINANCE is deprecated on core + df = GL2ES2.GL_RED; + } else { + // ALPHA/LUMINANCE is supported on ES2 and GL2, i.e. <= GL3 [core] or compatibility + df = GL.GL_LUMINANCE; + } } break; - case BGR888: + case RGB565: if( glp.isGL2GL3() ) { - df = GL2GL3.GL_BGR; + df = GL.GL_RGB; dt = GL2GL3.GL_UNSIGNED_SHORT_5_6_5_REV; + } + break; + case BGR565: + if( glp.isGL2GL3() ) { + df = GL.GL_RGB; dt = GL.GL_UNSIGNED_SHORT_5_6_5; + } + break; + case RGBA5551: + if( glp.isGL2GL3() ) { + df = GL.GL_RGBA; dt = GL2GL3.GL_UNSIGNED_SHORT_1_5_5_5_REV; + } + break; + case ABGR1555: + if( glp.isGL2GL3() ) { + df = GL.GL_RGBA; dt = GL.GL_UNSIGNED_SHORT_5_5_5_1; } break; case RGB888: - df = GL.GL_RGB; + if( !glesReadMode ) { + df = GL.GL_RGB; + } + break; + case BGR888: + if( glp.isGL2GL3() ) { + df = GL2GL3.GL_BGR; + } break; + case RGBx8888: case RGBA8888: df = GL.GL_RGBA; break; @@ -239,85 +404,107 @@ public class GLPixelBuffer { df = GL.GL_RGBA; dt = GL2GL3.GL_UNSIGNED_INT_8_8_8_8; } break; - case BGRA8888: - df = GL.GL_BGRA; - break; case ARGB8888: if( glp.isGL2GL3() ) { df = GL.GL_BGRA; dt = GL2GL3.GL_UNSIGNED_INT_8_8_8_8; } break; - default: + case BGRx8888: + case BGRA8888: + if( glp.isGL2GL3() ) { // FIXME: or if( !glesReadMode ) ? BGRA n/a on GLES + df = GL.GL_BGRA; + } break; } - if( 0 != df ) { - return new GLPixelAttributes(pixFmt.componentCount, df, dt, true); - } - return null; + dfRes[0] = df; + dtRes[0] = dt; + return df; } - private GLPixelAttributes(final int componentCount, final int dataFormat, final int dataType, final boolean checkArgs) { - this.componentCount = componentCount; - this.format = dataFormat; - this.type = dataType; - this.bytesPerPixel = ( 0 < dataFormat && 0 < dataType ) ? GLBuffers.bytesPerPixel(dataFormat, dataType) : 0; - if( checkArgs ) { - if( 0 == componentCount || 0 == format || 0 == type ) { - throw new GLException("Zero components, format and/or type: "+this); - } - if( 0 == bytesPerPixel ) { - throw new GLException("Zero bytesPerPixel: "+this); - } + + /** The OpenGL pixel data format */ + public final int format; + /** The OpenGL pixel data type */ + public final int type; + + /** {@link PixelFormat} describing the {@link PixelFormat.Composition component} layout */ + public final PixelFormat pfmt; + + @Override + public final int hashCode() { + // 31 * x == (x << 5) - x + int hash = pfmt.hashCode(); + hash = ((hash << 5) - hash) + format; + return ((hash << 5) - hash) + type; + } + + @Override + public final boolean equals(final Object obj) { + if(this == obj) { return true; } + if( obj instanceof GLPixelAttributes ) { + final GLPixelAttributes other = (GLPixelAttributes) obj; + return format == other.format && + type == other.type && + pfmt.equals(other.pfmt); + } else { + return false; } } /** - * Returns the matching {@link PixelFormat} of this {@link GLPixelAttributes} if exists, - * otherwise returns <code>null</code>. + * Create a new {@link GLPixelAttributes} instance based on GL format and type. + * @param dataFormat GL data format + * @param dataType GL data type + * @throws GLException if {@link PixelFormat} could not be determined, see {@link #getPixelFormat(int, int)}. */ - public final PixelFormat getPixelFormat() { - final PixelFormat pixFmt; - // FIXME: Take 'type' into consideration and complete mapping! - switch(format) { - case GL.GL_ALPHA: - case GL.GL_LUMINANCE: - case GL2ES2.GL_RED: - pixFmt = PixelFormat.LUMINANCE; - break; - case GL.GL_RGB: - pixFmt = PixelFormat.RGB888; - break; - case GL.GL_RGBA: - pixFmt = PixelFormat.RGBA8888; - break; - case GL2GL3.GL_BGR: - pixFmt = PixelFormat.BGR888; - break; - case GL.GL_BGRA: - pixFmt = PixelFormat.BGRA8888; - break; - default: - switch( bytesPerPixel ) { - case 1: - pixFmt = PixelFormat.LUMINANCE; - break; - case 3: - pixFmt = PixelFormat.RGB888; - break; - case 4: - pixFmt = PixelFormat.RGBA8888; - break; - default: - pixFmt = null; - break; - } - break; + public GLPixelAttributes(final int dataFormat, final int dataType) throws GLException { + this(null, null, dataFormat, dataType, true /* not used */, true); + } + + /** + * Create a new {@link GLPixelAttributes} instance based on {@link GLProfile}, {@link PixelFormat} and {@code pack}. + * @param glp the corresponding {@link GLProfile} + * @param pixFmt the to be matched {@link PixelFormat pixel format} + * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}. + * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}. + * @throws GLException if GL format or type could not be determined, see {@link #convert(GLProfile, PixelFormat, boolean)}. + */ + public GLPixelAttributes(final GLProfile glp, final PixelFormat pixFmt, final boolean pack) throws GLException { + this(glp, pixFmt, 0, 0, pack, true); + } + + private GLPixelAttributes(final GLProfile glp, final PixelFormat pixFmt, + final int dataFormat, final int dataType, final boolean pack, final boolean checkArgs) throws GLException { + if( checkArgs && ( 0 == dataFormat || 0 == dataType ) ) { + if( null == pixFmt || null == glp ) { + throw new GLException("Zero format and/or type w/o pixFmt or glp: "+this); + } + final int[] df = new int[1]; + final int[] dt = new int[1]; + if( 0 == convert(glp, pixFmt, pack, df, dt) ) { + throw new GLException("Could not find format and type for "+pixFmt+" and "+glp+", "+this); + } + this.format = df[0]; + this.type = dt[0]; + this.pfmt = pixFmt; + } else { + this.format = dataFormat; + this.type = dataType; + this.pfmt = null != pixFmt ? pixFmt : getPixelFormat(dataFormat, dataType); + if( null == this.pfmt ) { + throw new GLException("Could not find PixelFormat for format and/or type: "+this); + } + } + if( checkArgs ) { + final int bytesPerPixel = GLBuffers.bytesPerPixel(this.format, this.type); + if( 0 == bytesPerPixel ) { + throw new GLException("Zero bytesPerPixel: "+this); + } } - return pixFmt; } @Override public String toString() { - return "PixelAttributes[comp "+componentCount+", fmt 0x"+Integer.toHexString(format)+", type 0x"+Integer.toHexString(type)+", bytesPerPixel "+bytesPerPixel+"]"; + return "PixelAttributes[fmt 0x"+Integer.toHexString(format)+", type 0x"+Integer.toHexString(type)+", "+pfmt+"]"; } } @@ -339,14 +526,18 @@ public class GLPixelBuffer { public final int height; /** Depth in pixels. */ public final int depth; - /** Data packing direction. If <code>true</code> for read mode GPU -> CPU, <code>false</code> for write mode CPU -> GPU. */ + /** + * Data packing direction. + * <p>{@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}.</p> + * <p>{@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}.</p> + */ public final boolean pack; /** Byte size of the buffer. Actually the number of {@link Buffer#remaining()} bytes when passed in ctor. */ public final int byteSize; /** * Buffer holding the pixel data. If {@link #rewind()}, it holds <code>byteSize</code> {@link Buffer#remaining()} bytes. * <p> - * By default the {@link Buffer} is a {@link ByteBuffer}, due to {@link DefProvider#allocate(GL, GLPixelAttributes, int, int, int, boolean, int)}. + * By default the {@link Buffer} is a {@link ByteBuffer}, due to {@link DefProvider#allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int)}. * However, other {@link GLPixelBufferProvider} may utilize different {@link Buffer} types. * </p> */ @@ -375,14 +566,16 @@ public class GLPixelBuffer { /** * @param pixelAttributes the desired {@link GLPixelAttributes} + * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}. + * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}. * @param width in pixels * @param height in pixels * @param depth in pixels - * @param pack true for read mode GPU -> CPU, otherwise false for write mode CPU -> GPU * @param buffer the backing array * @param allowRowStride If <code>true</code>, allow row-stride, otherwise not. See {@link #requiresNewBuffer(GL, int, int, int)}. + * @param hostPixelComp the host {@link PixelFormat.Composition} */ - public GLPixelBuffer(final GLPixelAttributes pixelAttributes, final int width, final int height, final int depth, final boolean pack, final Buffer buffer, final boolean allowRowStride) { + public GLPixelBuffer(final GLPixelAttributes pixelAttributes, final boolean pack, final int width, final int height, final int depth, final Buffer buffer, final boolean allowRowStride) { this.pixelAttributes = pixelAttributes; this.width = width; this.height = height; @@ -462,7 +655,7 @@ public class GLPixelBuffer { * @param newWidth new width in pixels * @param newHeight new height in pixels * @param newByteSize if > 0, the pre-calculated minimum byte-size for the resulting buffer, otherwise ignore. - * @see GLPixelBufferProvider#allocate(GL, GLPixelAttributes, int, int, int, boolean, int) + * @see GLPixelBufferProvider#allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int) */ public boolean requiresNewBuffer(final GL gl, final int newWidth, final int newHeight, int newByteSize) { if( !isValid() ) { @@ -470,7 +663,7 @@ public class GLPixelBuffer { } if( 0 >= newByteSize ) { final int[] tmp = { 0 }; - newByteSize = GLBuffers.sizeof(gl, tmp, pixelAttributes.bytesPerPixel, newWidth, newHeight, 1, true); + newByteSize = GLBuffers.sizeof(gl, tmp, pixelAttributes.pfmt.comp.bytesPerPixel(), newWidth, newHeight, 1, true); } if( allowRowStride ) { return byteSize < newByteSize; diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLPixelStorageModes.java b/src/jogl/classes/com/jogamp/opengl/util/GLPixelStorageModes.java index 290033e99..7ac555f78 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/GLPixelStorageModes.java +++ b/src/jogl/classes/com/jogamp/opengl/util/GLPixelStorageModes.java @@ -180,7 +180,7 @@ public class GLPixelStorageModes { if( gl.isGL2GL3() ) { gl.glPixelStorei(GL2GL3.GL_PACK_SWAP_BYTES, GL.GL_FALSE); // gl3 gl.glPixelStorei(GL2GL3.GL_PACK_LSB_FIRST, GL.GL_FALSE); // gl3 - if( gl.getContext().getGLVersionNumber().compareTo(GLContext.Version120) >= 0 ) { + if( gl.getContext().getGLVersionNumber().compareTo(GLContext.Version1_2) >= 0 ) { gl.glPixelStorei(GL2GL3.GL_PACK_IMAGE_HEIGHT, 0); // gl3, GL_VERSION_1_2 gl.glPixelStorei(GL2GL3.GL_PACK_SKIP_IMAGES, 0); // gl3, GL_VERSION_1_2 } @@ -251,7 +251,7 @@ public class GLPixelStorageModes { gl.glPixelStorei(GL2ES2.GL_UNPACK_SKIP_ROWS, 0); // es3, gl3 gl.glPixelStorei(GL2ES2.GL_UNPACK_SKIP_PIXELS, 0); // es3, gl3 if( gl.isGL2GL3() ) { - if( gl.getContext().getGLVersionNumber().compareTo(GLContext.Version120) >= 0 ) { + if( gl.getContext().getGLVersionNumber().compareTo(GLContext.Version1_2) >= 0 ) { gl.glPixelStorei(GL2ES3.GL_UNPACK_IMAGE_HEIGHT, 0); // es3, gl3, GL_VERSION_1_2 gl.glPixelStorei(GL2ES3.GL_UNPACK_SKIP_IMAGES, 0); // es3, gl3, GL_VERSION_1_2 } diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java b/src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java index e84a1d874..597498c9d 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java +++ b/src/jogl/classes/com/jogamp/opengl/util/GLReadBufferUtil.java @@ -31,6 +31,7 @@ package com.jogamp.opengl.util; import java.io.File; import java.io.IOException; +import javax.media.nativewindow.util.PixelFormat; import javax.media.opengl.GL; import javax.media.opengl.GL2ES3; import javax.media.opengl.GLAutoDrawable; @@ -51,10 +52,10 @@ import com.jogamp.opengl.util.texture.TextureIO; */ public class GLReadBufferUtil { protected final GLPixelBufferProvider pixelBufferProvider; - protected final int componentCount, alignment; protected final Texture readTexture; protected final GLPixelStorageModes psm; + protected boolean hasAlpha; protected GLPixelBuffer readPixelBuffer = null; protected TextureData readTextureData = null; @@ -68,10 +69,9 @@ public class GLReadBufferUtil { public GLReadBufferUtil(final GLPixelBufferProvider pixelBufferProvider, final boolean alpha, final boolean write2Texture) { this.pixelBufferProvider = pixelBufferProvider; - this.componentCount = alpha ? 4 : 3 ; - this.alignment = alpha ? 4 : 1 ; this.readTexture = write2Texture ? new Texture(GL.GL_TEXTURE_2D) : null ; this.psm = new GLPixelStorageModes(); + this.hasAlpha = alpha; // preset } /** Returns the {@link GLPixelBufferProvider} used by this instance. */ @@ -81,7 +81,7 @@ public class GLReadBufferUtil { return null!=readTextureData && null!=readPixelBuffer && readPixelBuffer.isValid(); } - public boolean hasAlpha() { return 4 == componentCount ? true : false ; } + public boolean hasAlpha() { return hasAlpha; } public GLPixelStorageModes getGLPixelStorageModes() { return psm; } @@ -173,13 +173,13 @@ public class GLReadBufferUtil { if(GL.GL_NO_ERROR != glerr0) { System.err.println("Info: GLReadBufferUtil.readPixels: pre-exisiting GL error 0x"+Integer.toHexString(glerr0)); } - final GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(gl, componentCount); - final int internalFormat; - if(gl.isGL2GL3() && 3 == componentCount) { - internalFormat = GL.GL_RGB; - } else { - internalFormat = (4 == componentCount) ? GL.GL_RGBA : GL.GL_RGB; - } + final int reqCompCount = hasAlpha ? 4 : 3; + final PixelFormat.Composition hostPixelComp = pixelBufferProvider.getHostPixelComp(gl.getGLProfile(), reqCompCount); + final GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(gl, reqCompCount, true); + final int componentCount = pixelAttribs.pfmt.comp.componenCount(); + hasAlpha = 0 <= pixelAttribs.pfmt.comp.find(PixelFormat.CType.A); + final int alignment = 4 == componentCount ? 4 : 1 ; + final int internalFormat = 4 == componentCount ? GL.GL_RGBA : GL.GL_RGB; final boolean flipVertically; if( drawable.isGLOriented() ) { @@ -189,11 +189,11 @@ public class GLReadBufferUtil { } final int tmp[] = new int[1]; - final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.bytesPerPixel, width, height, 1, true); + final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.pfmt.comp.bytesPerPixel(), width, height, 1, true); boolean newData = false; if( null == readPixelBuffer || readPixelBuffer.requiresNewBuffer(gl, width, height, readPixelSize) ) { - readPixelBuffer = pixelBufferProvider.allocate(gl, pixelAttribs, width, height, 1, true, readPixelSize); + readPixelBuffer = pixelBufferProvider.allocate(gl, hostPixelComp, pixelAttribs, true, width, height, 1, readPixelSize); Buffers.rangeCheckBytes(readPixelBuffer.buffer, readPixelSize); try { readTextureData = new TextureData( diff --git a/src/jogl/classes/com/jogamp/opengl/util/ImmModeSink.java b/src/jogl/classes/com/jogamp/opengl/util/ImmModeSink.java index 150e92c2e..eea76116c 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/ImmModeSink.java +++ b/src/jogl/classes/com/jogamp/opengl/util/ImmModeSink.java @@ -16,6 +16,7 @@ import javax.media.opengl.fixedfunc.GLPointerFunc; import jogamp.opengl.Debug; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.nio.Buffers; import com.jogamp.common.os.Platform; import com.jogamp.common.util.PropertyAccess; @@ -1376,7 +1377,7 @@ public class ImmModeSink { if(DEBUG_BUFFER) { System.err.println("ImmModeSink.realloc.X: "+this.toString()); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return true; } diff --git a/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java b/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java index 11acb0c58..6dd8ae032 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java +++ b/src/jogl/classes/com/jogamp/opengl/util/PMVMatrix.java @@ -660,8 +660,14 @@ public final class PMVMatrix implements GLMatrixFunc { glMultMatrixf( FloatUtil.makeOrtho(mat4Tmp1, 0, true, left, right, bottom, top, zNear, zFar), 0 ); } + /** + * {@inheritDoc} + * + * @throws GLException with GL_INVALID_VALUE if zNear is <= 0, or zFar < 0, + * or if left == right, or bottom == top, or zNear == zFar. + */ @Override - public final void glFrustumf(final float left, final float right, final float bottom, final float top, final float zNear, final float zFar) { + public final void glFrustumf(final float left, final float right, final float bottom, final float top, final float zNear, final float zFar) throws GLException { glMultMatrixf( FloatUtil.makeFrustum(mat4Tmp1, 0, true, left, right, bottom, top, zNear, zFar), 0 ); } @@ -676,8 +682,9 @@ public final class PMVMatrix implements GLMatrixFunc { * @param aspect aspect ratio width / height * @param zNear * @param zFar + * @throws GLException with GL_INVALID_VALUE if zNear is <= 0, or zFar < 0, or if zNear == zFar. */ - public final void gluPerspective(final float fovy_deg, final float aspect, final float zNear, final float zFar) { + public final void gluPerspective(final float fovy_deg, final float aspect, final float zNear, final float zFar) throws GLException { glMultMatrixf( FloatUtil.makePerspective(mat4Tmp1, 0, true, fovy_deg * FloatUtil.PI / 180.0f, aspect, zNear, zFar), 0 ); } diff --git a/src/jogl/classes/com/jogamp/opengl/util/PNGPixelRect.java b/src/jogl/classes/com/jogamp/opengl/util/PNGPixelRect.java index 64da547c2..29e1cf353 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/PNGPixelRect.java +++ b/src/jogl/classes/com/jogamp/opengl/util/PNGPixelRect.java @@ -137,7 +137,7 @@ public class PNGPixelRect extends PixelRectangle.GenericPixelRect { } else { destFmt = ddestFmt; // user choice } - final int destStrideInBytes = Math.max(destMinStrideInBytes, destFmt.bytesPerPixel() * width); + final int destStrideInBytes = Math.max(destMinStrideInBytes, destFmt.comp.bytesPerPixel() * width); final ByteBuffer destPixels = destDirectBuffer ? Buffers.newDirectByteBuffer(destStrideInBytes * height) : ByteBuffer.allocate(destStrideInBytes * height); { @@ -153,7 +153,7 @@ public class PNGPixelRect extends PixelRectangle.GenericPixelRect { System.err.println("PNGPixelRect: indexed "+indexed+", alpha "+hasAlpha+", grayscale "+imgInfo.greyscale+", channels "+channels+"/"+imgInfo.channels+ ", bytesPerPixel "+bytesPerPixel+"/"+imgInfo.bytesPixel+ ", grayAlpha "+isGrayAlpha+", pixels "+width+"x"+height+", dpi "+dpiX+"x"+dpiY+", format "+srcFmt); - System.err.println("PNGPixelRect: destFormat "+destFmt+" ("+ddestFmt+", bytesPerPixel "+destFmt.bytesPerPixel()+", fast-path "+(destFmt==srcFmt)+"), destDirectBuffer "+destDirectBuffer+", destIsGLOriented (flip) "+destIsGLOriented); + System.err.println("PNGPixelRect: destFormat "+destFmt+" ("+ddestFmt+", fast-path "+(destFmt==srcFmt)+"), destDirectBuffer "+destDirectBuffer+", destIsGLOriented (flip) "+destIsGLOriented); System.err.println("PNGPixelRect: destStrideInBytes "+destStrideInBytes+" (destMinStrideInBytes "+destMinStrideInBytes+")"); } @@ -227,7 +227,7 @@ public class PNGPixelRect extends PixelRectangle.GenericPixelRect { (byte)scanline[lineOff+1], // G (byte)scanline[lineOff+2], // B srcHasAlpha ? (byte)scanline[lineOff+3] : (byte)0xff); // A - final int dbpp = dest_fmt.bytesPerPixel(); + final int dbpp = dest_fmt.comp.bytesPerPixel(); d.put(dOff++, (byte) ( p )); // 1 if( 1 < dbpp ) { d.put(dOff++, (byte) ( p >>> 8 )); // 2 @@ -261,7 +261,7 @@ public class PNGPixelRect extends PixelRectangle.GenericPixelRect { if(hasAlpha) { line.scanline[lineOff + 3] = 0xff & ( p >>> 24 ); // A } - return srcOff + pixelformat.bytesPerPixel(); + return srcOff + pixelformat.comp.bytesPerPixel(); } private static void setPixelRGBA8(final PixelFormat pixelformat, final ImageLine line, final int lineOff, final int srcPix, final int bytesPerPixel, final boolean hasAlpha) { @@ -304,7 +304,7 @@ public class PNGPixelRect extends PixelRectangle.GenericPixelRect { public void write(final OutputStream outstream, final boolean closeOutstream) throws IOException { final int width = size.getWidth(); final int height = size.getHeight(); - final int bytesPerPixel = pixelformat.bytesPerPixel(); + final int bytesPerPixel = pixelformat.comp.bytesPerPixel(); final ImageInfo imi = new ImageInfo(width, height, 8 /* bitdepth */, (4 == bytesPerPixel) ? true : false /* alpha */, (1 == bytesPerPixel) ? true : false /* grayscale */, @@ -349,7 +349,7 @@ public class PNGPixelRect extends PixelRectangle.GenericPixelRect { final OutputStream outstream, final boolean closeOutstream) throws IOException { final int width = size.getWidth(); final int height = size.getHeight(); - final int bytesPerPixel = pixelformat.bytesPerPixel(); + final int bytesPerPixel = pixelformat.comp.bytesPerPixel(); final ImageInfo imi = new ImageInfo(width, height, 8 /* bitdepth */, (4 == bytesPerPixel) ? true : false /* alpha */, (1 == bytesPerPixel) ? true : false /* grayscale */, diff --git a/src/jogl/classes/com/jogamp/opengl/util/RandomTileRenderer.java b/src/jogl/classes/com/jogamp/opengl/util/RandomTileRenderer.java index 3b65b0824..bf7cf668c 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/RandomTileRenderer.java +++ b/src/jogl/classes/com/jogamp/opengl/util/RandomTileRenderer.java @@ -176,7 +176,7 @@ public class RandomTileRenderer extends TileRendererBase { final int srcY = 0; final int srcWidth = currentTileWidth; final int srcHeight = currentTileHeight; - final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.bytesPerPixel, srcWidth, srcHeight, 1, true); + final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.pfmt.comp.bytesPerPixel(), srcWidth, srcHeight, 1, true); tileBuffer.clear(); if( tileBuffer.requiresNewBuffer(gl, srcWidth, srcHeight, readPixelSize) ) { throw new IndexOutOfBoundsException("Required " + readPixelSize + " bytes of buffer, only had " + tileBuffer); @@ -200,9 +200,9 @@ public class RandomTileRenderer extends TileRendererBase { psm.setPackRowLength(gl2es3, rowLength); /* read the tile into the final image */ - final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.bytesPerPixel, srcWidth, srcHeight, 1, true); + final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.pfmt.comp.bytesPerPixel(), srcWidth, srcHeight, 1, true); - final int ibPos = ( currentTileXPos + ( currentTileYPos * rowLength ) ) * pixelAttribs.bytesPerPixel; // skipPixels + skipRows + final int ibPos = ( currentTileXPos + ( currentTileYPos * rowLength ) ) * pixelAttribs.pfmt.comp.bytesPerPixel(); // skipPixels + skipRows final int ibLim = ibPos + readPixelSize; imageBuffer.clear(); if( imageBuffer.requiresNewBuffer(gl, srcWidth, srcHeight, readPixelSize) ) { diff --git a/src/jogl/classes/com/jogamp/opengl/util/TileRenderer.java b/src/jogl/classes/com/jogamp/opengl/util/TileRenderer.java index d8410a102..fee2e5933 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/TileRenderer.java +++ b/src/jogl/classes/com/jogamp/opengl/util/TileRenderer.java @@ -479,7 +479,7 @@ public class TileRenderer extends TileRendererBase { final int srcY = tileBorder; final int srcWidth = tileSizeNB.getWidth(); final int srcHeight = tileSizeNB.getHeight(); - final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.bytesPerPixel, srcWidth, srcHeight, 1, true); + final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.pfmt.comp.bytesPerPixel(), srcWidth, srcHeight, 1, true); tileBuffer.clear(); if( tileBuffer.requiresNewBuffer(gl, srcWidth, srcHeight, readPixelSize) ) { throw new IndexOutOfBoundsException("Required " + readPixelSize + " bytes of buffer, only had " + tileBuffer); @@ -503,11 +503,11 @@ public class TileRenderer extends TileRendererBase { psm.setPackRowLength(gl2es3, rowLength); /* read the tile into the final image */ - final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.bytesPerPixel, srcWidth, srcHeight, 1, true); + final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.pfmt.comp.bytesPerPixel(), srcWidth, srcHeight, 1, true); final int skipPixels = currentColumn * tileSizeNB.getWidth(); final int skipRows = currentRow * tileSizeNB.getHeight(); - final int ibPos = ( skipPixels + ( skipRows * rowLength ) ) * pixelAttribs.bytesPerPixel; + final int ibPos = ( skipPixels + ( skipRows * rowLength ) ) * pixelAttribs.pfmt.comp.bytesPerPixel(); final int ibLim = ibPos + readPixelSize; imageBuffer.clear(); if( imageBuffer.requiresNewBuffer(gl, srcWidth, srcHeight, readPixelSize) ) { diff --git a/src/jogl/classes/com/jogamp/opengl/util/awt/AWTGLPixelBuffer.java b/src/jogl/classes/com/jogamp/opengl/util/awt/AWTGLPixelBuffer.java index 04bc0a15d..81cb34239 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/awt/AWTGLPixelBuffer.java +++ b/src/jogl/classes/com/jogamp/opengl/util/awt/AWTGLPixelBuffer.java @@ -36,10 +36,14 @@ import java.awt.image.SinglePixelPackedSampleModel; import java.awt.image.WritableRaster; import java.nio.Buffer; import java.nio.IntBuffer; +import java.util.Iterator; +import javax.media.nativewindow.util.PixelFormat; import javax.media.opengl.GL; +import javax.media.opengl.GLProfile; import com.jogamp.common.nio.Buffers; +import com.jogamp.common.util.IntObjectHashMap; import com.jogamp.opengl.util.GLPixelBuffer; /** @@ -50,7 +54,7 @@ import com.jogamp.opengl.util.GLPixelBuffer; * </p> * <p> * {@link AWTGLPixelBuffer} can be produced via {@link AWTGLPixelBufferProvider}'s - * {@link AWTGLPixelBufferProvider#allocate(GL, GLPixelAttributes, int, int, int, boolean, int) allocate(..)}. + * {@link AWTGLPixelBufferProvider#allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int) allocate(..)}. * </p> * <p> * See {@link AWTGLPixelBuffer#requiresNewBuffer(GL, int, int, int)} for {@link #allowRowStride} details. @@ -61,30 +65,49 @@ import com.jogamp.opengl.util.GLPixelBuffer; * </p> */ public class AWTGLPixelBuffer extends GLPixelBuffer { - public static final GLPixelAttributes awtPixelAttributesIntRGBA4 = new GLPixelAttributes(4, GL.GL_BGRA, GL.GL_UNSIGNED_BYTE); - public static final GLPixelAttributes awtPixelAttributesIntRGB3 = new GLPixelAttributes(3, GL.GL_BGRA, GL.GL_UNSIGNED_BYTE); + /** + * Ignoring componentCount, since otherwise no AWT/GL matching types are found. + * <p> + * Due to using RGBA and BGRA, pack/unpack usage has makes no difference. + * </p> + */ + private static final GLPixelAttributes awtPixelAttributesIntBGRA = new GLPixelAttributes(GL.GL_BGRA, GL.GL_UNSIGNED_BYTE); + private static final GLPixelAttributes awtPixelAttributesIntRGBA = new GLPixelAttributes(GL.GL_RGBA, GL.GL_UNSIGNED_BYTE); /** The underlying {@link BufferedImage}. */ public final BufferedImage image; + private final PixelFormat.Composition hostPixelComp; + private final int awtFormat; + /** - * + * @param hostPixelComp the host {@link PixelFormat.Composition} * @param pixelAttributes the desired {@link GLPixelAttributes} + * @param pack {@code true} for read mode GPU -> CPU, e.g. {@link GL#glReadPixels(int, int, int, int, int, int, Buffer) glReadPixels}. + * {@code false} for write mode CPU -> GPU, e.g. {@link GL#glTexImage2D(int, int, int, int, int, int, int, int, Buffer) glTexImage2D}. + * @param awtFormat the used AWT format, i.e. {@link AWTGLPixelBufferProvider#getAWTFormat(GLProfile, int)} * @param width in pixels * @param height in pixels * @param depth in pixels - * @param pack true for read mode GPU -> CPU, otherwise false for write mode CPU -> GPU * @param image the AWT image * @param buffer the backing array * @param allowRowStride If <code>true</code>, allow row-stride, otherwise not. See {@link #requiresNewBuffer(GL, int, int, int)}. * If <code>true</code>, user shall decide whether to use a {@link #getAlignedImage(int, int) width-aligned image}. */ - public AWTGLPixelBuffer(final GLPixelAttributes pixelAttributes, final int width, final int height, final int depth, final boolean pack, final BufferedImage image, - final Buffer buffer, final boolean allowRowStride) { - super(pixelAttributes, width, height, depth, pack, buffer, allowRowStride); + public AWTGLPixelBuffer(final PixelFormat.Composition hostPixelComp, + final GLPixelAttributes pixelAttributes, + final boolean pack, + final int awtFormat, final int width, final int height, final int depth, + final BufferedImage image, final Buffer buffer, final boolean allowRowStride) { + super(pixelAttributes, pack, width, height, depth, buffer, allowRowStride); this.image = image; + this.hostPixelComp = hostPixelComp; + this.awtFormat = awtFormat; } + public final PixelFormat.Composition getHostPixelComp() { return hostPixelComp; } + public final int getAWTFormat() { return awtFormat; } + @Override public void dispose() { image.flush(); @@ -147,12 +170,57 @@ public class AWTGLPixelBuffer extends GLPixelBuffer { public AWTGLPixelBufferProvider(final boolean allowRowStride) { this.allowRowStride = allowRowStride; } + @Override public boolean getAllowRowStride() { return allowRowStride; } @Override - public GLPixelAttributes getAttributes(final GL gl, final int componentCount) { - return 4 == componentCount ? awtPixelAttributesIntRGBA4 : awtPixelAttributesIntRGB3; + public GLPixelAttributes getAttributes(final GL gl, final int componentCount, final boolean pack) { + return gl.isGLES() ? awtPixelAttributesIntRGBA : awtPixelAttributesIntBGRA; + } + + public GLPixelAttributes getAttributes(final GLProfile glp, final int componentCount) { + return glp.isGLES() ? awtPixelAttributesIntRGBA : awtPixelAttributesIntBGRA; + } + + /** + * {@inheritDoc} + * <p> + * Returns a valid {@link PixelFormat.Composition} instance from {@link #getAWTPixelFormat(GLProfile, int)}. + * </p> + */ + @Override + public PixelFormat.Composition getHostPixelComp(final GLProfile glp, final int componentCount) { + return getAWTPixelFormat(glp, componentCount).comp; + } + + /** + * Returns one of + * <ul> + * <li>GL__, 4c -> 4c: {@link BufferedImage#TYPE_INT_ARGB} <-> {@link GL#GL_BGRA}</li> + * <li>GLES, 4c -> 4c: {@link BufferedImage#TYPE_INT_BGR} <-> {@link GL#GL_RGBA}</li> + * <li>GL__, 3c -> 4c: {@link BufferedImage#TYPE_INT_RGB} <-> {@link GL#GL_BGRA}</li> + * <li>GLES, 3c -> 4c: {@link BufferedImage#TYPE_INT_BGR} <-> {@link GL#GL_RGBA}</li> + * </ul> + * @param glp + * @param componentCount + * @return + */ + public int getAWTFormat(final GLProfile glp, final int componentCount) { + if( 4 == componentCount ) { + // FIXME: 4 component solution BufferedImage.TYPE_INT_ARGB: GLES format missing (i.e. GL_BGRA) + return glp.isGLES() ? BufferedImage.TYPE_INT_BGR : BufferedImage.TYPE_INT_ARGB; + } else { + return glp.isGLES() ? BufferedImage.TYPE_INT_BGR : BufferedImage.TYPE_INT_RGB; + } + } + + public PixelFormat getAWTPixelFormat(final GLProfile glp, final int componentCount) { + if( 4 == componentCount ) { + return glp.isGLES() ? PixelFormat.RGBx8888 : PixelFormat.BGRA8888; + } else { + return glp.isGLES() ? PixelFormat.RGBx8888 : PixelFormat.BGRx8888; + } } /** @@ -162,11 +230,17 @@ public class AWTGLPixelBuffer extends GLPixelBuffer { * </p> */ @Override - public AWTGLPixelBuffer allocate(final GL gl, final GLPixelAttributes pixelAttributes, final int width, final int height, final int depth, final boolean pack, final int minByteSize) { - final BufferedImage image = new BufferedImage(width, height, 4 == pixelAttributes.componentCount ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB); + public AWTGLPixelBuffer allocate(final GL gl, final PixelFormat.Composition hostPixComp, final GLPixelAttributes pixelAttributes, final boolean pack, + final int width, final int height, final int depth, final int minByteSize) { + if( null == hostPixComp ) { + throw new IllegalArgumentException("Null hostPixComp"); + } + final int awtFormat = getAWTFormat(gl.getGLProfile(), hostPixComp.componenCount()); + final BufferedImage image = new BufferedImage(width, height, awtFormat); final int[] readBackIntBuffer = ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); final Buffer ibuffer = IntBuffer.wrap( readBackIntBuffer ); - return new AWTGLPixelBuffer(pixelAttributes, width, height, depth, pack, image, ibuffer, allowRowStride); + return new AWTGLPixelBuffer(hostPixComp, pixelAttributes, pack, + awtFormat, width, height, depth, image, ibuffer, allowRowStride); } } @@ -174,15 +248,22 @@ public class AWTGLPixelBuffer extends GLPixelBuffer { * Provider for singleton {@link AWTGLPixelBuffer} instances. * <p> * Provider instance holds the last {@link AWTGLPixelBuffer} instance - * {@link #allocate(GL, GLPixelAttributes, int, int, int, boolean, int) allocated}. - * A new {@link #allocate(GL, GLPixelAttributes, int, int, int, boolean, int) allocation} + * {@link #allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int) allocated}. + * A new {@link #allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int) allocation} * will return same instance, if a new buffer is not {@link AWTGLPixelBuffer#requiresNewBuffer(GL, int, int, int) required}. * The latter is true if size are compatible, hence <code>allowRowStride</code> should be enabled, if possible. * </p> */ public static class SingleAWTGLPixelBufferProvider extends AWTGLPixelBufferProvider implements SingletonGLPixelBufferProvider { - private AWTGLPixelBuffer singleRGBA4 = null; - private AWTGLPixelBuffer singleRGB3 = null; + private final IntObjectHashMap bufferMap = new IntObjectHashMap(8); + + private static int getHashCode(final PixelFormat.Composition hostPixelComp, final GLPixelAttributes pixelAttributes, final boolean pack) { + // 31 * x == (x << 5) - x + int hash = hostPixelComp.hashCode(); + hash = ((hash << 5) - hash) + pixelAttributes.hashCode(); + // hash = ((hash << 5) - hash) + (pack ? 100 : 0); // no difference due to RGBA/BGRA only modes. + return hash; + } /** * @param allowRowStride If <code>true</code>, allow row-stride, otherwise not. See {@link AWTGLPixelBuffer#requiresNewBuffer(GL, int, int, int)}. @@ -198,52 +279,72 @@ public class AWTGLPixelBuffer extends GLPixelBuffer { * </p> */ @Override - public AWTGLPixelBuffer allocate(final GL gl, final GLPixelAttributes pixelAttributes, final int width, final int height, final int depth, final boolean pack, final int minByteSize) { - if( 4 == pixelAttributes.componentCount ) { - if( null == singleRGBA4 || singleRGBA4.requiresNewBuffer(gl, width, height, minByteSize) ) { - singleRGBA4 = allocateImpl(pixelAttributes, width, height, depth, pack, minByteSize); - } - return singleRGBA4; - } else { - if( null == singleRGB3 || singleRGB3.requiresNewBuffer(gl, width, height, minByteSize) ) { - singleRGB3 = allocateImpl(pixelAttributes, width, height, depth, pack, minByteSize); + public AWTGLPixelBuffer allocate(final GL gl, PixelFormat.Composition hostPixComp, final GLPixelAttributes pixelAttributes, + final boolean pack, final int width, final int height, final int depth, final int minByteSize) { + if( null == hostPixComp ) { + hostPixComp = pixelAttributes.pfmt.comp; + } + final int bufferKey = getHashCode(hostPixComp, pixelAttributes, pack); + AWTGLPixelBuffer r = (AWTGLPixelBuffer) bufferMap.get(bufferKey); + if( null == r || r.requiresNewBuffer(gl, width, height, minByteSize) ) { + if( null != r ) { + r.dispose(); } - return singleRGB3; + r = allocateImpl(hostPixComp, pixelAttributes, pack, + getAWTFormat(gl.getGLProfile(), hostPixComp.componenCount()), width, height, depth, minByteSize); + bufferMap.put(bufferKey, r); } + return r; } - private AWTGLPixelBuffer allocateImpl(final GLPixelAttributes pixelAttributes, final int width, final int height, final int depth, final boolean pack, final int minByteSize) { - final BufferedImage image = new BufferedImage(width, height, 4 == pixelAttributes.componentCount ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB); + private AWTGLPixelBuffer allocateImpl(final PixelFormat.Composition hostPixComp, + final GLPixelAttributes pixelAttributes, + final boolean pack, + final int awtFormat, final int width, final int height, final int depth, + final int minByteSize) { + final BufferedImage image = new BufferedImage(width, height, awtFormat); final int[] readBackIntBuffer = ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); final Buffer ibuffer = IntBuffer.wrap( readBackIntBuffer ); - return new AWTGLPixelBuffer(pixelAttributes, width, height, depth, pack, image, ibuffer, getAllowRowStride()); + return new AWTGLPixelBuffer(hostPixComp, pixelAttributes, pack, + awtFormat, width, height, depth, image, ibuffer, getAllowRowStride()); } - /** Return the last {@link #allocate(GL, GLPixelAttributes, int, int, int, boolean, int) allocated} {@link AWTGLPixelBuffer} w/ {@link GLPixelAttributes#componentCount}. */ + /** + * Return the last {@link #allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int) allocated} + * {@link AWTGLPixelBuffer}, if compatible w/ the given {@link PixelFormat.Composition} and {@link GLPixelAttributes}. + **/ @Override - public AWTGLPixelBuffer getSingleBuffer(final GLPixelAttributes pixelAttributes) { - return 4 == pixelAttributes.componentCount ? singleRGBA4 : singleRGB3; + public AWTGLPixelBuffer getSingleBuffer(final PixelFormat.Composition hostPixelComp, final GLPixelAttributes pixelAttributes, final boolean pack) { + return (AWTGLPixelBuffer) bufferMap.get(getHashCode(hostPixelComp, pixelAttributes, pack)); } /** - * Initializes the single {@link AWTGLPixelBuffer} w/ a given size, if not yet {@link #allocate(GL, GLPixelAttributes, int, int, int, boolean, int) allocated}. + * Initializes the single {@link AWTGLPixelBuffer} w/ a given size, if not yet {@link #allocate(GL, PixelFormat.Composition, GLPixelAttributes, boolean, int, int, int, int) allocated}. * @return the newly initialized single {@link AWTGLPixelBuffer}, or null if already allocated. */ @Override - public AWTGLPixelBuffer initSingleton(final int componentCount, final int width, final int height, final int depth, final boolean pack) { - if( 4 == componentCount ) { - if( null != singleRGBA4 ) { - return null; - } - singleRGBA4 = allocateImpl(AWTGLPixelBuffer.awtPixelAttributesIntRGBA4, width, height, depth, pack, 0); - return singleRGBA4; - } else { - if( null != singleRGB3 ) { - return null; - } - singleRGB3 = allocateImpl(AWTGLPixelBuffer.awtPixelAttributesIntRGB3, width, height, depth, pack, 0); - return singleRGB3; + public AWTGLPixelBuffer initSingleton(final GLProfile glp, final int componentCount, + final boolean pack, final int width, final int height, final int depth) { + final GLPixelAttributes pixelAttributes = getAttributes(glp, componentCount); + final PixelFormat awtPixelFormat = getAWTPixelFormat(glp, componentCount); + final int awtFormat = getAWTFormat(glp, componentCount); + final int bufferKey = getHashCode(awtPixelFormat.comp, pixelAttributes, pack); + AWTGLPixelBuffer r = (AWTGLPixelBuffer) bufferMap.get(bufferKey); + if( null != r ) { + return null; + } + r = allocateImpl(awtPixelFormat.comp, pixelAttributes, pack, awtFormat, width, height, depth, 0); + bufferMap.put(bufferKey, r); + return r; + } + + @Override + public void dispose() { + for(final Iterator<IntObjectHashMap.Entry> i=bufferMap.iterator(); i.hasNext(); ) { + final AWTGLPixelBuffer b = (AWTGLPixelBuffer)i.next().value; + b.dispose(); } + bufferMap.clear(); } } } diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java index 3b8706a24..acbb943a7 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java +++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java @@ -1049,7 +1049,7 @@ public class ShaderCode { public static final boolean requiresGL3DefaultPrecision(final GL2ES2 gl) { if( gl.isGL3() ) { final VersionNumber glslVersion = gl.getContext().getGLSLVersionNumber(); - return glslVersion.compareTo(GLContext.Version130) >= 0 && glslVersion.compareTo(GLContext.Version150) < 0 ; + return glslVersion.compareTo(GLContext.Version1_30) >= 0 && glslVersion.compareTo(GLContext.Version1_50) < 0 ; } else { return false; } diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java index d758fc121..428252ad4 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java +++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java @@ -40,6 +40,7 @@ import javax.media.opengl.GLUniformData; import jogamp.opengl.Debug; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.os.Platform; import com.jogamp.common.util.PropertyAccess; import com.jogamp.opengl.util.GLArrayDataEditable; @@ -161,7 +162,7 @@ public class ShaderState { final int newId = (null!=prog)?prog.id():-1; System.err.println("ShaderState: attachShaderProgram: "+curId+" -> "+newId+" (enable: "+enable+")\n\t"+shaderProgram+"\n\t"+prog); if(DEBUG) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } if(null!=shaderProgram) { @@ -405,7 +406,7 @@ public class ShaderState { } else if(verbose) { System.err.println("ShaderState: glGetAttribLocation failed, no location for: "+name+", loc: "+location); if(DEBUG) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } } @@ -448,7 +449,7 @@ public class ShaderState { } else if(verbose) { System.err.println("ShaderState: glGetAttribLocation failed, no location for: "+name+", loc: "+location); if(DEBUG) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } } @@ -483,7 +484,7 @@ public class ShaderState { if(verbose) { System.err.println("ShaderState: glEnableVertexAttribArray failed, no index for: "+name); if(DEBUG) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } return false; @@ -558,7 +559,7 @@ public class ShaderState { if(verbose) { System.err.println("ShaderState: glDisableVertexAttribArray failed, no index for: "+name); if(DEBUG) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } return false; @@ -875,7 +876,7 @@ public class ShaderState { } else if(verbose) { System.err.println("ShaderState: glUniform failed, no location for: "+name+", index: "+location); if(DEBUG) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } } @@ -916,7 +917,7 @@ public class ShaderState { } else if(verbose) { System.err.println("ShaderState: glUniform failed, no location for: "+name+", index: "+location); if(DEBUG) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } } diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderUtil.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderUtil.java index 06f7d9268..499917732 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderUtil.java +++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderUtil.java @@ -221,7 +221,7 @@ public class ShaderUtil { /** Returns true if GeometryShader is supported, i.e. whether GLContext is ≥ 3.2 or ARB_geometry_shader4 extension is available. */ public static boolean isGeometryShaderSupported(final GL _gl) { final GLContext ctx = _gl.getContext(); - return ctx.getGLVersionNumber().compareTo(GLContext.Version320) >= 0 || + return ctx.getGLVersionNumber().compareTo(GLContext.Version3_2) >= 0 || ctx.isExtensionAvailable(GLExtensions.ARB_geometry_shader4); } diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java index 6011afe7b..14fb90662 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java +++ b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java @@ -1125,12 +1125,12 @@ public class TextureIO { final String fileSuffix) throws IOException { if (PNG.equals(fileSuffix)) { final PNGPixelRect image = PNGPixelRect.read(stream, null, true /* directBuffer */, 0 /* destMinStrideInBytes */, true /* destIsGLOriented */); - final GLPixelAttributes glpa = GLPixelAttributes.convert(image.getPixelformat(), glp); + final GLPixelAttributes glpa = new GLPixelAttributes(glp, image.getPixelformat(), false /* pack */); if ( 0 == pixelFormat ) { pixelFormat = glpa.format; } // else FIXME: Actually not supported w/ preset pixelFormat! if ( 0 == internalFormat ) { - final boolean hasAlpha = 4 == glpa.bytesPerPixel; + final boolean hasAlpha = 4 == glpa.pfmt.comp.bytesPerPixel(); if(glp.isGL2ES3()) { internalFormat = hasAlpha ? GL.GL_RGBA8 : GL.GL_RGB8; } else { @@ -1351,8 +1351,8 @@ public class TextureIO { final GLPixelAttributes pixelAttribs = data.getPixelAttributes(); final int pixelFormat = pixelAttribs.format; final int pixelType = pixelAttribs.type; - final int bytesPerPixel = pixelAttribs.bytesPerPixel; - final PixelFormat pixFmt = pixelAttribs.getPixelFormat(); + final int bytesPerPixel = pixelAttribs.pfmt.comp.bytesPerPixel(); + final PixelFormat pixFmt = pixelAttribs.pfmt; if ( ( 1 == bytesPerPixel || 3 == bytesPerPixel || 4 == bytesPerPixel) && ( pixelType == GL.GL_BYTE || pixelType == GL.GL_UNSIGNED_BYTE)) { Buffer buf0 = data.getBuffer(); diff --git a/src/jogl/classes/javax/media/opengl/DefaultGLCapabilitiesChooser.java b/src/jogl/classes/javax/media/opengl/DefaultGLCapabilitiesChooser.java index 412af25e0..1991ad7d0 100644 --- a/src/jogl/classes/javax/media/opengl/DefaultGLCapabilitiesChooser.java +++ b/src/jogl/classes/javax/media/opengl/DefaultGLCapabilitiesChooser.java @@ -46,6 +46,7 @@ import java.util.List; import javax.media.nativewindow.CapabilitiesImmutable; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.util.PropertyAccess; import jogamp.opengl.Debug; @@ -126,7 +127,7 @@ public class DefaultGLCapabilitiesChooser implements GLCapabilitiesChooser { final int availnum = available.size(); if (DEBUG) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); System.err.println("Desired: " + gldes); System.err.println("Available: " + availnum); for (int i = 0; i < available.size(); i++) { diff --git a/src/jogl/classes/javax/media/opengl/GLBase.java b/src/jogl/classes/javax/media/opengl/GLBase.java index 48455c525..802da3b6c 100644 --- a/src/jogl/classes/javax/media/opengl/GLBase.java +++ b/src/jogl/classes/javax/media/opengl/GLBase.java @@ -584,6 +584,9 @@ public interface GLBase { /** * Return the framebuffer name bound to this context, * see {@link GL#glBindFramebuffer(int, int)}. + * <p> + * Calls {@link GLContext#getBoundFramebuffer(int)}. + * </p> */ public int getBoundFramebuffer(int target); @@ -594,6 +597,9 @@ public interface GLBase { * in case an framebuffer object ({@link com.jogamp.opengl.FBObject}) based drawable * is being used. * </p> + * <p> + * Calls {@link GLContext#getDefaultDrawFramebuffer()}. + * </p> */ public int getDefaultDrawFramebuffer(); @@ -604,6 +610,9 @@ public interface GLBase { * in case an framebuffer object ({@link com.jogamp.opengl.FBObject}) based drawable * is being used. * </p> + * <p> + * Calls {@link GLContext#getDefaultReadFramebuffer()}. + * </p> */ public int getDefaultReadFramebuffer(); @@ -628,6 +637,9 @@ public interface GLBase { * Note-3: See {@link com.jogamp.opengl.util.GLDrawableUtil#swapBuffersBeforeRead(GLCapabilitiesImmutable) swapBuffersBeforeRead} * for read-pixels and swap-buffers implications. * </p> + * <p> + * Calls {@link GLContext#getDefaultReadBuffer()}. + * </p> */ public int getDefaultReadBuffer(); } diff --git a/src/jogl/classes/javax/media/opengl/GLContext.java b/src/jogl/classes/javax/media/opengl/GLContext.java index e2498e6f1..01e0e8270 100644 --- a/src/jogl/classes/javax/media/opengl/GLContext.java +++ b/src/jogl/classes/javax/media/opengl/GLContext.java @@ -123,31 +123,43 @@ public abstract class GLContext { public static final int CONTEXT_CURRENT_NEW = 2; /** Version 1.00, i.e. GLSL 1.00 for ES 2.0. */ - public static final VersionNumber Version100 = new VersionNumber(1, 0, 0); + public static final VersionNumber Version1_0 = new VersionNumber(1, 0, 0); /** Version 1.10, i.e. GLSL 1.10 for GL 2.0. */ - public static final VersionNumber Version110 = new VersionNumber(1, 10, 0); + public static final VersionNumber Version1_10 = new VersionNumber(1, 10, 0); /** Version 1.20, i.e. GLSL 1.20 for GL 2.1. */ - public static final VersionNumber Version120 = new VersionNumber(1, 20, 0); + public static final VersionNumber Version1_20 = new VersionNumber(1, 20, 0); /** Version 1.30, i.e. GLSL 1.30 for GL 3.0. */ - public static final VersionNumber Version130 = new VersionNumber(1, 30, 0); + public static final VersionNumber Version1_30 = new VersionNumber(1, 30, 0); /** Version 1.40, i.e. GLSL 1.40 for GL 3.1. */ - public static final VersionNumber Version140 = new VersionNumber(1, 40, 0); + public static final VersionNumber Version1_40 = new VersionNumber(1, 40, 0); /** Version 1.50, i.e. GLSL 1.50 for GL 3.2. */ - public static final VersionNumber Version150 = new VersionNumber(1, 50, 0); + public static final VersionNumber Version1_50 = new VersionNumber(1, 50, 0); + + /** Version 1.1, i.e. GL 1.1 */ + public static final VersionNumber Version1_1 = new VersionNumber(1, 1, 0); + + /** Version 1.2, i.e. GL 1.2 */ + public static final VersionNumber Version1_2 = new VersionNumber(1, 2, 0); + + /** Version 1.4, i.e. GL 1.4 */ + public static final VersionNumber Version1_4 = new VersionNumber(1, 4, 0); + + /** Version 1.5, i.e. GL 1.5 */ + public static final VersionNumber Version1_5 = new VersionNumber(1, 5, 0); /** Version 3.0. As an OpenGL version, it qualifies for desktop {@link #isGL2()} only, or ES 3.0. Or GLSL 3.00 for ES 3.0. */ - public static final VersionNumber Version300 = new VersionNumber(3, 0, 0); + public static final VersionNumber Version3_0 = new VersionNumber(3, 0, 0); /** Version 3.1. As an OpenGL version, it qualifies for {@link #isGL3core()}, {@link #isGL3bc()} and {@link #isGL3()} */ - public static final VersionNumber Version310 = new VersionNumber(3, 1, 0); + public static final VersionNumber Version3_1 = new VersionNumber(3, 1, 0); /** Version 3.2. As an OpenGL version, it qualifies for geometry shader */ - public static final VersionNumber Version320 = new VersionNumber(3, 2, 0); + public static final VersionNumber Version3_2 = new VersionNumber(3, 2, 0); /** Version 4.3. As an OpenGL version, it qualifies for <code>GL_ARB_ES3_compatibility</code> */ - public static final VersionNumber Version430 = new VersionNumber(4, 3, 0); + public static final VersionNumber Version4_3 = new VersionNumber(4, 3, 0); - protected static final VersionNumber Version800 = new VersionNumber(8, 0, 0); + protected static final VersionNumber Version8_0 = new VersionNumber(8, 0, 0); private static final String S_EMPTY = ""; @@ -321,10 +333,11 @@ public abstract class GLContext { * if the {@link #getGLReadDrawable() read-drawable} differs * from the {@link #getGLDrawable() write-drawable}. * Otherwise set both drawables, read and write. - * @return The previous read/write drawable + * @return The previous read/write drawable if operation succeeds * - * @throws GLException in case <code>null</code> is being passed or - * this context is made current on another thread. + * @throws GLException in case <code>null</code> is being passed, + * this context is made current on another thread + * or operation fails. * * @see #isGLReadDrawableAvailable() * @see #setGLReadDrawable(GLDrawable) @@ -844,11 +857,11 @@ public abstract class GLContext { final int minor = ctxGLSLVersion.getMinor(); final String profileOpt; if( isGLES() ) { - profileOpt = ctxGLSLVersion.compareTo(Version300) >= 0 ? " es" : S_EMPTY; + profileOpt = ctxGLSLVersion.compareTo(Version3_0) >= 0 ? " es" : S_EMPTY; } else if( isGLCoreProfile() ) { - profileOpt = ctxGLSLVersion.compareTo(Version150) >= 0 ? " core" : S_EMPTY; + profileOpt = ctxGLSLVersion.compareTo(Version1_50) >= 0 ? " core" : S_EMPTY; } else if( isGLCompatibilityProfile() ) { - profileOpt = ctxGLSLVersion.compareTo(Version150) >= 0 ? " compatibility" : S_EMPTY; + profileOpt = ctxGLSLVersion.compareTo(Version1_50) >= 0 ? " compatibility" : S_EMPTY; } else { throw new InternalError("Neither ES, Core nor Compat: "+this); // see validateProfileBits(..) } @@ -858,22 +871,22 @@ public abstract class GLContext { protected static final VersionNumber getStaticGLSLVersionNumber(final int glMajorVersion, final int glMinorVersion, final int ctxOptions) { if( 0 != ( CTX_PROFILE_ES & ctxOptions ) ) { if( 3 == glMajorVersion ) { - return Version300; // ES 3.0 -> GLSL 3.00 + return Version3_0; // ES 3.0 -> GLSL 3.00 } else if( 2 == glMajorVersion ) { - return Version100; // ES 2.0 -> GLSL 1.00 + return Version1_0; // ES 2.0 -> GLSL 1.00 } } else if( 1 == glMajorVersion ) { - return Version110; // GL 1.x -> GLSL 1.10 + return Version1_10; // GL 1.x -> GLSL 1.10 } else if( 2 == glMajorVersion ) { switch ( glMinorVersion ) { - case 0: return Version110; // GL 2.0 -> GLSL 1.10 - default: return Version120; // GL 2.1 -> GLSL 1.20 + case 0: return Version1_10; // GL 2.0 -> GLSL 1.10 + default: return Version1_20; // GL 2.1 -> GLSL 1.20 } } else if( 3 == glMajorVersion && 2 >= glMinorVersion ) { switch ( glMinorVersion ) { - case 0: return Version130; // GL 3.0 -> GLSL 1.30 - case 1: return Version140; // GL 3.1 -> GLSL 1.40 - default: return Version150; // GL 3.2 -> GLSL 1.50 + case 0: return Version1_30; // GL 3.0 -> GLSL 1.30 + case 1: return Version1_40; // GL 3.1 -> GLSL 1.40 + default: return Version1_50; // GL 3.2 -> GLSL 1.50 } } // The new default: GL >= 3.3, ES >= 3.0 @@ -1032,7 +1045,7 @@ public abstract class GLContext { */ public final boolean isGL3bc() { return 0 != (ctxOptions & CTX_PROFILE_COMPAT) && - ctxVersion.compareTo(Version310) >= 0 ; + ctxVersion.compareTo(Version3_1) >= 0 ; } /** @@ -1041,7 +1054,7 @@ public abstract class GLContext { */ public final boolean isGL3() { return 0 != (ctxOptions & (CTX_PROFILE_COMPAT|CTX_PROFILE_CORE)) && - ctxVersion.compareTo(Version310) >= 0 ; + ctxVersion.compareTo(Version3_1) >= 0 ; } /** @@ -1049,7 +1062,7 @@ public abstract class GLContext { */ public final boolean isGL3core() { return 0 != ( ctxOptions & CTX_PROFILE_CORE ) && - ctxVersion.compareTo(Version310) >= 0; + ctxVersion.compareTo(Version3_1) >= 0; } /** @@ -1058,7 +1071,7 @@ public abstract class GLContext { public final boolean isGLcore() { return ( 0 != ( ctxOptions & CTX_PROFILE_ES ) && ctxVersion.getMajor() >= 2 ) || ( 0 != ( ctxOptions & CTX_PROFILE_CORE ) && - ctxVersion.compareTo(Version310) >= 0 + ctxVersion.compareTo(Version3_1) >= 0 ) ; } @@ -1106,7 +1119,7 @@ public abstract class GLContext { return // ES 3.x not included, see above. ( 0 != ( ctxOptions & CTX_PROFILE_ES ) && ctxVersion.getMajor() >= 3 ) || ( 0 != ( ctxOptions & CTX_IS_ARB_CREATED ) && 0 != ( ctxOptions & CTX_PROFILE_CORE ) && - ctxVersion.compareTo(Version310) >= 0 + ctxVersion.compareTo(Version3_1) >= 0 ) ; } @@ -1461,13 +1474,13 @@ public abstract class GLContext { /* 1.*/ { 0, 1, 2, 3, 4, 5 }, /* 2.*/ { 0, 1 }, /* 3.*/ { 0, 1, 2, 3 }, - /* 4.*/ { 0, 1, 2, 3, 4 } }; + /* 4.*/ { 0, 1, 2, 3, 4, 5 } }; public static final int ES_VERSIONS[][] = { /* 0.*/ { -1 }, /* 1.*/ { 0, 1 }, /* 2.*/ { 0 }, - /* 3.*/ { 0 } }; + /* 3.*/ { 0, 1 } }; public static final int getMaxMajor(final int ctxProfile) { return ( 0 != ( CTX_PROFILE_ES & ctxProfile ) ) ? ES_VERSIONS.length-1 : GL_VERSIONS.length-1; @@ -1626,11 +1639,15 @@ public abstract class GLContext { } } - protected static void setAvailableGLVersionsSet(final AbstractGraphicsDevice device) { + protected static void setAvailableGLVersionsSet(final AbstractGraphicsDevice device, final boolean set) { synchronized ( deviceVersionsAvailableSet ) { final String devKey = device.getUniqueID(); - if( null != deviceVersionsAvailableSet.put(devKey, devKey) ) { - throw new InternalError("Already set: "+devKey); + if( set ) { + if( null != deviceVersionsAvailableSet.put(devKey, devKey) ) { + throw new InternalError("Already set: "+devKey); + } + } else { + deviceVersionsAvailableSet.remove(devKey); } if (DEBUG) { System.err.println(getThreadName() + ": createContextARB: SET mappedVersionsAvailableSet "+devKey); diff --git a/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java b/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java index 71568ee76..dabd3531b 100644 --- a/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java +++ b/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java @@ -144,7 +144,7 @@ public abstract class GLDrawableFactory { } } } - if (null != factoryClassName) { + if (null != factoryClassName && !GLProfile.disableOpenGLDesktop) { if (DEBUG || GLProfile.DEBUG) { System.err.println("GLDrawableFactory.static - Native OS Factory for: "+nwt+": "+factoryClassName); } @@ -387,13 +387,14 @@ public abstract class GLDrawableFactory { * </p> * * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. + * @param glp {@link GLProfile} to identify the device's {@link GLRendererQuirks}, maybe {@code null} * @param quirk the quirk to be tested, e.g. {@link GLRendererQuirks#NoDoubleBufferedPBuffer}. * @throws IllegalArgumentException if the quirk is out of range - * @see #getRendererQuirks(AbstractGraphicsDevice) + * @see #getRendererQuirks(AbstractGraphicsDevice, GLProfile) * @see GLRendererQuirks */ - public final boolean hasRendererQuirk(final AbstractGraphicsDevice device, final int quirk) { - final GLRendererQuirks glrq = getRendererQuirks(device); + public final boolean hasRendererQuirk(final AbstractGraphicsDevice device, final GLProfile glp, final int quirk) { + final GLRendererQuirks glrq = getRendererQuirks(device, glp); return null != glrq ? glrq.exist(quirk) : false; } @@ -407,10 +408,11 @@ public abstract class GLDrawableFactory { * the result is always <code>null</code>. * </p> * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. + * @param glp {@link GLProfile} to identify the device's {@link GLRendererQuirks}, maybe {@code null} * @see GLContext#getRendererQuirks() * @see GLRendererQuirks */ - public abstract GLRendererQuirks getRendererQuirks(AbstractGraphicsDevice device); + public abstract GLRendererQuirks getRendererQuirks(AbstractGraphicsDevice device, final GLProfile glp); /** * Returns the sole GLDrawableFactory instance for the desktop (X11, WGL, ..) if exist or null diff --git a/src/jogl/classes/javax/media/opengl/GLProfile.java b/src/jogl/classes/javax/media/opengl/GLProfile.java index c7aaca5d3..7f29bb7dc 100644 --- a/src/jogl/classes/javax/media/opengl/GLProfile.java +++ b/src/jogl/classes/javax/media/opengl/GLProfile.java @@ -41,6 +41,7 @@ import jogamp.opengl.Debug; import jogamp.opengl.GLDrawableFactoryImpl; import jogamp.opengl.DesktopGLDynamicLookupHelper; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.GlueGenVersion; import com.jogamp.common.jvm.JNILibLoaderBase; import com.jogamp.common.os.Platform; @@ -52,6 +53,7 @@ import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveThreadGroupLock; import com.jogamp.gluegen.runtime.FunctionAddressResolver; import com.jogamp.nativewindow.NativeWindowVersion; +import com.jogamp.opengl.GLRendererQuirks; import com.jogamp.opengl.JoglVersion; import javax.media.nativewindow.AbstractGraphicsDevice; @@ -79,13 +81,6 @@ public class GLProfile { public static final boolean DEBUG; /** - * In case no OpenGL ES profiles are required - * and if one platform may have a buggy implementation, - * setting the property <code>jogl.disable.opengles</code> disables querying possible existing OpenGL ES profiles. - */ - public static final boolean disableOpenGLES; - - /** * In case no native OpenGL core profiles are required * and if one platform may have a buggy implementation, * setting the property <code>jogl.disable.openglcore</code> disables querying possible existing native OpenGL core profiles. @@ -100,12 +95,43 @@ public class GLProfile { * context creation extension is buggy on one platform, * setting the property <code>jogl.disable.openglarbcontext</code> disables utilizing it. * <p> + * This exclusion also disables {@link #disableOpenGLES OpenGL ES}. + * </p> + * <p> * This exclusion is disabled for {@link Platform.OSType#MACOS}. * </p> */ public static final boolean disableOpenGLARBContext; /** + * In case no OpenGL ES profiles are required + * and if one platform may have a buggy implementation, + * setting the property <code>jogl.disable.opengles</code> disables querying possible existing OpenGL ES profiles. + */ + public static final boolean disableOpenGLES; + + /** + * In case no OpenGL desktop profiles are required + * and if one platform may have a buggy implementation, + * setting the property <code>jogl.disable.opengldesktop</code> disables querying possible existing OpenGL desktop profiles. + */ + public static final boolean disableOpenGLDesktop; + + /** + * Disable surfaceless OpenGL context capability and its probing + * by setting the property <code>jogl.disable.surfacelesscontext</code>. + * <p> + * By default surfaceless OpenGL context capability is probed, + * i.e. whether an OpenGL context can be made current without a default framebuffer. + * </p> + * <p> + * If probing fails or if this property is set, the {@link GLRendererQuirks quirk} {@link GLRendererQuirks#NoSurfacelessCtx} + * is being set. + * </p> + */ + public static final boolean disableSurfacelessContext; + + /** * We have to disable support for ANGLE, the D3D ES2 emulation on Windows provided w/ Firefox and Chrome. * When run in the mentioned browsers, the eglInitialize(..) implementation crashes. * <p> @@ -121,9 +147,11 @@ public class GLProfile { final boolean isOSX = Platform.OSType.MACOS == Platform.getOSType(); DEBUG = Debug.debug("GLProfile"); - disableOpenGLES = PropertyAccess.isPropertyDefined("jogl.disable.opengles", true); disableOpenGLCore = PropertyAccess.isPropertyDefined("jogl.disable.openglcore", true) && !isOSX; disableOpenGLARBContext = PropertyAccess.isPropertyDefined("jogl.disable.openglarbcontext", true) && !isOSX; + disableOpenGLES = disableOpenGLARBContext || PropertyAccess.isPropertyDefined("jogl.disable.opengles", true); + disableOpenGLDesktop = PropertyAccess.isPropertyDefined("jogl.disable.opengldesktop", true); + disableSurfacelessContext = PropertyAccess.isPropertyDefined("jogl.disable.surfacelesscontext", true); enableANGLE = PropertyAccess.isPropertyDefined("jogl.enable.ANGLE", true); } @@ -175,7 +203,7 @@ public class GLProfile { justInitialized = true; if(DEBUG) { System.err.println("GLProfile.initSingleton() - thread "+Thread.currentThread().getName()); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } if(ReflectionUtil.DEBUG_STATS_FORNAME) { @@ -246,7 +274,7 @@ public class GLProfile { initialized = false; if(DEBUG) { System.err.println("GLProfile.shutdown() - thread "+Thread.currentThread().getName()); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } GLDrawableFactory.shutdown(); } @@ -1894,7 +1922,7 @@ public class GLProfile { // also test GLES1, GLES2 and GLES3 on desktop, since we have implementations / emulations available. if( deviceIsEGLCompatible && ( hasGLES3Impl || hasGLES1Impl ) ) { // 1st pretend we have all EGL profiles .. - computeProfileMap(device, false /* desktopCtxUndef*/, true /* esCtxUndef */); + computeProfileMap(device, true /* desktopCtxUndef*/, true /* esCtxUndef */); // Triggers eager initialization of share context in GLDrawableFactory for the device, // hence querying all available GLProfiles @@ -1934,7 +1962,7 @@ public class GLProfile { } if(!GLContext.getAvailableGLVersionsSet(device)) { - GLContext.setAvailableGLVersionsSet(device); + GLContext.setAvailableGLVersionsSet(device, true); } if (DEBUG) { diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java index 8d23d79ff..6e9e28c19 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -63,6 +63,7 @@ import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.ScalableSurface; import javax.media.nativewindow.SurfaceUpdatedListener; import javax.media.nativewindow.WindowClosingProtocol; +import javax.media.nativewindow.util.PixelFormat; import javax.media.opengl.GL; import javax.media.opengl.GL2; import javax.media.opengl.GL2ES3; @@ -265,12 +266,14 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing private final int[] hasPixelScale = new int[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE }; private final int[] reqPixelScale = new int[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE }; - // For handling reshape events lazily: reshapeWidth -> panelWidth -> backend.width + /** For handling reshape events lazily: reshapeWidth -> panelWidth -> backend.width in pixel units (scaled) */ private int reshapeWidth; + /** For handling reshape events lazily: reshapeHeight -> panelHeight -> backend.height in pixel units (scaled) */ private int reshapeHeight; - // Width of the actual GLJPanel: reshapeWidth -> panelWidth -> backend.width + /** Scaled pixel width of the actual GLJPanel: reshapeWidth -> panelWidth -> backend.width */ private int panelWidth = 0; + /** Scaled pixel height of the actual GLJPanel: reshapeHeight -> panelHeight -> backend.height */ private int panelHeight = 0; // These are always set to (0, 0) except when the Java2D / OpenGL @@ -578,14 +581,14 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing @Override public final void setSurfaceScale(final int[] pixelScale) { // HiDPI support SurfaceScaleUtils.validateReqPixelScale(reqPixelScale, pixelScale, DEBUG ? getClass().getSimpleName() : null); - final Backend b = backend; - if ( isInitialized && null != b ) { - final int hadPixelScaleX = hasPixelScale[0]; - final int hadPixelScaleY = hasPixelScale[1]; - SurfaceScaleUtils.computePixelScale(hasPixelScale, hasPixelScale, reqPixelScale, nativePixelScale, DEBUG ? getClass().getSimpleName() : null); - if( hadPixelScaleX != hasPixelScale[0] || hadPixelScaleY != hasPixelScale[1] ) { + final int hadPixelScaleX = hasPixelScale[0]; + final int hadPixelScaleY = hasPixelScale[1]; + SurfaceScaleUtils.computePixelScale(hasPixelScale, hasPixelScale, reqPixelScale, nativePixelScale, DEBUG ? getClass().getSimpleName() : null); + if( hadPixelScaleX != hasPixelScale[0] || hadPixelScaleY != hasPixelScale[1] ) { + reshapeImpl(getWidth(), getHeight()); + final Backend b = backend; + if ( isInitialized && null != b ) { updateWrappedSurfaceScale(b.getDrawable()); - reshapeImpl(getWidth(), getHeight()); display(); } } @@ -1882,27 +1885,36 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing alignment = 4; } - final GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(gl, componentCount); + final PixelFormat awtPixelFormat = pixelBufferProvider.getAWTPixelFormat(gl.getGLProfile(), componentCount); + final GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(gl, componentCount, true); if( useSingletonBuffer ) { // attempt to fetch the latest AWTGLPixelBuffer - pixelBuffer = (AWTGLPixelBuffer) ((SingletonGLPixelBufferProvider)pixelBufferProvider).getSingleBuffer(pixelAttribs); + pixelBuffer = (AWTGLPixelBuffer) ((SingletonGLPixelBufferProvider)pixelBufferProvider).getSingleBuffer(awtPixelFormat.comp, pixelAttribs, true); } if( null != pixelBuffer && pixelBuffer.requiresNewBuffer(gl, panelWidth, panelHeight, 0) ) { pixelBuffer.dispose(); pixelBuffer = null; alignedImage = null; } + final boolean DEBUG_INIT; if ( null == pixelBuffer ) { if (0 >= panelWidth || 0 >= panelHeight ) { return; } - pixelBuffer = pixelBufferProvider.allocate(gl, pixelAttribs, panelWidth, panelHeight, 1, true, 0); + pixelBuffer = pixelBufferProvider.allocate(gl, awtPixelFormat.comp, pixelAttribs, true, panelWidth, panelHeight, 1, 0); if(DEBUG) { System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: "+GLJPanel.this.getName()+" pixelBufferProvider isSingletonBufferProvider "+useSingletonBuffer+", 0x"+Integer.toHexString(pixelBufferProvider.hashCode())+", "+pixelBufferProvider.getClass().getSimpleName()); System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: "+GLJPanel.this.getName()+" pixelBuffer 0x"+Integer.toHexString(pixelBuffer.hashCode())+", "+pixelBuffer+", alignment "+alignment); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: "+GLJPanel.this.getName()+" flippedVertical "+flipVertical+", glslTextureRaster "+(null!=glslTextureRaster)); + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: "+GLJPanel.this.getName()+" flippedVertical "+flipVertical+", glslTextureRaster "+(null!=glslTextureRaster)+", isGL2ES3 "+gl.isGL2ES3()); System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: "+GLJPanel.this.getName()+" panelSize "+panelWidth+"x"+panelHeight+" @ scale "+getPixelScaleStr()); + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: "+GLJPanel.this.getName()+" pixelAttribs "+pixelAttribs); + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: "+GLJPanel.this.getName()+" awtPixelFormat "+awtPixelFormat); + DEBUG_INIT = true; + } else { + DEBUG_INIT = false; } + } else { + DEBUG_INIT = false; } if( offscreenDrawable.getSurfaceWidth() != panelWidth || offscreenDrawable.getSurfaceHeight() != panelHeight ) { throw new InternalError("OffscreenDrawable panelSize mismatch (reshape missed): panelSize "+panelWidth+"x"+panelHeight+" != drawable "+offscreenDrawable.getSurfaceWidth()+"x"+offscreenDrawable.getSurfaceHeight()+", on thread "+getThreadName()); @@ -1937,6 +1949,13 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing final GL2ES3 gl2es3 = gl.getGL2ES3(); psm.setPackRowLength(gl2es3, panelWidth); gl2es3.glReadBuffer(gl2es3.getDefaultReadBuffer()); + if( DEBUG_INIT ) { + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.0: fboDrawable "+offscreenDrawable); + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.0: isGL2ES3, readBuffer 0x"+Integer.toHexString(gl2es3.getDefaultReadBuffer())); + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.0: def-readBuffer 0x"+Integer.toHexString(gl2es3.getDefaultReadBuffer())); + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.0: def-readFBO 0x"+Integer.toHexString(gl2es3.getDefaultReadFramebuffer())); + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.0: bound-readFBO 0x"+Integer.toHexString(gl2es3.getBoundFramebuffer(GL2ES3.GL_READ_FRAMEBUFFER))); + } } if(null != glslTextureRaster) { // implies flippedVertical @@ -1965,9 +1984,26 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing // gl.glClear(GL.GL_DEPTH_BUFFER_BIT); // fboFlipped runs w/o DEPTH! glslTextureRaster.display(gl.getGL2ES2()); + if( DEBUG_INIT ) { + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.1: fboDrawable "+fboDrawable); + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.1: read from fbo-rb "+fboFlipped.getReadFramebuffer()+", fbo "+fboFlipped); + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.1: isGL2ES3, readBuffer 0x"+Integer.toHexString(gl.getDefaultReadBuffer())); + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.1: def-readBuffer 0x"+Integer.toHexString(gl.getDefaultReadBuffer())); + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.1: def-readFBO 0x"+Integer.toHexString(gl.getDefaultReadFramebuffer())); + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.1: bound-readFBO 0x"+Integer.toHexString(gl.getBoundFramebuffer(GL2ES3.GL_READ_FRAMEBUFFER))); + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.1: "+GLJPanel.this.getName()+" pixelAttribs "+pixelAttribs); + } gl.glReadPixels(0, 0, panelWidth, panelHeight, pixelAttribs.format, pixelAttribs.type, readBackInts); fboFlipped.unbind(gl); + if( DEBUG_INIT ) { + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.2: fboDrawable "+fboDrawable); + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.2: read from fbo-rb "+fboFlipped.getReadFramebuffer()+", fbo "+fboFlipped); + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.2: isGL2ES3, readBuffer 0x"+Integer.toHexString(gl.getDefaultReadBuffer())); + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.2: def-readBuffer 0x"+Integer.toHexString(gl.getDefaultReadBuffer())); + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.2: def-readFBO 0x"+Integer.toHexString(gl.getDefaultReadFramebuffer())); + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.2: bound-readFBO 0x"+Integer.toHexString(gl.getBoundFramebuffer(GL2ES3.GL_READ_FRAMEBUFFER))); + } if( viewportChange ) { gl.glViewport(usrViewport[0], usrViewport[1], usrViewport[2], usrViewport[3]); } diff --git a/src/jogl/classes/jogamp/opengl/GLBufferObjectTracker.java b/src/jogl/classes/jogamp/opengl/GLBufferObjectTracker.java index 7e49b3464..f278f73ae 100644 --- a/src/jogl/classes/jogamp/opengl/GLBufferObjectTracker.java +++ b/src/jogl/classes/jogamp/opengl/GLBufferObjectTracker.java @@ -34,6 +34,7 @@ import java.nio.IntBuffer; import javax.media.opengl.*; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.nio.Buffers; import com.jogamp.common.util.IntObjectHashMap; import com.jogamp.common.util.PropertyAccess; @@ -266,7 +267,7 @@ public class GLBufferObjectTracker { if( null == objOld ) { if (DEBUG) { System.err.printf("%s: %s.notifyBuffersDeleted()[%d/%d]: Buffer %d not tracked%n", warning, msgClazzName, i+1, count, bufferName); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return; } @@ -409,7 +410,7 @@ public class GLBufferObjectTracker { if ( 0 == addr ) { if( DEBUG ) { System.err.printf("%s.%s: %s MapBuffer null result for target 0x%X -> %d: %s, off %d, len %d, acc 0x%X%n", msgClazzName, msgMapBuffer, warning, target, bufferName, store, offset, length, access); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } // User shall handle the glError ! } else { @@ -442,14 +443,14 @@ public class GLBufferObjectTracker { if( 0 == bufferName ) { if (DEBUG) { System.err.printf("%s: %s.%s: Buffer for target 0x%X not bound%n", warning, msgClazzName, msgUnmapped, target); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } store = null; } else { store = (GLBufferStorageImpl) bufferName2StorageMap.get(bufferName); if( DEBUG && null == store ) { System.err.printf("%s: %s.%s: Buffer %d not tracked%n", warning, msgClazzName, msgUnmapped, bufferName); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } final boolean res = dispatch.unmap(target, glProcAddress); @@ -459,7 +460,7 @@ public class GLBufferObjectTracker { if( DEBUG ) { System.err.printf("%s.%s %s target: 0x%X -> %d: %s%n", msgClazzName, msgUnmapped, res ? "OK" : "Failed", target, bufferName, store.toString(false)); if(!res) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } return res; @@ -476,7 +477,7 @@ public class GLBufferObjectTracker { final GLBufferStorageImpl store = (GLBufferStorageImpl) bufferName2StorageMap.get(bufferName); if (DEBUG && null == store ) { System.err.printf("%s: %s.%s: Buffer %d not tracked%n", warning, msgClazzName, msgUnmapped, bufferName); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } final boolean res = dispatch.unmap(bufferName, glProcAddress); if( res && null != store ) { @@ -485,7 +486,7 @@ public class GLBufferObjectTracker { if (DEBUG) { System.err.printf("%s.%s %s %d: %s%n", msgClazzName, msgUnmapped, res ? "OK" : "Failed", bufferName, store.toString(false)); if(!res) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } return res; @@ -505,7 +506,7 @@ public class GLBufferObjectTracker { public synchronized final void clear() { if (DEBUG) { System.err.printf("%s.clear() - Thread %s%n", msgClazzName, Thread.currentThread().getName()); - // Thread.dumpStack(); + // ExceptionUtils.dumpStackTrace(System.err); } bufferName2StorageMap.clear(); } diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index a44075e90..b6db1813f 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -48,6 +48,7 @@ import java.security.PrivilegedAction; import java.util.HashMap; import java.util.Map; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.os.DynamicLookupHelper; import com.jogamp.common.os.Platform; import com.jogamp.common.util.ReflectionUtil; @@ -64,6 +65,7 @@ import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.ProxySurface; import javax.media.opengl.GL; import javax.media.opengl.GL2ES2; import javax.media.opengl.GL2ES3; @@ -118,6 +120,12 @@ public abstract class GLContextImpl extends GLContext { protected GLDrawableImpl drawable; protected GLDrawableImpl drawableRead; + /** + * If GL >= 3.0 (ES or desktop) and not having {@link GLRendererQuirks#NoSurfacelessCtx}, + * being evaluated if not surface-handle is null and not yet set at makeCurrent(..). + */ + private boolean surfacelessOK = false; + private boolean pixelDataEvaluated; private int /* pixelDataInternalFormat, */ pixelDataFormat, pixelDataType; @@ -194,6 +202,7 @@ public abstract class GLContextImpl extends GLContext { boundFBOTarget[1] = 0; // read } + surfacelessOK = false; pixelDataEvaluated = false; super.resetStates(isInit); @@ -245,8 +254,9 @@ public abstract class GLContextImpl extends GLContext { if( drawable == readWrite && ( setWriteOnly || drawableRead == readWrite ) ) { return drawable; // no change. } - final GLDrawableImpl old = drawable; - if( isCreated() && null != old && old.isRealized() ) { + final GLDrawableImpl oldDrawableWrite = drawable; + final GLDrawableImpl oldDrawableRead = drawableRead; + if( isCreated() && null != oldDrawableWrite && oldDrawableWrite.isRealized() ) { if(!lockHeld) { makeCurrent(); } @@ -266,12 +276,36 @@ public abstract class GLContextImpl extends GLContext { drawableRetargeted |= null != drawable && readWrite != drawable; drawable = (GLDrawableImpl) readWrite ; if( isCreated() && null != drawable && drawable.isRealized() ) { - makeCurrent(true); // implicit: associateDrawable(true) + int res = CONTEXT_NOT_CURRENT; + GLException gle = null; + try { + res = makeCurrent(true); // implicit: associateDrawable(true) + } catch ( final GLException e ) { + gle = e; + } finally { + if( CONTEXT_NOT_CURRENT == res ) { + // Failure, recover and bail out w/ GLException + drawableRead = oldDrawableRead; + drawable = oldDrawableWrite; + if( drawable.isRealized() ) { + makeCurrent(true); // implicit: associateDrawable(true) + } + if( !lockHeld ) { + release(false); + } + final String msg = "Error: makeCurrent() failed with new drawable "+readWrite; + if( null != gle ) { + throw new GLException(msg, gle); + } else { + throw new GLException(msg); + } + } + } if( !lockHeld ) { release(false); } } - return old; + return oldDrawableWrite; } @Override @@ -305,7 +339,7 @@ public abstract class GLContextImpl extends GLContext { final String sgl1 = (null!=this.gl)?this.gl.getClass().getSimpleName()+", "+this.gl.toString():"<null>"; final String sgl2 = (null!=gl)?gl.getClass().getSimpleName()+", "+gl.toString():"<null>"; System.err.println("Info: setGL (OpenGL "+getGLVersion()+"): "+getThreadName()+", "+sgl1+" -> "+sgl2); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } this.gl = gl; return gl; @@ -383,7 +417,7 @@ public abstract class GLContextImpl extends GLContext { lastCtxReleaseStack = new Throwable(msg); if( TRACE_SWITCH ) { System.err.println(msg); - // Thread.dumpStack(); + // ExceptionUtils.dumpStackTrace(System.err, 0, 10); } } } @@ -419,7 +453,7 @@ public abstract class GLContextImpl extends GLContext { if ( DEBUG_TRACE_SWITCH ) { if ( lock.getHoldCount() > 2 ) { System.err.println(getThreadName() + ": GLContextImpl.destroy: Lock was hold more than once - makeCurrent/release imbalance: "+getTraceSwitchMsg()); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } try { @@ -564,11 +598,23 @@ public abstract class GLContextImpl extends GLContext { int res = CONTEXT_NOT_CURRENT; try { if ( drawable.isRealized() ) { - if ( 0 == drawable.getHandle() ) { - throw new GLException("drawable has invalid handle: "+drawable); - } lock.lock(); try { + if ( 0 == drawable.getHandle() && !surfacelessOK ) { + if( DEBUG ) { + System.err.println(getThreadName() +": GLContext.makeCurrent: Surfaceless evaluate"); + } + if( hasRendererQuirk(GLRendererQuirks.NoSurfacelessCtx) ) { + throw new GLException(String.format("Surfaceless not supported due to quirk %s: %s", + GLRendererQuirks.toString(GLRendererQuirks.NoSurfacelessCtx), toString())); + } + // Allow probing if ProxySurface && OPT_UPSTREAM_SURFACELESS + final NativeSurface surface = drawable.getNativeSurface(); + if( !(surface instanceof ProxySurface) || + !((ProxySurface)surface).containsUpstreamOptionBits( ProxySurface.OPT_UPSTREAM_SURFACELESS ) ) { + throw new GLException(String.format("non-surfaceless drawable has zero-handle: %s", drawable.toString())); + } + } // One context can only be current by one thread, // and one thread can only have one context current! final GLContext current = getCurrent(); @@ -618,6 +664,16 @@ public abstract class GLContextImpl extends GLContext { } if (res != CONTEXT_NOT_CURRENT) { // still locked! + if( 0 == drawable.getHandle() && !surfacelessOK ) { + if( hasRendererQuirk(GLRendererQuirks.NoSurfacelessCtx) ) { + throw new GLException(String.format("Surfaceless not supported due to quirk %s: %s", + GLRendererQuirks.toString(GLRendererQuirks.NoSurfacelessCtx), toString())); + } + if( DEBUG ) { + System.err.println(getThreadName() +": GLContext.makeCurrent: Surfaceless OK - validate"); + } + surfacelessOK = true; + } setCurrent(this); if(res == CONTEXT_CURRENT_NEW) { // check if the drawable's and the GL's GLProfile are equal @@ -698,12 +754,10 @@ public abstract class GLContextImpl extends GLContext { if( created && hasNoDefaultVAO() ) { final int[] tmp = new int[1]; final GL rootGL = gl.getRootGL(); - if( rootGL.isGL2ES3() ) { // FIXME remove if ES2 == ES3 later - final GL2ES3 gl2es3 = rootGL.getGL2ES3(); - gl2es3.glGenVertexArrays(1, tmp, 0); - defaultVAO = tmp[0]; - gl2es3.glBindVertexArray(defaultVAO); - } + final GL2ES3 gl2es3 = rootGL.getGL2ES3(); + gl2es3.glGenVertexArrays(1, tmp, 0); + defaultVAO = tmp[0]; + gl2es3.glBindVertexArray(defaultVAO); } } finally { if ( null != sharedMaster ) { @@ -712,7 +766,7 @@ public abstract class GLContextImpl extends GLContext { } if ( DEBUG_TRACE_SWITCH ) { System.err.println(getThreadName() + ": Create GL context "+(created?"OK":"FAILED")+": For " + getClass().getName()+" - "+getGLVersion()+" - "+getTraceSwitchMsg()); - // Thread.dumpStack(); + // ExceptionUtils.dumpStackTrace(System.err, 0, 10); } if(!created) { return CONTEXT_NOT_CURRENT; @@ -728,7 +782,7 @@ public abstract class GLContextImpl extends GLContext { if( 0 == ( ctxOptions & GLContext.CTX_PROFILE_ES) ) { // not ES profile final int reqMajor; final int reqProfile; - if( ctxVersion.compareTo(Version300) <= 0 ) { + if( ctxVersion.compareTo(Version3_0) <= 0 ) { reqMajor = 2; } else { reqMajor = ctxVersion.getMajor(); @@ -759,7 +813,7 @@ public abstract class GLContextImpl extends GLContext { GLContext.mapAvailableGLVersion(device, 3, reqProfile, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions); } } - GLContext.setAvailableGLVersionsSet(device); + GLContext.setAvailableGLVersionsSet(device, true); if (DEBUG) { System.err.println(getThreadName() + ": createContextOLD-MapVersionsAvailable HAVE: " + device+" -> "+reqMajor+"."+reqProfile+ " -> "+getGLVersion()); @@ -879,6 +933,9 @@ public abstract class GLContextImpl extends GLContext { GLContext.getAvailableGLVersionsSet(device)); } + final GLCapabilitiesImmutable glCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); + final GLProfile glp = glCaps.getGLProfile(); + if ( !GLContext.getAvailableGLVersionsSet(device) ) { if(!mapGLVersions(device)) { // none of the ARB context creation calls was successful, bail out @@ -886,12 +943,11 @@ public abstract class GLContextImpl extends GLContext { } } - final GLCapabilitiesImmutable glCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); final int[] reqMajorCTP = new int[] { 0, 0 }; - GLContext.getRequestMajorAndCompat(glCaps.getGLProfile(), reqMajorCTP); + GLContext.getRequestMajorAndCompat(glp, reqMajorCTP); if(DEBUG) { - System.err.println(getThreadName() + ": createContextARB: Requested "+GLContext.getGLVersion(reqMajorCTP[0], 0, reqMajorCTP[0], null)); + System.err.println(getThreadName() + ": createContextARB: Requested "+glp+" -> "+GLContext.getGLVersion(reqMajorCTP[0], 0, reqMajorCTP[1], null)); } final int _major[] = { 0 }; final int _minor[] = { 0 }; @@ -1023,7 +1079,7 @@ public abstract class GLContextImpl extends GLContext { } if(success) { // only claim GL versions set [and hence detected] if ARB context creation was successful - GLContext.setAvailableGLVersionsSet(device); + GLContext.setAvailableGLVersionsSet(device, true); if(DEBUG) { final long t1 = System.nanoTime(); System.err.println("GLContextImpl.mapGLVersions: "+device+", profileAliasing: "+PROFILE_ALIASING+", total "+(t1-t0)/1e6 +"ms"); @@ -1051,17 +1107,23 @@ public abstract class GLContextImpl extends GLContext { int majorMin, minorMin; final int major[] = new int[1]; final int minor[] = new int[1]; - if( 4 == reqMajor ) { - majorMax=4; minorMax=GLContext.getMaxMinor(ctp, majorMax); - majorMin=4; minorMin=0; - } else if( 3 == reqMajor ) { - majorMax=3; minorMax=GLContext.getMaxMinor(ctp, majorMax); - majorMin=3; minorMin=1; - } else /* if( glp.isGL2() ) */ { - // our minimum desktop OpenGL runtime requirements are 1.1, - // nevertheless we restrict ARB context creation to 2.0 to spare us futile attempts - majorMax=3; minorMax=0; - majorMin=2; minorMin=0; + + if( CTX_PROFILE_ES == reqProfile ) { + majorMax=reqMajor; minorMax=GLContext.getMaxMinor(ctp, majorMax); + majorMin=reqMajor; minorMin=0; + } else { + if( 4 == reqMajor ) { + majorMax=4; minorMax=GLContext.getMaxMinor(ctp, majorMax); + majorMin=4; minorMin=0; + } else if( 3 == reqMajor ) { + majorMax=3; minorMax=GLContext.getMaxMinor(ctp, majorMax); + majorMin=3; minorMin=1; + } else /* if( glp.isGL2() ) */ { + // our minimum desktop OpenGL runtime requirements are 1.1, + // nevertheless we restrict ARB context creation to 2.0 to spare us futile attempts + majorMax=3; minorMax=0; + majorMin=2; minorMin=0; + } } _context = createContextARBVersions(0, true, ctp, /* max */ majorMax, minorMax, @@ -1181,16 +1243,19 @@ public abstract class GLContextImpl extends GLContext { // Helpers for various context implementations // - private Object createInstance(final GLProfile glp, final boolean glObject, final Object[] cstrArgs) { + private final Object createInstance(final GLProfile glp, final boolean glObject, final Object[] cstrArgs) { return ReflectionUtil.createInstance(glp.getGLCtor(glObject), cstrArgs); } - private boolean verifyInstance(final GLProfile glp, final String suffix, final Object instance) { + private final boolean verifyInstance(final GLProfile glp, final String suffix, final Object instance) { return ReflectionUtil.instanceOf(instance, glp.getGLImplBaseClassName()+suffix); } - /** Create the GL for this context. */ - protected GL createGL(final GLProfile glp) { + /** + * Create the GL instance for this context, + * requires valid {@link #getGLProcAddressTable()} result! + */ + private final GL createGL(final GLProfile glp) { final GL gl = (GL) createInstance(glp, true, new Object[] { glp, this } ); /* FIXME: refactor dependence on Java 2D / JOGL bridge @@ -1219,6 +1284,8 @@ public abstract class GLContextImpl extends GLContext { } if( null != finalizeInit ) { ReflectionUtil.callMethod(gl, finalizeInit, new Object[]{ }); + } else { + throw new InternalError("Missing 'void finalizeInit(ProcAddressTable)' in "+gl.getClass().getName()); } } @@ -1296,7 +1363,7 @@ public abstract class GLContextImpl extends GLContext { if(0 == _glGetString) { System.err.println("Error: Entry point to 'glGetString' is NULL."); if(DEBUG) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return false; } else { @@ -1304,7 +1371,7 @@ public abstract class GLContextImpl extends GLContext { if(null == _glVendor) { if(DEBUG) { System.err.println("Warning: GL_VENDOR is NULL."); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return false; } @@ -1314,7 +1381,7 @@ public abstract class GLContextImpl extends GLContext { if(null == _glRenderer) { if(DEBUG) { System.err.println("Warning: GL_RENDERER is NULL."); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return false; } @@ -1326,7 +1393,7 @@ public abstract class GLContextImpl extends GLContext { // FIXME if(DEBUG) { System.err.println("Warning: GL_VERSION is NULL."); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return false; } @@ -1370,7 +1437,7 @@ public abstract class GLContextImpl extends GLContext { if( 0 == _glGetIntegerv ) { System.err.println("Error: Entry point to 'glGetIntegerv' is NULL."); if(DEBUG) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return false; } else { @@ -1396,8 +1463,8 @@ public abstract class GLContextImpl extends GLContext { * * @param force force the setting, even if is already being set. * This might be useful if you change the OpenGL implementation. - * @param major OpenGL major version - * @param minor OpenGL minor version + * @param major requested OpenGL major version + * @param minor requested OpenGL minor version * @param ctxProfileBits OpenGL context profile and option bits, see {@link javax.media.opengl.GLContext#CTX_OPTION_ANY} * @param strictMatch if <code>true</code> the ctx must * <ul> @@ -1418,7 +1485,7 @@ public abstract class GLContextImpl extends GLContext { */ protected final boolean setGLFunctionAvailability(final boolean force, int major, int minor, int ctxProfileBits, final boolean strictMatch, final boolean withinGLVersionsMapping) { - if(null!=this.gl && null!=glProcAddressTable && !force) { + if( null != this.gl && null != glProcAddressTable && !force ) { return true; // already done and not forced } @@ -1426,11 +1493,6 @@ public abstract class GLContextImpl extends GLContext { throw new GLException("Invalid GL Version Request "+GLContext.getGLVersion(major, minor, ctxProfileBits, null)); } - if(null==this.gl || !verifyInstance(gl.getGLProfile(), "Impl", this.gl)) { - setGL( createGL( drawable.getGLProfile() ) ); - } - updateGLXProcAddressTable(); - final AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration(); final AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice(); final int reqCtxProfileBits = ctxProfileBits; @@ -1501,7 +1563,7 @@ public abstract class GLContextImpl extends GLContext { // - _and_ a valid int version was fetched, // otherwise cont. w/ version-string method -> 3.0 > Version || Version > MAX! // - if ( ( major >= 3 || hasGLVersionByString.compareTo(Version300) >= 0 ) && + if ( ( major >= 3 || hasGLVersionByString.compareTo(Version3_0) >= 0 ) && GLContext.isValidGLVersion(ctxProfileBits, hasGLVersionByInt.getMajor(), hasGLVersionByInt.getMinor()) ) { // Strict Match (GLVersionMapping): // Relaxed match for versions ( !isES && major < 3 ) requests, last resort! @@ -1622,54 +1684,67 @@ public abstract class GLContextImpl extends GLContext { System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.0 validated FQN: "+contextFQN+" - "+GLContext.getGLVersion(major, minor, ctxProfileBits, glVersion)); } + updateGLXProcAddressTable(); + // // UpdateGLProcAddressTable functionality + // _and_ setup GL instance, which ctor requires valid getGLProcAddressTable() result! // - ProcAddressTable table = null; - synchronized(mappedContextTypeObjectLock) { - table = mappedGLProcAddress.get( contextFQN ); - if(null != table && !verifyInstance(gl.getGLProfile(), "ProcAddressTable", table)) { - throw new InternalError("GLContext GL ProcAddressTable mapped key("+contextFQN+" - " + GLContext.getGLVersion(major, minor, ctxProfileBits, null)+ - ") -> "+ table.getClass().getName()+" not matching "+gl.getGLProfile().getGLImplBaseClassName()); - } - } - if(null != table) { - glProcAddressTable = table; - if(DEBUG) { - System.err.println(getThreadName() + ": GLContext GL ProcAddressTable reusing key("+contextFQN+") -> "+toHexString(table.hashCode())); - } - } else { - glProcAddressTable = (ProcAddressTable) createInstance(gl.getGLProfile(), false, - new Object[] { new GLProcAddressResolver() } ); - resetProcAddressTable(getGLProcAddressTable()); + { + final GLProfile glp = drawable.getGLProfile(); + + ProcAddressTable table = null; synchronized(mappedContextTypeObjectLock) { - mappedGLProcAddress.put(contextFQN, getGLProcAddressTable()); + table = mappedGLProcAddress.get( contextFQN ); + if(null != table && !verifyInstance(glp, "ProcAddressTable", table)) { + throw new InternalError("GLContext GL ProcAddressTable mapped key("+contextFQN+" - " + GLContext.getGLVersion(major, minor, ctxProfileBits, null)+ + ") -> "+ table.getClass().getName()+" not matching "+glp.getGLImplBaseClassName()); + } + } + if(null != table) { + glProcAddressTable = table; if(DEBUG) { - System.err.println(getThreadName() + ": GLContext GL ProcAddressTable mapping key("+contextFQN+") -> "+toHexString(getGLProcAddressTable().hashCode())); + System.err.println(getThreadName() + ": GLContext GL ProcAddressTable reusing key("+contextFQN+") -> "+toHexString(table.hashCode())); + } + } else { + glProcAddressTable = (ProcAddressTable) createInstance(glp, false, + new Object[] { new GLProcAddressResolver() } ); + resetProcAddressTable( glProcAddressTable ); + synchronized(mappedContextTypeObjectLock) { + mappedGLProcAddress.put(contextFQN, glProcAddressTable); + if(DEBUG) { + System.err.println(getThreadName() + ": GLContext GL ProcAddressTable mapping key("+contextFQN+") -> "+toHexString(glProcAddressTable.hashCode())); + } } } + + if( null == this.gl || !verifyInstance(glp, "Impl", this.gl) ) { + setGL( createGL( glp ) ); + } } // // Update ExtensionAvailabilityCache // - ExtensionAvailabilityCache eCache; - synchronized(mappedContextTypeObjectLock) { - eCache = mappedExtensionAvailabilityCache.get( contextFQN ); - } - if(null != eCache) { - extensionAvailability = eCache; - if(DEBUG) { - System.err.println(getThreadName() + ": GLContext GL ExtensionAvailabilityCache reusing key("+contextFQN+") -> "+toHexString(eCache.hashCode()) + " - entries: "+eCache.getTotalExtensionCount()); - } - } else { - extensionAvailability = new ExtensionAvailabilityCache(); - setContextVersion(major, minor, ctxProfileBits, vendorVersion, false); // pre-set of GL version, required for extension cache usage - extensionAvailability.reset(this); + { + ExtensionAvailabilityCache eCache; synchronized(mappedContextTypeObjectLock) { - mappedExtensionAvailabilityCache.put(contextFQN, extensionAvailability); + eCache = mappedExtensionAvailabilityCache.get( contextFQN ); + } + if(null != eCache) { + extensionAvailability = eCache; if(DEBUG) { - System.err.println(getThreadName() + ": GLContext GL ExtensionAvailabilityCache mapping key("+contextFQN+") -> "+toHexString(extensionAvailability.hashCode()) + " - entries: "+extensionAvailability.getTotalExtensionCount()); + System.err.println(getThreadName() + ": GLContext GL ExtensionAvailabilityCache reusing key("+contextFQN+") -> "+toHexString(eCache.hashCode()) + " - entries: "+eCache.getTotalExtensionCount()); + } + } else { + extensionAvailability = new ExtensionAvailabilityCache(); + setContextVersion(major, minor, ctxProfileBits, vendorVersion, false); // pre-set of GL version, required for extension cache usage + extensionAvailability.reset(this); + synchronized(mappedContextTypeObjectLock) { + mappedExtensionAvailabilityCache.put(contextFQN, extensionAvailability); + if(DEBUG) { + System.err.println(getThreadName() + ": GLContext GL ExtensionAvailabilityCache mapping key("+contextFQN+") -> "+toHexString(extensionAvailability.hashCode()) + " - entries: "+extensionAvailability.getTotalExtensionCount()); + } } } } @@ -1770,6 +1845,22 @@ public abstract class GLContextImpl extends GLContext { } } } + if( GLProfile.disableSurfacelessContext ) { + final int quirk = GLRendererQuirks.NoSurfacelessCtx; + if(DEBUG) { + System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: disabled"); + } + quirks.addQuirk( quirk ); + if( withinGLVersionsMapping ) { + // Thread safe due to single threaded initialization! + GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk); + } else { + // FIXME: Remove when moving EGL/ES to ARB ctx creation + synchronized(GLContextImpl.class) { + GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk); + } + } + } // // OS related quirks @@ -1903,7 +1994,7 @@ public abstract class GLContextImpl extends GLContext { // final int quirk = GLRendererQuirks.DontCloseX11Display; if( glRenderer.contains(MesaSP) ) { - if ( glRenderer.contains("X11") && vendorVersion.compareTo(Version800) < 0 ) { + if ( glRenderer.contains("X11") && vendorVersion.compareTo(Version8_0) < 0 ) { if(DEBUG) { System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: X11 Renderer=" + glRenderer + ", Version=[vendor " + vendorVersion + ", GL " + glVersion+"]"); } @@ -2309,9 +2400,6 @@ public abstract class GLContextImpl extends GLContext { } switch(target) { case GL.GL_FRAMEBUFFER: - boundFBOTarget[0] = framebufferName; // draw - boundFBOTarget[1] = framebufferName; // read - break; case GL2ES3.GL_DRAW_FRAMEBUFFER: boundFBOTarget[0] = framebufferName; // draw break; diff --git a/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java b/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java index 7519d568b..e682431a9 100644 --- a/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java +++ b/src/jogl/classes/jogamp/opengl/GLDebugMessageHandler.java @@ -33,13 +33,13 @@ import java.util.ArrayList; import javax.media.nativewindow.NativeWindowException; import javax.media.opengl.GL2ES2; -import javax.media.opengl.GL2GL3; import javax.media.opengl.GLDebugListener; import javax.media.opengl.GLDebugMessage; import javax.media.opengl.GLException; import jogamp.common.os.PlatformPropsImpl; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.os.Platform; import com.jogamp.gluegen.runtime.ProcAddressTable; import com.jogamp.opengl.GLExtensions; @@ -308,7 +308,7 @@ public class GLDebugMessageHandler { public void messageSent(final GLDebugMessage event) { System.err.println(event); if(threadDump) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } } diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java index b51f290e9..ee984b74a 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java @@ -67,6 +67,7 @@ import javax.media.opengl.GLFBODrawable; import javax.media.opengl.GLOffscreenAutoDrawable; import javax.media.opengl.GLProfile; +import com.jogamp.common.ExceptionUtils; import com.jogamp.nativewindow.MutableGraphicsConfiguration; import com.jogamp.nativewindow.DelegatedUpstreamSurfaceHookWithSurfaceSize; import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; @@ -128,16 +129,16 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { protected final boolean createSharedResourceImpl(final AbstractGraphicsDevice device) { final SharedResourceRunner.Resource sr = getOrCreateSharedResource( device ); if(null!=sr) { - return sr.isValid(); + return sr.isAvailable(); } return false; } @Override - public final GLRendererQuirks getRendererQuirks(final AbstractGraphicsDevice device) { + public final GLRendererQuirks getRendererQuirks(final AbstractGraphicsDevice device, final GLProfile glp) { final SharedResourceRunner.Resource sr = getOrCreateSharedResource( device ); if(null!=sr) { - return sr.getRendererQuirks(); + return sr.getRendererQuirks(glp); } return null; } @@ -195,7 +196,7 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { System.err.println("chosenCapsMod: "+chosenCapsMod); System.err.println("OffscreenLayerSurface: **** "+ols); System.err.println("Target: **** "+target); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } if( ! ( target instanceof MutableSurface ) ) { throw new IllegalArgumentException("Passed NativeSurface must implement SurfaceChangeable for offscreen layered surface: "+target); @@ -271,9 +272,9 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { @Override public final GLOffscreenAutoDrawable createOffscreenAutoDrawable(final AbstractGraphicsDevice deviceReq, - final GLCapabilitiesImmutable capsRequested, - final GLCapabilitiesChooser chooser, - final int width, final int height) { + final GLCapabilitiesImmutable capsRequested, + final GLCapabilitiesChooser chooser, + final int width, final int height) { final GLDrawable drawable = createOffscreenDrawable( deviceReq, capsRequested, chooser, width, height ); try { drawable.setRealized(true); @@ -306,24 +307,32 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { @Override public final GLDrawable createOffscreenDrawable(final AbstractGraphicsDevice deviceReq, - final GLCapabilitiesImmutable capsRequested, - final GLCapabilitiesChooser chooser, - final int width, final int height) { + final GLCapabilitiesImmutable capsRequested, + final GLCapabilitiesChooser chooser, + final int width, final int height) { if(width<=0 || height<=0) { throw new GLException("initial size must be positive (were (" + width + " x " + height + "))"); } - final AbstractGraphicsDevice device = getOrCreateSharedDevice(deviceReq); - if(null == device) { + final SharedResourceRunner.Resource sr = getOrCreateSharedResource( deviceReq ); + if( null == sr ) { throw new GLException("No shared device for requested: "+deviceReq); } - + final AbstractGraphicsDevice device = sr.getDevice(); final GLCapabilitiesImmutable capsChosen = GLGraphicsConfigurationUtil.fixOffscreenGLCapabilities(capsRequested, this, device); if( capsChosen.isFBO() ) { // Use minimum GLCapabilities for the dummy surface w/ same profile - final ProxySurface dummySurface = createDummySurfaceImpl(device, true, new GLCapabilities(capsChosen.getGLProfile()), capsRequested, null, width, height); - final GLDrawableImpl dummyDrawable = createOnscreenDrawableImpl(dummySurface); - return new GLFBODrawableImpl.ResizeableImpl(this, dummyDrawable, dummySurface, capsChosen, 0); + final GLProfile glp = capsChosen.getGLProfile(); + final GLCapabilitiesImmutable glCapsMin = new GLCapabilities(glp); + final GLRendererQuirks glrq = sr.getRendererQuirks(glp); + final ProxySurface surface; + if( null != glrq && !glrq.exist(GLRendererQuirks.NoSurfacelessCtx) ) { + surface = createSurfacelessImpl(device, true, glCapsMin, capsRequested, null, width, height); + } else { + surface = createDummySurfaceImpl(device, true, glCapsMin, capsRequested, null, width, height); + } + final GLDrawableImpl drawable = createOnscreenDrawableImpl(surface); + return new GLFBODrawableImpl.ResizeableImpl(this, drawable, surface, capsChosen, 0); } return createOffscreenDrawableImpl( createMutableSurfaceImpl(device, true, capsChosen, capsRequested, chooser, new UpstreamSurfaceHookMutableSize(width, height) ) ); @@ -380,8 +389,7 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstreamHook); /** - * A dummy surface is not visible on screen and will not be used to render directly to, - * it maybe on- or offscreen. + * A dummy surface is not visible on screen, it may be on- or offscreen. * <p> * It is used to allow the creation of a {@link GLDrawable} and {@link GLContext} to query information. * It also allows creation of framebuffer objects which are used for rendering or using a shared GLContext w/o actually rendering to a usable framebuffer. @@ -409,8 +417,7 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { } /** - * A dummy surface is not visible on screen and will not be used to render directly to, - * it maybe on- or offscreen. + * A dummy surface is not visible on screen and may be on- or offscreen. * <p> * It is used to allow the creation of a {@link GLDrawable} and {@link GLContext} to query information. * It also allows creation of framebuffer objects which are used for rendering or using a shared GLContext w/o actually rendering to a usable framebuffer. @@ -430,6 +437,27 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { public abstract ProxySurface createDummySurfaceImpl(AbstractGraphicsDevice device, boolean createNewDevice, GLCapabilitiesImmutable chosenCaps, GLCapabilitiesImmutable requestedCaps, GLCapabilitiesChooser chooser, int width, int height); + /** + * A surfaceless {@link ProxySurface} is a non-existing surface and will not be used as a render target. + * <p> + * It is used to allow the creation of a {@link GLDrawable} and {@link GLContext} w/o default framebuffer to query information. + * It also allows creation of framebuffer objects which are used for rendering or using a shared GLContext w/o actually rendering to a usable framebuffer. + * </p> + * @param device a valid platform dependent target device. + * @param createNewDevice if <code>true</code> a new device instance is created using <code>device</code> details, + * otherwise <code>device</code> instance is used as-is. + * @param chosenCaps + * @param requestedCaps + * @param chooser the custom chooser, may be null for default + * @param width the initial width as returned by {@link NativeSurface#getSurfaceWidth()}, not the actual dummy surface width. + * The latter is platform specific and small + * @param height the initial height as returned by {@link NativeSurface#getSurfaceHeight()}, not the actual dummy surface height, + * The latter is platform specific and small + * @return the created {@link ProxySurface} instance w/o defined surface handle but platform specific {@link UpstreamSurfaceHook}. + */ + public abstract ProxySurface createSurfacelessImpl(AbstractGraphicsDevice device, boolean createNewDevice, + GLCapabilitiesImmutable chosenCaps, GLCapabilitiesImmutable requestedCaps, GLCapabilitiesChooser chooser, int width, int height); + //--------------------------------------------------------------------------- // // ProxySurface (Wrapped pre-existing native surface) construction diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java index 3847b4042..6982418a9 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java @@ -355,7 +355,7 @@ public class GLDrawableHelper { } if( DEBUG && ( 0>=newWidth || 0>=newHeight) ) { System.err.println("WARNING: Odd size detected: "+newWidth+"x"+newHeight+", using safe size 1x1. Drawable "+drawable); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } if( 0 >= newWidth ) { newWidth = 1; validateSize=false; } if( 0 >= newHeight ) { newHeight = 1; validateSize=false; } @@ -734,7 +734,7 @@ public class GLDrawableHelper { final int glerr0 = drawable.getGL().glGetError(); if( GL.GL_NO_ERROR != glerr0 ) { System.err.println("Info: GLDrawableHelper.reshape: pre-exisiting GL error 0x"+Integer.toHexString(glerr0)); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } drawable.getGL().glViewport(x, y, width, height); diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java index 544aaf064..7cd887fee 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java @@ -51,6 +51,8 @@ import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; +import com.jogamp.common.ExceptionUtils; + public abstract class GLDrawableImpl implements GLDrawable { protected static final boolean DEBUG = GLDrawableFactoryImpl.DEBUG; @@ -176,7 +178,7 @@ public abstract class GLDrawableImpl implements GLDrawable { final boolean isProxySurface = surface instanceof ProxySurface; if(DEBUG) { System.err.println(getThreadName() + ": setRealized: drawable "+getClass().getSimpleName()+", surface "+surface.getClass().getSimpleName()+", isProxySurface "+isProxySurface+": "+realized+" -> "+realizedArg); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } final AbstractGraphicsDevice aDevice = surface.getGraphicsConfiguration().getScreen().getDevice(); if(realizedArg) { diff --git a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java index 991a351e6..98d1cea71 100644 --- a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java @@ -11,6 +11,7 @@ import javax.media.opengl.GLContext; import javax.media.opengl.GLException; import javax.media.opengl.GLFBODrawable; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.util.PropertyAccess; import com.jogamp.common.util.VersionUtil; import com.jogamp.nativewindow.MutableGraphicsConfiguration; @@ -104,7 +105,7 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { private final void setupFBO(final GL gl, final int idx, final int width, final int height, final int samples, final boolean useAlpha, final int depthBits, final int stencilBits, - final boolean useTexture, final boolean realUnbind) { + final boolean useTexture, final boolean setupViewportScissors, final boolean realUnbind) { final FBObject fbo = new FBObject(); fbos[idx] = fbo; @@ -155,6 +156,11 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { // Also remedy for Bug 1020, i.e. OSX/Nvidia's FBO needs to be cleared before blitting, // otherwise first MSAA frame lacks antialiasing. fbo.bind(gl); + if( setupViewportScissors ) { + // Surfaceless: Set initial viewport/scissors + gl.glViewport(0, 0, width, height); + gl.glScissor(0, 0, width, height); + } if( useDepth ) { gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); } else { @@ -171,7 +177,7 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { if( !initialized && !realize ) { if( DEBUG ) { System.err.println("GLFBODrawableImpl.initialize(): WARNING - Already unrealized!"); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return; // NOP, no exception for de-init twice or no init! } @@ -216,7 +222,9 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { for(int i=0; i<fbosN; i++) { setupFBO(gl, i, width, height, samples, useAlpha, - chosenFBOCaps.getDepthBits(), chosenFBOCaps.getStencilBits(), useTexture, fbosN-1==i); + chosenFBOCaps.getDepthBits(), chosenFBOCaps.getStencilBits(), useTexture, + 0==i && 0 == parent.getHandle() /* setupViewportScissors for surfaceless */, + fbosN-1==i /* unbind */); } fbos[0].formatToGLCapabilities(chosenFBOCaps); chosenFBOCaps.setDoubleBuffered( chosenFBOCaps.getDoubleBuffered() || samples > 0 ); @@ -233,7 +241,7 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { if(DEBUG) { System.err.println("GLFBODrawableImpl.initialize("+realize+"): "+this); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } @@ -270,7 +278,7 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { // resetQuirk fallback fbos[idx].destroy(gl); final boolean useTexture = 0 != ( FBOMODE_USE_TEXTURE & fboModeBits ); - setupFBO(gl, idx, width, height, samples, useAlpha, depthBits, stencilBits, useTexture, true); + setupFBO(gl, idx, width, height, samples, useAlpha, depthBits, stencilBits, useTexture, false, true); } private final void reset(final GL gl, int newSamples) throws GLException { @@ -284,7 +292,7 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { final boolean ctxSwitch = null != curContext && curContext != ourContext; if(DEBUG) { System.err.println("GLFBODrawableImpl.reset(newSamples "+newSamples+"): BEGIN - ctxSwitch "+ctxSwitch+", "+this); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } Throwable tFBO = null; Throwable tGL = null; diff --git a/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java b/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java index 1fb27cfcf..4d6de8d13 100644 --- a/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java +++ b/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java @@ -204,7 +204,7 @@ public class GLGraphicsConfigurationUtil { final boolean fboAvailable = GLContext.isFBOAvailable(device, glp); final boolean pbufferAvailable = factory.canCreateGLPbuffer(device, glp); - final GLRendererQuirks glrq = factory.getRendererQuirks(device); + final GLRendererQuirks glrq = factory.getRendererQuirks(device, glp); final boolean bitmapAvailable; final boolean doubleBufferAvailable; diff --git a/src/jogl/classes/jogamp/opengl/ProjectFloat.java b/src/jogl/classes/jogamp/opengl/ProjectFloat.java index 5921eb9a9..235d3eb60 100644 --- a/src/jogl/classes/jogamp/opengl/ProjectFloat.java +++ b/src/jogl/classes/jogamp/opengl/ProjectFloat.java @@ -118,6 +118,7 @@ package jogamp.opengl; import java.nio.FloatBuffer; import java.nio.IntBuffer; +import javax.media.opengl.GLException; import javax.media.opengl.fixedfunc.GLMatrixFunc; import com.jogamp.opengl.math.FloatUtil; @@ -169,8 +170,9 @@ public class ProjectFloat { * @param aspect * @param zNear * @param zFar + * @throws GLException with GL_INVALID_VALUE if zNear is <= 0, or zFar < 0, or if zNear == zFar. */ - public void gluPerspective(final GLMatrixFunc gl, final float fovy_deg, final float aspect, final float zNear, final float zFar) { + public void gluPerspective(final GLMatrixFunc gl, final float fovy_deg, final float aspect, final float zNear, final float zFar) throws GLException { gl.glMultMatrixf(FloatUtil.makePerspective(mat4Tmp1, 0, true, fovy_deg * FloatUtil.PI / 180.0f, aspect, zNear, zFar), 0); } diff --git a/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java b/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java index 93a4eb32e..bf8891a25 100644 --- a/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java +++ b/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java @@ -30,21 +30,24 @@ package jogamp.opengl; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; + import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.opengl.GLProfile; +import com.jogamp.common.ExceptionUtils; import com.jogamp.opengl.GLRendererQuirks; public class SharedResourceRunner implements Runnable { protected static final boolean DEBUG = GLDrawableImpl.DEBUG; public static interface Resource { - boolean isValid(); + boolean isAvailable(); AbstractGraphicsDevice getDevice(); AbstractGraphicsScreen getScreen(); GLDrawableImpl getDrawable(); GLContextImpl getContext(); - GLRendererQuirks getRendererQuirks(); + GLRendererQuirks getRendererQuirks(GLProfile glp); } public static interface Implementation { @@ -52,19 +55,19 @@ public class SharedResourceRunner implements Runnable { * <p> * Called within synchronized block. * </p> - * @param connection for creation a {@link AbstractGraphicsDevice} instance. + * @param device for creation a {@link AbstractGraphicsDevice} instance. * @return <code>true</code> if the device supports all protocols required for the implementation, otherwise <code>false</code>. */ - boolean isDeviceSupported(String connection); + boolean isDeviceSupported(final AbstractGraphicsDevice device); /** * <p> * Called within synchronized block. * </p> - * @param connection for creation a {@link AbstractGraphicsDevice} instance. + * @param device for creation a {@link AbstractGraphicsDevice} instance. * @return A new shared resource instance */ - Resource createSharedResource(String connection); + Resource createSharedResource(final AbstractGraphicsDevice device); /** Called within synchronized block. */ void releaseSharedResource(Resource shared); @@ -72,9 +75,9 @@ public class SharedResourceRunner implements Runnable { void clear(); /** Called within synchronized block. */ - Resource mapPut(String connection, Resource resource); + Resource mapPut(final AbstractGraphicsDevice device, final Resource resource); /** Called within synchronized block. */ - Resource mapGet(String connection); + Resource mapGet(final AbstractGraphicsDevice device); /** Called within synchronized block. */ Collection<Resource> mapValues(); } @@ -86,17 +89,17 @@ public class SharedResourceRunner implements Runnable { boolean running; boolean ready; boolean shouldRelease; - String initConnection; - String releaseConnection; + AbstractGraphicsDevice initDevice; + AbstractGraphicsDevice releaseDevice; - private boolean getDeviceTried(final String connection) { // synchronized call - return devicesTried.contains(connection); + private boolean getDeviceTried(final AbstractGraphicsDevice device) { // synchronized call + return devicesTried.contains(device.getConnection()); } - private void addDeviceTried(final String connection) { // synchronized call - devicesTried.add(connection); + private void addDeviceTried(final AbstractGraphicsDevice device) { // synchronized call + devicesTried.add(device.getConnection()); } - private void removeDeviceTried(final String connection) { // synchronized call - devicesTried.remove(connection); + private void removeDeviceTried(final AbstractGraphicsDevice device) { // synchronized call + devicesTried.remove(device.getConnection()); } public SharedResourceRunner(final Implementation impl) { @@ -110,8 +113,8 @@ public class SharedResourceRunner implements Runnable { ready = false; running = false; shouldRelease = false; - initConnection = null; - releaseConnection = null; + initDevice = null; + releaseDevice = null; } /** @@ -176,20 +179,20 @@ public class SharedResourceRunner implements Runnable { if(null != device) { synchronized (this) { start(); - final String connection = device.getConnection(); - sr = impl.mapGet(connection); + sr = impl.mapGet(device); if (null == sr) { - if ( !getDeviceTried(connection) ) { - addDeviceTried(connection); + if ( !getDeviceTried(device) ) { + addDeviceTried(device); if (DEBUG) { - System.err.println("SharedResourceRunner.getOrCreateShared() " + connection + ": trying - "+getThreadName()); + System.err.println("SharedResourceRunner.getOrCreateShared() " + device + ": trying - "+getThreadName()); + ExceptionUtils.dumpStack(System.err); } - if ( impl.isDeviceSupported(connection) ) { - doAndWait(connection, null); - sr = impl.mapGet(connection); + if ( impl.isDeviceSupported(device) ) { + doAndWait(device, null); + sr = impl.mapGet(device); } if (DEBUG) { - System.err.println("SharedResourceRunner.getOrCreateShared() " + connection + ": "+ ( ( null != sr ) ? "success" : "failed" ) +" - "+getThreadName()); + System.err.println("SharedResourceRunner.getOrCreateShared() " + device + ": "+ ( ( null != sr ) ? "success" : "failed" ) +" - "+getThreadName()); } } } @@ -202,16 +205,15 @@ public class SharedResourceRunner implements Runnable { SharedResourceRunner.Resource sr = null; if(null != device) { synchronized (this) { - final String connection = device.getConnection(); - sr = impl.mapGet(connection); + sr = impl.mapGet(device); if (null != sr) { - removeDeviceTried(connection); + removeDeviceTried(device); if (DEBUG) { - System.err.println("SharedResourceRunner.releaseShared() " + connection + ": trying - "+getThreadName()); + System.err.println("SharedResourceRunner.releaseShared() " + device + ": trying - "+getThreadName()); } - doAndWait(null, connection); + doAndWait(null, device); if (DEBUG) { - System.err.println("SharedResourceRunner.releaseShared() " + connection + ": done - "+getThreadName()); + System.err.println("SharedResourceRunner.releaseShared() " + device + ": done - "+getThreadName()); } } } @@ -219,13 +221,13 @@ public class SharedResourceRunner implements Runnable { return sr; } - private final void doAndWait(final String initConnection, final String releaseConnection) { + private final void doAndWait(final AbstractGraphicsDevice initDevice, final AbstractGraphicsDevice releaseDevice) { synchronized (this) { // wait until thread becomes ready to init new device, // pass the device and release the sync final String threadName = getThreadName(); if (DEBUG) { - System.err.println("SharedResourceRunner.doAndWait() START init: " + initConnection + ", release: "+releaseConnection+" - "+threadName); + System.err.println("SharedResourceRunner.doAndWait() START init: " + initDevice + ", release: "+releaseDevice+" - "+threadName); } while (!ready && running) { try { @@ -233,20 +235,20 @@ public class SharedResourceRunner implements Runnable { } catch (final InterruptedException ex) { } } if (DEBUG) { - System.err.println("SharedResourceRunner.doAndWait() set command: " + initConnection + ", release: "+releaseConnection+" - "+threadName); + System.err.println("SharedResourceRunner.doAndWait() set command: " + initDevice + ", release: "+releaseDevice+" - "+threadName); } - this.initConnection = initConnection; - this.releaseConnection = releaseConnection; + this.initDevice = initDevice; + this.releaseDevice = releaseDevice; this.notifyAll(); // wait until thread has init/released the device - while ( running && ( !ready || null != this.initConnection || null != this.releaseConnection ) ) { + while ( running && ( !ready || null != this.initDevice || null != this.releaseDevice ) ) { try { this.wait(); } catch (final InterruptedException ex) { } } if (DEBUG) { - System.err.println("SharedResourceRunner.initializeAndWait END init: " + initConnection + ", release: "+releaseConnection+" - "+threadName); + System.err.println("SharedResourceRunner.initializeAndWait END init: " + initDevice + ", release: "+releaseDevice+" - "+threadName); } } // done @@ -283,40 +285,40 @@ public class SharedResourceRunner implements Runnable { if (!shouldRelease) { if (DEBUG) { - System.err.println("SharedResourceRunner.run(): WOKE UP for device connection init: " + initConnection + - ", release: " + releaseConnection + " - " + threadName); + System.err.println("SharedResourceRunner.run(): WOKE UP for device connection init: " + initDevice + + ", release: " + releaseDevice + " - " + threadName); } - if(null != initConnection) { + if(null != initDevice) { if (DEBUG) { - System.err.println("SharedResourceRunner.run(): create Shared for: " + initConnection + " - " + threadName); + System.err.println("SharedResourceRunner.run(): create Shared for: " + initDevice + " - " + threadName); } Resource sr = null; try { - sr = impl.createSharedResource(initConnection); + sr = impl.createSharedResource(initDevice); } catch (final Exception e) { e.printStackTrace(); } if (null != sr) { - impl.mapPut(initConnection, sr); + impl.mapPut(initDevice, sr); } } - if(null != releaseConnection) { + if(null != releaseDevice) { if (DEBUG) { - System.err.println("SharedResourceRunner.run(): release Shared for: " + releaseConnection + " - " + threadName); + System.err.println("SharedResourceRunner.run(): release Shared for: " + releaseDevice + " - " + threadName); } - final Resource sr = impl.mapGet(releaseConnection); + final Resource sr = impl.mapGet(releaseDevice); if (null != sr) { try { impl.releaseSharedResource(sr); - impl.mapPut(releaseConnection, null); + impl.mapPut(releaseDevice, null); } catch (final Exception e) { e.printStackTrace(); } } } } - initConnection = null; - releaseConnection = null; + initDevice = null; + releaseDevice = null; } if (DEBUG) { diff --git a/src/jogl/classes/jogamp/opengl/awt/AWTTilePainter.java b/src/jogl/classes/jogamp/opengl/awt/AWTTilePainter.java index a5f5b4702..b6fa68600 100644 --- a/src/jogl/classes/jogamp/opengl/awt/AWTTilePainter.java +++ b/src/jogl/classes/jogamp/opengl/awt/AWTTilePainter.java @@ -46,6 +46,7 @@ import java.util.Map.Entry; import javax.imageio.ImageIO; import javax.media.nativewindow.util.DimensionImmutable; +import javax.media.nativewindow.util.PixelFormat; import javax.media.opengl.GL; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLCapabilitiesImmutable; @@ -288,8 +289,9 @@ public class AWTTilePainter { final int tWidth = renderer.getParam(TileRenderer.TR_TILE_WIDTH); final int tHeight = renderer.getParam(TileRenderer.TR_TILE_HEIGHT); final AWTGLPixelBufferProvider printBufferProvider = new AWTGLPixelBufferProvider( true /* allowRowStride */ ); - final GLPixelAttributes pixelAttribs = printBufferProvider.getAttributes(gl, componentCount); - tBuffer = printBufferProvider.allocate(gl, pixelAttribs, tWidth, tHeight, 1, true, 0); + final PixelFormat.Composition hostPixelComp = printBufferProvider.getHostPixelComp(gl.getGLProfile(), componentCount); + final GLPixelAttributes pixelAttribs = printBufferProvider.getAttributes(gl, componentCount, true); + tBuffer = printBufferProvider.allocate(gl, hostPixelComp, pixelAttribs, true, tWidth, tHeight, 1, 0); renderer.setTileBuffer(tBuffer); if( flipVertical ) { vFlipImage = new BufferedImage(tBuffer.width, tBuffer.height, tBuffer.image.getType()); diff --git a/src/jogl/classes/jogamp/opengl/egl/DesktopES2DynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/egl/DesktopES2DynamicLibraryBundleInfo.java index 8c6091273..245b6a945 100644 --- a/src/jogl/classes/jogamp/opengl/egl/DesktopES2DynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/egl/DesktopES2DynamicLibraryBundleInfo.java @@ -28,9 +28,12 @@ package jogamp.opengl.egl; -import java.util.*; +import java.util.ArrayList; +import java.util.List; -import jogamp.opengl.*; +import com.jogamp.opengl.egl.EGL; + +import jogamp.opengl.GLDynamicLibraryBundleInfo; /** * Implementation of the DynamicLookupHelper for Desktop ES2 (AMD, ..) @@ -56,7 +59,7 @@ public final class DesktopES2DynamicLibraryBundleInfo extends GLDynamicLibraryBu @Override public final long toolGetProcAddress(final long toolGetProcAddressHandle, final String funcName) { - return EGL.eglGetProcAddress(toolGetProcAddressHandle, funcName); + return EGLContext.eglGetProcAddress(toolGetProcAddressHandle, funcName); } @Override diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLContext.java b/src/jogl/classes/jogamp/opengl/egl/EGLContext.java index 964401244..b3c848012 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLContext.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLContext.java @@ -50,20 +50,31 @@ import javax.media.opengl.GLProfile; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLDrawableImpl; +import jogamp.opengl.egl.EGLExtImpl; +import jogamp.opengl.egl.EGLExtProcAddressTable; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.nio.Buffers; import com.jogamp.gluegen.runtime.ProcAddressTable; import com.jogamp.gluegen.runtime.opengl.GLProcAddressResolver; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; import com.jogamp.opengl.GLRendererQuirks; +import com.jogamp.opengl.egl.EGL; +import com.jogamp.opengl.egl.EGLExt; public class EGLContext extends GLContextImpl { - private boolean eglQueryStringInitialized; - private boolean eglQueryStringAvailable; - private EGLExt _eglExt; // Table that holds the addresses of the native C-language entry points for // EGL extension functions. private EGLExtProcAddressTable eglExtProcAddressTable; + private EGLExtImpl eglExtImpl; + + static final int CTX_PROFILE_COMPAT = GLContext.CTX_PROFILE_COMPAT; + static final int CTX_PROFILE_CORE = GLContext.CTX_PROFILE_CORE; + static final int CTX_PROFILE_ES = GLContext.CTX_PROFILE_ES; + + public static String getGLProfile(final int major, final int minor, final int ctp) throws GLException { + return GLContext.getGLProfile(major, minor, ctp); + } EGLContext(final GLDrawableImpl drawable, final GLContext shareWith) { @@ -72,10 +83,8 @@ public class EGLContext extends GLContextImpl { @Override protected void resetStates(final boolean isInit) { - eglQueryStringInitialized = false; - eglQueryStringAvailable = false; eglExtProcAddressTable = null; - // no inner state _eglExt = null; + eglExtImpl = null; super.resetStates(isInit); } @@ -84,11 +93,8 @@ public class EGLContext extends GLContextImpl { return getEGLExt(); } - public EGLExt getEGLExt() { - if (_eglExt == null) { - _eglExt = new EGLExtImpl(this); - } - return _eglExt; + public final EGLExt getEGLExt() { + return eglExtImpl; } @Override @@ -96,10 +102,6 @@ public class EGLContext extends GLContextImpl { return eglExtProcAddressTable; } - public final EGLExtProcAddressTable getEGLExtProcAddressTable() { - return eglExtProcAddressTable; - } - @Override protected Map<String, String> getFunctionNameMap() { return null; } @@ -140,11 +142,6 @@ public class EGLContext extends GLContextImpl { } @Override - protected long createContextARBImpl(final long share, final boolean direct, final int ctp, final int major, final int minor) { - return 0; // FIXME - } - - @Override protected void destroyContextARBImpl(final long _context) { if (!EGL.eglDestroyContext(drawable.getNativeSurface().getDisplayHandle(), _context)) { final int eglError = EGL.eglGetError(); @@ -155,14 +152,35 @@ public class EGLContext extends GLContextImpl { } } + private static final int ctx_attribs_idx_major = 0; + private static final int ctx_attribs_rom[] = { + /* 0 */ EGLExt.EGL_CONTEXT_MAJOR_VERSION_KHR, 0, // alias of EGL.EGL_CONTEXT_CLIENT_VERSION + /* 2 */ EGL.EGL_NONE, EGL.EGL_NONE, // EGLExt.EGL_CONTEXT_MINOR_VERSION_KHR + /* 4 */ EGL.EGL_NONE, EGL.EGL_NONE, // EGLExt.EGL_CONTEXT_FLAGS_KHR + /* 6 */ EGL.EGL_NONE, EGL.EGL_NONE, // EGLExt.EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR + /* 8 */ EGL.EGL_NONE, EGL.EGL_NONE, // EGLExt.EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR + /* 10 */ EGL.EGL_NONE + }; + @Override - protected boolean createImpl(final long shareWithHandle) throws GLException { + protected long createContextARBImpl(final long share, final boolean direct, final int ctp, final int reqMajor, final int reqMinor) { final EGLGraphicsConfiguration config = (EGLGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration(); - final long eglDisplay = config.getScreen().getDevice().getHandle(); - final GLProfile glProfile = drawable.getGLProfile(); + final EGLGraphicsDevice device = (EGLGraphicsDevice) config.getScreen().getDevice(); + final long eglDisplay = device.getHandle(); final long eglConfig = config.getNativeConfig(); - // 0 == EGL.EGL_NO_CONTEXT; - + final EGLDrawableFactory factory = (EGLDrawableFactory) drawable.getFactoryImpl(); + + final boolean useKHRCreateContext = !GLProfile.disableOpenGLARBContext && factory.hasDefaultDeviceKHRCreateContext(); + final boolean ctDesktopGL = 0 == ( GLContext.CTX_PROFILE_ES & ctp ); + final boolean ctBwdCompat = 0 != ( CTX_PROFILE_COMPAT & ctp ) ; + final boolean ctFwdCompat = 0 != ( CTX_OPTION_FORWARD & ctp ) ; + final boolean ctDebug = 0 != ( CTX_OPTION_DEBUG & ctp ) ; + + if(DEBUG) { + System.err.println(getThreadName() + ": EGLContext.createContextARBImpl: Start "+getGLVersion(reqMajor, reqMinor, ctp, "@creation") + + ", useKHRCreateContext "+useKHRCreateContext + + ", device "+device); + } if ( 0 == eglDisplay ) { throw new GLException("Error: attempted to create an OpenGL context without a display connection"); } @@ -170,72 +188,150 @@ public class EGLContext extends GLContextImpl { throw new GLException("Error: attempted to create an OpenGL context without a graphics configuration"); } + if( !useKHRCreateContext && ctDesktopGL ) { + if(DEBUG) { + System.err.println(getThreadName() + ": EGLContext.createContextARBImpl: DesktopGL not avail "+getGLVersion(reqMajor, reqMinor, ctp, "@creation")); + } + return 0; // n/a + } try { // might be unavailable on EGL < 1.2 - if( !EGL.eglBindAPI(EGL.EGL_OPENGL_ES_API) ) { - throw new GLException("Caught: eglBindAPI to ES failed , error "+toHexString(EGL.eglGetError())); + if( !EGL.eglBindAPI( ctDesktopGL ? EGL.EGL_OPENGL_API : EGL.EGL_OPENGL_ES_API) ) { + throw new GLException("Caught: eglBindAPI to "+(ctDesktopGL ? "ES" : "GL")+" failed , error "+toHexString(EGL.eglGetError())+" - "+getGLVersion(reqMajor, reqMinor, ctp, "@creation")); } } catch (final GLException glex) { if (DEBUG) { - glex.printStackTrace(); + ExceptionUtils.dumpThrowable("", glex); } } - // Cannot check extension 'EGL_KHR_create_context' before having one current! + final int useMajor; + if( reqMajor >= 3 && + GLRendererQuirks.existStickyDeviceQuirk( GLDrawableFactory.getEGLFactory().getDefaultDevice(), GLRendererQuirks.GLES3ViaEGLES2Config) ) { + useMajor = 2; + } else { + useMajor = reqMajor; + } + + final IntBuffer attribs = Buffers.newDirectIntBuffer(ctx_attribs_rom); + if( useKHRCreateContext ) { + attribs.put(ctx_attribs_idx_major + 1, useMajor); - final IntBuffer contextAttrsNIO; - final int contextVersionReq, contextVersionAttr; - { - if ( glProfile.usesNativeGLES3() ) { - contextVersionReq = 3; - if( GLRendererQuirks.existStickyDeviceQuirk( GLDrawableFactory.getEGLFactory().getDefaultDevice(), GLRendererQuirks.GLES3ViaEGLES2Config) ) { - contextVersionAttr = 2; + int index = ctx_attribs_idx_major + 2; + + /** if( ctDesktopGL && reqMinor >= 0 ) { // FIXME: No minor version probing for ES currently! + attribs.put(index + 0, EGLExt.EGL_CONTEXT_MINOR_VERSION_KHR); + attribs.put(index + 1, reqMinor); + index += 2; + } */ + + if( ctDesktopGL && ( useMajor > 3 || useMajor == 3 && reqMinor >= 2 ) ) { + attribs.put(index + 0, EGLExt.EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR); + if( ctBwdCompat ) { + attribs.put(index + 1, EGLExt.EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR); } else { - contextVersionAttr = 3; + attribs.put(index + 1, EGLExt.EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR); + } + index += 2; + } + int flags = 0; + if( ctDesktopGL && useMajor >= 3 && !ctBwdCompat && ctFwdCompat ) { + flags |= EGLExt.EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; + } + if( ctDebug ) { + flags |= EGLExt.EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; + } + // TODO: flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR + if( 0 != flags ) { + attribs.put(index + 0, EGLExt.EGL_CONTEXT_FLAGS_KHR); + attribs.put(index + 1, flags); + index += 2; + } + if(DEBUG) { + System.err.println(getThreadName() + ": EGLContext.createContextARBImpl: attrs.1: major "+useMajor+", flags "+toHexString(flags)+", index "+index); + } + } else { + attribs.put(ctx_attribs_idx_major + 1, useMajor); + if(DEBUG) { + System.err.println(getThreadName() + ": EGLContext.createContextARBImpl: attrs.2: major "+useMajor); + } + } + + long ctx=0; + try { + ctx = EGL.eglCreateContext(eglDisplay, eglConfig, share, attribs); + } catch (final RuntimeException re) { + if(DEBUG) { + System.err.println(getThreadName()+": Info: EGLContext.createContextARBImpl glXCreateContextAttribsARB failed with "+getGLVersion(reqMajor, reqMinor, ctp, "@creation")); + ExceptionUtils.dumpThrowable("", re); + } + } + + if(0!=ctx) { + if (!EGL.eglMakeCurrent(eglDisplay, drawable.getHandle(), drawableRead.getHandle(), ctx)) { + if(DEBUG) { + System.err.println(getThreadName()+": EGLContext.createContextARBImpl couldn't make current "+getGLVersion(reqMajor, reqMinor, ctp, "@creation")+" - error "+toHexString(EGL.eglGetError())); } + // release & destroy + EGL.eglMakeCurrent(eglDisplay, EGL.EGL_NO_SURFACE, EGL.EGL_NO_SURFACE, EGL.EGL_NO_CONTEXT); + EGL.eglDestroyContext(eglDisplay, ctx); + ctx = 0; + } else if (DEBUG) { + System.err.println(getThreadName() + ": EGLContext.createContextARBImpl: OK "+getGLVersion(reqMajor, reqMinor, ctp, "@creation")+", share "+share+", direct "+direct); + } + } else if (DEBUG) { + System.err.println(getThreadName() + ": EGLContext.createContextARBImpl: NO "+getGLVersion(reqMajor, reqMinor, ctp, "@creation")+" - error "+toHexString(EGL.eglGetError())); + } + + return ctx; + } + + @Override + protected boolean createImpl(final long shareWithHandle) throws GLException { + final EGLGraphicsConfiguration config = (EGLGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration(); + final AbstractGraphicsDevice device = config.getScreen().getDevice(); + final boolean availableGLVersionsSet = GLContext.getAvailableGLVersionsSet(device); + + if( !GLProfile.disableOpenGLARBContext && availableGLVersionsSet ) { + contextHandle = createContextARB(shareWithHandle, true); + if( 0 == contextHandle ) { + throw new GLException(getThreadName()+": Unable to create temp OpenGL context(0) on eglDevice "+device+ + ", eglConfig "+config+", "+drawable.getGLProfile()+", shareWith "+toHexString(shareWithHandle)+", error "+toHexString(EGL.eglGetError())); + } + } else { + final GLProfile glProfile = drawable.getGLProfile(); + final int reqMajor; + if ( glProfile.usesNativeGLES3() ) { + reqMajor = 3; } else if ( glProfile.usesNativeGLES2() ) { - contextVersionReq = 2; - contextVersionAttr = 2; + reqMajor = 2; } else if ( glProfile.usesNativeGLES1() ) { - contextVersionReq = 1; - contextVersionAttr = 1; + reqMajor = 1; } else { throw new GLException("Error creating OpenGL context - invalid GLProfile: "+glProfile); } - // EGLExt.EGL_CONTEXT_MAJOR_VERSION_KHR == EGL.EGL_CONTEXT_CLIENT_VERSION - final int[] contextAttrs = new int[] { EGL.EGL_CONTEXT_CLIENT_VERSION, contextVersionAttr, EGL.EGL_NONE }; - contextAttrsNIO = Buffers.newDirectIntBuffer(contextAttrs); - } - contextHandle = EGL.eglCreateContext(eglDisplay, eglConfig, shareWithHandle, contextAttrsNIO); - if (contextHandle == 0) { - throw new GLException("Error creating OpenGL context: eglDisplay "+toHexString(eglDisplay)+ - ", eglConfig "+config+", "+glProfile+", shareWith "+toHexString(shareWithHandle)+", error "+toHexString(EGL.eglGetError())); + final int ctp = GLContext.CTX_PROFILE_ES | getContextCreationFlags(); + contextHandle = createContextARBImpl(shareWithHandle, true, ctp, reqMajor, 0); + if( 0 == contextHandle ) { + throw new GLException(getThreadName()+": Unable to create temp OpenGL context(1) on eglDevice "+device+ + ", eglConfig "+config+", "+drawable.getGLProfile()+", shareWith "+toHexString(shareWithHandle)+", error "+toHexString(EGL.eglGetError())); + } + if( !setGLFunctionAvailability(true, reqMajor, 0, ctp, false /* strictMatch */, false /* withinGLVersionsMapping */) ) { + EGL.eglMakeCurrent(drawable.getNativeSurface().getDisplayHandle(), EGL.EGL_NO_SURFACE, EGL.EGL_NO_SURFACE, EGL.EGL_NO_CONTEXT); + EGL.eglDestroyContext(drawable.getNativeSurface().getDisplayHandle(), contextHandle); + contextHandle = 0; + throw new InternalError("setGLFunctionAvailability !strictMatch failed"); + } } if (DEBUG) { - System.err.println(getThreadName() + ": Created OpenGL context 0x" + + System.err.println(getThreadName() + ": EGLContext.createImpl: Created OpenGL context 0x" + Long.toHexString(contextHandle) + ",\n\twrite surface 0x" + Long.toHexString(drawable.getHandle()) + ",\n\tread surface 0x" + Long.toHexString(drawableRead.getHandle())+ ",\n\t"+this+ ",\n\tsharing with 0x" + Long.toHexString(shareWithHandle)); } - if (!EGL.eglMakeCurrent(eglDisplay, drawable.getHandle(), drawableRead.getHandle(), contextHandle)) { - throw new GLException("Error making context " + - toHexString(contextHandle) + " current: error code " + toHexString(EGL.eglGetError())); - } - if( !setGLFunctionAvailability(true, contextVersionReq, 0, CTX_PROFILE_ES, - true /* strictMatch */, // always req. strict match - false /* withinGLVersionsMapping */) ) { - if(DEBUG) { - System.err.println(getThreadName() + ": createImpl: setGLFunctionAvailability FAILED delete "+toHexString(contextHandle)); - } - EGL.eglMakeCurrent(drawable.getNativeSurface().getDisplayHandle(), EGL.EGL_NO_SURFACE, EGL.EGL_NO_SURFACE, EGL.EGL_NO_CONTEXT); - EGL.eglDestroyContext(drawable.getNativeSurface().getDisplayHandle(), contextHandle); - contextHandle = 0; - return false; - } else { - return true; - } + return true; } @Override @@ -246,8 +342,6 @@ public class EGLContext extends GLContextImpl { if (DEBUG) { System.err.println(getThreadName() + ": Initializing EGLextension address table: "+key); } - eglQueryStringInitialized = false; - eglQueryStringAvailable = false; ProcAddressTable table = null; synchronized(mappedContextTypeObjectLock) { @@ -258,31 +352,52 @@ public class EGLContext extends GLContextImpl { if(DEBUG) { System.err.println(getThreadName() + ": GLContext EGL ProcAddressTable reusing key("+key+") -> "+toHexString(table.hashCode())); } + if( null == eglExtImpl || eglExtImpl.getProcAdressTable() != eglExtProcAddressTable ) { + eglExtImpl = new EGLExtImpl(this, eglExtProcAddressTable); + } } else { eglExtProcAddressTable = new EGLExtProcAddressTable(new GLProcAddressResolver()); - resetProcAddressTable(getEGLExtProcAddressTable()); + resetProcAddressTable(eglExtProcAddressTable); synchronized(mappedContextTypeObjectLock) { - mappedGLXProcAddress.put(key, getEGLExtProcAddressTable()); + mappedGLXProcAddress.put(key, eglExtProcAddressTable); if(DEBUG) { - System.err.println(getThreadName() + ": GLContext EGL ProcAddressTable mapping key("+key+") -> "+toHexString(getEGLExtProcAddressTable().hashCode())); + System.err.println(getThreadName() + ": GLContext EGL ProcAddressTable mapping key("+key+") -> "+toHexString(eglExtProcAddressTable.hashCode())); } } + eglExtImpl = new EGLExtImpl(this, eglExtProcAddressTable); } } @Override protected final StringBuilder getPlatformExtensionsStringImpl() { + final EGLGraphicsDevice device = (EGLGraphicsDevice) drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice(); + return getPlatformExtensionsStringImpl(device); + } + final static StringBuilder getPlatformExtensionsStringImpl(final EGLGraphicsDevice device) { final StringBuilder sb = new StringBuilder(); - if (!eglQueryStringInitialized) { - eglQueryStringAvailable = getDrawableImpl().getGLDynamicLookupHelper().isFunctionAvailable("eglQueryString"); - eglQueryStringInitialized = true; - } - if (eglQueryStringAvailable) { - final String ret = EGL.eglQueryString(drawable.getNativeSurface().getDisplayHandle(), EGL.EGL_EXTENSIONS); + device.lock(); + try{ + final long handle = device.getHandle(); if (DEBUG) { - System.err.println("EGL extensions: " + ret); + System.err.println("EGL PlatformExtensions: Device "+device); + EGLDrawableFactory.dumpEGLInfo("EGL PlatformExtensions: ", handle); } - sb.append(ret); + if( device.getEGLVersion().compareTo(Version1_5) >= 0 ) { + final String ret = EGL.eglQueryString(EGL.EGL_NO_DISPLAY, EGL.EGL_EXTENSIONS); + if (DEBUG) { + System.err.println("EGL extensions (Client): " + ret); + } + sb.append(ret).append(" "); + } + if( 0 != handle ) { + final String ret = EGL.eglQueryString(handle, EGL.EGL_EXTENSIONS); + if (DEBUG) { + System.err.println("EGL extensions (Server): " + ret); + } + sb.append(ret).append(" "); + } + } finally { + device.unlock(); } return sb; } @@ -295,6 +410,16 @@ public class EGLContext extends GLContextImpl { return EGL.eglSwapInterval(drawable.getNativeSurface().getDisplayHandle(), interval); } + static long eglGetProcAddress(final long eglGetProcAddressHandle, final String procname) + { + if (0 == eglGetProcAddressHandle) { + throw new GLException("Passed null pointer for method \"eglGetProcAddress\""); + } + return dispatch_eglGetProcAddress0(procname, eglGetProcAddressHandle); + } + /** Entry point to C language function: <code> __EGLFuncPtr eglGetProcAddress(const char * procname) </code> <br>Part of <code>EGL_VERSION_1_X</code> */ + static private native long dispatch_eglGetProcAddress0(String procname, long procAddress); + // // Accessible .. // @@ -343,8 +468,8 @@ public class EGLContext extends GLContextImpl { protected static boolean getAvailableGLVersionsSet(final AbstractGraphicsDevice device) { return GLContext.getAvailableGLVersionsSet(device); } - protected static void setAvailableGLVersionsSet(final AbstractGraphicsDevice device) { - GLContext.setAvailableGLVersionsSet(device); + protected static void setAvailableGLVersionsSet(final AbstractGraphicsDevice device, final boolean set) { + GLContext.setAvailableGLVersionsSet(device, set); } protected static String toHexString(final int hex) { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java b/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java index 9499c70f4..199b20464 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java @@ -39,8 +39,11 @@ import javax.media.opengl.GLException; import jogamp.opengl.Debug; +import com.jogamp.common.ExceptionUtils; +import com.jogamp.common.nio.Buffers; import com.jogamp.common.util.LongObjectHashMap; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; +import com.jogamp.opengl.egl.EGL; /** * This implementation provides recursive calls to @@ -148,7 +151,7 @@ public class EGLDisplayUtil { if(DEBUG || verbose || openEGLDisplays.size() > 0 ) { System.err.println("EGLDisplayUtil.EGLDisplays: Shutdown (open: "+openEGLDisplays.size()+")"); if(DEBUG) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } if( openEGLDisplays.size() > 0) { dumpOpenDisplayConnections(); @@ -198,17 +201,30 @@ public class EGLDisplayUtil { * * @see EGL#eglInitialize(long, IntBuffer, IntBuffer) */ - private static synchronized boolean eglInitialize(final long eglDisplay, final IntBuffer major, final IntBuffer minor) { + private static synchronized boolean eglInitialize(final long eglDisplay, final int[] major, final int[] minor) { if( EGL.EGL_NO_DISPLAY == eglDisplay) { return false; } - final EGLDisplayRef d = EGLDisplayRef.getOrCreateOpened(eglDisplay, major, minor); + final EGLDisplayRef d = EGLDisplayRef.getOrCreateOpened(eglDisplay, _eglMajorVersion, _eglMinorVersion); + final int _major = _eglMajorVersion.get(0); + final int _minor = _eglMinorVersion.get(0); + if( null != major && null != minor ) { + if( null != d ) { + major[0] = _major; + minor[0] = _minor; + } else { + major[0] = 0; + minor[0] = 0; + } + } if(DEBUG) { - System.err.println("EGLDisplayUtil.eglInitialize("+EGLContext.toHexString(eglDisplay)+" ...): "+d+" = "+(null != d)+", singletonEGLDisplay "+singletonEGLDisplay+" (use "+useSingletonEGLDisplay+")"); + System.err.println("EGLDisplayUtil.eglInitialize("+EGLContext.toHexString(eglDisplay)+" ...): "+d+" = "+(null != d)+", eglVersion "+_major+"."+_minor+", singletonEGLDisplay "+singletonEGLDisplay+" (use "+useSingletonEGLDisplay+")"); // Thread.dumpStack(); } return null != d; } + private static final IntBuffer _eglMajorVersion = Buffers.newDirectIntBuffer(1); + private static final IntBuffer _eglMinorVersion = Buffers.newDirectIntBuffer(1); /** * @param nativeDisplayID @@ -222,7 +238,7 @@ public class EGLDisplayUtil { * @see #eglGetDisplay(long) * @see #eglInitialize(long, IntBuffer, IntBuffer) */ - private static synchronized int eglGetDisplayAndInitialize(final long nativeDisplayID, final long[] eglDisplay, final int[] eglErr, final IntBuffer major, final IntBuffer minor) { + private static synchronized int eglGetDisplayAndInitialize(final long nativeDisplayID, final long[] eglDisplay, final int[] eglErr, final int[] major, final int[] minor) { eglDisplay[0] = EGL.EGL_NO_DISPLAY; final long _eglDisplay = eglGetDisplay( nativeDisplayID ); if ( EGL.EGL_NO_DISPLAY == _eglDisplay ) { @@ -244,13 +260,15 @@ public class EGLDisplayUtil { * * @throws GLException if {@link EGL#eglGetDisplay(long)} or {@link EGL#eglInitialize(long, int[], int, int[], int)} fails incl fallback * @param nativeDisplayID in/out array of size 1, passing the requested nativeVisualID, may return a different revised nativeVisualID handle + * @param major + * @param minor * @return the initialized EGL display ID * @throws GLException if not successful */ - private static synchronized long eglGetDisplayAndInitialize(final long[] nativeDisplayID) { + private static synchronized long eglGetDisplayAndInitialize(final long[] nativeDisplayID, final int[] major, final int[] minor) { final long[] eglDisplay = new long[1]; final int[] eglError = new int[1]; - int eglRes = EGLDisplayUtil.eglGetDisplayAndInitialize(nativeDisplayID[0], eglDisplay, eglError, null, null); + int eglRes = EGLDisplayUtil.eglGetDisplayAndInitialize(nativeDisplayID[0], eglDisplay, eglError, major, minor); if( EGL.EGL_SUCCESS == eglRes ) { return eglDisplay[0]; } @@ -258,7 +276,7 @@ public class EGLDisplayUtil { if(DEBUG) { System.err.println("EGLDisplayUtil.eglGetAndInitDisplay failed with native "+EGLContext.toHexString(nativeDisplayID[0])+", error "+EGLContext.toHexString(eglRes)+"/"+EGLContext.toHexString(eglError[0])+" - fallback!"); } - eglRes = EGLDisplayUtil.eglGetDisplayAndInitialize(EGL.EGL_DEFAULT_DISPLAY, eglDisplay, eglError, null, null); + eglRes = EGLDisplayUtil.eglGetDisplayAndInitialize(EGL.EGL_DEFAULT_DISPLAY, eglDisplay, eglError, major, minor); if( EGL.EGL_SUCCESS == eglRes ) { nativeDisplayID[0] = EGL.EGL_DEFAULT_DISPLAY; return eglDisplay[0]; @@ -286,8 +304,8 @@ public class EGLDisplayUtil { private static final EGLGraphicsDevice.EGLDisplayLifecycleCallback eglLifecycleCallback = new EGLGraphicsDevice.EGLDisplayLifecycleCallback() { @Override - public long eglGetAndInitDisplay(final long[] nativeDisplayID) { - return eglGetDisplayAndInitialize(nativeDisplayID); + public long eglGetAndInitDisplay(final long[] nativeDisplayID, final int[] major, final int[] minor) { + return eglGetDisplayAndInitialize(nativeDisplayID, major, minor); } @Override public void eglTerminate(final long eglDisplayHandle) { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java index bacf9f18e..5b080a183 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java @@ -36,114 +36,66 @@ package jogamp.opengl.egl; -import java.nio.IntBuffer; - -import javax.media.nativewindow.NativeSurface; -import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.ProxySurface; import javax.media.opengl.GLContext; import javax.media.opengl.GLException; +import jogamp.nativewindow.ProxySurfaceImpl; import jogamp.opengl.GLDrawableImpl; import jogamp.opengl.GLDynamicLookupHelper; -import com.jogamp.common.nio.Buffers; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; +import com.jogamp.opengl.egl.EGL; -public abstract class EGLDrawable extends GLDrawableImpl { +public class EGLDrawable extends GLDrawableImpl { + static boolean DEBUG = GLDrawableImpl.DEBUG; - protected EGLDrawable(final EGLDrawableFactory factory, final NativeSurface component) throws GLException { + protected EGLDrawable(final EGLDrawableFactory factory, final EGLSurface component) throws GLException { super(factory, component, false); } @Override - public abstract GLContext createContext(GLContext shareWith); - - protected abstract long createSurface(EGLGraphicsConfiguration config, int width, int height, long nativeSurfaceHandle); - - private final long createEGLSurface() { - final EGLWrappedSurface eglws = (EGLWrappedSurface) surface; - final EGLGraphicsConfiguration eglConfig = (EGLGraphicsConfiguration) eglws.getGraphicsConfiguration(); - final NativeSurface upstreamSurface = eglws.getUpstreamSurface(); - - long eglSurface = createSurface(eglConfig, eglws.getSurfaceWidth(), eglws.getSurfaceHeight(), upstreamSurface.getSurfaceHandle()); - - int eglError0; - if (EGL.EGL_NO_SURFACE == eglSurface) { - eglError0 = EGL.eglGetError(); - if(EGL.EGL_BAD_NATIVE_WINDOW == eglError0) { - // Try window handle if available and differs (Windows HDC / HWND). - // ANGLE impl. required HWND on Windows. - if(upstreamSurface instanceof NativeWindow) { - final NativeWindow nw = (NativeWindow) upstreamSurface; - if(nw.getWindowHandle() != nw.getSurfaceHandle()) { - 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, eglws.getSurfaceWidth(), eglws.getSurfaceHeight(), nw.getWindowHandle()); - if (EGL.EGL_NO_SURFACE == eglSurface) { - eglError0 = EGL.eglGetError(); - } - } - } - } - } else { - eglError0 = EGL.EGL_SUCCESS; - } - 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() + ": createEGLSurface handle "+toHexString(eglSurface)); - } - return eglSurface; + public final GLContext createContext(final GLContext shareWith) { + return new EGLContext(this, shareWith); } @Override protected final void createHandle() { - final EGLWrappedSurface eglws = (EGLWrappedSurface) surface; + final EGLSurface eglSurf = (EGLSurface) surface; if(DEBUG) { - System.err.println(getThreadName() + ": createHandle of "+eglws); + System.err.println(getThreadName() + ": createHandle of "+eglSurf); + ProxySurfaceImpl.dumpHierarchy(System.err, eglSurf); } - 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); + if( eglSurf.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) { + if( EGL.EGL_NO_SURFACE != eglSurf.getSurfaceHandle() ) { + throw new InternalError("Set surface but claimed to be invalid: "+eglSurf); + } + if( !eglSurf.containsUpstreamOptionBits( ProxySurface.OPT_UPSTREAM_SURFACELESS ) ) { + eglSurf.setEGLSurfaceHandle(); } - eglws.setSurfaceHandle( createEGLSurface() ); - } else if( EGL.EGL_NO_SURFACE == eglws.getSurfaceHandle() ) { - throw new InternalError("Nil surface but claimed to be valid: "+eglws); + } else if( EGL.EGL_NO_SURFACE == eglSurf.getSurfaceHandle() ) { + throw new InternalError("Nil surface but claimed to be valid: "+eglSurf); } } @Override protected void destroyHandle() { - final EGLWrappedSurface eglws = (EGLWrappedSurface) surface; + final EGLSurface eglSurf = (EGLSurface) surface; + final long eglSurfHandle = eglSurf.getSurfaceHandle(); if(DEBUG) { - System.err.println(getThreadName() + ": destroyHandle of "+eglws); + System.err.println(getThreadName() + ": destroyHandle of "+eglSurf); } - 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(final long eglDisplayHandle, final long surfaceHandle) { - if( 0 == surfaceHandle ) { - return false; + if( !eglSurf.containsUpstreamOptionBits( ProxySurface.OPT_UPSTREAM_SURFACELESS ) && + EGL.EGL_NO_SURFACE == eglSurfHandle ) { + throw new InternalError("Nil surface but claimed to be valid: "+eglSurf); } - 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)); + final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) eglSurf.getGraphicsConfiguration().getScreen().getDevice(); + if( eglSurf.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) { + if( EGL.EGL_NO_SURFACE != eglSurfHandle ) { + EGL.eglDestroySurface(eglDevice.getHandle(), eglSurfHandle); + eglSurf.setSurfaceHandle(EGL.EGL_NO_SURFACE); } } - return eglSurfaceValid; } @Override diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java index 2edb22314..967bcb6da 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java @@ -40,7 +40,6 @@ import java.nio.IntBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; @@ -66,7 +65,6 @@ import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; import jogamp.common.os.PlatformPropsImpl; -import jogamp.nativewindow.WrappedSurface; import jogamp.opengl.Debug; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLDrawableFactoryImpl; @@ -75,13 +73,18 @@ import jogamp.opengl.GLDynamicLookupHelper; import jogamp.opengl.GLGraphicsConfigurationUtil; import jogamp.opengl.SharedResourceRunner; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.nio.Buffers; import com.jogamp.common.nio.PointerBuffer; +import com.jogamp.common.os.DynamicLookupHelper; import com.jogamp.common.os.Platform; import com.jogamp.common.util.PropertyAccess; import com.jogamp.common.util.ReflectionUtil; +import com.jogamp.common.util.VersionNumber; +import com.jogamp.nativewindow.GenericUpstreamSurfacelessHook; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; import com.jogamp.opengl.GLRendererQuirks; +import com.jogamp.opengl.egl.EGL; public class EGLDrawableFactory extends GLDrawableFactoryImpl { protected static final boolean DEBUG = GLDrawableFactoryImpl.DEBUG; // allow package access @@ -93,8 +96,10 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { QUERY_EGL_ES_NATIVE_TK = PropertyAccess.isPropertyDefined("jogl.debug.EGLDrawableFactory.QueryNativeTK", true); } + private static boolean eglDynamicLookupHelperInit = false; private static GLDynamicLookupHelper eglES1DynamicLookupHelper = null; private static GLDynamicLookupHelper eglES2DynamicLookupHelper = null; + private static GLDynamicLookupHelper eglGLnDynamicLookupHelper = null; private static final boolean isANGLE(final GLDynamicLookupHelper dl) { if(Platform.OSType.WINDOWS == PlatformPropsImpl.OS_TYPE) { @@ -112,50 +117,100 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { dl.isFunctionAvailable("glColorPointer"); } - public EGLDrawableFactory() { - super(); - - // Register our GraphicsConfigurationFactory implementations - // The act of constructing them causes them to be registered - EGLGraphicsConfigurationFactory.registerFactory(); + private static class EGLFeatures { + public final String vendor; + public final VersionNumber version; + public final boolean hasGLAPI; + public final boolean hasKHRCreateContext; + public final boolean hasKHRSurfaceless; - // Check for other underlying stuff .. - if(NativeWindowFactory.TYPE_X11 == NativeWindowFactory.getNativeWindowType(true)) { - hasX11 = true; - try { - ReflectionUtil.createInstance("jogamp.opengl.x11.glx.X11GLXGraphicsConfigurationFactory", EGLDrawableFactory.class.getClassLoader()); - } catch (final Exception jre) { /* n/a .. */ } + public EGLFeatures(final EGLGraphicsDevice device) { + final long eglDisplay = device.getHandle(); + vendor = EGL.eglQueryString(eglDisplay, EGL.EGL_VENDOR); + if(DEBUG) { + System.err.println("EGLFeatures on device "+device+", vendor "+vendor); + } + version = device.getEGLVersion(); + final boolean hasEGL_1_4 = version.compareTo(GLContext.Version1_4) >= 0; + final boolean hasEGL_1_5 = version.compareTo(GLContext.Version1_5) >= 0; + { + final String eglClientAPIStr = EGL.eglQueryString(eglDisplay, EGL.EGL_CLIENT_APIS); + final String[] eglClientAPIs = eglClientAPIStr.split("\\s"); + boolean _hasGLAPI = false; + for(int i=eglClientAPIs.length-1; i>=0; i--) { + _hasGLAPI = eglClientAPIs[i].equals("OpenGL"); + } + hasGLAPI = _hasGLAPI; + if(DEBUG) { + System.err.println(" Client APIs: "+eglClientAPIStr+"; has OpenGL "+hasGLAPI); + } + } + { + final String extensions = EGLContext.getPlatformExtensionsStringImpl(device).toString(); + if( hasEGL_1_5 ) { + // subsumed in EGL 1.5 + hasKHRCreateContext = true; + hasKHRSurfaceless = true; + } else { + if( hasEGL_1_4 ) { + hasKHRCreateContext = extensions.contains("EGL_KHR_create_context"); + } else { + hasKHRCreateContext = false; + } + hasKHRSurfaceless = extensions.contains("EGL_KHR_surfaceless_context"); + } + if(DEBUG) { + System.err.println(" Extensions: "+extensions); + System.err.println(" KHR_create_context: "+hasKHRCreateContext); + System.err.println(" KHR_surfaceless_context: "+hasKHRSurfaceless); + } + } + } + public final String toString() { + return "EGLFeatures[vendor "+vendor+", version "+version+ + ", has[GL-API "+hasGLAPI+", KHR[CreateContext "+hasKHRCreateContext+", Surfaceless "+hasKHRSurfaceless+"]]]"; } + } + + static class EGLAcc extends EGL { + protected static boolean resetProcAddressTable(final DynamicLookupHelper lookup) { + return EGL.resetProcAddressTable(lookup); + } + } + static final String eglInitializeFuncName = "eglInitialize"; - // FIXME: Probably need to move EGL from a static model - // to a dynamic one, where there can be 2 instances - // for each ES profile with their own ProcAddressTable. + public EGLDrawableFactory() { + super(); synchronized(EGLDrawableFactory.class) { - final boolean hasDesktopES2 = null != eglES2DynamicLookupHelper; + if( eglDynamicLookupHelperInit ) { + return; + } + eglDynamicLookupHelperInit = true; - if(!hasDesktopES2 && null==eglES1DynamicLookupHelper) { - GLDynamicLookupHelper tmp=null; + // Check for other underlying stuff .. + if(NativeWindowFactory.TYPE_X11 == NativeWindowFactory.getNativeWindowType(true)) { + hasX11 = true; try { - tmp = new GLDynamicLookupHelper(new EGLES1DynamicLibraryBundleInfo()); - } catch (final GLException gle) { - if(DEBUG) { - gle.printStackTrace(); - } - } - if(null!=tmp && tmp.isLibComplete()) { - eglES1DynamicLookupHelper = tmp; - EGL.resetProcAddressTable(eglES1DynamicLookupHelper); - final boolean isANGLEES1 = isANGLE(eglES1DynamicLookupHelper); - isANGLE |= isANGLEES1; - if (DEBUG || GLProfile.DEBUG) { - System.err.println("Info: EGLDrawableFactory: EGL ES1 - OK, isANGLE: "+isANGLEES1); - } - } else if (DEBUG || GLProfile.DEBUG) { - System.err.println("Info: EGLDrawableFactory: EGL ES1 - NOPE (ES1 lib)"); - } + ReflectionUtil.createInstance("jogamp.opengl.x11.glx.X11GLXGraphicsConfigurationFactory", EGLDrawableFactory.class.getClassLoader()); + } catch (final Exception jre) { /* n/a .. */ } } - if(!hasDesktopES2 && null==eglES2DynamicLookupHelper) { + + /** + * FIXME: Probably need to move EGL from a static model + * to a dynamic one, where there can be 2 instances + * for each ES profile with their own ProcAddressTable. + * + * Since EGL is designed to be static + * we validate the function address of 'eglInitialize' + * with all EGL/ES and EGL/GL combinations. + * In case this address doesn't match the primary tuple EGL/ES2 + * the profile is skipped! + */ + boolean eglTableReset = false; + long eglInitializeAddress = 0; + // Setup: eglES2DynamicLookupHelper[, eglES1DynamicLookupHelper] + { GLDynamicLookupHelper tmp=null; try { tmp = new GLDynamicLookupHelper(new EGLES2DynamicLibraryBundleInfo()); @@ -164,9 +219,9 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { gle.printStackTrace(); } } - if(null!=tmp && tmp.isLibComplete()) { + if( null != tmp && tmp.isLibComplete() && true == ( eglTableReset = EGLAcc.resetProcAddressTable(tmp) ) ) { + eglInitializeAddress = tmp.dynamicLookupFunction(eglInitializeFuncName); eglES2DynamicLookupHelper = tmp; - EGL.resetProcAddressTable(eglES2DynamicLookupHelper); final boolean includesES1 = null == eglES1DynamicLookupHelper && includesES1(eglES2DynamicLookupHelper); if(includesES1) { eglES1DynamicLookupHelper = tmp; @@ -174,7 +229,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { final boolean isANGLEES2 = isANGLE(eglES2DynamicLookupHelper); isANGLE |= isANGLEES2; if (DEBUG || GLProfile.DEBUG) { - System.err.println("Info: EGLDrawableFactory: EGL ES2 - OK (includesES1 "+includesES1+", isANGLE: "+isANGLEES2+")"); + System.err.println("Info: EGLDrawableFactory: EGL ES2 - OK (includesES1 "+includesES1+", isANGLE: "+isANGLEES2+", eglInitialize 0x"+Long.toHexString(eglInitializeAddress)+")"); if(includesES1) { System.err.println("Info: EGLDrawableFactory: EGL ES1 - OK (ES2 lib)"); } @@ -183,7 +238,85 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { System.err.println("Info: EGLDrawableFactory: EGL ES2 - NOPE"); } } - if( null != eglES2DynamicLookupHelper || null != eglES1DynamicLookupHelper ) { + // Setup: eglES1DynamicLookupHelper + if( null == eglES1DynamicLookupHelper ) { + GLDynamicLookupHelper tmp=null; + try { + tmp = new GLDynamicLookupHelper(new EGLES1DynamicLibraryBundleInfo()); + } catch (final GLException gle) { + if(DEBUG) { + gle.printStackTrace(); + } + } + if( null != tmp && tmp.isLibComplete() ) { + final boolean ok; + final long _eglInitializeAddress; + if( !eglTableReset ) { + if( true == ( eglTableReset = EGLAcc.resetProcAddressTable(tmp) ) ) { + _eglInitializeAddress = tmp.dynamicLookupFunction(eglInitializeFuncName); + eglInitializeAddress = _eglInitializeAddress; + ok = true; + } else { + _eglInitializeAddress = 0; + ok = false; + } + } else { + _eglInitializeAddress = tmp.dynamicLookupFunction(eglInitializeFuncName); + ok = _eglInitializeAddress == eglInitializeAddress; + } + if( ok ) { + eglES1DynamicLookupHelper = tmp; + final boolean isANGLEES1 = isANGLE(eglES1DynamicLookupHelper); + isANGLE |= isANGLEES1; + if (DEBUG || GLProfile.DEBUG) { + System.err.println("Info: EGLDrawableFactory: EGL ES1 - OK (isANGLE: "+isANGLEES1+", eglTableReset "+eglTableReset+", eglInitialize 0x"+Long.toHexString(_eglInitializeAddress)+")"); + } + } else if (DEBUG || GLProfile.DEBUG) { + System.err.println("Info: EGLDrawableFactory: EGL ES1 - NOPE (ES1 proc, eglTableReset "+eglTableReset+", eglInitialize 0x"+Long.toHexString(_eglInitializeAddress)+")"); + } + } else if (DEBUG || GLProfile.DEBUG) { + System.err.println("Info: EGLDrawableFactory: EGL ES1 - NOPE (ES1 lib)"); + } + } + // Setup: eglGLnDynamicLookupHelper + if( null == eglGLnDynamicLookupHelper ) { + GLDynamicLookupHelper tmp=null; + try { + tmp = new GLDynamicLookupHelper(new EGLGLnDynamicLibraryBundleInfo()); + } catch (final GLException gle) { + if(DEBUG) { + gle.printStackTrace(); + } + } + if( null != tmp && tmp.isLibComplete() ) { + final boolean ok; + final long _eglInitializeAddress; + if( !eglTableReset ) { + if( true == ( eglTableReset = EGLAcc.resetProcAddressTable(tmp) ) ) { + _eglInitializeAddress = tmp.dynamicLookupFunction(eglInitializeFuncName); + eglInitializeAddress = _eglInitializeAddress; + ok = true; + } else { + _eglInitializeAddress = 0; + ok = false; + } + } else { + _eglInitializeAddress = tmp.dynamicLookupFunction(eglInitializeFuncName); + ok = _eglInitializeAddress == eglInitializeAddress; + } + if( ok ) { + eglGLnDynamicLookupHelper = tmp; + if (DEBUG || GLProfile.DEBUG) { + System.err.println("Info: EGLDrawableFactory: EGL GLn - OK (eglTableReset "+eglTableReset+", eglInitialize 0x"+Long.toHexString(_eglInitializeAddress)+")"); + } + } else if (DEBUG || GLProfile.DEBUG) { + System.err.println("Info: EGLDrawableFactory: EGL GLn - NOPE (GLn proc, eglTableReset "+eglTableReset+", eglInitialize 0x"+Long.toHexString(_eglInitializeAddress)+")"); + } + } else if (DEBUG || GLProfile.DEBUG) { + System.err.println("Info: EGLDrawableFactory: EGL GLn - NOPE (GLn lib)"); + } + } + if( null != eglES2DynamicLookupHelper || null != eglES1DynamicLookupHelper || null != eglGLnDynamicLookupHelper ) { if(isANGLE && !GLProfile.enableANGLE) { if(DEBUG || GLProfile.DEBUG) { System.err.println("Info: EGLDrawableFactory.init - EGL/ES2 ANGLE disabled"); @@ -192,13 +325,22 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { if( isANGLE && ( DEBUG || GLProfile.DEBUG ) ) { System.err.println("Info: EGLDrawableFactory.init - EGL/ES2 ANGLE enabled"); } - sharedMap = new HashMap<String /*uniqueKey*/, SharedResource>(); - sharedMapCreateAttempt = new HashSet<String>(); + // Register our GraphicsConfigurationFactory implementations + // The act of constructing them causes them to be registered + EGLGraphicsConfigurationFactory.registerFactory(); + + sharedMap = new HashMap<String, SharedResourceRunner.Resource>(); + // FIXME: defaultDevice.open() triggers eglInitialize(..) which crashed on Windows w/ Chrome/ANGLE, FF/ANGLE! defaultDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(EGL.EGL_DEFAULT_DISPLAY, AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); + + // Init shared resources off thread + // Will be released via ShutdownHook + sharedResourceRunner = new SharedResourceRunner(new SharedResourceImplementation()); + sharedResourceRunner.start(); } } - } + } // synchronized(EGLDrawableFactory.class) } @Override @@ -212,26 +354,15 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { if( DEBUG ) { System.err.println("EGLDrawableFactory.shutdown"); } + if(null != sharedResourceRunner) { + sharedResourceRunner.stop(); + sharedResourceRunner = null; + } if(null != sharedMap) { - if(DEBUG) { - dumpMap(); - } - final Collection<SharedResource> srl = sharedMap.values(); - for(final Iterator<SharedResource> sri = srl.iterator(); sri.hasNext(); ) { - final SharedResource sr = sri.next(); - if(DEBUG) { - System.err.println("EGLDrawableFactory.shutdown: "+sr.device.toString()); - } - sr.device.close(); - } sharedMap.clear(); - sharedMapCreateAttempt.clear(); sharedMap = null; - sharedMapCreateAttempt = null; - } - if(null != defaultSharedResource) { - defaultSharedResource = null; } + if(null != defaultDevice) { defaultDevice.close(); defaultDevice = null; @@ -247,6 +378,10 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { // eglES2DynamicLookupHelper.destroy(); eglES2DynamicLookupHelper = null; } + if(null != eglGLnDynamicLookupHelper) { + // eglGLDynamicLookupHelper.destroy(); + eglGLnDynamicLookupHelper = null; + } EGLGraphicsConfigurationFactory.unregisterFactory(); EGLDisplayUtil.shutdown(DEBUG); } @@ -258,65 +393,59 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { final Set<String> keys = sharedMap.keySet(); for(final Iterator<String> keyI = keys.iterator(); keyI.hasNext(); i++) { final String key = keyI.next(); - final SharedResource sr = sharedMap.get(key); - System.err.println("EGLDrawableFactory.map["+i+"] "+key+" -> "+sr.getDevice()+", "+ - "es1 [avail "+sr.wasES1ContextCreated+", pbuffer "+sr.hasPBufferES1+", quirks "+sr.rendererQuirksES1+", ctp "+EGLContext.getGLVersion(1, 0, sr.ctpES1, null)+"], "+ - "es2/3 [es2 "+sr.wasES2ContextCreated+", es3 "+sr.wasES3ContextCreated+", [pbuffer "+sr.hasPBufferES3ES2+", quirks "+sr.rendererQuirksES3ES2+", ctp "+EGLContext.getGLVersion(2, 0, sr.ctpES3ES2, null)+"]]"); + final SharedResource sr = (SharedResource) sharedMap.get(key); + System.err.println("EGLDrawableFactory.map["+i+"] "+key+" -> "+sr.getDevice()+", avail "+sr.isAvailable+ + "gln [quirks "+sr.rendererQuirksGLn+", ctp "+EGLContext.getGLVersion(3, 0, sr.ctpGLn, null)+"], "+ + "es1 [quirks "+sr.rendererQuirksES1+", ctp "+EGLContext.getGLVersion(1, 0, sr.ctpES1, null)+"], "+ + "es2/3 [quirks "+sr.rendererQuirksES3ES2+", ctp "+EGLContext.getGLVersion(2, 0, sr.ctpES3ES2, null)+"]"); } ; } } - private HashMap<String /*uniqueKey*/, SharedResource> sharedMap = null; - private HashSet<String> sharedMapCreateAttempt = null; - private EGLGraphicsDevice defaultDevice = null; - private SharedResource defaultSharedResource = null; private boolean isANGLE = false; private boolean hasX11 = false; + private EGLGraphicsDevice defaultDevice = null; + private EGLFeatures defaultDeviceEGLFeatures; + private SharedResourceRunner sharedResourceRunner; + private HashMap<String /* uniqueKey */, SharedResourceRunner.Resource> sharedMap; static class SharedResource implements SharedResourceRunner.Resource { - private final EGLGraphicsDevice device; + private EGLGraphicsDevice device; // private final EGLContext contextES1; // private final EGLContext contextES2; // private final EGLContext contextES3; - private final boolean wasES1ContextCreated; - private final boolean wasES2ContextCreated; - private final boolean wasES3ContextCreated; - private final GLRendererQuirks rendererQuirksES1; - private final GLRendererQuirks rendererQuirksES3ES2; - private final int ctpES1; - private final int ctpES3ES2; - private final boolean hasPBufferES1; - private final boolean hasPBufferES3ES2; - - SharedResource(final EGLGraphicsDevice dev, - final boolean wasContextES1Created, final boolean hasPBufferES1, final GLRendererQuirks rendererQuirksES1, final int ctpES1, - final boolean wasContextES2Created, final boolean wasContextES3Created, - final boolean hasPBufferES3ES2, final GLRendererQuirks rendererQuirksES3ES2, final int ctpES3ES2) { + final boolean isAvailable; + final GLRendererQuirks rendererQuirksGLn; + final GLRendererQuirks rendererQuirksES1; + final GLRendererQuirks rendererQuirksES3ES2; + final int ctpGLn; + final int ctpES1; + final int ctpES3ES2; + + SharedResource(final EGLGraphicsDevice dev, final boolean isAvailable, + final GLRendererQuirks rendererQuirksGLn, final int ctpGLn, + final GLRendererQuirks rendererQuirksES1, final int ctpES1, + final GLRendererQuirks rendererQuirksES3ES2, final int ctpES3ES2) { this.device = dev; - // this.contextES1 = ctxES1; - this.wasES1ContextCreated = wasContextES1Created; - this.hasPBufferES1= hasPBufferES1; + this.isAvailable = isAvailable; + + this.rendererQuirksGLn = rendererQuirksGLn; + this.ctpGLn = ctpGLn; + this.rendererQuirksES1 = rendererQuirksES1; this.ctpES1 = ctpES1; - // this.contextES2 = ctxES2; - // this.contextES3 = ctxES3; - this.wasES2ContextCreated = wasContextES2Created; - this.wasES3ContextCreated = wasContextES3Created; - this.hasPBufferES3ES2= hasPBufferES3ES2; this.rendererQuirksES3ES2 = rendererQuirksES3ES2; this.ctpES3ES2 = ctpES3ES2; } + @Override - public final boolean isValid() { - return wasES1ContextCreated || wasES2ContextCreated || wasES3ContextCreated; + public final boolean isAvailable() { + return isAvailable; } @Override public final EGLGraphicsDevice getDevice() { return device; } - // final EGLContext getContextES1() { return contextES1; } - // final EGLContext getContextES2() { return contextES2; } - // final EGLContext getContextES3() { return contextES3; } @Override public AbstractGraphicsScreen getScreen() { @@ -331,368 +460,424 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { return null; } @Override - public GLRendererQuirks getRendererQuirks() { - return null != rendererQuirksES3ES2 ? rendererQuirksES3ES2 : rendererQuirksES1 ; + public GLRendererQuirks getRendererQuirks(final GLProfile glp) { + if( null == glp ) { + if( null != rendererQuirksES3ES2 ) { + return rendererQuirksES3ES2; + } else if( null != rendererQuirksES1 ) { + return rendererQuirksES1; + } else { + return rendererQuirksGLn; + } + } else if( !glp.isGLES() ) { + return rendererQuirksGLn; + } else if( glp.isGLES1() ) { + return rendererQuirksES1; + } else { + return rendererQuirksES3ES2; + } } - } - - @Override - public final AbstractGraphicsDevice getDefaultDevice() { - return defaultDevice; - } + } - @Override - public final boolean getIsDeviceCompatible(final AbstractGraphicsDevice device) { - // via mappings (X11/WGL/.. -> EGL) we shall be able to handle all types. - return null != sharedMap ; // null!=eglES2DynamicLookupHelper || null!=eglES1DynamicLookupHelper; - } + class SharedResourceImplementation implements SharedResourceRunner.Implementation { + @Override + public void clear() { + sharedMap.clear(); + } + @Override + public SharedResourceRunner.Resource mapPut(final AbstractGraphicsDevice device, final SharedResourceRunner.Resource resource) { + return sharedMap.put(device.getConnection(), resource); + } + @Override + public SharedResourceRunner.Resource mapGet(final AbstractGraphicsDevice device) { + return sharedMap.get(device.getConnection()); + } + @Override + public Collection<SharedResourceRunner.Resource> mapValues() { + return sharedMap.values(); + } - private static List<GLCapabilitiesImmutable> getAvailableEGLConfigs(final EGLGraphicsDevice eglDisplay, final 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())); + @Override + public boolean isDeviceSupported(final AbstractGraphicsDevice device) { + return null != sharedMap; // null != eglES2DynamicLookupHelper || null != eglES1DynamicLookupHelper } - 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 */, false /* onlyFirstValid */); + + @Override + public SharedResourceRunner.Resource createSharedResource(final AbstractGraphicsDevice adevice) { + adevice.lock(); + try { + return createEGLSharedResourceImpl(adevice); + } catch (final Throwable t) { + throw new GLException("EGLGLXDrawableFactory - Could not initialize shared resources for "+adevice, t); + } finally { + adevice.unlock(); } } - return new ArrayList<GLCapabilitiesImmutable>(0); - } - private static void dumpEGLInfo(final String prefix, final long eglDisplay) { - final String eglVendor = EGL.eglQueryString(eglDisplay, EGL.EGL_VENDOR); - final String eglClientAPIs = EGL.eglQueryString(eglDisplay, EGL.EGL_CLIENT_APIS); - final String eglVersion = EGL.eglQueryString(eglDisplay, EGL.EGL_VERSION); - System.err.println(prefix+"EGL vendor "+eglVendor+", version "+eglVersion+", clientAPIs "+eglClientAPIs); - } - - private boolean mapAvailableEGLESConfig(final AbstractGraphicsDevice adevice, final int[] esProfile, - final boolean[] hasPBuffer, final GLRendererQuirks[] rendererQuirks, final int[] ctp) { - final String profileString; - switch( esProfile[0] ) { - 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[0]); - } - if ( !GLProfile.isAvailable(adevice, profileString) ) { - if( DEBUG ) { - System.err.println("EGLDrawableFactory.mapAvailableEGLESConfig: "+profileString+" n/a on "+adevice); + private SharedResource createEGLSharedResourceImpl(final AbstractGraphicsDevice adevice) { + final GLRendererQuirks[] rendererQuirksES1 = new GLRendererQuirks[] { null }; + final GLRendererQuirks[] rendererQuirksES3ES2 = new GLRendererQuirks[] { null }; + final GLRendererQuirks[] rendererQuirksGLn = new GLRendererQuirks[] { null }; + final int[] ctpES1 = new int[] { EGLContext.CTX_PROFILE_ES }; + final int[] ctpES3ES2 = new int[] { EGLContext.CTX_PROFILE_ES }; + final int[] ctpGLn = new int[] { EGLContext.CTX_PROFILE_CORE }; + + if (DEBUG) { + System.err.println("EGLDrawableFactory.createShared(): device "+adevice); } - return false; - } - final GLProfile glp = GLProfile.get(adevice, profileString) ; - final GLDrawableFactoryImpl desktopFactory = (GLDrawableFactoryImpl) GLDrawableFactory.getDesktopFactory(); - final boolean initDefaultDevice = 0 == defaultDevice.getHandle(); // Note: GLProfile always triggers EGL device initialization first! - final boolean mapsADeviceToDefaultDevice = !QUERY_EGL_ES_NATIVE_TK || initDefaultDevice || - null == desktopFactory || adevice instanceof EGLGraphicsDevice ; - if( DEBUG ) { - System.err.println("EGLDrawableFactory.mapAvailableEGLESConfig: "+profileString+" ( "+esProfile[0]+" ), "+ - "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, .. - ProxySurface downstreamSurface = null; // EGL - boolean success = 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. - if( initDefaultDevice ) { - defaultDevice.open(); - - // Probe for GLRendererQuirks.SingletonEGLDisplayOnly - final long secondEGLDisplay = EGL.eglGetDisplay(EGL.EGL_DEFAULT_DISPLAY); - if ( EGL.EGL_NO_DISPLAY == secondEGLDisplay ) { - final int[] quirks = { GLRendererQuirks.SingletonEGLDisplayOnly }; - GLRendererQuirks.addStickyDeviceQuirks(adevice, quirks, 0, 1); - EGLDisplayUtil.setSingletonEGLDisplayOnly(true); - if(DEBUG) { - System.err.println("Quirk: "+GLRendererQuirks.toString(quirks[0])+": cause: Second eglGetDisplay(EGL_DEFAULT_DISPLAY) failed"); + + boolean madeCurrentES1 = false; + boolean madeCurrentES2 = false; + boolean madeCurrentES3 = false; + boolean madeCurrentGLn = false; + + if( null != eglGLnDynamicLookupHelper ) { + // OpenGL 3.1 core -> GL3 + final int[] major = { 3 }; + final int[] minor = { 1 }; // FIXME: No minor version probing for ES currently! + madeCurrentGLn = mapAvailableEGLESConfig(adevice, major, minor, + ctpGLn, rendererQuirksGLn) && 0 != major[0]; + } else { + madeCurrentGLn = false; + } + if( null != eglES1DynamicLookupHelper ) { + final int[] major = { 1 }; + final int[] minor = { 0 }; + madeCurrentES1 = mapAvailableEGLESConfig(adevice, major, minor, + ctpES1, rendererQuirksES1) && 1 == major[0]; + } else { + madeCurrentES1 = false; + } + if( null != eglES2DynamicLookupHelper ) { + // ES3 Query + final int[] major = { 3 }; + final int[] minor = { 0 }; + madeCurrentES3 = mapAvailableEGLESConfig(adevice, major, minor, + ctpES3ES2, rendererQuirksES3ES2) && 3 == major[0]; + if( !madeCurrentES3 ) { + // ES2 Query, may result in ES3 + major[0] = 2; + if( mapAvailableEGLESConfig(adevice, major, minor, + ctpES3ES2, rendererQuirksES3ES2) ) + { + switch( major[0] ) { + case 2: madeCurrentES2 = true; break; + case 3: madeCurrentES3 = true; break; + default: throw new InternalError("XXXX Got "+major[0]); } } } + } + + if( !EGLContext.getAvailableGLVersionsSet(adevice) ) { + // Even though we override the non EGL native mapping intentionally, + // avoid exception due to double 'set' - careful exception of the rule. + EGLContext.setAvailableGLVersionsSet(adevice, true); + } + if( hasX11 ) { + handleDontCloseX11DisplayQuirk(rendererQuirksES1[0]); + handleDontCloseX11DisplayQuirk(rendererQuirksES3ES2[0]); + } + final SharedResource sr = new SharedResource(defaultDevice, + madeCurrentGLn || madeCurrentES1 || madeCurrentES2 || madeCurrentES3, + rendererQuirksGLn[0], ctpGLn[0], + rendererQuirksES1[0], ctpES1[0], + rendererQuirksES3ES2[0], ctpES3ES2[0]); + + if (DEBUG) { + System.err.println("EGLDrawableFactory.createShared: devices: queried nativeTK "+QUERY_EGL_ES_NATIVE_TK+", adevice " + adevice + ", defaultDevice " + defaultDevice); + System.err.println("EGLDrawableFactory.createShared: context GLn: " + madeCurrentGLn + ", quirks "+rendererQuirksGLn[0]); + System.err.println("EGLDrawableFactory.createShared: context ES1: " + madeCurrentES1 + ", quirks "+rendererQuirksES1[0]); + System.err.println("EGLDrawableFactory.createShared: context ES2: " + madeCurrentES2 + ", quirks "+rendererQuirksES3ES2[0]); + System.err.println("EGLDrawableFactory.createShared: context ES3: " + madeCurrentES3 + ", quirks "+rendererQuirksES3ES2[0]); + dumpMap(); + } + return sr; + } + + private void handleDontCloseX11DisplayQuirk(final GLRendererQuirks quirks) { + if( null != quirks && quirks.exist( GLRendererQuirks.DontCloseX11Display ) ) { + jogamp.nativewindow.x11.X11Util.markAllDisplaysUnclosable(); + } + } + + private boolean mapAvailableEGLESConfig(final AbstractGraphicsDevice adevice, + final int[] majorVersion, final int[] minorVersion, + final int[] ctxProfile, final GLRendererQuirks[] rendererQuirks) { + final String profileString = EGLContext.getGLProfile(majorVersion[0], minorVersion[0], ctxProfile[0]); + + if ( !GLProfile.isAvailable(adevice, profileString) ) { if( DEBUG ) { - dumpEGLInfo("EGLDrawableFactory.mapAvailableEGLESConfig: ", defaultDevice.getHandle()); + 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 initDefaultDevice = 0 == defaultDevice.getHandle(); // Note: GLProfile always triggers EGL device initialization first! + final boolean mapsADeviceToDefaultDevice = !QUERY_EGL_ES_NATIVE_TK || initDefaultDevice || + null == desktopFactory; + // FIXME || adevice instanceof EGLGraphicsDevice ; + if( DEBUG ) { + System.err.println("EGLDrawableFactory.mapAvailableEGLESConfig: "+profileString+" ( "+majorVersion[0]+" ), "+ + "mapsADeviceToDefaultDevice "+mapsADeviceToDefaultDevice+ + " (QUERY_EGL_ES_NATIVE_TK "+QUERY_EGL_ES_NATIVE_TK+", initDefaultDevice "+initDefaultDevice+", hasDesktopFactory "+(null != desktopFactory)+ + ", isEGLGraphicsDevice "+(adevice instanceof EGLGraphicsDevice)+")"); + } - 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[0]) { - 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; + boolean hasPBuffer; + EGLGraphicsDevice eglDevice = null; + EGLFeatures eglFeatures = null; + NativeSurface surface = null; + ProxySurface upstreamSurface = null; // X11, GLX, .. + ProxySurface downstreamSurface = null; // EGL + boolean allowsSurfacelessCtx = false; + boolean success = 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. + if( initDefaultDevice ) { + defaultDevice.open(); + defaultDeviceEGLFeatures = new EGLFeatures(defaultDevice); + + // Probe for GLRendererQuirks.SingletonEGLDisplayOnly + final long secondEGLDisplay = EGL.eglGetDisplay(EGL.EGL_DEFAULT_DISPLAY); + if ( EGL.EGL_NO_DISPLAY == secondEGLDisplay ) { + final int quirk = GLRendererQuirks.SingletonEGLDisplayOnly; + GLRendererQuirks.addStickyDeviceQuirk(adevice, quirk); + EGLDisplayUtil.setSingletonEGLDisplayOnly(true); + if(DEBUG) { + System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: Second eglGetDisplay(EGL_DEFAULT_DISPLAY) failed"); } - rendererQuirks[0] = defaultSharedResource.rendererQuirksES1; - ctp[0] = defaultSharedResource.ctpES1; - break; + } } - if( null != rendererQuirks[0] ) { - GLRendererQuirks.addStickyDeviceQuirks(adevice, rendererQuirks[0]); + eglDevice = defaultDevice; // reuse + eglFeatures = defaultDeviceEGLFeatures; + if( DEBUG ) { + System.err.println("EGLDrawableFactory.mapAvailableEGLESConfig.0: "+eglFeatures); } - EGLContext.mapStaticGLVersion(adevice, esProfile[0], 0, ctp[0]); - return true; - } - - // attempt to created the default shared resources .. - if( hasPBuffer[0] ) { - // 2nd case create defaultDevice shared resource using pbuffer surface - downstreamSurface = createDummySurfaceImpl(defaultDevice, false, reqCapsPBuffer, reqCapsPBuffer, null, 64, 64); // egl pbuffer offscreen - if( null != downstreamSurface ) { - downstreamSurface.createNotify(); - surface = downstreamSurface; + if( !glp.isGLES() && !eglFeatures.hasGLAPI ) { + if(DEBUG) { + System.err.println("EGLDrawableFactory.mapAvailableEGLESConfig() OpenGL API not supported (1)"); + } + } else { + final GLCapabilitiesImmutable reqCapsPBuffer = GLGraphicsConfigurationUtil.fixGLPBufferGLCapabilities(reqCapsAny); + final List<GLCapabilitiesImmutable> availablePBufferCapsL = getAvailableEGLConfigs(eglDevice, reqCapsPBuffer); + hasPBuffer = availablePBufferCapsL.size() > 0; + + // attempt to created the default shared resources .. + if( hasPBuffer ) { + // 2nd case create defaultDevice shared resource using pbuffer surface + downstreamSurface = createDummySurfaceImpl(eglDevice, false, reqCapsPBuffer, reqCapsPBuffer, null, 64, 64); // egl pbuffer offscreen + if( null != downstreamSurface ) { + downstreamSurface.createNotify(); + surface = downstreamSurface; + } + } 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 { - // 3rd case fake creation of defaultDevice shared resource, no pbuffer available - final List<GLCapabilitiesImmutable> capsAnyL = getAvailableEGLConfigs(defaultDevice, reqCapsAny); - if(capsAnyL.size() > 0) { - final GLCapabilitiesImmutable chosenCaps = capsAnyL.get(0); - EGLContext.mapStaticGLESVersion(defaultDevice, chosenCaps); - success = true; - } - if(DEBUG) { - System.err.println("EGLDrawableFactory.mapAvailableEGLESConfig() no pbuffer config available, detected !pbuffer config: "+success); - EGLGraphicsConfigurationFactory.printCaps("!PBufferCaps", capsAnyL, System.err); - } - } - eglDevice = defaultDevice; // reuse - } else { - // 4th case always creates a true mapping of given device to EGL - upstreamSurface = desktopFactory.createDummySurface(adevice, reqCapsAny, null, 64, 64); // X11, WGL, .. dummy window - if(null != upstreamSurface) { - upstreamSurface.createNotify(); - eglDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(upstreamSurface); - eglDevice.open(); - if( DEBUG ) { - dumpEGLInfo("EGLDrawableFactory.mapAvailableEGLESConfig: ", eglDevice.getHandle()); + // 4th case always creates a true mapping of given device to EGL + upstreamSurface = desktopFactory.createDummySurface(adevice, reqCapsAny, null, 64, 64); // X11, WGL, .. dummy window + if(null != upstreamSurface) { + upstreamSurface.createNotify(); + eglDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(upstreamSurface); + eglDevice.open(); + eglFeatures = new EGLFeatures(eglDevice); + if( DEBUG ) { + System.err.println("EGLDrawableFactory.mapAvailableEGLESConfig.1: "+eglFeatures); + } + if( !glp.isGLES() && !eglFeatures.hasGLAPI ) { + if(DEBUG) { + System.err.println("EGLDrawableFactory.mapAvailableEGLESConfig() OpenGL API not supported (2)"); + } + // disposed at finalized: eglDevice, upstreamSurface + } else { + hasPBuffer = true; + surface = upstreamSurface; + } } - hasPBuffer[0] = true; - surface = upstreamSurface; } - } - 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(); - esProfile[0] = context.getGLVersionNumber().getMajor(); - success = true; - } else { - // Oops .. something is wrong - if(DEBUG) { - System.err.println("EGLDrawableFactory.mapAvailableEGLESConfig: "+eglDevice+", "+context.getGLVersion()+" - VERSION is null, dropping availability!"); + if(null != surface) { + GLDrawableImpl zeroDrawable = null; + final EGLDrawable drawable = (EGLDrawable) createOnscreenDrawableImpl ( surface ); + drawable.setRealized(true); + final EGLContext context = (EGLContext) drawable.createContext(null); + if (null != context) { + try { + if( GLContext.CONTEXT_NOT_CURRENT != context.makeCurrent() ) { // could cause exception + // context.isCurrent() ! + final String glVersionString = context.getGL().glGetString(GL.GL_VERSION); + if(null != glVersionString) { + context.mapCurrentAvailableGLVersion(eglDevice); + if(eglDevice != adevice) { + context.mapCurrentAvailableGLVersion(adevice); + } + + if( eglFeatures.hasKHRSurfaceless && + !context.hasRendererQuirk(GLRendererQuirks.NoSurfacelessCtx) ) + { + try { + final ProxySurface zeroSurface = createSurfacelessImpl(eglDevice, true, reqCapsAny, reqCapsAny, null, 64, 64); + zeroDrawable = createOnscreenDrawableImpl(zeroSurface); + zeroDrawable.setRealized(true); + + // Since sharedContext is still current, + // will keep sharedContext current w/ zeroDrawable or throws GLException + context.setGLDrawable(zeroDrawable, false); + allowsSurfacelessCtx = true; // if setGLDrawable is successful, i.e. no GLException + + // no switch back, will be destroyed anyways + // context.setGLDrawable(drawable, false); + } catch (final Throwable t) { + if( DEBUG ) { + ExceptionUtils.dumpThrowable("", t); + } + } + } + if( !allowsSurfacelessCtx ) { + final int quirk = GLRendererQuirks.NoSurfacelessCtx; + if(DEBUG) { + System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+" -> "+eglDevice+": cause: probe"); + } + final GLRendererQuirks glrq = context.getRendererQuirks(); + if( null != glrq ) { + glrq.addQuirk(quirk); + } + GLRendererQuirks.addStickyDeviceQuirk(eglDevice, quirk); + } + rendererQuirks[0] = context.getRendererQuirks(); + ctxProfile[0] = context.getContextOptions(); + majorVersion[0] = context.getGLVersionNumber().getMajor(); + minorVersion[0] = context.getGLVersionNumber().getMinor(); + success = true; + } else { + // Oops .. something is wrong + if(DEBUG) { + System.err.println("EGLDrawableFactory.mapAvailableEGLESConfig: "+eglDevice+", "+context.getGLVersion()+" - VERSION is null, dropping availability!"); + } } } + } catch (final Throwable t) { + if (DEBUG) { + System.err.println("EGLDrawableFactory.mapAvailableEGLESConfig: INFO: context create/makeCurrent failed"); + t.printStackTrace(); + } + } finally { + if( context.isCreated() ) { + context.destroy(); + } } - } catch (final Throwable t) { - if (DEBUG) { - System.err.println("EGLDrawableFactory.mapAvailableEGLESConfig: INFO: context create/makeCurrent failed"); - t.printStackTrace(); - } - } finally { - context.destroy(); } + if( null != zeroDrawable ) { + zeroDrawable.setRealized(false); + } + drawable.setRealized(false); } - drawable.setRealized(false); - } - } catch (final Throwable t) { - if(DEBUG) { - System.err.println("Caught exception on thread "+getThreadName()); - t.printStackTrace(); - } - success = false; - } finally { - if(null != downstreamSurface) { - downstreamSurface.destroyNotify(); - } - if( defaultDevice != eglDevice ) { // don't close default device - if(null != eglDevice) { - eglDevice.close(); + } catch (final Throwable t) { + if(DEBUG) { + System.err.println("Caught exception on thread "+getThreadName()); + t.printStackTrace(); } - if(null != upstreamSurface) { - upstreamSurface.destroyNotify(); + success = false; + } finally { + if(null != downstreamSurface) { + downstreamSurface.destroyNotify(); } - } - } - return success; - } - - private final boolean needsToCreateSharedResource(final String key, final SharedResource[] existing) { - synchronized(sharedMap) { - final SharedResource sr = sharedMap.get(key); - if( null == sr ) { - final boolean createAttempted = sharedMapCreateAttempt.contains(key); - if(!createAttempted) { - sharedMapCreateAttempt.add(key); + if( defaultDevice != eglDevice ) { // don't close default device + if(null != eglDevice) { + eglDevice.close(); + } } - return !createAttempted; - } else { - if(null != existing) { - existing[0] = sr; + if(null != upstreamSurface) { + upstreamSurface.destroyNotify(); } - return false; } + return success; } - } - @Override - protected final SharedResource getOrCreateSharedResourceImpl(final AbstractGraphicsDevice adevice) { - if(null == sharedMap) { // null == eglES1DynamicLookupHelper && null == eglES2DynamicLookupHelper - return null; - } - - if( needsToCreateSharedResource(defaultDevice.getUniqueID(), null) ) { + @Override + public void releaseSharedResource(final SharedResourceRunner.Resource shared) { + final SharedResource sr = (SharedResource) shared; if (DEBUG) { - System.err.println("EGLDrawableFactory.createShared: (defaultDevice): req. device: "+adevice+", defaultDevice "+defaultDevice); - Thread.dumpStack(); - } - if(null != defaultSharedResource) { - dumpMap(); - throw new InternalError("defaultSharedResource already exist: "+defaultSharedResource); + System.err.println("Shutdown Shared:"); + System.err.println("Device : " + sr.device); + ExceptionUtils.dumpStack(System.err); } - defaultSharedResource = createEGLSharedResourceImpl(defaultDevice); - } - final String key = adevice.getUniqueID(); - if( defaultDevice.getUniqueID().equals(key) ) { - return defaultSharedResource; - } else { - if( null == defaultSharedResource) { // defaultDevice must be initialized before host-device - dumpMap(); - throw new InternalError("defaultSharedResource does not exist"); - } - final SharedResource[] existing = new SharedResource[] { null }; - if ( !needsToCreateSharedResource(key, existing) ) { - return existing[0]; + if (null != sr.device) { + // may cause JVM SIGSEGV: + sr.device.close(); + sr.device = null; } - return createEGLSharedResourceImpl(adevice); } } - private SharedResource createEGLSharedResourceImpl(final AbstractGraphicsDevice adevice) { - final boolean madeCurrentES1; - final boolean[] hasPBufferES1 = new boolean[] { false }; - final boolean[] hasPBufferES3ES2 = new boolean[] { false }; - // EGLContext[] eglCtxES1 = new EGLContext[] { null }; - // EGLContext[] eglCtxES2 = new EGLContext[] { null }; - final GLRendererQuirks[] rendererQuirksES1 = new GLRendererQuirks[] { null }; - final GLRendererQuirks[] rendererQuirksES3ES2 = new GLRendererQuirks[] { null }; - final int[] ctpES1 = new int[] { -1 }; - final int[] ctpES3ES2 = new int[] { -1 }; + public final boolean hasDefaultDeviceKHRCreateContext() { + return defaultDeviceEGLFeatures.hasKHRCreateContext; + } + @Override + public final AbstractGraphicsDevice getDefaultDevice() { + return defaultDevice; + } - if (DEBUG) { - System.err.println("EGLDrawableFactory.createShared(): device "+adevice); - } + @Override + public final boolean getIsDeviceCompatible(final AbstractGraphicsDevice device) { + // via mappings (X11/WGL/.. -> EGL) we shall be able to handle all types. + return null != sharedMap ; // null!=eglES2DynamicLookupHelper || null!=eglES1DynamicLookupHelper; + } - if( null != eglES1DynamicLookupHelper ) { - final int[] esProfile = { 1 }; - madeCurrentES1 = mapAvailableEGLESConfig(adevice, esProfile, hasPBufferES1, rendererQuirksES1, ctpES1) && 1 == esProfile[0]; - } else { - madeCurrentES1 = false; - } - boolean madeCurrentES2 = false; - boolean madeCurrentES3 = false; - if( null != eglES2DynamicLookupHelper ) { - // ES3 Query - final int[] esProfile = { 3 }; - madeCurrentES3 = mapAvailableEGLESConfig(adevice, esProfile, hasPBufferES3ES2, rendererQuirksES3ES2, ctpES3ES2) && 3 == esProfile[0]; - if( !madeCurrentES3 ) { - // ES2 Query, may result in ES3 - esProfile[0] = 2; - if( mapAvailableEGLESConfig(adevice, esProfile, hasPBufferES3ES2, rendererQuirksES3ES2, ctpES3ES2) ) { - switch( esProfile[0] ) { - case 2: madeCurrentES2 = true; break; - case 3: madeCurrentES3 = true; break; - default: throw new InternalError("XXXX Got "+esProfile[0]); - } - } - } - } - if( !EGLContext.getAvailableGLVersionsSet(adevice) ) { - // Even though we override the non EGL native mapping intentionally, - // avoid exception due to double 'set' - carefull exception of the rule. - EGLContext.setAvailableGLVersionsSet(adevice); + private static List<GLCapabilitiesImmutable> getAvailableEGLConfigs(final EGLGraphicsDevice eglDisplay, final 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( hasX11 ) { - handleDontCloseX11DisplayQuirk(rendererQuirksES1[0]); - handleDontCloseX11DisplayQuirk(rendererQuirksES3ES2[0]); + 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 */, false /* onlyFirstValid */); + } } - final SharedResource sr = new SharedResource(defaultDevice, madeCurrentES1, hasPBufferES1[0], rendererQuirksES1[0], ctpES1[0], - madeCurrentES2, madeCurrentES3, hasPBufferES3ES2[0], rendererQuirksES3ES2[0], ctpES3ES2[0]); + return new ArrayList<GLCapabilitiesImmutable>(0); + } - synchronized(sharedMap) { - sharedMap.put(adevice.getUniqueID(), sr); - } - if (DEBUG) { - System.err.println("EGLDrawableFactory.createShared: devices: queried nativeTK "+QUERY_EGL_ES_NATIVE_TK+", adevice " + adevice + ", defaultDevice " + defaultDevice); - System.err.println("EGLDrawableFactory.createShared: context ES1: " + madeCurrentES1 + ", hasPBuffer "+hasPBufferES1[0]+", quirks "+rendererQuirksES1[0]); - System.err.println("EGLDrawableFactory.createShared: context ES2: " + madeCurrentES2 + ", hasPBuffer "+hasPBufferES3ES2[0]+", quirks "+rendererQuirksES3ES2[0]); - System.err.println("EGLDrawableFactory.createShared: context ES3: " + madeCurrentES3 + ", hasPBuffer "+hasPBufferES3ES2[0]+", quirks "+rendererQuirksES3ES2[0]); - dumpMap(); - } - return sr; + static void dumpEGLInfo(final String prefix, final long eglDisplay) { + final String eglVendor = EGL.eglQueryString(eglDisplay, EGL.EGL_VENDOR); + final String eglClientAPIs = EGL.eglQueryString(eglDisplay, EGL.EGL_CLIENT_APIS); + final String eglClientVersion = EGL.eglQueryString(EGL.EGL_NO_DISPLAY, EGL.EGL_VERSION); + final String eglServerVersion = EGL.eglQueryString(eglDisplay, EGL.EGL_VERSION); + System.err.println(prefix+"EGL vendor "+eglVendor+", version [client "+eglClientVersion+", server "+eglServerVersion+"], clientAPIs "+eglClientAPIs); } - private void handleDontCloseX11DisplayQuirk(final GLRendererQuirks quirks) { - if( null != quirks && quirks.exist( GLRendererQuirks.DontCloseX11Display ) ) { - jogamp.nativewindow.x11.X11Util.markAllDisplaysUnclosable(); - } + @Override + protected final SharedResource getOrCreateSharedResourceImpl(final AbstractGraphicsDevice adevice) { + return (SharedResource) sharedResourceRunner.getOrCreateShared(adevice); } @Override protected final Thread getSharedResourceThread() { - return null; + return sharedResourceRunner.start(); } public final boolean isANGLE() { @@ -706,7 +891,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { } else if (1==esProfile) { return eglES1DynamicLookupHelper; } else { - throw new GLException("Unsupported: ES"+esProfile); + return eglGLnDynamicLookupHelper; } } @@ -723,7 +908,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { if (target == null) { throw new IllegalArgumentException("Null target"); } - return new EGLOnscreenDrawable(this, EGLWrappedSurface.get(target)); + return new EGLDrawable(this, EGLSurface.get(target)); } @Override @@ -737,7 +922,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { throw new GLException("Non pbuffer not yet implemented"); } // PBuffer GLDrawable Creation - return new EGLPbufferDrawable(this, EGLWrappedSurface.get(target)); + return new EGLDrawable(this, EGLSurface.get(target)); } @Override @@ -747,28 +932,35 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { return true; } - @Override - protected ProxySurface createMutableSurfaceImpl(final AbstractGraphicsDevice deviceReq, final boolean createNewDevice, - final GLCapabilitiesImmutable capsChosen, final GLCapabilitiesImmutable capsRequested, - final GLCapabilitiesChooser chooser, final UpstreamSurfaceHook upstreamHook) { - final boolean ownDevice; + private final EGLGraphicsConfiguration evalConfig(final boolean[] ownDevice, final AbstractGraphicsDevice deviceReq, final boolean createNewDevice, + final GLCapabilitiesImmutable capsChosen, final GLCapabilitiesImmutable capsRequested, + final GLCapabilitiesChooser chooser) { final EGLGraphicsDevice device; if( createNewDevice || ! (deviceReq instanceof EGLGraphicsDevice) ) { final long nativeDisplayID = ( deviceReq instanceof EGLGraphicsDevice) ? ( (EGLGraphicsDevice) deviceReq ).getNativeDisplayID() : deviceReq.getHandle() ; device = EGLDisplayUtil.eglCreateEGLGraphicsDevice(nativeDisplayID, deviceReq.getConnection(), deviceReq.getUnitID()); device.open(); - ownDevice = true; + ownDevice[0] = true; } else { device = (EGLGraphicsDevice) deviceReq; - ownDevice = false; + ownDevice[0] = 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, upstreamHook, ownDevice); + return config; + } + + @Override + protected final ProxySurface createMutableSurfaceImpl(final AbstractGraphicsDevice deviceReq, final boolean createNewDevice, + final GLCapabilitiesImmutable capsChosen, final GLCapabilitiesImmutable capsRequested, + final GLCapabilitiesChooser chooser, final UpstreamSurfaceHook upstreamHook) { + final boolean[] ownDevice = { false }; + final EGLGraphicsConfiguration config = evalConfig(ownDevice, deviceReq, createNewDevice, capsChosen, capsRequested, chooser); + return EGLSurface.createWrapped(config, 0, upstreamHook, ownDevice[0]); } @Override @@ -778,6 +970,15 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser, new EGLDummyUpstreamSurfaceHook(width, height)); } + @Override + public final ProxySurface createSurfacelessImpl(final AbstractGraphicsDevice deviceReq, final boolean createNewDevice, + GLCapabilitiesImmutable chosenCaps, final GLCapabilitiesImmutable requestedCaps, final GLCapabilitiesChooser chooser, final int width, final int height) { + chosenCaps = GLGraphicsConfigurationUtil.fixOnscreenGLCapabilities(chosenCaps); + final boolean[] ownDevice = { false }; + final EGLGraphicsConfiguration config = evalConfig(ownDevice, deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser); + return EGLSurface.createSurfaceless(config, new GenericUpstreamSurfacelessHook(width, height), ownDevice[0]); + } + /** * @param ms {@link MutableSurface} which dimensions and config are being used to create the pbuffer surface. * It will also hold the resulting pbuffer surface handle. @@ -813,13 +1014,15 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { } @Override - protected ProxySurface createProxySurfaceImpl(final AbstractGraphicsDevice deviceReq, final int screenIdx, final long windowHandle, final GLCapabilitiesImmutable capsRequested, final GLCapabilitiesChooser chooser, final UpstreamSurfaceHook upstream) { + protected ProxySurface createProxySurfaceImpl(final AbstractGraphicsDevice deviceReq, final int screenIdx, final long windowHandle, + final GLCapabilitiesImmutable capsRequested, final GLCapabilitiesChooser chooser, + final UpstreamSurfaceHook upstream) { final EGLGraphicsDevice eglDeviceReq = (EGLGraphicsDevice) deviceReq; final EGLGraphicsDevice device = EGLDisplayUtil.eglCreateEGLGraphicsDevice(eglDeviceReq.getNativeDisplayID(), deviceReq.getConnection(), deviceReq.getUnitID()); device.open(); 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, upstream, true); + return EGLSurface.createWrapped(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 index f00d7059d..0757bd98e 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDummyUpstreamSurfaceHook.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDummyUpstreamSurfaceHook.java @@ -6,6 +6,7 @@ import javax.media.nativewindow.UpstreamSurfaceHook; import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; +import com.jogamp.opengl.egl.EGL; /** Uses a PBuffer offscreen surface */ public class EGLDummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/egl/EGLDynamicLibraryBundleInfo.java index 05dae0b9d..1b433cc30 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDynamicLibraryBundleInfo.java @@ -28,13 +28,15 @@ package jogamp.opengl.egl; -import com.jogamp.common.os.AndroidVersion; -import com.jogamp.common.os.Platform; - -import java.util.*; +import java.util.ArrayList; +import java.util.List; import jogamp.common.os.PlatformPropsImpl; -import jogamp.opengl.*; +import jogamp.opengl.GLDynamicLibraryBundleInfo; + +import com.jogamp.common.os.AndroidVersion; +import com.jogamp.common.os.Platform; +import com.jogamp.opengl.egl.EGL; /** * Abstract implementation of the DynamicLookupHelper for EGL, @@ -43,7 +45,7 @@ import jogamp.opengl.*; * Currently two implementations exist, one for ES1 and one for ES3 and ES2. */ public abstract class EGLDynamicLibraryBundleInfo extends GLDynamicLibraryBundleInfo { - static final List<String> glueLibNames; + private static final List<String> glueLibNames; static { glueLibNames = new ArrayList<String>(); glueLibNames.add("jogl_mobile"); @@ -79,7 +81,7 @@ public abstract class EGLDynamicLibraryBundleInfo extends GLDynamicLibraryBundle @Override public final long toolGetProcAddress(final long toolGetProcAddressHandle, final String funcName) { - return EGL.eglGetProcAddress(toolGetProcAddressHandle, funcName); + return EGLContext.eglGetProcAddress(toolGetProcAddressHandle, funcName); } @Override diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLES1DynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/egl/EGLES1DynamicLibraryBundleInfo.java index 361ec26ff..3c7ee410a 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLES1DynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLES1DynamicLibraryBundleInfo.java @@ -28,7 +28,8 @@ package jogamp.opengl.egl; -import java.util.*; +import java.util.ArrayList; +import java.util.List; public final class EGLES1DynamicLibraryBundleInfo extends EGLDynamicLibraryBundleInfo { protected EGLES1DynamicLibraryBundleInfo() { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLES2DynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/egl/EGLES2DynamicLibraryBundleInfo.java index 74738463f..d37efc455 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLES2DynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLES2DynamicLibraryBundleInfo.java @@ -28,7 +28,8 @@ package jogamp.opengl.egl; -import java.util.*; +import java.util.ArrayList; +import java.util.List; /** * <p> diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLGLCapabilities.java b/src/jogl/classes/jogamp/opengl/egl/EGLGLCapabilities.java index a8dd7d5c8..258765ba3 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLGLCapabilities.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLGLCapabilities.java @@ -34,6 +34,8 @@ import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; +import com.jogamp.opengl.egl.EGL; +import com.jogamp.opengl.egl.EGLExt; public class EGLGLCapabilities extends GLCapabilities { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLGLnDynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/egl/EGLGLnDynamicLibraryBundleInfo.java new file mode 100644 index 000000000..6a3a20100 --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/egl/EGLGLnDynamicLibraryBundleInfo.java @@ -0,0 +1,83 @@ +/** + * Copyright 2014 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package jogamp.opengl.egl; + +import java.util.ArrayList; +import java.util.List; + +import com.jogamp.common.os.Platform; + +/** + * <p> + * Covering Desktop GL + * </p> + */ +public final class EGLGLnDynamicLibraryBundleInfo extends EGLDynamicLibraryBundleInfo { + private static final List<String> glueLibNames; + static { + glueLibNames = new ArrayList<String>(); + glueLibNames.add("jogl_desktop"); + } + + protected EGLGLnDynamicLibraryBundleInfo() { + super(); + } + + @Override + public final List<List<String>> getToolLibNames() { + final List<List<String>> libsList = new ArrayList<List<String>>(); + { + final List<String> libsGL = new ArrayList<String>(); + + final Platform.OSType osType = Platform.getOSType(); + if( Platform.OSType.MACOS == osType ) { + libsGL.add("/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"); + libsGL.add("GL"); + } else if( Platform.OSType.WINDOWS == Platform.getOSType() ) { + libsGL.add("OpenGL32"); + } else { + // this is the default lib name, according to the spec + libsGL.add("libGL.so.1"); + + // try this one as well, if spec fails + libsGL.add("libGL.so"); + + // last but not least .. the generic one + libsGL.add("GL"); + } + + libsList.add(libsGL); + } + libsList.add(getEGLLibNamesList()); + + return libsList; + } + +} + diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java index 1d90e63af..6f0d7ae4d 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java @@ -57,6 +57,8 @@ import com.jogamp.common.nio.PointerBuffer; import com.jogamp.nativewindow.MutableGraphicsConfiguration; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; import com.jogamp.opengl.GLRendererQuirks; +import com.jogamp.opengl.egl.EGL; +import com.jogamp.opengl.egl.EGLExt; public class EGLGraphicsConfiguration extends MutableGraphicsConfiguration implements Cloneable { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfigurationFactory.java index d4e5e7d62..4aa34ce4e 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfigurationFactory.java @@ -33,36 +33,37 @@ package jogamp.opengl.egl; +import java.io.PrintStream; +import java.nio.IntBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.AbstractGraphicsScreen; import javax.media.nativewindow.CapabilitiesChooser; import javax.media.nativewindow.CapabilitiesImmutable; import javax.media.nativewindow.GraphicsConfigurationFactory; +import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.VisualIDHolder; import javax.media.nativewindow.VisualIDHolder.VIDType; -import javax.media.nativewindow.NativeWindowFactory; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesChooser; import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; -import javax.media.opengl.GLDrawableFactory; + +import jogamp.opengl.GLGraphicsConfigurationFactory; +import jogamp.opengl.GLGraphicsConfigurationUtil; import com.jogamp.common.nio.Buffers; import com.jogamp.common.nio.PointerBuffer; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; import com.jogamp.opengl.GLRendererQuirks; - -import jogamp.opengl.GLGraphicsConfigurationFactory; -import jogamp.opengl.GLGraphicsConfigurationUtil; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.io.PrintStream; -import java.nio.IntBuffer; +import com.jogamp.opengl.egl.EGL; /** Subclass of GraphicsConfigurationFactory used when non-AWT tookits diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java deleted file mode 100644 index 4c018fe25..000000000 --- a/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. - * Copyright (c) 2010 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed or intended for use - * in the design, construction, operation or maintenance of any nuclear - * facility. - * - * Sun gratefully acknowledges that this software was originally authored - * and developed by Kenneth Bradley Russell and Christopher John Kline. - */ - -package jogamp.opengl.egl; - -import javax.media.opengl.*; -import javax.media.nativewindow.*; - -public class EGLOnscreenDrawable extends EGLDrawable { - protected EGLOnscreenDrawable(final EGLDrawableFactory factory, final NativeSurface component) throws GLException { - super(factory, component); - } - - @Override - public GLContext createContext(final GLContext shareWith) { - return new EGLContext(this, shareWith); - } - - @Override - protected long createSurface(final EGLGraphicsConfiguration config, final int width, final int height, final long nativeSurfaceHandle) { - return EGL.eglCreateWindowSurface(config.getScreen().getDevice().getHandle(), config.getNativeConfig(), nativeSurfaceHandle, null); - } -} - diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java deleted file mode 100644 index 8842edbc0..000000000 --- a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved. - * Copyright (c) 2010 JogAmp Community. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that this software is not designed or intended for use - * in the design, construction, operation or maintenance of any nuclear - * facility. - * - * Sun gratefully acknowledges that this software was originally authored - * and developed by Kenneth Bradley Russell and Christopher John Kline. - */ - -package jogamp.opengl.egl; - -import javax.media.nativewindow.NativeSurface; -import javax.media.opengl.GLContext; - -public class EGLPbufferDrawable extends EGLDrawable { - protected static final boolean useTexture = false; // No yet .. - - protected EGLPbufferDrawable(final EGLDrawableFactory factory, final NativeSurface target) { - super(factory, target); - } - - @Override - protected long createSurface(final EGLGraphicsConfiguration config, final int width, final int height, final long nativeSurfaceHandle) { - return EGLDrawableFactory.createPBufferSurfaceImpl(config, width, height, false); - } - - @Override - public GLContext createContext(final GLContext shareWith) { - return new EGLContext(this, shareWith); - } -} - diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLSurface.java b/src/jogl/classes/jogamp/opengl/egl/EGLSurface.java new file mode 100644 index 000000000..796a9e2c8 --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/egl/EGLSurface.java @@ -0,0 +1,165 @@ +/** + * Copyright 2014 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.opengl.egl; + +import java.nio.IntBuffer; + +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindow; +import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.UpstreamSurfaceHook; +import javax.media.opengl.GLCapabilitiesImmutable; +import javax.media.opengl.GLException; + +import com.jogamp.common.nio.Buffers; +import com.jogamp.nativewindow.GenericUpstreamSurfacelessHook; +import com.jogamp.opengl.egl.EGL; + +import jogamp.nativewindow.ProxySurfaceImpl; +import jogamp.nativewindow.WrappedSurface; +import jogamp.opengl.GLDrawableImpl; + +/** + * <pre> + * EGLSurface [ is_a -> WrappedSurface -> ProxySurfaceImpl -> ProxySurface -> MutableSurface -> NativeSurface] has_a + * EGLUpstreamSurfaceHook [ is_a -> UpstreamSurfaceHook.MutableSize -> UpstreamSurfaceHook ] has_a + * NativeSurface (e.g. native [X11, WGL, ..] surface, or WrappedSurface, ..) + * </pre> + */ +public class EGLSurface extends WrappedSurface { + static boolean DEBUG = EGLDrawable.DEBUG || ProxySurface.DEBUG; + + public static EGLSurface get(final NativeSurface surface) { + if(surface instanceof EGLSurface) { + return (EGLSurface)surface; + } + return new EGLSurface(surface); + } + private EGLSurface(final NativeSurface surface) { + super(surface.getGraphicsConfiguration(), EGL.EGL_NO_SURFACE, new EGLUpstreamSurfaceHook(surface), false /* tbd in UpstreamSurfaceHook */); + if(EGLDrawableFactory.DEBUG) { + System.err.println("EGLSurface.ctor().1: "+this); + ProxySurfaceImpl.dumpHierarchy(System.err, this); + } + } + + public static EGLSurface createWrapped(final EGLGraphicsConfiguration cfg, final long handle, + final UpstreamSurfaceHook upstream, final boolean ownsDevice) { + return new EGLSurface(cfg, handle, upstream, ownsDevice); + } + private EGLSurface(final EGLGraphicsConfiguration cfg, final long handle, + final UpstreamSurfaceHook upstream, final boolean ownsDevice) { + super(cfg, EGL.EGL_NO_SURFACE, new EGLUpstreamSurfaceHook(cfg, handle, upstream, ownsDevice), false /* tbd in UpstreamSurfaceHook */); + if(EGLDrawableFactory.DEBUG) { + System.err.println("EGLSurface.ctor().2: "+this); + ProxySurfaceImpl.dumpHierarchy(System.err, this); + } + } + + public static EGLSurface createSurfaceless(final EGLGraphicsConfiguration cfg, final GenericUpstreamSurfacelessHook upstream, final boolean ownsDevice) { + return new EGLSurface(cfg, upstream, ownsDevice); + } + private EGLSurface(final EGLGraphicsConfiguration cfg, final GenericUpstreamSurfacelessHook upstream, final boolean ownsDevice) { + super(cfg, EGL.EGL_NO_SURFACE, upstream, ownsDevice); + if(EGLDrawableFactory.DEBUG) { + System.err.println("EGLSurface.ctor().3: "+this); + ProxySurfaceImpl.dumpHierarchy(System.err, this); + } + } + + public void setEGLSurfaceHandle() throws GLException { + setSurfaceHandle( createEGLSurfaceHandle() ); + } + private long createEGLSurfaceHandle() throws GLException { + final EGLGraphicsConfiguration config = (EGLGraphicsConfiguration) getGraphicsConfiguration(); + final NativeSurface nativeSurface = getUpstreamSurface(); + final boolean isPBuffer = ((GLCapabilitiesImmutable) config.getChosenCapabilities()).isPBuffer(); + + long eglSurface = createEGLSurfaceHandle(isPBuffer, true /* useSurfaceHandle */, config, nativeSurface); + if ( EGL.EGL_NO_SURFACE == eglSurface ) { + final int eglError0 = EGL.eglGetError(); + if( EGL.EGL_BAD_NATIVE_WINDOW == eglError0 && !isPBuffer ) { + // Try window handle if available and differs (Windows HDC / HWND). + // ANGLE impl. required HWND on Windows. + if( hasUniqueNativeWindowHandle(nativeSurface) ) { + if(DEBUG) { + System.err.println(getThreadName() + ": Info: Creation of window surface w/ surface handle failed: "+config+", error "+GLDrawableImpl.toHexString(eglError0)+", retry w/ windowHandle"); + } + eglSurface = createEGLSurfaceHandle(isPBuffer, false /* useSurfaceHandle */, config, nativeSurface); + if (EGL.EGL_NO_SURFACE == eglSurface) { + throw new GLException("Creation of window surface w/ window handle failed: "+config+", "+this+", error "+GLDrawableImpl.toHexString(EGL.eglGetError())); + } + } else { + throw new GLException("Creation of window surface w/ surface handle failed (2): "+config+", "+this+", error "+GLDrawableImpl.toHexString(eglError0)); + } + } else { + throw new GLException("Creation of window surface w/ surface handle failed (1): "+config+", "+this+", error "+GLDrawableImpl.toHexString(eglError0)); + } + } + if(DEBUG) { + System.err.println(getThreadName() + ": createEGLSurface handle "+GLDrawableImpl.toHexString(eglSurface)); + } + return eglSurface; + } + private long createEGLSurfaceHandle(final boolean isPBuffer, final boolean useSurfaceHandle, + final EGLGraphicsConfiguration config, final NativeSurface nativeSurface) { + if( isPBuffer ) { + return EGLDrawableFactory.createPBufferSurfaceImpl(config, getSurfaceWidth(), getSurfaceHeight(), false); + } else { + if( useSurfaceHandle ) { + return EGL.eglCreateWindowSurface(config.getScreen().getDevice().getHandle(), + config.getNativeConfig(), + nativeSurface.getSurfaceHandle(), null); + } else { + return EGL.eglCreateWindowSurface(config.getScreen().getDevice().getHandle(), + config.getNativeConfig(), + ((NativeWindow)nativeSurface).getWindowHandle(), null); + } + } + } + private static boolean hasUniqueNativeWindowHandle(final NativeSurface nativeSurface) { + return nativeSurface instanceof NativeWindow && + ((NativeWindow)nativeSurface).getWindowHandle() != nativeSurface.getSurfaceHandle(); + } + static String getThreadName() { return Thread.currentThread().getName(); } + + public static boolean isValidEGLSurfaceHandle(final long eglDisplayHandle, final long eglSurfaceHandle) { + if( 0 == eglSurfaceHandle ) { + return false; + } + final IntBuffer val = Buffers.newDirectIntBuffer(1); + final boolean eglSurfaceValid = EGL.eglQuerySurface(eglDisplayHandle, eglSurfaceHandle, EGL.EGL_CONFIG_ID, val); + if( !eglSurfaceValid ) { + final int eglErr = EGL.eglGetError(); + if(DEBUG) { + System.err.println(getThreadName() + ": EGLSurface.isValidEGLSurfaceHandle eglQuerySuface failed: error "+GLDrawableImpl.toHexString(eglErr)+", "+GLDrawableImpl.toHexString(eglSurfaceHandle)); + } + } + return eglSurfaceValid; + } +} diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java b/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java index cc15f0cd6..92e13dc61 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java @@ -1,3 +1,30 @@ +/** + * Copyright 2014 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ package jogamp.opengl.egl; import javax.media.nativewindow.AbstractGraphicsConfiguration; @@ -11,13 +38,16 @@ import javax.media.nativewindow.VisualIDHolder.VIDType; import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLException; +import jogamp.nativewindow.WrappedSurface; + import com.jogamp.nativewindow.egl.EGLGraphicsDevice; +import com.jogamp.opengl.egl.EGL; /** * <pre> - * EGLWrappedSurface [ is_a -> WrappedSurface -> ProxySurfaceImpl -> ProxySurface -> MutableSurface -> NativeSurface] has_a + * EGLSurface [ is_a -> WrappedSurface -> ProxySurfaceImpl -> ProxySurface -> MutableSurface -> NativeSurface] has_a * EGLUpstreamSurfaceHook [ is_a -> UpstreamSurfaceHook.MutableSize -> UpstreamSurfaceHook ] has_a - * NativeSurface (e.g. native X11 surface) + * NativeSurface (e.g. native [X11, WGL, ..] surface, or WrappedSurface, ..) * </pre> */ public class EGLUpstreamSurfaceHook implements UpstreamSurfaceHook.MutableSize { @@ -40,6 +70,11 @@ public class EGLUpstreamSurfaceHook implements UpstreamSurfaceHook.MutableSize { } } + public EGLUpstreamSurfaceHook(final EGLGraphicsConfiguration cfg, final long handle, + final UpstreamSurfaceHook upstream, final boolean ownsDevice) { + this( new WrappedSurface(cfg, handle, upstream, ownsDevice) ); + } + static String getThreadName() { return Thread.currentThread().getName(); } /** @@ -176,10 +211,10 @@ public class EGLUpstreamSurfaceHook implements UpstreamSurfaceHook.MutableSize { } surface.setGraphicsConfiguration(eglConfig); - if(isEGLSurfaceValid) { - isEGLSurfaceValid = EGLDrawable.isValidEGLSurface(eglDevice.getHandle(), upstreamSurface.getSurfaceHandle()); + if( isEGLSurfaceValid ) { + isEGLSurfaceValid = EGLSurface.isValidEGLSurfaceHandle(eglDevice.getHandle(), upstreamSurface.getSurfaceHandle()); } - if(isEGLSurfaceValid) { + if( isEGLSurfaceValid ) { surface.setSurfaceHandle(upstreamSurface.getSurfaceHandle()); surface.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); if(DEBUG) { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLWrappedSurface.java b/src/jogl/classes/jogamp/opengl/egl/EGLWrappedSurface.java deleted file mode 100644 index 89024eed3..000000000 --- a/src/jogl/classes/jogamp/opengl/egl/EGLWrappedSurface.java +++ /dev/null @@ -1,30 +0,0 @@ -package jogamp.opengl.egl; - -import javax.media.nativewindow.NativeSurface; - -import jogamp.nativewindow.WrappedSurface; - -/** - * <pre> - * EGLWrappedSurface [ is_a -> WrappedSurface -> ProxySurfaceImpl -> ProxySurface -> MutableSurface -> NativeSurface] has_a - * EGLUpstreamSurfaceHook [ is_a -> UpstreamSurfaceHook.MutableSize -> UpstreamSurfaceHook ] has_a - * NativeSurface (i.e. native X11 surface) - * </pre> - */ -public class EGLWrappedSurface extends WrappedSurface { - - public static EGLWrappedSurface get(final NativeSurface surface) { - if(surface instanceof EGLWrappedSurface) { - return (EGLWrappedSurface)surface; - } - return new EGLWrappedSurface(surface); - } - - public EGLWrappedSurface(final 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); - } - } - -} diff --git a/src/jogl/classes/jogamp/opengl/glu/mipmap/Mipmap.java b/src/jogl/classes/jogamp/opengl/glu/mipmap/Mipmap.java index 51d8ca6fe..d5a4d9a09 100644 --- a/src/jogl/classes/jogamp/opengl/glu/mipmap/Mipmap.java +++ b/src/jogl/classes/jogamp/opengl/glu/mipmap/Mipmap.java @@ -257,7 +257,7 @@ public class Mipmap { public static void closestFit( final GL gl, final int target, final int width, final int height, final int internalFormat, final int format, final int type, final int[] newWidth, final int[] newHeight ) { // Use proxy textures if OpenGL GL2/GL3 version >= 1.1 - if( gl.isGL2GL3() && gl.getContext().getGLVersionNumber().compareTo(GLContext.Version110) >= 0 ) { + if( gl.isGL2GL3() && gl.getContext().getGLVersionNumber().compareTo(GLContext.Version1_1) >= 0 ) { int widthPowerOf2 = nearestPower( width ); int heightPowerOf2 = nearestPower( height ); final int[] proxyWidth = new int[1]; diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java index 045abca4c..6cc696d16 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java @@ -74,6 +74,7 @@ import jogamp.opengl.SharedResourceRunner; import com.jogamp.common.nio.Buffers; import com.jogamp.common.util.ReflectionUtil; +import com.jogamp.nativewindow.GenericUpstreamSurfacelessHook; import com.jogamp.nativewindow.MutableGraphicsConfiguration; import com.jogamp.nativewindow.macosx.MacOSXGraphicsDevice; import com.jogamp.opengl.GLExtensions; @@ -175,7 +176,7 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { this.hasAppleFloatPixels = hasAppletFloatPixels; } @Override - public final boolean isValid() { + public final boolean isAvailable() { return valid; } @Override @@ -197,7 +198,7 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { return null; } @Override - public GLRendererQuirks getRendererQuirks() { + public GLRendererQuirks getRendererQuirks(final GLProfile glp) { return glRendererQuirks; } } @@ -263,8 +264,7 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { } try { - sharedContext.makeCurrent(); // could cause exception - isValid = sharedContext.isCurrent(); + isValid = GLContext.CONTEXT_NOT_CURRENT != sharedContext.makeCurrent(); // could cause exception if(isValid) { final GL gl = sharedContext.getGL(); hasNPOTTextures = gl.isNPOTTextureAvailable(); @@ -373,6 +373,13 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { } @Override + public final ProxySurface createSurfacelessImpl(final AbstractGraphicsDevice deviceReq, final boolean createNewDevice, + GLCapabilitiesImmutable chosenCaps, final GLCapabilitiesImmutable requestedCaps, final GLCapabilitiesChooser chooser, final int width, final int height) { + chosenCaps = GLGraphicsConfigurationUtil.fixOnscreenGLCapabilities(chosenCaps); + return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser, new GenericUpstreamSurfacelessHook(width, height)); + } + + @Override protected ProxySurface createProxySurfaceImpl(final AbstractGraphicsDevice deviceReq, final int screenIdx, final long windowHandle, final GLCapabilitiesImmutable capsRequested, final GLCapabilitiesChooser chooser, final UpstreamSurfaceHook upstream) { final MacOSXGraphicsDevice device = new MacOSXGraphicsDevice(deviceReq.getUnitID()); final AbstractGraphicsScreen screen = new DefaultGraphicsScreen(device, screenIdx); diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDynamicLibraryBundleInfo.java index 3ec40ffce..5cf4f36a1 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDynamicLibraryBundleInfo.java @@ -28,8 +28,10 @@ package jogamp.opengl.macosx.cgl; -import jogamp.opengl.*; -import java.util.*; +import java.util.ArrayList; +import java.util.List; + +import jogamp.opengl.DesktopGLDynamicLibraryBundleInfo; public final class MacOSXCGLDynamicLibraryBundleInfo extends DesktopGLDynamicLibraryBundleInfo { protected MacOSXCGLDynamicLibraryBundleInfo() { diff --git a/src/jogl/classes/jogamp/opengl/openal/av/ALAudioSink.java b/src/jogl/classes/jogamp/opengl/openal/av/ALAudioSink.java index 003b9148e..562d4883d 100644 --- a/src/jogl/classes/jogamp/opengl/openal/av/ALAudioSink.java +++ b/src/jogl/classes/jogamp/opengl/openal/av/ALAudioSink.java @@ -33,6 +33,7 @@ import java.util.Arrays; import jogamp.opengl.Debug; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.util.LFRingbuffer; import com.jogamp.common.util.PropertyAccess; import com.jogamp.common.util.Ringbuffer; @@ -262,7 +263,7 @@ public class ALAudioSink implements AudioSink { if( ALCConstants.ALC_NO_ERROR != alcErr ) { final String err = getThreadName()+": ALCError "+toHexString(alcErr)+" while makeCurrent. "+this; System.err.println(err); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); lock.unlock(); throw new RuntimeException(err); } @@ -270,7 +271,7 @@ public class ALAudioSink implements AudioSink { if( ALCConstants.ALC_NO_ERROR != alErr ) { if( DEBUG ) { System.err.println(getThreadName()+": Prev - ALError "+toHexString(alErr)+" @ makeCurrent. "+this); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } } @@ -290,8 +291,7 @@ public class ALAudioSink implements AudioSink { alc.alcDestroyContext(context); } catch (final Throwable t) { if( DEBUG ) { - System.err.println("Caught "+t.getClass().getName()+": "+t.getMessage()); - t.printStackTrace(); + ExceptionUtils.dumpThrowable("", t); } } context = null; @@ -652,7 +652,7 @@ public class ALAudioSink implements AudioSink { alBufferBytesQueued = 0; if(DEBUG_TRACE) { System.err.println("<< _FLUSH_ [al "+val[0]+", err "+toHexString(alErr)+"] <- "+shortString()+" @ "+getThreadName()); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } diff --git a/src/jogl/classes/jogamp/opengl/util/av/EGLMediaPlayerImpl.java b/src/jogl/classes/jogamp/opengl/util/av/EGLMediaPlayerImpl.java index f9df9153f..8e60b9cc7 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/EGLMediaPlayerImpl.java +++ b/src/jogl/classes/jogamp/opengl/util/av/EGLMediaPlayerImpl.java @@ -33,13 +33,13 @@ import java.nio.IntBuffer; import javax.media.opengl.GL; import com.jogamp.common.nio.Buffers; +import com.jogamp.opengl.egl.EGL; +import com.jogamp.opengl.egl.EGLExt; import com.jogamp.opengl.util.texture.Texture; import com.jogamp.opengl.util.texture.TextureSequence; -import jogamp.opengl.egl.EGL; import jogamp.opengl.egl.EGLContext; import jogamp.opengl.egl.EGLDrawable; -import jogamp.opengl.egl.EGLExt; public abstract class EGLMediaPlayerImpl extends GLMediaPlayerImpl { final protected TextureType texType; diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/OMXGLMediaPlayer.java b/src/jogl/classes/jogamp/opengl/util/av/impl/OMXGLMediaPlayer.java index 5baf9e543..74a051b77 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/impl/OMXGLMediaPlayer.java +++ b/src/jogl/classes/jogamp/opengl/util/av/impl/OMXGLMediaPlayer.java @@ -33,9 +33,9 @@ import java.io.IOException; import javax.media.opengl.GL; import javax.media.opengl.GLException; +import com.jogamp.opengl.egl.EGL; import com.jogamp.opengl.util.texture.TextureSequence; -import jogamp.opengl.egl.EGL; import jogamp.opengl.util.av.EGLMediaPlayerImpl; /** diff --git a/src/jogl/classes/jogamp/opengl/util/jpeg/JPEGDecoder.java b/src/jogl/classes/jogamp/opengl/util/jpeg/JPEGDecoder.java index e3e43b30c..8254f164c 100644 --- a/src/jogl/classes/jogamp/opengl/util/jpeg/JPEGDecoder.java +++ b/src/jogl/classes/jogamp/opengl/util/jpeg/JPEGDecoder.java @@ -470,11 +470,11 @@ public class JPEGDecoder { } private final int readUInt8() throws IOException { - return bstream.readUInt8(true /* msbFirst */); + return bstream.readUInt8(); } private final int readUInt16() throws IOException { - return bstream.readUInt16(true /* msbFirst */, true /* bigEndian */); + return bstream.readUInt16(true /* bigEndian */); } private final int readNumber() throws IOException { diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java index ebd107c47..6cc29dddb 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLContext.java @@ -316,6 +316,8 @@ public class WindowsWGLContext extends GLContextImpl { throw new GLException("Error making temp context current: 0x" + toHexString(temp_ctx) + ", werr: "+GDI.GetLastError()); } if( !setGLFunctionAvailability(true, 0, 0, CTX_PROFILE_COMPAT, false /* strictMatch */, null == sharedContext /* withinGLVersionsMapping */) ) { // use GL_VERSION + WGL.wglMakeCurrent(0, 0); // release temp context + WGL.wglDeleteContext(temp_ctx); throw new InternalError("setGLFunctionAvailability !strictMatch failed"); } WGL.wglMakeCurrent(0, 0); // release temp context @@ -368,7 +370,7 @@ public class WindowsWGLContext extends GLContextImpl { // otherwise context of similar profile but different creation method may not be share-able. WGL.wglMakeCurrent(0, 0); WGL.wglDeleteContext(temp_ctx); - throw new GLException(getThreadName()+": WindowsWGLContex.createContextImpl ctx !ARB but ARB is used, profile > GL2 requested (OpenGL >= 3.0.1). Requested: "+glCaps.getGLProfile()+", current: "+getGLVersion()); + throw new GLException(getThreadName()+": WindowsWGLContex.createContextImpl ctx !ARB but ARB is used, profile > GL2 requested (OpenGL >= 3.1). Requested: "+glCaps.getGLProfile()+", current: "+getGLVersion()); } if(DEBUG) { System.err.println("WindowsWGLContext.createContext ARB not used, fall back to !ARB context "+getGLVersion()); diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java index fa052d784..8b67cc9ee 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java @@ -80,6 +80,7 @@ import jogamp.opengl.SharedResourceRunner; import com.jogamp.common.nio.PointerBuffer; import com.jogamp.common.util.PropertyAccess; import com.jogamp.common.util.ReflectionUtil; +import com.jogamp.nativewindow.GenericUpstreamSurfacelessHook; import com.jogamp.nativewindow.windows.WindowsGraphicsDevice; import com.jogamp.opengl.GLExtensions; import com.jogamp.opengl.GLRendererQuirks; @@ -275,7 +276,7 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { } @Override - public final boolean isValid() { + public final boolean isAvailable() { return null != context; } @Override @@ -287,7 +288,7 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { @Override final public GLContextImpl getContext() { return context; } @Override - public GLRendererQuirks getRendererQuirks() { + public GLRendererQuirks getRendererQuirks(final GLProfile glp) { return null != context ? context.getRendererQuirks() : null; } @@ -303,12 +304,12 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { sharedMap.clear(); } @Override - public SharedResourceRunner.Resource mapPut(final String connection, final SharedResourceRunner.Resource resource) { - return sharedMap.put(connection, resource); + public SharedResourceRunner.Resource mapPut(final AbstractGraphicsDevice device, final SharedResourceRunner.Resource resource) { + return sharedMap.put(device.getConnection(), resource); } @Override - public SharedResourceRunner.Resource mapGet(final String connection) { - return sharedMap.get(connection); + public SharedResourceRunner.Resource mapGet(final AbstractGraphicsDevice device) { + return sharedMap.get(device.getConnection()); } @Override public Collection<SharedResourceRunner.Resource> mapValues() { @@ -318,13 +319,13 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { } @Override - public boolean isDeviceSupported(final String connection) { + public boolean isDeviceSupported(final AbstractGraphicsDevice device) { return true; } @Override - public SharedResourceRunner.Resource createSharedResource(final String connection) { - final WindowsGraphicsDevice sharedDevice = new WindowsGraphicsDevice(connection, AbstractGraphicsDevice.DEFAULT_UNIT); + public SharedResourceRunner.Resource createSharedResource(final AbstractGraphicsDevice device) { + final WindowsGraphicsDevice sharedDevice = new WindowsGraphicsDevice(device.getConnection(), device.getUnitID()); sharedDevice.lock(); try { final AbstractGraphicsScreen absScreen = new DefaultGraphicsScreen(sharedDevice, 0); @@ -367,7 +368,7 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { hasARBPixelFormat, hasARBMultisample, hasARBPBuffer, hasARBReadDrawableAvailable); } catch (final Throwable t) { - throw new GLException("WindowsWGLDrawableFactory - Could not initialize shared resources for "+connection, t); + throw new GLException("WindowsWGLDrawableFactory - Could not initialize shared resources for "+device, t); } finally { sharedDevice.unlock(); } @@ -555,6 +556,13 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { } @Override + public final ProxySurface createSurfacelessImpl(final AbstractGraphicsDevice deviceReq, final boolean createNewDevice, + GLCapabilitiesImmutable chosenCaps, final GLCapabilitiesImmutable requestedCaps, final GLCapabilitiesChooser chooser, final int width, final int height) { + chosenCaps = GLGraphicsConfigurationUtil.fixOnscreenGLCapabilities(chosenCaps); + return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser, new GenericUpstreamSurfacelessHook(width, height)); + } + + @Override protected final ProxySurface createProxySurfaceImpl(final AbstractGraphicsDevice deviceReq, final int screenIdx, final long windowHandle, final GLCapabilitiesImmutable capsRequested, final GLCapabilitiesChooser chooser, final UpstreamSurfaceHook upstream) { final WindowsGraphicsDevice device = new WindowsGraphicsDevice(deviceReq.getConnection(), deviceReq.getUnitID()); final AbstractGraphicsScreen screen = new DefaultGraphicsScreen(device, screenIdx); diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDynamicLibraryBundleInfo.java index 2285ae996..d13e4ddad 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDynamicLibraryBundleInfo.java @@ -28,8 +28,10 @@ package jogamp.opengl.windows.wgl; -import jogamp.opengl.*; -import java.util.*; +import java.util.ArrayList; +import java.util.List; + +import jogamp.opengl.DesktopGLDynamicLibraryBundleInfo; public final class WindowsWGLDynamicLibraryBundleInfo extends DesktopGLDynamicLibraryBundleInfo { protected WindowsWGLDynamicLibraryBundleInfo() { diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java index 5785f8041..84b2ad719 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java @@ -48,6 +48,7 @@ import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.nio.Buffers; import com.jogamp.nativewindow.MutableGraphicsConfiguration; import com.jogamp.opengl.GLRendererQuirks; @@ -281,7 +282,7 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio System.err.println("GetPixelFormatAttribivARB: Failed - HDC 0x" + Long.toHexString(hdc) + ", value "+iresults.get(0)+ ", LastError: " + GDI.GetLastError()); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return 0; } @@ -290,7 +291,7 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio if(DEBUG) { System.err.println("GetPixelFormatAttribivARB: No formats - HDC 0x" + Long.toHexString(hdc) + ", LastError: " + GDI.GetLastError()); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } return pfdIDCount; @@ -351,7 +352,7 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio iattributes, accelerationMode, null) ) { if (DEBUG) { System.err.println("wglChoosePixelFormatARB: GLCapabilities2AttribList failed: " + GDI.GetLastError()); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return null; } @@ -365,7 +366,7 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio pformatsTmp, numFormatsTmp) ) { if (DEBUG) { System.err.println("wglChoosePixelFormatARB: wglChoosePixelFormatARB failed: " + GDI.GetLastError()); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return null; } @@ -508,7 +509,7 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio caps.getAccumGreenBits() > 0 || caps.getAccumBlueBits() > 0 || caps.getAccumAlphaBits() > 0 ) { - final GLRendererQuirks sharedQuirks = sharedResource.getRendererQuirks(); + final GLRendererQuirks sharedQuirks = sharedResource.getRendererQuirks(null); if ( !usePBuffer || null==sharedQuirks || !sharedQuirks.exist(GLRendererQuirks.NoPBufferWithAccum) ) { iattributes.put(niattribs++, WGLExt.WGL_ACCUM_BITS_ARB); iattributes.put(niattribs++, ( caps.getAccumRedBits() + diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java index ea9b86712..7c387827a 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java @@ -50,6 +50,7 @@ import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.nio.Buffers; import com.jogamp.opengl.GLRendererQuirks; @@ -131,7 +132,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat List<GLCapabilitiesImmutable> availableCaps = null; final GLContext sharedContext; - if ( factory.hasRendererQuirk(device, GLRendererQuirks.NeedCurrCtx4ARBPixFmtQueries) ) { + if ( factory.hasRendererQuirk(device, null, GLRendererQuirks.NeedCurrCtx4ARBPixFmtQueries) ) { sharedContext = sharedResource.getContext(); if(GLContext.CONTEXT_NOT_CURRENT == sharedContext.makeCurrent()) { throw new GLException("Could not make Shared Context current: "+device); @@ -299,7 +300,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat final AbstractGraphicsDevice device = config.getScreen().getDevice(); final WindowsWGLDrawableFactory.SharedResource sharedResource = ((WindowsWGLDrawableFactory)factory).getOrCreateSharedResourceImpl(device); final GLContext sharedContext; - if ( factory.hasRendererQuirk(device, GLRendererQuirks.NeedCurrCtx4ARBPixFmtQueries) ) { + if ( factory.hasRendererQuirk(device, null, GLRendererQuirks.NeedCurrCtx4ARBPixFmtQueries) ) { sharedContext = sharedResource.getContext(); if(GLContext.CONTEXT_NOT_CURRENT == sharedContext.makeCurrent()) { throw new GLException("Could not make Shared Context current: "+device); @@ -417,7 +418,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat if (null == pformats) { if (DEBUG) { System.err.println("updateGraphicsConfigurationARB: failed, return false"); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return false; } @@ -431,7 +432,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat if( null == availableCaps || 0 == availableCaps.size() ) { if (DEBUG) { System.err.println("updateGraphicsConfigurationARB: wglARBPFIDs2GLCapabilities failed with " + pformats.length + " pfd ids"); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return false; } @@ -453,7 +454,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat } if ( 0 > chosenIndex ) { if (DEBUG) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return false; } @@ -603,7 +604,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat if ( 0 > chosenIndex ) { if (DEBUG) { System.err.println("updateGraphicsConfigurationGDI: failed, return false"); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return false; } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java index 9631dbb5b..4337eaf54 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXContext.java @@ -59,6 +59,7 @@ import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLDrawableImpl; import jogamp.opengl.GLXExtensions; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.nio.Buffers; import com.jogamp.common.util.VersionNumber; import com.jogamp.gluegen.runtime.ProcAddressTable; @@ -220,8 +221,6 @@ public class X11GLXContext extends GLContextImpl { final boolean ctFwdCompat = 0 != ( CTX_OPTION_FORWARD & ctp ) ; final boolean ctDebug = 0 != ( CTX_OPTION_DEBUG & ctp ) ; - long ctx=0; - final IntBuffer attribs = Buffers.newDirectIntBuffer(ctx_arb_attribs_rom); attribs.put(ctx_arb_attribs_idx_major + 1, major); attribs.put(ctx_arb_attribs_idx_minor + 1, minor); @@ -249,6 +248,7 @@ public class X11GLXContext extends GLContextImpl { final X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)drawable.getNativeSurface().getGraphicsConfiguration(); final AbstractGraphicsDevice device = config.getScreen().getDevice(); final long display = device.getHandle(); + long ctx=0; try { // critical path, a remote display might not support this command, @@ -258,8 +258,8 @@ public class X11GLXContext extends GLContextImpl { ctx = _glXExt.glXCreateContextAttribsARB(display, config.getFBConfig(), share, direct, attribs); } catch (final RuntimeException re) { if(DEBUG) { - final Throwable t = new Throwable(getThreadName()+": Info: X11GLXContext.createContextARBImpl glXCreateContextAttribsARB failed with "+getGLVersion(major, minor, ctp, "@creation"), re); - t.printStackTrace(); + System.err.println(getThreadName()+": Info: X11GLXContext.createContextARBImpl glXCreateContextAttribsARB failed with "+getGLVersion(major, minor, ctp, "@creation")); + ExceptionUtils.dumpThrowable("", re); } } @@ -314,7 +314,10 @@ public class X11GLXContext extends GLContextImpl { throw new GLException(getThreadName()+": Error making temp context(0) current: display "+toHexString(display)+", context "+toHexString(contextHandle)+", drawable "+drawable); } if( !setGLFunctionAvailability(true, 0, 0, CTX_PROFILE_COMPAT, false /* strictMatch */, null == sharedContext /* withinGLVersionsMapping */) ) { // use GL_VERSION - throw new InternalError("setGLFunctionAvailability !strictMatch failed"); + glXMakeContextCurrent(display, 0, 0, 0); // release temp context + GLX.glXDestroyContext(display, contextHandle); + contextHandle = 0; + throw new InternalError("setGLFunctionAvailability !strictMatch failed.1"); } isDirect = GLX.glXIsDirect(display, contextHandle); if (DEBUG) { @@ -345,7 +348,11 @@ public class X11GLXContext extends GLContextImpl { if ( !glXMakeContextCurrent(display, drawable.getHandle(), drawableRead.getHandle(), temp_ctx) ) { throw new GLException(getThreadName()+": Error making temp context(1) current: display "+toHexString(display)+", context "+toHexString(temp_ctx)+", drawable "+drawable); } - setGLFunctionAvailability(true, 0, 0, CTX_PROFILE_COMPAT, false /* strictMatch */, null == sharedContext /* withinGLVersionsMapping */); // use GL_VERSION + if( !setGLFunctionAvailability(true, 0, 0, CTX_PROFILE_COMPAT, false /* strictMatch */, null == sharedContext /* withinGLVersionsMapping */) ) { // use GL_VERSION + glXMakeContextCurrent(display, 0, 0, 0); // release temp context + GLX.glXDestroyContext(display, temp_ctx); + throw new InternalError("setGLFunctionAvailability !strictMatch failed.2"); + } glXMakeContextCurrent(display, 0, 0, 0); // release temp context if( !createContextARBTried ) { // is*Available calls are valid since setGLFunctionAvailability(..) was called @@ -387,7 +394,7 @@ public class X11GLXContext extends GLContextImpl { // otherwise context of similar profile but different creation method may not be share-able. glXMakeContextCurrent(display, 0, 0, 0); GLX.glXDestroyContext(display, temp_ctx); - throw new GLException(getThreadName()+": X11GLXContext.createContextImpl ctx !ARB but ARB is used, profile > GL2 requested (OpenGL >= 3.0.1). Requested: "+glp+", current: "+getGLVersion()); + throw new GLException(getThreadName()+": X11GLXContext.createContextImpl ARB n/a but required, profile > GL2 requested (OpenGL >= 3.1). Requested: "+glp+", current: "+getGLVersion()); } if(DEBUG) { @@ -491,7 +498,7 @@ public class X11GLXContext extends GLContextImpl { x11Device.lock(); try{ if (DEBUG) { - System.err.println("GLX Version client version "+ GLXUtil.getClientVersionNumber()+ + System.err.println("GLX Version client "+ GLXUtil.getClientVersionNumber()+ ", server: "+ GLXUtil.getGLXServerVersionNumber(x11Device)); } if(((X11GLXDrawableFactory)drawable.getFactoryImpl()).isGLXVersionGreaterEqualOneOne(x11Device)) { diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java index 60e4438d0..69d612da1 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java @@ -72,8 +72,10 @@ import jogamp.opengl.GLDynamicLookupHelper; import jogamp.opengl.GLGraphicsConfigurationUtil; import jogamp.opengl.SharedResourceRunner; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.nio.Buffers; import com.jogamp.common.util.VersionNumber; +import com.jogamp.nativewindow.GenericUpstreamSurfacelessHook; import com.jogamp.nativewindow.x11.X11GraphicsDevice; import com.jogamp.nativewindow.x11.X11GraphicsScreen; import com.jogamp.opengl.GLRendererQuirks; @@ -183,7 +185,8 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { SharedResource(final X11GraphicsDevice dev, final X11GraphicsScreen scrn, final GLDrawableImpl draw, final GLContextImpl ctx, - final VersionNumber glXServerVer, final String glXServerVendor, final boolean glXServerMultisampleAvail) { + final VersionNumber glXServerVer, final String glXServerVendor, + final boolean glXServerMultisampleAvail) { device = dev; screen = scrn; drawable = draw; @@ -197,7 +200,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { glXMultisampleAvailable = glXServerMultisampleAvail; } @Override - public final boolean isValid() { + public final boolean isAvailable() { return null != context; } @Override @@ -209,7 +212,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { @Override final public GLContextImpl getContext() { return context; } @Override - public GLRendererQuirks getRendererQuirks() { + public GLRendererQuirks getRendererQuirks(final GLProfile glp) { return null != context ? context.getRendererQuirks() : null; } @@ -228,12 +231,12 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { sharedMap.clear(); } @Override - public SharedResourceRunner.Resource mapPut(final String connection, final SharedResourceRunner.Resource resource) { - return sharedMap.put(connection, resource); + public SharedResourceRunner.Resource mapPut(final AbstractGraphicsDevice device, final SharedResourceRunner.Resource resource) { + return sharedMap.put(device.getConnection(), resource); } @Override - public SharedResourceRunner.Resource mapGet(final String connection) { - return sharedMap.get(connection); + public SharedResourceRunner.Resource mapGet(final AbstractGraphicsDevice device) { + return sharedMap.get(device.getConnection()); } @Override public Collection<SharedResourceRunner.Resource> mapValues() { @@ -241,9 +244,9 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { } @Override - public boolean isDeviceSupported(final String connection) { + public boolean isDeviceSupported(final AbstractGraphicsDevice device) { final boolean res; - final X11GraphicsDevice x11Device = new X11GraphicsDevice(X11Util.openDisplay(connection), AbstractGraphicsDevice.DEFAULT_UNIT, true /* owner */); + final X11GraphicsDevice x11Device = new X11GraphicsDevice(X11Util.openDisplay(device.getConnection()), device.getUnitID(), true /* owner */); x11Device.lock(); try { res = GLXUtil.isGLXAvailableOnServer(x11Device); @@ -258,51 +261,88 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { } @Override - public SharedResourceRunner.Resource createSharedResource(final String connection) { - final X11GraphicsDevice sharedDevice = new X11GraphicsDevice(X11Util.openDisplay(connection), AbstractGraphicsDevice.DEFAULT_UNIT, true /* owner */); - sharedDevice.lock(); + public SharedResourceRunner.Resource createSharedResource(final AbstractGraphicsDevice adevice) { + final X11GraphicsDevice x11Device = new X11GraphicsDevice(X11Util.openDisplay(adevice.getConnection()), adevice.getUnitID(), true /* owner */); + GLContextImpl context = null; + boolean contextIsCurrent = false; + x11Device.lock(); try { - final X11GraphicsScreen sharedScreen = new X11GraphicsScreen(sharedDevice, sharedDevice.getDefaultScreen()); + final X11GraphicsScreen screen = new X11GraphicsScreen(x11Device, x11Device.getDefaultScreen()); - GLXUtil.initGLXClientDataSingleton(sharedDevice); - final String glXServerVendorName = GLX.glXQueryServerString(sharedDevice.getHandle(), 0, GLX.GLX_VENDOR); - final boolean glXServerMultisampleAvailable = GLXUtil.isMultisampleAvailable(GLX.glXQueryServerString(sharedDevice.getHandle(), 0, GLX.GLX_EXTENSIONS)); + GLXUtil.initGLXClientDataSingleton(x11Device); + final String glXServerVendorName = GLX.glXQueryServerString(x11Device.getHandle(), 0, GLX.GLX_VENDOR); + final boolean glXServerMultisampleAvailable = GLXUtil.isMultisampleAvailable(GLX.glXQueryServerString(x11Device.getHandle(), 0, GLX.GLX_EXTENSIONS)); - final GLProfile glp = GLProfile.get(sharedDevice, GLProfile.GL_PROFILE_LIST_MIN_DESKTOP, false); + final GLProfile glp = GLProfile.get(x11Device, GLProfile.GL_PROFILE_LIST_MIN_DESKTOP, false); if (null == glp) { - throw new GLException("Couldn't get default GLProfile for device: "+sharedDevice); + throw new GLException("Couldn't get default GLProfile for device: "+x11Device); } final GLCapabilitiesImmutable caps = new GLCapabilities(glp); - final GLDrawableImpl sharedDrawable = createOnscreenDrawableImpl(createDummySurfaceImpl(sharedDevice, false, caps, caps, null, 64, 64)); - sharedDrawable.setRealized(true); - final X11GLCapabilities chosenCaps = (X11GLCapabilities) sharedDrawable.getChosenGLCapabilities(); + final GLDrawableImpl drawable = createOnscreenDrawableImpl(createDummySurfaceImpl(x11Device, false, caps, caps, null, 64, 64)); + drawable.setRealized(true); + final X11GLCapabilities chosenCaps = (X11GLCapabilities) drawable.getChosenGLCapabilities(); final boolean glxForcedOneOne = !chosenCaps.hasFBConfig(); final VersionNumber glXServerVersion; if( glxForcedOneOne ) { glXServerVersion = versionOneOne; } else { - glXServerVersion = GLXUtil.getGLXServerVersionNumber(sharedDevice); + glXServerVersion = GLXUtil.getGLXServerVersionNumber(x11Device); } - final GLContextImpl sharedContext = (GLContextImpl) sharedDrawable.createContext(null); - if (null == sharedContext) { - throw new GLException("Couldn't create shared context for drawable: "+sharedDrawable); + context = (GLContextImpl) drawable.createContext(null); + if (null == context) { + throw new GLException("Couldn't create shared context for drawable: "+drawable); } + contextIsCurrent = GLContext.CONTEXT_NOT_CURRENT != context.makeCurrent(); + + final boolean noSurfacelessCtxQuirk = context.hasRendererQuirk(GLRendererQuirks.NoSurfacelessCtx); + boolean allowsSurfacelessCtx = false; - boolean madeCurrent = false; - sharedContext.makeCurrent(); - try { - madeCurrent = sharedContext.isCurrent(); - } finally { - sharedContext.release(); + if( contextIsCurrent && + context.getGLVersionNumber().compareTo(GLContext.Version3_0) >= 0 && + !noSurfacelessCtxQuirk ) + { + GLDrawableImpl zeroDrawable = null; + try { + final ProxySurface zeroSurface = createSurfacelessImpl(x11Device, true, caps, caps, null, 64, 64); + zeroDrawable = createOnscreenDrawableImpl(zeroSurface); + zeroDrawable.setRealized(true); + + // Since sharedContext is still current, + // will keep sharedContext current w/ zeroDrawable or throws GLException + context.setGLDrawable(zeroDrawable, false); + allowsSurfacelessCtx = true; // if setGLDrawable is successful, i.e. no GLException + + // switch back + context.setGLDrawable(drawable, false); + } catch (final Throwable t) { + if( DEBUG ) { + ExceptionUtils.dumpThrowable("", t); + } + } finally { + if( null != zeroDrawable ) { + zeroDrawable.setRealized(false); + } + } } - if( sharedContext.hasRendererQuirk( GLRendererQuirks.DontCloseX11Display ) ) { + if( context.hasRendererQuirk( GLRendererQuirks.DontCloseX11Display ) ) { X11Util.markAllDisplaysUnclosable(); } + if( !noSurfacelessCtxQuirk && !allowsSurfacelessCtx ) { + final int quirk = GLRendererQuirks.NoSurfacelessCtx; + if(DEBUG) { + System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+" -> "+x11Device+": cause: probe"); + } + final GLRendererQuirks glrq = context.getRendererQuirks(); + if( null != glrq ) { + glrq.addQuirk(quirk); + } + GLRendererQuirks.addStickyDeviceQuirk(x11Device, quirk); + } if (DEBUG) { - System.err.println("SharedDevice: " + sharedDevice); - System.err.println("SharedScreen: " + sharedScreen); - System.err.println("SharedContext: " + sharedContext + ", madeCurrent " + madeCurrent); + System.err.println("SharedDevice: " + x11Device); + System.err.println("SharedScreen: " + screen); + System.err.println("SharedContext: " + context + ", madeCurrent " + contextIsCurrent); System.err.println("GLX Server Vendor: " + glXServerVendorName); System.err.println("GLX Server Version: " + glXServerVersion + ", forced "+glxForcedOneOne); System.err.println("GLX Server Multisample: " + glXServerMultisampleAvailable); @@ -310,13 +350,16 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { System.err.println("GLX Client Version: " + GLXUtil.getClientVersionNumber()); System.err.println("GLX Client Multisample: " + GLXUtil.isClientMultisampleAvailable()); } - return new SharedResource(sharedDevice, sharedScreen, sharedDrawable, sharedContext, + return new SharedResource(x11Device, screen, drawable, context, glXServerVersion, glXServerVendorName, glXServerMultisampleAvailable && GLXUtil.isClientMultisampleAvailable()); } catch (final Throwable t) { - throw new GLException("X11GLXDrawableFactory - Could not initialize shared resources for "+connection, t); + throw new GLException("X11GLXDrawableFactory - Could not initialize shared resources for "+adevice, t); } finally { - sharedDevice.unlock(); + if ( contextIsCurrent ) { + context.release(); + } + x11Device.unlock(); } } @@ -329,7 +372,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { System.err.println("Screen : " + sr.screen); System.err.println("Drawable: " + sr.drawable); System.err.println("CTX : " + sr.context); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } if (null != sr.context) { @@ -524,6 +567,13 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { } @Override + public final ProxySurface createSurfacelessImpl(final AbstractGraphicsDevice deviceReq, final boolean createNewDevice, + GLCapabilitiesImmutable chosenCaps, final GLCapabilitiesImmutable requestedCaps, final GLCapabilitiesChooser chooser, final int width, final int height) { + chosenCaps = GLGraphicsConfigurationUtil.fixOnscreenGLCapabilities(chosenCaps); + return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser, new GenericUpstreamSurfacelessHook(width, height)); + } + + @Override protected final ProxySurface createProxySurfaceImpl(final AbstractGraphicsDevice deviceReq, final int screenIdx, final long windowHandle, final GLCapabilitiesImmutable capsRequested, final GLCapabilitiesChooser chooser, final UpstreamSurfaceHook upstream) { final X11GraphicsDevice device = new X11GraphicsDevice(X11Util.openDisplay(deviceReq.getConnection()), deviceReq.getUnitID(), true /* owner */); final X11GraphicsScreen screen = new X11GraphicsScreen(device, screenIdx); diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDynamicLibraryBundleInfo.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDynamicLibraryBundleInfo.java index 0e91a6a65..bfe36dbc8 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDynamicLibraryBundleInfo.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDynamicLibraryBundleInfo.java @@ -28,8 +28,10 @@ package jogamp.opengl.x11.glx; -import jogamp.opengl.*; -import java.util.*; +import java.util.ArrayList; +import java.util.List; + +import jogamp.opengl.DesktopGLDynamicLibraryBundleInfo; public final class X11GLXDynamicLibraryBundleInfo extends DesktopGLDynamicLibraryBundleInfo { protected X11GLXDynamicLibraryBundleInfo() { diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java index 44479acc0..caa336d5a 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java @@ -49,6 +49,7 @@ import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.nio.Buffers; import com.jogamp.common.nio.PointerBuffer; import com.jogamp.nativewindow.x11.X11GraphicsDevice; @@ -375,7 +376,7 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF if ( 0 > chosenIndex ) { if (DEBUG) { System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationFBConfig: failed, return null"); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return null; } @@ -472,7 +473,7 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF if ( 0 > chosenIndex ) { if (DEBUG) { System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationXVisual: failed, return null"); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return null; } |