diff options
136 files changed, 4610 insertions, 1955 deletions
diff --git a/make/build-jogl.xml b/make/build-jogl.xml index 4efe992de..7c34691a0 100644 --- a/make/build-jogl.xml +++ b/make/build-jogl.xml @@ -99,7 +99,7 @@ value="com/jogamp/opengl/cg com/jogamp/opengl/cg/* jogamp/opengl/cg/*"/> <property name="java.part.egl" - value="jogamp/opengl/egl/*"/> + value="com/jogamp/opengl/egl/* jogamp/opengl/egl/*"/> <property name="java.part.glu" value="javax/media/opengl/glu/* javax/media/opengl/glu/gl2es1/* jogamp/opengl/glu/* jogamp/opengl/glu/error/* jogamp/opengl/glu/tessellator/** jogamp/opengl/glu/mipmap/**"/> @@ -1517,6 +1517,7 @@ <patternset id="c.src.files.jogl.desktop"> <include name="${rootrel.src.c}/JoglCommon.c"/> <include name="${rootrel.src.c}/GLContext.c"/> + <include name="${rootrel.src.c}/EGLContext.c"/> <include name="${rootrel.src.c}/GLDebugMessageHandler.c"/> <include name="${rootrel.src.c}/timespec.c" if="isOSX"/> <!-- currently only used for OSX --> <include name="${rootrel.src.c}/macosx/MacOSXCustomCGLCode.c" if="isOSX"/> @@ -1543,6 +1544,7 @@ <patternset id="c.src.files.jogl.mobile"> <include name="${rootrel.src.c}/JoglCommon.c"/> <include name="${rootrel.src.c}/GLContext.c"/> + <include name="${rootrel.src.c}/EGLContext.c"/> <include name="${rootrel.src.c}/GLDebugMessageHandler.c"/> <include name="${rootrel.src.c}/GLXGetProcAddressARB.c" if="isX11"/> <include name="${rootrel.src.c.libav}/ffmpeg_static.c"/> diff --git a/make/config/jogl/egl-CustomCCode.c b/make/config/jogl/egl-CustomCCode.c index 0163c6742..5dd34232c 100644 --- a/make/config/jogl/egl-CustomCCode.c +++ b/make/config/jogl/egl-CustomCCode.c @@ -4,10 +4,10 @@ #include <EGL/egl.h> /* Java->C glue code: - * Java package: jogamp.opengl.egl.EGL + * Java package: com.jogamp.opengl.egl.EGL * Java method: void eglGetConfigAttributes(long dpy, long config, IntBuffer attributes, IntBuffer values) */ -Java_jogamp_opengl_egl_EGL_dispatch_1eglGetConfigAttributes(JNIEnv *env, jclass _unused, jlong dpy, jlong config, jint attributeCount, jobject attributes, jint attributes_byte_offset, jobject values, jint values_byte_offset, jlong procAddress) { +Java_com_jogamp_opengl_egl_EGL_dispatch_1eglGetConfigAttributes(JNIEnv *env, jclass _unused, jlong dpy, jlong config, jint attributeCount, jobject attributes, jint attributes_byte_offset, jobject values, jint values_byte_offset, jlong procAddress) { typedef EGLBoolean (EGLAPIENTRY*_local_PFNEGLGETCONFIGATTRIBPROC)(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint * value); _local_PFNEGLGETCONFIGATTRIBPROC ptr_eglGetConfigAttrib = (_local_PFNEGLGETCONFIGATTRIBPROC) (intptr_t) procAddress; assert(ptr_eglGetConfigAttrib != NULL); diff --git a/make/config/jogl/egl-CustomJavaCode.java b/make/config/jogl/egl-CustomJavaCode.java index 15689b5d8..0c3935691 100644 --- a/make/config/jogl/egl-CustomJavaCode.java +++ b/make/config/jogl/egl-CustomJavaCode.java @@ -1,7 +1,8 @@ private static EGLProcAddressTable _table = new EGLProcAddressTable(new GLProcAddressResolver()); - public static void resetProcAddressTable(DynamicLookupHelper lookup) { + protected static boolean resetProcAddressTable(DynamicLookupHelper lookup) { _table.reset(lookup); + return 0 != _table._addressof_eglGetDisplay && 0 != _table._addressof_eglInitialize; } // There are some #defines in egl.h that GlueGen and PCPP don't currently handle @@ -12,15 +13,6 @@ public static final int EGL_DONT_CARE = -1; public static final int EGL_UNKNOWN = -1; - protected static long eglGetProcAddress(long eglGetProcAddressHandle, java.lang.String procname) - { - if (eglGetProcAddressHandle == 0) { - throw new GLException("Passed null pointer for method \"eglGetProcAddress\""); - } - return dispatch_eglGetProcAddress0(procname, eglGetProcAddressHandle); - } - - /** * In case of an error on a particualr attribute, the attribute in the attributes-buffer is set to 0. * <p> diff --git a/make/config/jogl/egl-common.cfg b/make/config/jogl/egl-common.cfg index cf5d0b083..62694da53 100644 --- a/make/config/jogl/egl-common.cfg +++ b/make/config/jogl/egl-common.cfg @@ -29,7 +29,9 @@ Opaque long __EGLFuncPtr # Implement the first argument to eglGetProcAddress as String instead # of byte[] -ArgumentIsString eglGetProcAddress 0 +#ArgumentIsString eglGetProcAddress 0 +#Implemented in EGLContext +Ignore eglGetProcAddress ReturnsString eglQueryString # Force all of the methods to be emitted using dynamic linking so we diff --git a/make/config/jogl/egl.cfg b/make/config/jogl/egl.cfg index 94b67951d..453987d3e 100644 --- a/make/config/jogl/egl.cfg +++ b/make/config/jogl/egl.cfg @@ -3,7 +3,7 @@ JavaOutputDir gensrc/classes NativeOutputDir gensrc/native/jogl/egl -Package jogamp.opengl.egl +Package com.jogamp.opengl.egl JavaClass EGL Style AllStatic # Shouldn't matter which one of these we pick up @@ -19,10 +19,13 @@ HierarchicalNativeOutput false EmitProcAddressTable true ProcAddressTableClassName EGLProcAddressTable GetProcAddressTableExpr _table +AccessControl com.jogamp.opengl.egl.EGLProcAddressTable PACKAGE_PRIVATE # Implement the first argument to eglGetProcAddress as String instead # of byte[] -ArgumentIsString eglGetProcAddress 0 +#ArgumentIsString eglGetProcAddress 0 +#Implemented in EGLContext +Ignore eglGetProcAddress ReturnsString eglQueryString IncludeAs CustomJavaCode EGL egl-CustomJavaCode.java diff --git a/make/config/jogl/eglext.cfg b/make/config/jogl/eglext.cfg index 7fccce716..1da9b253d 100644 --- a/make/config/jogl/eglext.cfg +++ b/make/config/jogl/eglext.cfg @@ -3,7 +3,7 @@ JavaOutputDir gensrc/classes NativeOutputDir gensrc/native/jogl/egl -Package jogamp.opengl.egl +Package com.jogamp.opengl.egl Style InterfaceAndImpl JavaClass EGLExt ImplPackage jogamp.opengl.egl @@ -15,7 +15,7 @@ Include egl-common.cfg NIOOnly __ALL__ NIODirectOnly __ALL__ -ExtendedInterfaceSymbolsIgnore ../build-temp/gensrc/classes/jogamp/opengl/egl/EGL.java +ExtendedInterfaceSymbolsIgnore ../build-temp/gensrc/classes/com/jogamp/opengl/egl/EGL.java IgnoreExtension EGL_VERSION_1_X @@ -24,7 +24,11 @@ HierarchicalNativeOutput false # Use a ProcAddressTable so we dynamically look up the routines EmitProcAddressTable true ProcAddressTableClassName EGLExtProcAddressTable -GetProcAddressTableExpr _context.getEGLExtProcAddressTable() +GetProcAddressTableExpr _table +AccessControl jogamp.opengl.egl.EGLExtProcAddressTable PACKAGE_PRIVATE + +Import com.jogamp.opengl.egl.EGLExt +Import com.jogamp.opengl.egl.EGLClientPixmapHI CustomCCode #include <stdio.h> /* android */ CustomCCode #include <gluegen_stdint.h> @@ -47,8 +51,9 @@ CustomJavaCode EGLExt public static final long EGL_NO_SYNC_KHR = 0; CustomJavaCode EGLExt public boolean isFunctionAvailable(String glFunctionName); CustomJavaCode EGLExt public boolean isExtensionAvailable(String glExtensionName); -CustomJavaCode EGLExtImpl public EGLExtImpl(EGLContext context) { +CustomJavaCode EGLExtImpl public EGLExtImpl(EGLContext context, EGLExtProcAddressTable table) { CustomJavaCode EGLExtImpl this._context = context; +CustomJavaCode EGLExtImpl this._table = table; CustomJavaCode EGLExtImpl } CustomJavaCode EGLExtImpl public boolean isFunctionAvailable(String glFunctionName) @@ -61,5 +66,7 @@ CustomJavaCode EGLExtImpl { CustomJavaCode EGLExtImpl return _context.isExtensionAvailable(glExtensionName); CustomJavaCode EGLExtImpl } -CustomJavaCode EGLExtImpl private EGLContext _context; +CustomJavaCode EGLExtImpl private final EGLContext _context; +CustomJavaCode EGLExtImpl private final EGLExtProcAddressTable _table; +CustomJavaCode EGLExtImpl final EGLExtProcAddressTable getProcAdressTable() { return _table; } diff --git a/make/config/jogl/gl-es1.cfg b/make/config/jogl/gl-es1.cfg index b73b1a731..b66b18bfd 100644 --- a/make/config/jogl/gl-es1.cfg +++ b/make/config/jogl/gl-es1.cfg @@ -28,7 +28,8 @@ Include gl-common-extensions.cfg EmitProcAddressTable true ProcAddressTableClassName GLES1ProcAddressTable -GetProcAddressTableExpr ((GLES1ProcAddressTable)_context.getGLProcAddressTable()) +GetProcAddressTableExpr _pat +# GetProcAddressTableExpr ((GLES1ProcAddressTable)_context.getGLProcAddressTable()) # Force all of the methods to be emitted using dynamic linking so we # don't need to link against any emulation library on the desktop or diff --git a/make/config/jogl/gl-es3-impl.cfg b/make/config/jogl/gl-es3-impl.cfg index 9682e49af..00929765d 100644 --- a/make/config/jogl/gl-es3-impl.cfg +++ b/make/config/jogl/gl-es3-impl.cfg @@ -32,7 +32,8 @@ ForceExtension GL_ARB_ES3_compatibility EmitProcAddressTable true ProcAddressTableClassName GLES3ProcAddressTable -GetProcAddressTableExpr ((GLES3ProcAddressTable)_context.getGLProcAddressTable()) +GetProcAddressTableExpr _pat +# GetProcAddressTableExpr ((GLES3ProcAddressTable)_context.getGLProcAddressTable()) # Force all of the methods to be emitted using dynamic linking so we # don't need to link against any emulation library on the desktop or diff --git a/make/config/jogl/gl-gl4bc.cfg b/make/config/jogl/gl-gl4bc.cfg index 6ccbace44..344b4776a 100644 --- a/make/config/jogl/gl-gl4bc.cfg +++ b/make/config/jogl/gl-gl4bc.cfg @@ -116,7 +116,8 @@ LocalProcAddressCallingConvention __ALL__ APIENTRY EmitProcAddressTable true ProcAddressTableClassName GL4bcProcAddressTable -GetProcAddressTableExpr ((GL4bcProcAddressTable)_context.getGLProcAddressTable()) +GetProcAddressTableExpr _pat +# GetProcAddressTableExpr ((GL4bcProcAddressTable)_context.getGLProcAddressTable()) # Pick up on-line OpenGL javadoc thanks to user cylab on javagaming.org forums TagNativeBinding true diff --git a/make/config/jogl/gl-impl-CustomJavaCode-common.java b/make/config/jogl/gl-impl-CustomJavaCode-common.java index a2ca12960..6db08efa7 100644 --- a/make/config/jogl/gl-impl-CustomJavaCode-common.java +++ b/make/config/jogl/gl-impl-CustomJavaCode-common.java @@ -1,8 +1,10 @@ + private final GLProfile glProfile; + private final GLContextImpl _context; + @Override public GLProfile getGLProfile() { return this.glProfile; } - private final GLProfile glProfile; @Override public final int getBoundBuffer(int target) { @@ -85,8 +87,6 @@ return _context; } - private final GLContextImpl _context; - /** * @see javax.media.opengl.GLContext#setSwapInterval(int) */ diff --git a/make/config/jogl/gl-impl-CustomJavaCode-gl4bc.java b/make/config/jogl/gl-impl-CustomJavaCode-gl4bc.java index a8b5f8320..8ec1b3205 100644 --- a/make/config/jogl/gl-impl-CustomJavaCode-gl4bc.java +++ b/make/config/jogl/gl-impl-CustomJavaCode-gl4bc.java @@ -1,3 +1,5 @@ +private final GL4bcProcAddressTable _pat; + // Tracks glBegin/glEnd calls to determine whether it is legal to // query Vertex Buffer Object state private boolean inBeginEndPair; @@ -17,35 +19,21 @@ public void setObjectTracker(GLObjectTracker tracker) { public GL4bcImpl(GLProfile glp, GLContextImpl context) { this._context = context; - if(null != context) { - this.bufferObjectTracker = context.getBufferObjectTracker(); - this.bufferStateTracker = context.getBufferStateTracker(); - this.glStateTracker = context.getGLStateTracker(); - } else { - this.bufferObjectTracker = null; - this.bufferStateTracker = null; - this.glStateTracker = null; - } + this._pat = (GL4bcProcAddressTable)_context.getGLProcAddressTable(); + this.bufferObjectTracker = context.getBufferObjectTracker(); + this.bufferStateTracker = context.getBufferStateTracker(); + this.glStateTracker = context.getGLStateTracker(); this.glProfile = glp; } public final void finalizeInit() { - if(null != _context) { - haveARBPixelBufferObject = isExtensionAvailable("GL_ARB_pixel_buffer_object"); - haveEXTPixelBufferObject = isExtensionAvailable("GL_EXT_pixel_buffer_object"); - haveGL15 = isExtensionAvailable("GL_VERSION_1_5"); - haveGL21 = isExtensionAvailable("GL_VERSION_2_1"); - haveARBVertexBufferObject = isExtensionAvailable("GL_ARB_vertex_buffer_object"); - haveARBVertexArrayObject = _context.getGLVersionNumber().compareTo(GLContext.Version300) >= 0 || - isExtensionAvailable("GL_ARB_vertex_array_object"); - } else { - haveARBPixelBufferObject = false; - haveEXTPixelBufferObject = false; - haveGL15 = false; - haveGL21 = false; - haveARBVertexBufferObject = false; - haveARBVertexArrayObject = false; - } + haveARBPixelBufferObject = isExtensionAvailable("GL_ARB_pixel_buffer_object"); + haveEXTPixelBufferObject = isExtensionAvailable("GL_EXT_pixel_buffer_object"); + haveGL15 = isExtensionAvailable("GL_VERSION_1_5"); + haveGL21 = isExtensionAvailable("GL_VERSION_2_1"); + haveARBVertexBufferObject = isExtensionAvailable("GL_ARB_vertex_buffer_object"); + haveARBVertexArrayObject = _context.getGLVersionNumber().compareTo(GLContext.Version3_0) >= 0 || + isExtensionAvailable("GL_ARB_vertex_array_object"); } private int[] imageSizeTemp = new int[1]; @@ -482,7 +470,7 @@ public final void glTexCoordPointer(GLArrayData array) { @Override public final void glBufferData(int target, long size, Buffer data, int usage) { - final long glProcAddress = ((GL4bcProcAddressTable)_context.getGLProcAddressTable())._addressof_glBufferData; + final long glProcAddress = _pat._addressof_glBufferData; if ( 0 == glProcAddress ) { throw new GLException(String.format("Method \"%s\" not available", "glBufferData")); } @@ -493,7 +481,7 @@ public final void glBufferData(int target, long size, Buffer data, int usage) { /** FIXME Add for OpenGL 4.4 @Override public final void glBufferStorage(int target, long size, Buffer data, int flags) { - final long glProcAddress = ((GL4bcProcAddressTable)_context.getGLProcAddressTable())._addressof_glBufferStorage; + final long glProcAddress = _pat._addressof_glBufferStorage; if ( 0 == glProcAddress ) { throw new GLException(String.format("Method \"%s\" not available", "glBufferStorage")); } @@ -516,7 +504,7 @@ private native void dispatch_glBufferStorage(int target, long size, Object data, @Override public final void glNamedBufferDataEXT(int buffer, long size, Buffer data, int usage) { - final long glProcAddress = ((GL4bcProcAddressTable)_context.getGLProcAddressTable())._addressof_glNamedBufferDataEXT; + final long glProcAddress = _pat._addressof_glNamedBufferDataEXT; if ( 0 == glProcAddress ) { throw new GLException(String.format("Method \"%s\" not available", "glNamedBufferDataEXT")); } @@ -538,7 +526,7 @@ private native void dispatch_glNamedBufferDataEXT(int buffer, long size, Object @Override public boolean glUnmapBuffer(int target) { - final long glProcAddress = ((GL4bcProcAddressTable)_context.getGLProcAddressTable())._addressof_glUnmapBuffer; + final long glProcAddress = _pat._addressof_glUnmapBuffer; if ( 0 == glProcAddress ) { throw new GLException(String.format("Method \"%s\" not available", "glUnmapBuffer")); } @@ -547,7 +535,7 @@ public boolean glUnmapBuffer(int target) { @Override public boolean glUnmapNamedBufferEXT(int buffer) { - final long glProcAddress = ((GL4bcProcAddressTable)_context.getGLProcAddressTable())._addressof_glUnmapNamedBufferEXT; + final long glProcAddress = _pat._addressof_glUnmapNamedBufferEXT; if ( 0 == glProcAddress ) { throw new GLException(String.format("Method \"%s\" not available", "glUnmapNamedBufferEXT")); } @@ -563,7 +551,7 @@ private native boolean dispatch_glUnmapNamedBufferEXT(int buffer, long procAddre @Override public final GLBufferStorage mapBuffer(final int target, final int access) { - final long glProcAddress = ((GL4bcProcAddressTable)_context.getGLProcAddressTable())._addressof_glMapBuffer; + final long glProcAddress = _pat._addressof_glMapBuffer; if ( 0 == glProcAddress ) { throw new GLException("Method \"glMapBuffer\" not available"); } @@ -571,7 +559,7 @@ public final GLBufferStorage mapBuffer(final int target, final int access) { } @Override public final GLBufferStorage mapBufferRange(final int target, final long offset, final long length, final int access) { - final long glProcAddress = ((GL4bcProcAddressTable)_context.getGLProcAddressTable())._addressof_glMapBufferRange; + final long glProcAddress = _pat._addressof_glMapBufferRange; if ( 0 == glProcAddress ) { throw new GLException("Method \"glMapBufferRange\" not available"); } @@ -580,7 +568,7 @@ public final GLBufferStorage mapBufferRange(final int target, final long offset, @Override public final GLBufferStorage mapNamedBuffer(final int bufferName, final int access) { - final long glProcAddress = ((GL4bcProcAddressTable)_context.getGLProcAddressTable())._addressof_glMapNamedBufferEXT; + final long glProcAddress = _pat._addressof_glMapNamedBufferEXT; if ( 0 == glProcAddress ) { throw new GLException("Method \"glMapNamedBufferEXT\" not available"); } @@ -597,7 +585,7 @@ private native long dispatch_glMapNamedBufferEXT(int buffer, int access, long gl @Override public final GLBufferStorage mapNamedBufferRange(final int bufferName, final long offset, final long length, final int access) { - final long glProcAddress = ((GL4bcProcAddressTable)_context.getGLProcAddressTable())._addressof_glMapNamedBufferRangeEXT; + final long glProcAddress = _pat._addressof_glMapNamedBufferRangeEXT; if ( 0 == glProcAddress ) { throw new GLException("Method \"glMapNamedBufferRangeEXT\" not available"); } diff --git a/make/config/jogl/gl-impl-CustomJavaCode-gles1.java b/make/config/jogl/gl-impl-CustomJavaCode-gles1.java index 6a7e12ca1..636f20d60 100644 --- a/make/config/jogl/gl-impl-CustomJavaCode-gles1.java +++ b/make/config/jogl/gl-impl-CustomJavaCode-gles1.java @@ -1,14 +1,11 @@ +private final GLES1ProcAddressTable _pat; + public GLES1Impl(GLProfile glp, GLContextImpl context) { this._context = context; - if(null != context) { - this.bufferObjectTracker = context.getBufferObjectTracker(); - this.bufferStateTracker = context.getBufferStateTracker(); - this.glStateTracker = context.getGLStateTracker(); - } else { - this.bufferObjectTracker = null; - this.bufferStateTracker = null; - this.glStateTracker = null; - } + this._pat = (GLES1ProcAddressTable)_context.getGLProcAddressTable(); + this.bufferObjectTracker = context.getBufferObjectTracker(); + this.bufferStateTracker = context.getBufferStateTracker(); + this.glStateTracker = context.getGLStateTracker(); this.glProfile = glp; } @@ -312,7 +309,7 @@ public final void glTexCoordPointer(GLArrayData array) { @Override public final void glBufferData(int target, long size, Buffer data, int usage) { - final long glProcAddress = ((GLES1ProcAddressTable)_context.getGLProcAddressTable())._addressof_glBufferData; + final long glProcAddress = _pat._addressof_glBufferData; if ( 0 == glProcAddress ) { throw new GLException(String.format("Method \"%s\" not available", "glBufferData")); } @@ -323,7 +320,7 @@ public final void glBufferData(int target, long size, Buffer data, int usage) { @Override public boolean glUnmapBuffer(int target) { - final long glProcAddress = ((GLES1ProcAddressTable)_context.getGLProcAddressTable())._addressof_glUnmapBuffer; + final long glProcAddress = _pat._addressof_glUnmapBuffer; if ( 0 == glProcAddress ) { throw new GLException(String.format("Method \"%s\" not available", "glUnmapBuffer")); } @@ -332,7 +329,7 @@ public boolean glUnmapBuffer(int target) { @Override public final GLBufferStorage mapBuffer(final int target, final int access) { - final long glProcAddress = ((GLES1ProcAddressTable)_context.getGLProcAddressTable())._addressof_glMapBuffer; + final long glProcAddress = _pat._addressof_glMapBuffer; if ( 0 == glProcAddress ) { throw new GLException("Method \"glMapBuffer\" not available"); } @@ -340,7 +337,7 @@ public final GLBufferStorage mapBuffer(final int target, final int access) { } @Override public final GLBufferStorage mapBufferRange(final int target, final long offset, final long length, final int access) { - final long glProcAddress = ((GLES1ProcAddressTable)_context.getGLProcAddressTable())._addressof_glMapBufferRange; + final long glProcAddress = _pat._addressof_glMapBufferRange; if ( 0 == glProcAddress ) { throw new GLException("Method \"glMapBufferRange\" not available"); } diff --git a/make/config/jogl/gl-impl-CustomJavaCode-gles3.java b/make/config/jogl/gl-impl-CustomJavaCode-gles3.java index 42adca4b1..a0e3c6570 100644 --- a/make/config/jogl/gl-impl-CustomJavaCode-gles3.java +++ b/make/config/jogl/gl-impl-CustomJavaCode-gles3.java @@ -1,15 +1,11 @@ +private final GLES3ProcAddressTable _pat; public GLES3Impl(GLProfile glp, GLContextImpl context) { this._context = context; - if(null != context) { - this.bufferObjectTracker = context.getBufferObjectTracker(); - this.bufferStateTracker = context.getBufferStateTracker(); - this.glStateTracker = context.getGLStateTracker(); - } else { - this.bufferObjectTracker = null; - this.bufferStateTracker = null; - this.glStateTracker = null; - } + this._pat = (GLES3ProcAddressTable)_context.getGLProcAddressTable(); + this.bufferObjectTracker = context.getBufferObjectTracker(); + this.bufferStateTracker = context.getBufferStateTracker(); + this.glStateTracker = context.getGLStateTracker(); this.glProfile = glp; this._isES3 = glp.getImplName() == GLProfile.GLES3; } @@ -354,7 +350,7 @@ public final void glDepthRange(double zNear, double zFar) { @Override public final void glBufferData(int target, long size, Buffer data, int usage) { - final long glProcAddress = ((GLES3ProcAddressTable)_context.getGLProcAddressTable())._addressof_glBufferData; + final long glProcAddress = _pat._addressof_glBufferData; if ( 0 == glProcAddress ) { throw new GLException(String.format("Method \"%s\" not available", "glBufferData")); } @@ -365,7 +361,7 @@ public final void glBufferData(int target, long size, Buffer data, int usage) { @Override public boolean glUnmapBuffer(int target) { - final long glProcAddress = ((GLES3ProcAddressTable)_context.getGLProcAddressTable())._addressof_glUnmapBuffer; + final long glProcAddress = _pat._addressof_glUnmapBuffer; if ( 0 == glProcAddress ) { throw new GLException(String.format("Method \"%s\" not available", "glUnmapBuffer")); } @@ -374,7 +370,7 @@ public boolean glUnmapBuffer(int target) { @Override public final GLBufferStorage mapBuffer(final int target, final int access) { - final long glProcAddress = ((GLES3ProcAddressTable)_context.getGLProcAddressTable())._addressof_glMapBuffer; + final long glProcAddress = _pat._addressof_glMapBuffer; if ( 0 == glProcAddress ) { throw new GLException("Method \"glMapBuffer\" not available"); } @@ -382,7 +378,7 @@ public final GLBufferStorage mapBuffer(final int target, final int access) { } @Override public final GLBufferStorage mapBufferRange(final int target, final long offset, final long length, final int access) { - final long glProcAddress = ((GLES3ProcAddressTable)_context.getGLProcAddressTable())._addressof_glMapBufferRange; + final long glProcAddress = _pat._addressof_glMapBufferRange; if ( 0 == glProcAddress ) { throw new GLException("Method \"glMapBufferRange\" not available"); } diff --git a/make/config/jogl/glx-x11.cfg b/make/config/jogl/glx-x11.cfg index 6a5bdc484..38f56c26a 100644 --- a/make/config/jogl/glx-x11.cfg +++ b/make/config/jogl/glx-x11.cfg @@ -96,7 +96,7 @@ Ignore GLXHyperpipeConfigSGIX Ignore GLXPipeRect Ignore GLXPipeRectLimits -CustomJavaCode GLX protected static long glXGetProcAddress(long glXGetProcAddressHandle, java.lang.String procname) +CustomJavaCode GLX static long glXGetProcAddress(long glXGetProcAddressHandle, java.lang.String procname) CustomJavaCode GLX { CustomJavaCode GLX if (glXGetProcAddressHandle == 0) { CustomJavaCode GLX throw new GLException("Passed null pointer for method \"glXGetProcAddress\""); diff --git a/make/config/jogl/wgl-win32.cfg b/make/config/jogl/wgl-win32.cfg index d9dbb13e6..435cab0a0 100644 --- a/make/config/jogl/wgl-win32.cfg +++ b/make/config/jogl/wgl-win32.cfg @@ -62,7 +62,7 @@ DropUniqVendorExtensions SGIX DropUniqVendorExtensions SUN DropUniqVendorExtensions WIN -CustomJavaCode WGL protected static long wglGetProcAddress(long wglGetProcAddressHandle, java.lang.String procname) +CustomJavaCode WGL static long wglGetProcAddress(long wglGetProcAddressHandle, java.lang.String procname) CustomJavaCode WGL { CustomJavaCode WGL if (wglGetProcAddressHandle == 0) { CustomJavaCode WGL throw new GLException("Passed null pointer for method \"wglGetProcAddress\""); diff --git a/make/scripts/setenv-jogl.sh b/make/scripts/setenv-jogl.sh index bbaf5187c..79db4f9b1 100755 --- a/make/scripts/setenv-jogl.sh +++ b/make/scripts/setenv-jogl.sh @@ -115,17 +115,18 @@ JOGAMP_ALL_NOAWT_ALT_CLASSPATH=.:"$GLUEGEN_ALT_JAR":"$JOAL_JAR":"$JOGL_ALL_NOAWT JOGAMP_MOBILE_ALT_CLASSPATH=.:"$GLUEGEN_ALT_JAR":"$JOAL_JAR":"$JOGL_MOBILE_CLASSPATH":"$SWT_CLASSPATH":"$JUNIT_JAR":"$ANT_JARS":"$SEMVER_JAR":"$GLUEGEN_TESTUTIL_JAR" export JOGAMP_ALL_AWT_CLASSPATH JOGAMP_ALL_NOAWT_CLASSPATH JOGAMP_MOBILE_CLASSPATH JOGAMP_ATOMICS_NOAWT_CLASSPATH JOGAMP_ALL_NOAWT_ALT_CLASSPATH JOGAMP_MOBILE_ALT_CLASSPATH -CLASSPATH=.:"$GLUEGEN_JAR":"$JOAL_JAR":"$JOGL_CLASSPATH":"$SWT_CLASSPATH":"$JUNIT_JAR":"$ANT_JARS":"$SEMVER_JAR":"$GLUEGEN_TESTUTIL_JAR" -export CLASSPATH +JOGAMP_CLASSPATH=.:"$GLUEGEN_JAR":"$JOAL_JAR":"$JOGL_CLASSPATH":"$SWT_CLASSPATH":"$JUNIT_JAR":"$ANT_JARS":"$SEMVER_JAR":"$GLUEGEN_TESTUTIL_JAR" +export JOGAMP_CLASSPATH -# We use TempJarCache per default now! -#export LD_LIBRARY_PATH="$LD_LIBRARY_PATH":"$GLUEGEN_OS":"$JOGL_LIB_DIR" -#export DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH":"$GLUEGEN_OS:"$JOGL_LIB_DIR" +export JOGAMP_LD_LIBRARY_PATH="$LD_LIBRARY_PATH":"$GLUEGEN_OS":"$JOGL_LIB_DIR" +export JOGAMP_DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH":"$GLUEGEN_OS":"$JOGL_LIB_DIR" echo JOGAMP_ALL_AWT_CLASSPATH: "$JOGAMP_ALL_AWT_CLASSPATH" echo JOGAMP_ALL_NOAWT_CLASSPATH: "$JOGAMP_ALL_NOAWT_CLASSPATH" echo JOGAMP_MOBILE_CLASSPATH: "$JOGAMP_MOBILE_CLASSPATH" -echo CLASSPATH: "$CLASSPATH" +echo JOGAMP_CLASSPATH: "$JOGAMP_CLASSPATH" +echo JOGAMP_LD_LIBRARY_PATH: "$JOGAMP_LD_LIBRARY_PATH" +echo JOGAMP_DYLD_LIBRARY_PATH: "$JOGAMP_DYLD_LIBRARY_PATH" echo echo MacOSX REMEMBER to add the JVM arguments "-XstartOnFirstThread -Djava.awt.headless=true" for running demos without AWT, e.g. NEWT echo MacOSX REMEMBER to add the JVM arguments "-XstartOnFirstThread -Djava.awt.headless=true com.jogamp.newt.util.MainThread" for running demos with NEWT diff --git a/make/scripts/tests-x32-dbg.bat b/make/scripts/tests-x32-dbg.bat index 91d1d6fbc..c89eee449 100755 --- a/make/scripts/tests-x32-dbg.bat +++ b/make/scripts/tests-x32-dbg.bat @@ -1,4 +1,9 @@ +set TEMP=\\jordan\data\Incoming\windows\temp
+set TMP=\\jordan\data\Incoming\windows\temp
+REM set TEMP=C:\Documents and Settings\jogamp\temp
+REM set TMP=C:\Documents and Settings\jogamp\temp
+
set BLD_SUB=build-win32
set J2RE_HOME=c:\jre1.7.0_67_x32
set JAVA_HOME=c:\jdk1.7.0_67_x32
@@ -31,6 +36,8 @@ REM set D_ARGS="-Djogl.debug=all" "-Dnewt.debug=all" "-Dnativewindow.debug=all" REM set D_ARGS="-Djogl.debug=all" "-Dnewt.debug=all" "-Dnativewindow.debug=all" "-Djogl.debug.GLContext.TraceSwitch" "-Djogl.debug.GLContext"
REM set D_ARGS="-Djogl.debug.GLDrawable" "-Djogl.debug.windows.cpu_affinity_mode=0"
REM set D_ARGS="-Djogamp.debug.IOUtil" "-Djogl.debug.GLSLCode" "-Djogl.debug.GLMediaPlayer"
+REM set D_ARGS="-Djogamp.debug.IOUtil"
+set D_ARGS="-Djogl.debug.GLSLCode"
REM set D_ARGS="-Djogl.debug.ExtensionAvailabilityCache" "-Djogl.debug=all" "-Dnewt.debug=all" "-Dnativewindow.debug=all" "-Djogamp.debug.ProcAddressHelper=true" "-Djogamp.debug.NativeLibrary=true" "-Djogamp.debug.NativeLibrary.Lookup=true"
REM set D_ARGS="-Djogl.debug=all" "-Dnewt.debug=all" "-Dnativewindow.debug=all" "-Djogamp.debug.NativeLibrary=true"
REM set D_ARGS="-Djogamp.debug.JNILibLoader=true" "-Djogamp.debug.NativeLibrary=true" "-Djogamp.debug.NativeLibrary.Lookup=true" "-Djogl.debug.GLProfile=true"
diff --git a/make/scripts/tests-x64-dbg.bat b/make/scripts/tests-x64-dbg.bat index 1f0b88139..a46e578ca 100755 --- a/make/scripts/tests-x64-dbg.bat +++ b/make/scripts/tests-x64-dbg.bat @@ -1,4 +1,9 @@ +set TEMP=\\jordan\data\Incoming\windows\temp
+set TMP=\\jordan\data\Incoming\windows\temp
+REM set TEMP=C:\Documents and Settings\jogamp\temp
+REM set TMP=C:\Documents and Settings\jogamp\temp
+
set BLD_SUB=build-win64
set J2RE_HOME=c:\jre1.7.0_67_x64
set JAVA_HOME=c:\jdk1.7.0_67_x64
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index 00bd8571e..a8b557dc8 100644 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -42,6 +42,10 @@ if [ $MOSX -eq 1 ] ; then MOSX_MT=1 fi +# We use TempJarCache per default now! +#export LD_LIBRARY_PATH=$JOGAMP_LD_LIBRARY_PATH +#export DYLD_LIBRARY_PATH=$JOGAMP_DYLD_LIBRARY_PATH + #export LD_LIBRARY_PATH=$spath/../../EXTERNAL/PVRVFrame/OGLES-2.0/Linux_x86_64:$LD_LIBRARY_PATH #export LD_LIBRARY_PATH=$spath/../../EXTERNAL/PVRVFrame/OGLES-2.0/Linux_x86_32:$LD_LIBRARY_PATH #export LD_LIBRARY_PATH=/usr/local/projects/Xorg.modular/build-x86_64/lib:$LD_LIBRARY_PATH @@ -116,6 +120,7 @@ function jrun() { #D_ARGS="-Dnativewindow.debug.X11Util.ATI_HAS_NO_XCLOSEDISPLAY_BUG" #D_ARGS="-Dnativewindow.debug.X11Util.ATI_HAS_NO_MULTITHREADING_BUG" + #D_ARGS="-Djogl.disable.opengldesktop" #D_ARGS="-Djogl.disable.opengles" #D_ARGS="-Djogl.disable.openglcore" #D_ARGS="-Djogl.disable.openglarbcontext" @@ -150,6 +155,12 @@ function jrun() { #D_ARGS="-Djogl.debug.GLContext -Djogl.debug.GLDrawable -Dnativewindow.debug.GraphicsConfiguration" #D_ARGS="-Dnativewindow.debug.GraphicsConfiguration" #D_ARGS="-Djogl.debug.GLContext -Djogl.debug.GLDrawable" + #D_ARGS="-Djogl.debug.GLContext -Djogl.debug.GLDrawable -Djogl.debug.GLProfile -Djogamp.common.utils.locks.Lock.timeout=600000 -Djogamp.debug.Lock" + #D_ARGS="-Djogl.debug.GLContext -Djogl.debug.GLDrawable -Dnativewindow.debug.ProxySurface -Djogl.debug.GLProfile -Djogl.disable.opengldesktop" + #D_ARGS="-Djogl.debug.GLContext -Djogl.debug.GLDrawable -Dnativewindow.debug.ProxySurface -Djogl.debug.GLProfile" + #D_ARGS="-Djogl.disable.surfacelesscontext -Djogl.debug.GLContext -Djogl.debug.GLDrawable -Djogl.debug.GLJPanel -Djogl.debug.DebugGL" + #D_ARGS="-Djogl.debug.GLContext -Djogl.debug.GLJPanel -Djogl.debug.DebugGL" + #D_ARGS="-Djogl.debug.GLJPanel" #D_ARGS="-Djogl.debug.GLContext.NoProfileAliasing" #D_ARGS="-Djogl.debug.GLDrawable -Dnativewindow.debug.X11Util -Dnativewindow.debug.NativeWindow -Dnewt.debug.Display -Dnewt.debug.Screen -Dnewt.debug.Window" #D_ARGS="-Djogl.debug.Animator" @@ -398,8 +409,8 @@ function testawtswt() { # HiDPI # #testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT $* +testawt com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2GLJPanelAWT $* #testawt com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2AWT $* -#testawt com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2GLJPanelAWT $* #testawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NewtCanvasAWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.glsl.TestRulerNEWT01 $* #testnoawt com.jogamp.opengl.test.junit.graph.demos.GPUUISceneNewtDemo $* @@ -589,7 +600,7 @@ function testawtswt() { #testnoawt com.jogamp.opengl.test.junit.newt.TestWindows01NEWT $* #testnoawt com.jogamp.opengl.test.junit.newt.TestWindowClosingProtocol02NEWT $* -testnoawt com.jogamp.opengl.test.junit.newt.TestWindowAndPointerIconNEWT $* +#testnoawt com.jogamp.opengl.test.junit.newt.TestWindowAndPointerIconNEWT $* #testnoawt com.jogamp.opengl.test.junit.newt.TestGLWindows01NEWT $* #testnoawt com.jogamp.opengl.test.junit.newt.TestGLWindows02NEWTAnimated $* #testnoawt com.jogamp.opengl.test.junit.newt.TestGLWindows03NEWTAnimResize $* @@ -785,13 +796,14 @@ testnoawt com.jogamp.opengl.test.junit.newt.TestWindowAndPointerIconNEWT $* #testawt com.jogamp.opengl.test.junit.jogl.util.texture.TestTexture02AWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestJPEGImage01NEWT $* -#testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestJPEGJoglAWTCompareNewtAWT $* -#testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestJPEGJoglAWTBenchmarkNewtAWT $* +#testawt com.jogamp.opengl.test.junit.jogl.util.texture.TestJPEGJoglAWTCompareNewtAWT $* +#testawt com.jogamp.opengl.test.junit.jogl.util.texture.TestJPEGJoglAWTBenchmarkNewtAWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestJPEGTextureFromFileNEWT $* -#testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGPixelRect00NEWT $* -#testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGPixelRect01NEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPixelFormat00NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPixelFormatUtil00NEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPixelFormatUtil01NEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGPixelRect00NEWT $* +#testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGPixelRect01NEWT $* #testawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGTextureFromFileAWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestPNGTextureFromFileNEWT $* #testnoawt com.jogamp.opengl.test.junit.jogl.util.texture.TestTGATextureFromFileNEWT $* 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; } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/GenericUpstreamSurfacelessHook.java b/src/nativewindow/classes/com/jogamp/nativewindow/GenericUpstreamSurfacelessHook.java new file mode 100644 index 000000000..3fd5ad902 --- /dev/null +++ b/src/nativewindow/classes/com/jogamp/nativewindow/GenericUpstreamSurfacelessHook.java @@ -0,0 +1,88 @@ +/** + * 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 com.jogamp.nativewindow; + +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.UpstreamSurfaceHook; + +import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; + +public class GenericUpstreamSurfacelessHook extends UpstreamSurfaceHookMutableSize { + /** + * @param width the initial width as returned by {@link NativeSurface#getSurfaceWidth()} via {@link UpstreamSurfaceHook#getSurfaceWidth(ProxySurface)}, + * not the actual dummy surface width. + * The latter is platform specific and small + * @param height the initial height as returned by {@link NativeSurface#getSurfaceHeight()} via {@link UpstreamSurfaceHook#getSurfaceHeight(ProxySurface)}, + * not the actual dummy surface height, + * The latter is platform specific and small + */ + public GenericUpstreamSurfacelessHook(final int width, final int height) { + super(width, height); + } + + @Override + public final void create(final ProxySurface s) { + final AbstractGraphicsDevice device = s.getGraphicsConfiguration().getScreen().getDevice(); + device.lock(); + try { + if(0 == device.getHandle()) { + device.open(); + s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); + } + if( 0 != s.getSurfaceHandle() ) { + throw new InternalError("Upstream surface not null: "+s); + } + s.addUpstreamOptionBits( ProxySurface.OPT_UPSTREAM_SURFACELESS | + ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE | + ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE ); + } finally { + device.unlock(); + } + } + + @Override + public final void destroy(final ProxySurface s) { + if( s.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) { + final AbstractGraphicsDevice device = s.getGraphicsConfiguration().getScreen().getDevice(); + if( !s.containsUpstreamOptionBits( ProxySurface.OPT_UPSTREAM_SURFACELESS ) ) { + throw new InternalError("Owns upstream surface, but not a valid zero surface: "+s); + } + if( 0 != s.getSurfaceHandle() ) { + throw new InternalError("Owns upstream valid zero surface, but non zero surface: "+s); + } + device.lock(); + try { + s.clearUpstreamOptionBits( ProxySurface.OPT_UPSTREAM_SURFACELESS | ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + } finally { + device.unlock(); + } + } + } +} diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/DirectDataBufferInt.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/DirectDataBufferInt.java index c7055099f..0f103bfb3 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/DirectDataBufferInt.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/DirectDataBufferInt.java @@ -36,6 +36,7 @@ import java.awt.image.DirectColorModel; import java.awt.image.SampleModel; import java.awt.image.SinglePixelPackedSampleModel; import java.awt.image.WritableRaster; +import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.util.Hashtable; @@ -54,9 +55,12 @@ public final class DirectDataBufferInt extends DataBuffer { public static class BufferedImageInt extends BufferedImage { final int customImageType; - public BufferedImageInt (final int customImageType, final ColorModel cm, final WritableRaster raster, final Hashtable<?,?> properties) { + final DirectDataBufferInt dataBuffer; + public BufferedImageInt (final int customImageType, final ColorModel cm, + final DirectDataBufferInt dataBuffer, final WritableRaster raster, final Hashtable<?,?> properties) { super(cm, raster, false /* isRasterPremultiplied */, properties); this.customImageType = customImageType; + this.dataBuffer = dataBuffer; } /** @@ -68,6 +72,11 @@ public final class DirectDataBufferInt extends DataBuffer { return customImageType; } + /** + * Returns the underlying {@link DirectDataBufferInt} associated with this instance via {@link Raster} {@link #getRaster() instance}. + */ + public DirectDataBufferInt getDataBuffer() { return dataBuffer; } + @Override public String toString() { return "BufferedImageInt@"+Integer.toHexString(hashCode()) @@ -163,14 +172,18 @@ public final class DirectDataBufferInt extends DataBuffer { // final WritableRaster raster = new SunWritableRaster(sppsm, dataBuffer, location); final WritableRaster raster = new DirectWritableRaster(sppsm, dataBuffer, location); - return new BufferedImageInt(imageType, colorModel, raster, properties); + return new BufferedImageInt(imageType, colorModel, dataBuffer, raster, properties); } - /** Default data bank. */ - private final IntBuffer data; + /** Default NIO data bank storage, {@link ByteBuffer} representation. */ + private final ByteBuffer dataBytes; + /** Default NIO data bank storage, {@link IntBuffer} representation. */ + private final IntBuffer dataInts; - /** All data banks */ - private final IntBuffer bankdata[]; + /** All NIO data banks, {@link ByteBuffer} representation. */ + private final ByteBuffer bankdataBytes[]; + /** All NIO data banks, {@link IntBuffer} representation. */ + private final IntBuffer bankdataInts[]; /** * Constructs an nio integer-based {@link DataBuffer} with a single bank @@ -180,9 +193,12 @@ public final class DirectDataBufferInt extends DataBuffer { */ public DirectDataBufferInt(final int size) { super(TYPE_INT, size); - data = Buffers.newDirectIntBuffer(size); - bankdata = new IntBuffer[1]; - bankdata[0] = data; + dataBytes = Buffers.newDirectByteBuffer(size * Buffers.SIZEOF_INT); + dataInts = dataBytes.asIntBuffer(); + bankdataBytes = new ByteBuffer[1]; + bankdataInts = new IntBuffer[1]; + bankdataBytes[0] = dataBytes; + bankdataInts[0] = dataInts; } /** @@ -194,11 +210,14 @@ public final class DirectDataBufferInt extends DataBuffer { */ public DirectDataBufferInt(final int size, final int numBanks) { super(TYPE_INT,size,numBanks); - bankdata = new IntBuffer[numBanks]; + bankdataBytes = new ByteBuffer[numBanks]; + bankdataInts = new IntBuffer[numBanks]; for (int i= 0; i < numBanks; i++) { - bankdata[i] = Buffers.newDirectIntBuffer(size); + bankdataBytes[i] = Buffers.newDirectByteBuffer(size * Buffers.SIZEOF_INT); + bankdataInts[i] = bankdataBytes[i].asIntBuffer(); } - data = bankdata[0]; + dataBytes = bankdataBytes[0]; + dataInts = bankdataInts[0]; } /** @@ -210,33 +229,57 @@ public final class DirectDataBufferInt extends DataBuffer { * hold <code>size</code> elements. * </p> * - * @param dataArray The integer array for the {@link DataBuffer}. + * @param dataArray The NIO {@link ByteBuffer} array, holding the integer data for the {@link DataBuffer}. * @param size The size of the {@link DataBuffer} bank. */ - public DirectDataBufferInt(final IntBuffer dataArray, final int size) { + public DirectDataBufferInt(final ByteBuffer dataArray, final int size) { super(TYPE_INT,size); - data = dataArray; - bankdata = new IntBuffer[1]; - bankdata[0] = data; + dataBytes = Buffers.nativeOrder(dataArray); + dataInts = dataBytes.asIntBuffer(); + bankdataBytes = new ByteBuffer[1]; + bankdataInts = new IntBuffer[1]; + bankdataBytes[0] = dataBytes; + bankdataInts[0] = dataInts; } /** - * Returns the default (first) int data array in {@link DataBuffer}. + * Returns the default (first) int data array in {@link DataBuffer} as an {@link IntBuffer} representation. * * @return The first integer data array. + * @see #getDataBytes() */ public IntBuffer getData() { - return data; + return dataInts; + } + /** + * Returns the default (first) int data array in {@link DataBuffer} as a {@link ByteBuffer} representation. + * + * @return The first integer data array. + * @see #getData() + */ + public ByteBuffer getDataBytes() { + return dataBytes; } /** - * Returns the data array for the specified bank. + * Returns the data array for the specified bank as an {@link IntBuffer} representation. * * @param bank The bank whose data array you want to get. * @return The data array for the specified bank. + * @see #getDataBytes(int) */ public IntBuffer getData(final int bank) { - return bankdata[bank]; + return bankdataInts[bank]; + } + /** + * Returns the data array for the specified bank as a {@link ByteBuffer} representation. + * + * @param bank The bank whose data array you want to get. + * @return The data array for the specified bank. + * @see #getData(int) + */ + public ByteBuffer getDataBytes(final int bank) { + return bankdataBytes[bank]; } /** @@ -249,7 +292,7 @@ public final class DirectDataBufferInt extends DataBuffer { */ @Override public int getElem(final int i) { - return data.get(i+offset); + return dataInts.get(i+offset); } /** @@ -263,7 +306,7 @@ public final class DirectDataBufferInt extends DataBuffer { */ @Override public int getElem(final int bank, final int i) { - return bankdata[bank].get(i+offsets[bank]); + return bankdataInts[bank].get(i+offsets[bank]); } /** @@ -277,7 +320,7 @@ public final class DirectDataBufferInt extends DataBuffer { */ @Override public void setElem(final int i, final int val) { - data.put(i+offset, val); + dataInts.put(i+offset, val); } /** @@ -291,7 +334,7 @@ public final class DirectDataBufferInt extends DataBuffer { */ @Override public void setElem(final int bank, final int i, final int val) { - bankdata[bank].put(i+offsets[bank], val); + bankdataInts[bank].put(i+offsets[bank], val); } } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java index 6498ebd1e..32e4add75 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/awt/JAWTWindow.java @@ -37,6 +37,7 @@ package com.jogamp.nativewindow.awt; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.os.Platform; import com.jogamp.common.util.awt.AWTEDTExecutor; import com.jogamp.common.util.locks.LockFactory; @@ -558,7 +559,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, surfaceLock.unlock(); if(DEBUG) { System.err.println("JAWTWindow: Can't lock surface, component peer n/a. Component displayable "+component.isDisplayable()+", "+component); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } else { determineIfApplet(); @@ -765,7 +766,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, // avoid deadlock .. if(DEBUG) { System.err.println("Warning: JAWT Lock hold, but not the AWT tree lock: "+this); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } if( null == storage ) { storage = new Point(); @@ -788,7 +789,7 @@ public abstract class JAWTWindow implements NativeWindow, OffscreenLayerSurface, if(LOCK_SURFACE_NOT_READY == lockRes) { if(DEBUG) { System.err.println("Warning: JAWT Lock couldn't be acquired: "+this); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return null; } diff --git a/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java b/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java index d21994ea5..a38a48b85 100644 --- a/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java +++ b/src/nativewindow/classes/com/jogamp/nativewindow/egl/EGLGraphicsDevice.java @@ -34,11 +34,14 @@ package com.jogamp.nativewindow.egl; import javax.media.nativewindow.*; +import com.jogamp.common.util.VersionNumber; + /** Encapsulates a graphics device on EGL platforms. */ public class EGLGraphicsDevice extends DefaultGraphicsDevice implements Cloneable { - final long[] nativeDisplayID = new long[1]; - /* final */ EGLDisplayLifecycleCallback eglLifecycleCallback; + private final long[] nativeDisplayID = new long[1]; + private /* final */ EGLDisplayLifecycleCallback eglLifecycleCallback; + private VersionNumber eglVersion = VersionNumber.zeroVersion; /** * Hack to allow inject a EGL termination call. @@ -52,9 +55,11 @@ public class EGLGraphicsDevice extends DefaultGraphicsDevice implements Cloneabl * Implementation should issue an <code>EGL.eglGetDisplay(nativeDisplayID)</code> * inclusive <code>EGL.eglInitialize(eglDisplayHandle, ..)</code> call. * @param nativeDisplayID in/out array of size 1, passing the requested nativeVisualID, may return a different revised nativeVisualID handle + * @param major out array for EGL major version + * @param minor out array for EGL minor version * @return the initialized EGL display ID, or <code>0</code> if not successful */ - public long eglGetAndInitDisplay(long[] nativeDisplayID); + public long eglGetAndInitDisplay(final long[] nativeDisplayID, final int[] major, final int[] minor); /** * Implementation should issue an <code>EGL.eglTerminate(eglDisplayHandle)</code> call. @@ -79,6 +84,9 @@ public class EGLGraphicsDevice extends DefaultGraphicsDevice implements Cloneabl this.eglLifecycleCallback = eglLifecycleCallback; } + /** EGL server version as returned by {@code eglInitialize(..)}. Only valid after {@link #open()}. */ + public VersionNumber getEGLVersion() { return eglVersion; } + public long getNativeDisplayID() { return nativeDisplayID[0]; } @Override @@ -98,11 +106,16 @@ public class EGLGraphicsDevice extends DefaultGraphicsDevice implements Cloneabl if(DEBUG) { System.err.println(Thread.currentThread().getName() + " - EGLGraphicsDevice.open(): "+this); } - handle = eglLifecycleCallback.eglGetAndInitDisplay(nativeDisplayID); + final int[] major = { 0 }; + final int[] minor = { 0 }; + handle = eglLifecycleCallback.eglGetAndInitDisplay(nativeDisplayID, major, minor); if(0 == handle) { + eglVersion = VersionNumber.zeroVersion; throw new NativeWindowException("EGLGraphicsDevice.open() failed: "+this); + } else { + eglVersion = new VersionNumber(major[0], minor[0], 0); + return true; } - return true; } return false; } @@ -142,5 +155,10 @@ public class EGLGraphicsDevice extends DefaultGraphicsDevice implements Cloneabl eglLifecycleCallback = (EGLDisplayLifecycleCallback) newOwnership; return oldOwnership; } + + @Override + public String toString() { + return getClass().getSimpleName()+"[type "+getType()+", v"+eglVersion+", connection "+getConnection()+", unitID "+getUnitID()+", handle 0x"+Long.toHexString(getHandle())+", owner "+isHandleOwner()+", "+toolkitLock+"]"; + } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java b/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java index 3f8113baa..c73f544b0 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java +++ b/src/nativewindow/classes/javax/media/nativewindow/GraphicsConfigurationFactory.java @@ -33,7 +33,9 @@ package javax.media.nativewindow; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.util.ReflectionUtil; + import jogamp.nativewindow.Debug; import jogamp.nativewindow.DefaultGraphicsConfigurationFactoryImpl; @@ -226,7 +228,7 @@ public abstract class GraphicsConfigurationFactory { throw new IllegalArgumentException("Given capabilities class must implement CapabilitiesImmutable"); } if(DEBUG) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); System.err.println("GraphicsConfigurationFactory.getFactory: "+deviceType.getName()+", "+capabilitiesType.getName()); dumpFactories(); } diff --git a/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java b/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java index 7a69b9a40..377dd55cd 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java +++ b/src/nativewindow/classes/javax/media/nativewindow/ProxySurface.java @@ -65,6 +65,14 @@ public interface ProxySurface extends MutableSurface { */ public static final int OPT_UPSTREAM_WINDOW_INVISIBLE = 1 << 8; + /** + * Implementation specific bitvalue stating the upstream's {@link NativeSurface}'s zero handle is valid. + * @see #addUpstreamOptionBits(int) + * @see #clearUpstreamOptionBits(int) + * @see #getUpstreamOptionBits() + */ + public static final int OPT_UPSTREAM_SURFACELESS = 1 << 9; + /** Allow redefining the AbstractGraphicsConfiguration */ public void setGraphicsConfiguration(AbstractGraphicsConfiguration cfg); diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormat.java b/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormat.java index e5901f584..2016b2885 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormat.java +++ b/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormat.java @@ -28,6 +28,10 @@ package javax.media.nativewindow.util; +import java.util.Arrays; + +import com.jogamp.common.util.IntBitfield; + /** * Basic pixel formats * <p> @@ -60,7 +64,7 @@ package javax.media.nativewindow.util; */ public enum PixelFormat { /** - * Pixel size is 1 bytes (8 bits) with one component of size 1 byte (8 bits). + * Stride is 8 bits, 8 bits per pixel, 1 component of 8 bits. * Compatible with: * <ul> * <li>OpenGL: data-format GL_ALPHA (< GL3), GL_RED (>= GL3), data-type GL_UNSIGNED_BYTE</li> @@ -68,34 +72,138 @@ public enum PixelFormat { * </ul> * </p> */ - LUMINANCE(1, 8), + LUMINANCE(new CType[]{ CType.Y }, 1, 8, 8), /** - * Pixel size is 3 bytes (24 bits) with each component of size 1 byte (8 bits). + * Stride is 16 bits, 16 bits per pixel, 3 {@link PackedComposition#isUniform() discrete} components. + * <p> + * The {@link PackedComposition#isUniform() discrete} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>R: 0x1F << 0</li> + * <li>G: 0x3F << 5</li> + * <li>B: 0x1F << 11</li> + * </ol> + * </p> * <p> - * The components are interleaved in the order: + * Compatible with: * <ul> - * <li>Low to High: R, G, B</li> + * <li>OpenGL: data-format GL_RGB, data-type GL_UNSIGNED_SHORT_5_6_5_REV</li> + * <li>AWT: <i>None</i></li> * </ul> * </p> + */ + RGB565(new CType[]{ CType.R, CType.G, CType.B }, + new int[]{ 0x1F, 0x3F, 0x1F }, + new int[]{ 0, 5, 5+6 }, + 16 ), + + /** + * Stride is 16 bits, 16 bits per pixel, 3 {@link PackedComposition#isUniform() discrete} components. + * <p> + * The {@link PackedComposition#isUniform() discrete} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>B: 0x1F << 0</li> + * <li>G: 0x3F << 5</li> + * <li>R: 0x1F << 11</li> + * </ol> + * </p> * <p> * Compatible with: * <ul> - * <li>OpenGL: data-format GL_RGB, data-type GL_UNSIGNED_BYTE</li> + * <li>OpenGL: data-format GL_RGB, data-type GL_UNSIGNED_SHORT_5_6_5</li> + * <li>AWT: <i>None</i></li> + * </ul> + * </p> + */ + BGR565(new CType[]{ CType.B, CType.G, CType.R}, + new int[]{ 0x1F, 0x3F, 0x1F }, + new int[]{ 0, 5, 5+6 }, + 16 ), + + /** + * Stride is 16 bits, 16 bits per pixel, 4 {@link PackedComposition#isUniform() discrete} components. + * <p> + * The {@link PackedComposition#isUniform() discrete} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>R: 0x1F << 0</li> + * <li>G: 0x1F << 5</li> + * <li>B: 0x1F << 10</li> + * <li>A: 0x01 << 15</li> + * </ol> + * </p> + * <p> + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_SHORT_1_5_5_5_REV</li> + * <li>AWT: <i>None</i></li> + * </ul> + * </p> + */ + RGBA5551(new CType[]{ CType.R, CType.G, CType.B, CType.A}, + new int[]{ 0x1F, 0x1F, 0x1F, 0x01 }, + new int[]{ 0, 5, 5+5, 5+5+5 }, + 16 ), + + /** + * Stride is 16 bits, 16 bits per pixel, 4 {@link PackedComposition#isUniform() discrete} components. + * <p> + * The {@link PackedComposition#isUniform() discrete} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>A: 0x01 << 0</li> + * <li>B: 0x1F << 1</li> + * <li>G: 0x1F << 6</li> + * <li>R: 0x1F << 11</li> + * </ol> + * </p> + * <p> + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_SHORT_5_5_5_1</li> * <li>AWT: <i>None</i></li> * </ul> * </p> */ - RGB888(3, 24), + ABGR1555(new CType[]{ CType.A, CType.B, CType.G, CType.R }, + new int[]{ 0x01, 0x1F, 0x1F, 0x1F }, + new int[]{ 0, 1, 1+5, 1+5+5 }, + 16 ), /** - * Pixel size is 3 bytes (24 bits) with each component of size 1 byte (8 bits). + * Stride 24 bits, 24 bits per pixel, 3 {@link PackedComposition#isUniform() uniform} components of 8 bits. + * <p> + * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>R: 0xFF << 0</li> + * <li>G: 0xFF << 8</li> + * <li>B: 0xFF << 16</li> + * </ol> + * </p> * <p> - * The components are interleaved in the order: + * Compatible with: * <ul> - * <li>Low to High: B, G, R</li> + * <li>OpenGL: data-format GL_RGB, data-type GL_UNSIGNED_BYTE</li> + * <li>AWT: <i>None</i></li> * </ul> * </p> + */ + RGB888(new CType[]{ CType.R, CType.G, CType.B }, 3, 8, 24), + + /** + * Stride is 24 bits, 24 bits per pixel, 3 {@link PackedComposition#isUniform() uniform} components of of 8 bits. + * <p> + * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>B: 0xFF << 0</li> + * <li>G: 0xFF << 8</li> + * <li>R: 0xFF << 16</li> + * </ol> + * </p> * <p> * Compatible with: * <ul> @@ -104,16 +212,62 @@ public enum PixelFormat { * </ul> * </p> */ - BGR888(3, 24), + BGR888(new CType[]{ CType.B, CType.G, CType.R }, 3, 8, 24), + + /** + * Stride is 32 bits, 24 bits per pixel, 3 {@link PackedComposition#isUniform() uniform} components of 8 bits. + * <p> + * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>R: 0xFF << 0</li> + * <li>G: 0xFF << 8</li> + * <li>B: 0xFF << 16</li> + * </ol> + * </p> + * <p> + * Compatible with: + * <ul> + * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_BYTE, with alpha discarded!</li> + * <li>AWT: {@link java.awt.image.BufferedImage#TYPE_INT_BGR TYPE_INT_BGR}</li> + * </ul> + * </p> + */ + RGBx8888(new CType[]{ CType.R, CType.G, CType.B }, 3, 8, 32), /** - * Pixel size is 4 bytes (32 bits) with each component of size 1 byte (8 bits). + * Stride is 32 bits, 24 bits per pixel, 3 {@link PackedComposition#isUniform() uniform} components of 8 bits. + * <p> + * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>B: 0xFF << 0</li> + * <li>G: 0xFF << 8</li> + * <li>R: 0xFF << 16</li> + * </ol> + * </p> * <p> - * The components are interleaved in the order: + * Compatible with: * <ul> - * <li>Low to High: R, G, B, A</li> + * <li>OpenGL: data-format GL_BGRA, data-type GL_UNSIGNED_BYTE - with alpha discarded!</li> + * <li>AWT: {@link java.awt.image.BufferedImage#TYPE_INT_RGB TYPE_INT_RGB}</li> * </ul> * </p> + */ + BGRx8888(new CType[]{ CType.B, CType.G, CType.R }, 3, 8, 32), + + /** + * Stride is 32 bits, 32 bits per pixel, 4 {@link PackedComposition#isUniform() uniform} components of 8 bits. + * <p> + * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>R: 0xFF << 0</li> + * <li>G: 0xFF << 8</li> + * <li>B: 0xFF << 16</li> + * <li>A: 0xFF << 24</li> + * </ol> + * </p> * <p> * Compatible with: * <ul> @@ -125,33 +279,41 @@ public enum PixelFormat { * </ul> * </p> */ - RGBA8888(4, 32), + RGBA8888(new CType[]{ CType.R, CType.G, CType.B, CType.A }, 4, 8, 32), /** - * Pixel size is 4 bytes (32 bits) with each component of size 1 byte (8 bits). + * Stride is 32 bits, 32 bits per pixel, 4 {@link PackedComposition#isUniform() uniform} components of 8 bits. * <p> - * The components are interleaved in the order: - * <ul> - * <li>Low to High: A, B, G, R</li> - * </ul> + * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>A: 0xFF << 0</li> + * <li>B: 0xFF << 8</li> + * <li>G: 0xFF << 16</li> + * <li>R: 0xFF << 24</li> + * </ol> * </p> * <p> * Compatible with: * <ul> - * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_8_8_8_8</li> + * <li>OpenGL: data-format GL_RGBA, data-type GL_UNSIGNED_INT_8_8_8_8</li> * <li>AWT: {@link java.awt.image.BufferedImage#TYPE_4BYTE_ABGR TYPE_4BYTE_ABGR}</li> * </ul> * </p> */ - ABGR8888(4, 32), + ABGR8888(new CType[]{ CType.A, CType.B, CType.G, CType.R }, 4, 8, 32), /** - * Pixel size is 4 bytes (32 bits) with each component of size 1 byte (8 bits). + * Stride is 32 bits, 32 bits per pixel, 4 {@link PackedComposition#isUniform() uniform} components of 8 bits. * <p> - * The components are interleaved in the order: - * <ul> - * <li>Low to High: A, R, G, B</li> - * </ul> + * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>A: 0xFF << 0</li> + * <li>R: 0xFF << 8</li> + * <li>G: 0xFF << 16</li> + * <li>B: 0xFF << 24</li> + * </ol> * </p> * <p> * Compatible with: @@ -161,15 +323,19 @@ public enum PixelFormat { * </ul> * </p> */ - ARGB8888(4, 32), + ARGB8888(new CType[]{ CType.A, CType.R, CType.G, CType.B }, 4, 8, 32), /** - * Pixel size is 4 bytes (32 bits) with each component of size 1 byte (8 bits). + * Stride is 32 bits, 32 bits per pixel, 4 {@link PackedComposition#isUniform() uniform} components of 8 bits. * <p> - * The components are interleaved in the order: - * <ul> - * <li>Low to High: B, G, R, A</li> - * </ul> + * The {@link PackedComposition#isUniform() uniform} {@link PixelFormat#composition components} + * are interleaved in the order Low to High: + * <ol> + * <li>B: 0xFF << 0</li> + * <li>G: 0xFF << 8</li> + * <li>R: 0xFF << 16</li> + * <li>A: 0xFF << 24</li> + * </ol> * </p> * <p> * Compatible with: @@ -181,17 +347,393 @@ public enum PixelFormat { * </ul> * </p> */ - BGRA8888(4, 32); + BGRA8888(new CType[]{ CType.B, CType.G, CType.R, CType.A }, 4, 8, 32); + + /** Unique {@link Composition Pixel Composition}, i.e. layout of its components. */ + public final Composition comp; + + /** + * @param componentOrder {@link CType Component type} order of all components, see {@link Composition#componentBitMask()}. + * @param componentCount number of components + * @param bpc bits per component + * @param bitStride stride bits to next pixel + */ + private PixelFormat(final CType[] componentOrder, final int componentCount, final int bpc, final int bitStride) { + this.comp = new PackedComposition(componentOrder, componentCount, bpc, bitStride); + } + + /** + * @param componentOrder {@link CType Component type} order of all components, see {@link Composition#componentBitMask()}. + * @param componentMask bit-mask of of all components, see {@link Composition##componentBitMask()}. + * @param componentBitShift bit-shift of all components, see {@link Composition##componentBitMask()}. + * @param bitStride stride bits to next pixel + */ + private PixelFormat(final CType[] componentOrder, final int[] componentMask, final int[] componentBitShift, final int bitStride) { + this.comp = new PackedComposition(componentOrder, componentMask, componentBitShift, bitStride); + } + + /** + * Returns the unique matching {@link PixelFormat} of the given {@link Composition} + * or {@code null} if none is available. + */ + public static PixelFormat valueOf(final Composition comp) { + final PixelFormat[] all = PixelFormat.values(); + for(int i=all.length-1; i>=0; i--) { + final PixelFormat pf = all[i]; + if( comp.hashCode() == pf.comp.hashCode() && comp.equals(pf.comp) ) { + return pf; + } + } + return null; + } + + /** Component types */ + public static enum CType { + /** Red component */ + R, + /** Green component */ + G, + /** Blue component */ + B, + /** Alpha component */ + A, + /** Luminance component, e.g. grayscale or Y of YUV */ + Y, + /** U component of YUV */ + U, + /** V component of YUV */ + V; + } + + /** + * Pixel composition, i.e. layout of its components. + */ + public static interface Composition { + /** {@value} */ + public static final int UNDEF = -1; + + /** + * Returns {@code true} if all components are of same bit-size, e.g. {@link PixelFormat#RGBA8888 RGBA8888}, + * otherwise {@code false}, e.g. {@link PixelFormat#RGBA5551 RGBA5551} + */ + boolean isUniform(); + + /** + * Returns {@code true} if all components are packed, i.e. interleaved, e.g. {@link PixelFormat#RGBA8888 RGBA8888}, + * otherwise {@code false}. + */ + boolean isInterleaved(); + + /** Number of components per pixel, e.g. 3 for {@link PixelFormat#RGBx8888 RGBx8888}. */ + int componenCount(); + /** Number of bits per pixel, e.g. 24 bits for {@link PixelFormat#RGBx8888 RGBx8888}. */ + int bitsPerPixel(); + /** + * Bit distance between pixels. + * <p> + * For packed pixels e.g. 32 bits for {@link PixelFormat#RGBx8888 RGBx8888}. + * </p> + */ + int bitStride(); + /** Number of bytes per pixel, i.e. packed {@link #bitStride()} in bytes, e.g. 4 for {@link PixelFormat#RGBx8888 RGBx8888}. */ + int bytesPerPixel(); + /** + * Returns the {@link CType Component type} order of all components, see {@link #componentBitMask()}. + */ + CType[] componentOrder(); + /** + * Returns the index of given {@link CType} within {@link #componentOrder()}, -1 if not exists. + */ + int find(final PixelFormat.CType s); + /** + * Returns the un-shifted bit-mask of all components. + * <p> + * Components mask is returned in the order Low-Index to High-Index, e.g.: + * <ul> + * <li>{@link PixelFormat#RGB565 RGB565}: 0: R 0x1F, 1: G 0x3F, 2: B 0x1F</li> + * <li>{@link PixelFormat#RGBA5551 RGBA5551}: 0: R 0x1F, 1: G 0x1F, 2: B 0x1F, 3: A 0x01</li> + * <li>{@link PixelFormat#RGBA8888 RGBA8888}: 0: R 0xFF, 1: G 0xFF, 2: B 0xFF, 3: A 0xFF</li> + * </ul> + * </p> + * <p> + */ + int[] componentBitMask(); + /** + * Returns the number of bits of all components, see {@link #componentBitMask()}. + */ + int[] componentBitCount(); + /** + * Returns the bit-shift of all components, see {@link #componentBitMask()}. + */ + int[] componentBitShift(); + + /** + * Decodes a component from the shifted pixel data with a {@link #bytesPerPixel()} of up to 32bit. + * @param shifted complete pixel encoded into on 32bit integer + * @param cIdx the desired component index + * @return the decoded component value + */ + int decodeSingleI32(final int shifted, final int cIdx); + /** + * Decodes a component from the shifted pixel data with a {@link #bytesPerPixel()} of up to 64bit. + * @param shifted complete pixel encoded into on 64bit integer + * @param cIdx the desired component index + * @return the decoded component value + */ + int decodeSingleI64(final long shifted, final int cIdx); + + int encodeSingleI32(final int norm, final int cIdx); + long encodeSingleI64(final int norm, final int cIdx); + + int encode3CompI32(final int c1NormI32, final int c2NormI32, final int c3NormI32); + int encode4CompI32(final int c1NormI32, final int c2NormI32, final int c3NormI32, final int c4NormI32); + + int encodeSingleI8(final byte normalI8, final int cIdx); + int encode3CompI8(final byte c1NormI8, final byte c2NormI8, final byte c3NormI8); + int encode4CompI8(final byte c1NormI8, final byte c2NormI8, final byte c3NormI8, final byte c4NormI8); + + float toFloat(final int i32, final int cIdx, final boolean i32Shifted); + int fromFloat(final float f, final int cIdx, final boolean shiftResult); + + int defaultValue(final int cIdx, final boolean shiftResult); + + /** + * Returns cached immutable hash value, see {@link Object#hashCode()}. + */ + int hashCode(); + /** + * Returns {@link Object#equals(Object)} + */ + boolean equals(final Object o); + + /** + * Returns {@link Object#toString()}. + */ + String toString(); + } + + /** + * Packed pixel composition, see {@link Composition}. + * <p> + * Components are interleaved, i.e. packed. + * </p> + */ + public static class PackedComposition implements Composition { + private final CType[] compOrder; + private final int[] compMask; + private final int[] compBitCount; + private final int[] compBitShift; + private final int bitsPerPixel; + private final int bitStride; + private final boolean uniform; + private final int hashCode; + + public final String toString() { + return String.format("PackedComp[order %s, stride %d, bpp %d, uni %b, comp %d: %s]", + Arrays.toString(compOrder), bitStride, bitsPerPixel, uniform, + compMask.length, toHexString(compBitCount, compMask, compBitShift)); + } + + /** + * @param componentOrder {@link CType Component type} order of all components, see {@link #componentBitMask()}. + * @param componentCount number of components + * @param bpc bits per component + * @param bitStride stride bits to next pixel + */ + public PackedComposition(final CType[] componentOrder, final int componentCount, final int bpc, final int bitStride) { + this.compOrder = componentOrder; + this.compMask = new int[componentCount]; + this.compBitShift = new int[componentCount]; + this.compBitCount = new int[componentCount]; + final int compMask = ( 1 << bpc ) - 1; + for(int i=0; i<componentCount; i++) { + this.compMask[i] = compMask; + this.compBitShift[i] = bpc * i; + this.compBitCount[i] = bpc; + } + this.uniform = true; + this.bitsPerPixel = bpc * componentCount; + this.bitStride = bitStride; + if( this.bitStride < this.bitsPerPixel ) { + throw new IllegalArgumentException(String.format("bit-stride %d < bitsPerPixel %d", this.bitStride, this.bitsPerPixel)); + } + this.hashCode = hashCodeImpl(); + } - /** Number of components per pixel, e.g. 4 for RGBA. */ - public final int componentCount; - /** Number of bits per pixel, e.g. 32 for RGBA. */ - public final int bitsPerPixel; - /** Number of bytes per pixel, e.g. 4 for RGBA. */ - public final int bytesPerPixel() { return (7+bitsPerPixel)/8; } + /** + * @param componentOrder {@link CType Component type} order of all components, see {@link #componentBitMask()}. + * @param componentMask bit-mask of of all components, see {@link #componentBitMask()}. + * @param componentBitShift bit-shift of all components, see {@link #componentBitMask()}. + * @param bitStride stride bits to next pixel + */ + public PackedComposition(final CType[] componentOrder, final int[] componentMask, final int[] componentBitShift, final int bitStride) { + this.compOrder = componentOrder; + this.compMask = componentMask; + this.compBitShift = componentBitShift; + this.compBitCount = new int[componentMask.length]; + int bpp = 0; + boolean uniform = true; + for(int i = componentMask.length-1; i>=0; i--) { + final int cmask = componentMask[i]; + final int bitCount = IntBitfield.getBitCount(cmask); + bpp += bitCount; + this.compBitCount[i] = bitCount; + if( i > 0 && uniform ) { + uniform = componentMask[i-1] == cmask; + } + } + this.uniform = uniform; + this.bitsPerPixel = bpp; + this.bitStride = bitStride; + if( this.bitStride < this.bitsPerPixel ) { + throw new IllegalArgumentException(String.format("bit-stride %d < bitsPerPixel %d", this.bitStride, this.bitsPerPixel)); + } + this.hashCode = hashCodeImpl(); + } + + @Override + public final boolean isUniform() { return uniform; } + /** + * {@inheritDoc} + * <p> + * Instances of {@link PackedComposition} returns {@code true}. + * </p> + */ + @Override + public final boolean isInterleaved() { return true; } + @Override + public final int componenCount() { return compMask.length; } + @Override + public final int bitsPerPixel() { return bitsPerPixel; } + @Override + public final int bitStride() { return bitStride; } + @Override + public final int bytesPerPixel() { return (7+bitStride)/8; } + @Override + public final CType[] componentOrder() { return compOrder; } + @Override + public final int find(final PixelFormat.CType s) { return PixelFormatUtil.find(s, compOrder, false /* mapRGB2Y */); } + @Override + public final int[] componentBitMask() { return compMask; } + @Override + public final int[] componentBitCount() { return compBitCount; } + @Override + public final int[] componentBitShift() { return compBitShift; } + + @Override + public final int decodeSingleI32(final int shifted, final int cIdx) { + return ( shifted >>> compBitShift[cIdx] ) & compMask[cIdx]; + } + @Override + public final int decodeSingleI64(final long shifted, final int cIdx) { + return ( (int)( 0xffffffffL & ( shifted >>> compBitShift[cIdx] ) ) ) & compMask[cIdx]; + } + @Override + public final int encodeSingleI32(final int norm, final int cIdx) { + return ( norm & compMask[cIdx] ) << compBitShift[cIdx] ; + } + @Override + public final long encodeSingleI64(final int norm, final int cIdx) { + return ( 0xffffffffL & ( norm & compMask[cIdx] ) ) << compBitShift[cIdx] ; + } + @Override + public final int encode3CompI32(final int c1NormI32, final int c2NormI32, final int c3NormI32) { + return ( c1NormI32 & compMask[0] ) << compBitShift[0] | + ( c2NormI32 & compMask[1] ) << compBitShift[1] | + ( c3NormI32 & compMask[2] ) << compBitShift[2] ; + } + @Override + public final int encode4CompI32(final int c1NormI32, final int c2NormI32, final int c3NormI32, final int c4NormI32) { + return ( c1NormI32 & compMask[0] ) << compBitShift[0] | + ( c2NormI32 & compMask[1] ) << compBitShift[1] | + ( c3NormI32 & compMask[2] ) << compBitShift[2] | + ( c4NormI32 & compMask[3] ) << compBitShift[3] ; + } + @Override + public final int encodeSingleI8(final byte normI8, final int cIdx) { + return ( normI8 & compMask[cIdx] ) << compBitShift[cIdx] ; + } + @Override + public final int encode3CompI8(final byte c1NormI8, final byte c2NormI8, final byte c3NormI8) { + return ( c1NormI8 & compMask[0] ) << compBitShift[0] | + ( c2NormI8 & compMask[1] ) << compBitShift[1] | + ( c3NormI8 & compMask[2] ) << compBitShift[2] ; + } + @Override + public final int encode4CompI8(final byte c1NormI8, final byte c2NormI8, final byte c3NormI8, final byte c4NormI8) { + return ( c1NormI8 & compMask[0] ) << compBitShift[0] | + ( c2NormI8 & compMask[1] ) << compBitShift[1] | + ( c3NormI8 & compMask[2] ) << compBitShift[2] | + ( c4NormI8 & compMask[3] ) << compBitShift[3] ; + } + + @Override + public final float toFloat(final int i32, final int cIdx, final boolean i32Shifted) { + if( i32Shifted ) { + return ( ( i32 >>> compBitShift[cIdx] ) & compMask[cIdx] ) / (float)( compMask[cIdx] ) ; + } else { + return ( i32 & compMask[cIdx] ) / (float)( compMask[cIdx] ) ; + } + } + @Override + public final int fromFloat(final float f, final int cIdx, final boolean shiftResult) { + final int v = (int)(f * compMask[cIdx] + 0.5f); + return shiftResult ? v << compBitShift[cIdx] : v; + } + + @Override + public final int defaultValue(final int cIdx, final boolean shiftResult) { + final int v = ( CType.A == compOrder[cIdx] || CType.Y == compOrder[cIdx] ) + ? compMask[cIdx] : 0; + return shiftResult ? v << compBitShift[cIdx] : v; + } + + @Override + public final int hashCode() { return hashCode; } + private final int hashCodeImpl() { + // 31 * x == (x << 5) - x + int hash = 31 + bitStride; + hash = ((hash << 5) - hash) + bitsPerPixel; + hash = ((hash << 5) - hash) + compMask.length; + for(int i=compOrder.length-1; i>=0; i--) { + hash = ((hash << 5) - hash) + compOrder[i].ordinal(); + } + for(int i=compMask.length-1; i>=0; i--) { + hash = ((hash << 5) - hash) + compMask[i]; + } + for(int i=compBitShift.length-1; i>=0; i--) { + hash = ((hash << 5) - hash) + compBitShift[i]; + } + return hash; + } + + @Override + public final boolean equals(final Object obj) { + if(this == obj) { return true; } + if( obj instanceof PackedComposition ) { + final PackedComposition other = (PackedComposition) obj; + return bitStride == other.bitStride && + bitsPerPixel == other.bitsPerPixel && + Arrays.equals(compOrder, other.compOrder) && + Arrays.equals(compMask, other.compMask) && + Arrays.equals(compBitShift, other.compBitShift); + } else { + return false; + } + } + } - private PixelFormat(final int componentCount, final int bpp) { - this.componentCount = componentCount; - this.bitsPerPixel = bpp; + private static String toHexString(final int[] bitCount, final int[] mask, final int[] shift) { + final StringBuilder sb = new StringBuilder(); + sb.append("["); + final int l = mask.length; + for(int i=0; i < l; i++) { + if(i > 0) { + sb.append(", "); + } + sb.append(bitCount[i]).append(": "). + append("0x").append(Integer.toHexString(mask[i])).append(" << ").append(shift[i]); + } + return sb.append("]").toString(); } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormatUtil.java b/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormatUtil.java index 21bfa8a54..a449f8706 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormatUtil.java +++ b/src/nativewindow/classes/javax/media/nativewindow/util/PixelFormatUtil.java @@ -27,10 +27,12 @@ */ package javax.media.nativewindow.util; +import java.io.IOException; import java.nio.ByteBuffer; -import java.nio.ByteOrder; +import java.util.Arrays; import com.jogamp.common.nio.Buffers; +import com.jogamp.common.util.Bitstream; /** * Pixel Rectangle Utilities. @@ -39,46 +41,157 @@ import com.jogamp.common.nio.Buffers; * </p> */ public class PixelFormatUtil { - public static interface PixelSink { - /** Return the sink's destination pixelformat. */ - PixelFormat getPixelformat(); + private static boolean DEBUG = false; + public static class ComponentMap { /** - * Returns stride in byte-size, i.e. byte count from one line to the next. - * <p> - * Must be >= {@link #getPixelformat()}.{@link PixelFormat#bytesPerPixel() bytesPerPixel()} * {@link #getSize()}.{@link DimensionImmutable#getWidth() getWidth()}. - * </p> + * Contains the source index for each destination index, + * length is {@link Composition#componenCount()} of destination. */ - int getStride(); + final int[] dst2src; + /** + * Contains the destination index for each source index, + * length is {@link Composition#componenCount()} of source. + */ + final int[] src2dst; /** - * Returns <code>true</code> if the sink's memory is laid out in - * OpenGL's coordinate system, <i>origin at bottom left</i>. - * Otherwise returns <code>false</code>, i.e. <i>origin at top left</i>. + * Contains the source index of RGBA components. */ - boolean isGLOriented(); + final int[] srcRGBA; + final boolean hasSrcRGB; + + public ComponentMap(final PixelFormat.Composition src, final PixelFormat.Composition dst) { + final int sCompCount = src.componenCount(); + final int dCompCount = dst.componenCount(); + final PixelFormat.CType[] sCompOrder = src.componentOrder(); + final PixelFormat.CType[] dCompOrder = dst.componentOrder(); + + dst2src = new int[dCompCount]; + for(int dIdx=0; dIdx<dCompCount; dIdx++) { + dst2src[dIdx] = PixelFormatUtil.find(dCompOrder[dIdx], sCompOrder, true); + } + src2dst = new int[sCompCount]; + for(int sIdx=0; sIdx<sCompCount; sIdx++) { + src2dst[sIdx] = PixelFormatUtil.find(sCompOrder[sIdx], dCompOrder, true); + } + srcRGBA = new int[4]; + srcRGBA[0] = PixelFormatUtil.find(PixelFormat.CType.R, sCompOrder, false); + srcRGBA[1] = PixelFormatUtil.find(PixelFormat.CType.G, sCompOrder, false); + srcRGBA[2] = PixelFormatUtil.find(PixelFormat.CType.B, sCompOrder, false); + srcRGBA[3] = PixelFormatUtil.find(PixelFormat.CType.A, sCompOrder, false); + hasSrcRGB = 0 <= srcRGBA[0] && 0 <= srcRGBA[1] && 0 <= srcRGBA[2]; + } } + + public static final int find(final PixelFormat.CType s, + final PixelFormat.CType[] pool, final boolean mapRGB2Y) { + int i=pool.length-1; + while( i >= 0 && pool[i] != s) { i--; } + + if( 0 > i && mapRGB2Y && 1 == pool.length && pool[0] == PixelFormat.CType.Y && + ( PixelFormat.CType.R == s || + PixelFormat.CType.G == s || + PixelFormat.CType.B == s ) ) + { + // Special case, fallback for RGB mapping -> LUMINANCE/Y + return 0; + } else { + return i; + } + } + /** - * Pixel sink for up-to 32bit. + * Returns shifted bytes from the given {@code data} at given {@code offset} + * of maximal 4 {@code bytesPerPixel}. + * @param bytesPerPixel number of bytes per pixel to fetch, a maximum of 4 are allowed + * @param data byte buffer covering complete pixel at position {@code offset} + * @param offset byte offset of pixel {@code data} start + * @return the shifted 32bit integer value of the pixel */ - public static interface PixelSink32 extends PixelSink { - /** - * Will be invoked over all rows top-to down - * and all columns left-to-right. - * <p> - * Shall consider dest pixelformat and only store as much components - * as defined, up to 32bit. - * </p> - * <p> - * Implementation may better write single bytes from low-to-high bits, - * e.g. {@link ByteOrder#LITTLE_ENDIAN} order. - * Otherwise a possible endian conversion must be taken into consideration. - * </p> - * @param x - * @param y - * @param pixel - */ - void store(int x, int y, int pixel); + public static int getShiftedI32(final int bytesPerPixel, final byte[] data, final int offset) { + if( bytesPerPixel <= 4 ) { + int shiftedI32 = 0; + for(int i=0; i<bytesPerPixel; i++) { + shiftedI32 |= ( 0xff & data[offset+i] ) << 8*i; + } + return shiftedI32; + } else { + throw new UnsupportedOperationException(bytesPerPixel+" bytesPerPixel too big, i.e. > 4"); + } + } + /** + * Returns shifted bytes from the given {@code data} at given {@code offset} + * of maximal 8 {@code bytesPerPixel}. + * @param bytesPerPixel number of bytes per pixel to fetch, a maximum of 4 are allowed + * @param data byte buffer covering complete pixel at position {@code offset} + * @param offset byte offset of pixel {@code data} start + * @return the shifted 64bit integer value of the pixel + */ + public static long getShiftedI64(final int bytesPerPixel, final byte[] data, final int offset) { + if( bytesPerPixel <= 8 ) { + long shiftedI64 = 0; + for(int i=0; i<bytesPerPixel; i++) { + shiftedI64 |= ( 0xff & data[offset+i] ) << 8*i; + } + return shiftedI64; + } else { + throw new UnsupportedOperationException(bytesPerPixel+" bytesPerPixel too big, i.e. > 8"); + } + } + /** + * Returns shifted bytes from the given {@code data} at current position + * of maximal 4 {@code bytesPerPixel}. + * @param bytesPerPixel number of bytes per pixel to fetch, a maximum of 4 are allowed + * @param data byte buffer covering complete pixel at position {@code offset} + * @param retainDataPos if true, absolute {@link ByteBuffer#get(int)} is used and the {@code data} position stays unchanged. + * Otherwise relative {@link ByteBuffer#get()} is used and the {@code data} position changes. + * @return the shifted 32bit integer value of the pixel + */ + public static int getShiftedI32(final int bytesPerPixel, final ByteBuffer data, final boolean retainDataPos) { + if( bytesPerPixel <= 4 ) { + int shiftedI32 = 0; + if( retainDataPos ) { + final int offset = data.position(); + for(int i=0; i<bytesPerPixel; i++) { + shiftedI32 |= ( 0xff & data.get(offset+i) ) << 8*i; + } + } else { + for(int i=0; i<bytesPerPixel; i++) { + shiftedI32 |= ( 0xff & data.get() ) << 8*i; + } + } + return shiftedI32; + } else { + throw new UnsupportedOperationException(bytesPerPixel+" bytesPerPixel too big, i.e. > 4"); + } + } + /** + * Returns shifted bytes from the given {@code data} at current position + * of maximal 8 {@code bytesPerPixel}. + * @param bytesPerPixel number of bytes per pixel to fetch, a maximum of 4 are allowed + * @param data byte buffer covering complete pixel at position {@code offset} + * @param retainDataPos if true, absolute {@link ByteBuffer#get(int)} is used and the {@code data} position stays unchanged. + * Otherwise relative {@link ByteBuffer#get()} is used and the {@code data} position changes. + * @return the shifted 64bit integer value of the pixel + */ + public static long getShiftedI64(final int bytesPerPixel, final ByteBuffer data, final boolean retainDataPos) { + if( bytesPerPixel <= 8 ) { + long shiftedI64 = 0; + if( retainDataPos ) { + final int offset = data.position(); + for(int i=0; i<bytesPerPixel; i++) { + shiftedI64 |= ( 0xff & data.get(offset+i) ) << 8*i; + } + } else { + for(int i=0; i<bytesPerPixel; i++) { + shiftedI64 |= ( 0xff & data.get() ) << 8*i; + } + } + return shiftedI64; + } else { + throw new UnsupportedOperationException(bytesPerPixel+" bytesPerPixel too big, i.e. > 8"); + } } /** @@ -87,8 +200,14 @@ public class PixelFormatUtil { */ public static PixelFormat getReversed(final PixelFormat fmt) { switch(fmt) { - case LUMINANCE: - return PixelFormat.LUMINANCE; + case RGB565: + return PixelFormat.BGR565; + case BGR565: + return PixelFormat.RGB565; + case RGBA5551: + return PixelFormat.ABGR1555; + case ABGR1555: + return PixelFormat.RGBA5551; case RGB888: return PixelFormat.BGR888; case BGR888: @@ -102,42 +221,14 @@ public class PixelFormatUtil { case BGRA8888: return PixelFormat.ABGR8888; default: - throw new InternalError("Unhandled format "+fmt); + return fmt; } } - public static int getValue32(final PixelFormat src_fmt, final ByteBuffer src, int srcOff) { - switch(src_fmt) { + public static int convertToInt32(final PixelFormat dst_fmt, final byte r, final byte g, final byte b, final byte a) { + switch(dst_fmt) { case LUMINANCE: { - final byte c1 = src.get(srcOff++); - return ( 0xff ) << 24 | ( 0xff & c1 ) << 16 | ( 0xff & c1 ) << 8 | ( 0xff & c1 ); - } - case RGB888: - case BGR888: { - final byte c1 = src.get(srcOff++); - final byte c2 = src.get(srcOff++); - final byte c3 = src.get(srcOff++); - return ( 0xff ) << 24 | ( 0xff & c3 ) << 16 | ( 0xff & c2 ) << 8 | ( 0xff & c1 ); - } - case RGBA8888: - case ABGR8888: - case ARGB8888: - case BGRA8888: { - final byte c1 = src.get(srcOff++); - final byte c2 = src.get(srcOff++); - final byte c3 = src.get(srcOff++); - final byte c4 = src.get(srcOff++); - return ( 0xff & c4 ) << 24 | ( 0xff & c3 ) << 16 | ( 0xff & c2 ) << 8 | ( 0xff & c1 ); - } - default: - throw new InternalError("Unhandled format "+src_fmt); - } - } - - public static int convertToInt32(final PixelFormat dest_fmt, final byte r, final byte g, final byte b, final byte a) { - switch(dest_fmt) { - case LUMINANCE: { - final byte l = ( byte) ( ( ( ( 0xff & r ) + ( 0xff & g ) + ( 0xff & b ) ) / 3 ) ); + final byte l = ( byte) ( ( ( ( 0xff & r ) + ( 0xff & g ) + ( 0xff & b ) ) / 3 ) * a ); return ( 0xff ) << 24 | ( 0xff & l ) << 16 | ( 0xff & l ) << 8 | ( 0xff & l ); } case RGB888: @@ -153,11 +244,11 @@ public class PixelFormatUtil { case BGRA8888: return ( 0xff & a ) << 24 | ( 0xff & r ) << 16 | ( 0xff & g ) << 8 | ( 0xff & b ); default: - throw new InternalError("Unhandled format "+dest_fmt); + throw new InternalError("Unhandled format "+dst_fmt); } } - public static int convertToInt32(final PixelFormat dest_fmt, final PixelFormat src_fmt, final ByteBuffer src, int srcOff) { + public static int convertToInt32(final PixelFormat dst_fmt, final PixelFormat src_fmt, final ByteBuffer src, int srcOff) { final byte r, g, b, a; switch(src_fmt) { case LUMINANCE: @@ -205,7 +296,7 @@ public class PixelFormatUtil { default: throw new InternalError("Unhandled format "+src_fmt); } - return convertToInt32(dest_fmt, r, g, b, a); + return convertToInt32(dst_fmt, r, g, b, a); } public static int convertToInt32(final PixelFormat dest_fmt, final PixelFormat src_fmt, final int src_pixel) { @@ -259,115 +350,251 @@ public class PixelFormatUtil { return convertToInt32(dest_fmt, r, g, b, a); } - public static PixelRectangle convert32(final PixelRectangle src, - final PixelFormat destFmt, final int ddestStride, final boolean isGLOriented, - final boolean destIsDirect) { + public static PixelRectangle convert(final PixelRectangle src, + final PixelFormat destFmt, final int ddestStride, final boolean isGLOriented, + final boolean destIsDirect) { final int width = src.getSize().getWidth(); final int height = src.getSize().getHeight(); - final int bpp = destFmt.bytesPerPixel(); + final int bpp = destFmt.comp.bytesPerPixel(); final int destStride; if( 0 != ddestStride ) { destStride = ddestStride; - if( destStride < bpp * width ) { - throw new IllegalArgumentException("Invalid stride "+destStride+", must be greater than bytesPerPixel "+bpp+" * width "+width); - } } else { destStride = bpp * width; } final int capacity = destStride*height; - final ByteBuffer bb = destIsDirect ? Buffers.newDirectByteBuffer(capacity) : ByteBuffer.allocate(capacity).order(src.getPixels().order()); - - // System.err.println("XXX: SOURCE "+src); - // System.err.println("XXX: DEST fmt "+destFmt+", stride "+destStride+" ("+ddestStride+"), isGL "+isGLOriented+", "+width+"x"+height+", capacity "+capacity+", "+bb); - - final PixelFormatUtil.PixelSink32 imgSink = new PixelFormatUtil.PixelSink32() { - public void store(final int x, final int y, final int pixel) { - int o = destStride*y+x*bpp; - bb.put(o++, (byte) ( pixel )); // 1 - if( 3 <= bpp ) { - bb.put(o++, (byte) ( pixel >>> 8 )); // 2 - bb.put(o++, (byte) ( pixel >>> 16 )); // 3 - if( 4 <= bpp ) { - bb.put(o++, (byte) ( pixel >>> 24 )); // 4 - } - } - } - @Override - public final PixelFormat getPixelformat() { - return destFmt; - } - @Override - public final int getStride() { - return destStride; - } - @Override - public final boolean isGLOriented() { - return isGLOriented; - } - }; - convert32(imgSink, src); - return new PixelRectangle.GenericPixelRect(destFmt, src.getSize(), destStride, isGLOriented, bb); + final ByteBuffer destBB = destIsDirect ? Buffers.newDirectByteBuffer(capacity) : ByteBuffer.allocate(capacity).order(src.getPixels().order()); + convert(src, destBB, destFmt, isGLOriented, destStride); + return new PixelRectangle.GenericPixelRect(destFmt, src.getSize(), destStride, isGLOriented, destBB); } - public static void convert32(final PixelSink32 destInt32, final PixelRectangle src) { - convert32(destInt32, - src.getPixels(), src.getPixelformat(), - src.isGLOriented(), - src.getSize().getWidth(), src.getSize().getHeight(), - src.getStride()); + /** + * @param src + * @param dst_bb {@link ByteBuffer} sink + * @param dst_fmt destination {@link PixelFormat} + * @param dst_glOriented if true, the source memory is laid out in OpenGL's coordinate system, <i>origin at bottom left</i>, + * otherwise <i>origin at top left</i>. + * @param dst_lineStride line stride in byte-size for destination, i.e. byte count from one line to the next. + * Must be >= {@link PixelFormat.Composition#bytesPerPixel() dst_fmt.comp.bytesPerPixel()} * width + * or {@code zero} for default stride. + * + * @throws IllegalStateException + * @throws IllegalArgumentException if {@code src_lineStride} or {@code dst_lineStride} is invalid + */ + public static void convert(final PixelRectangle src, + final ByteBuffer dst_bb, final PixelFormat dst_fmt, final boolean dst_glOriented, final int dst_lineStride) + throws IllegalStateException + { + convert(src.getSize().getWidth(), src.getSize().getHeight(), + src.getPixels(), src.getPixelformat(), src.isGLOriented(), src.getStride(), + dst_bb, dst_fmt, dst_glOriented, dst_lineStride); } + /** - * - * @param dest32 32bit pixel sink - * @param src_bb - * @param src_fmt + * @param width width of the to be converted pixel rectangle + * @param height height of the to be converted pixel rectangle + * @param src_bb {@link ByteBuffer} source + * @param src_fmt source {@link PixelFormat} * @param src_glOriented if true, the source memory is laid out in OpenGL's coordinate system, <i>origin at bottom left</i>, * otherwise <i>origin at top left</i>. - * @param width - * @param height - * @param strideInBytes stride in byte-size, i.e. byte count from one line to the next. - * If zero, stride is set to <code>width * bytes-per-pixel</code>. - * If not zero, value must be >= <code>width * bytes-per-pixel</code>. - * @param stride_bytes stride in byte-size, i.e. byte count from one line to the next. - * Must be >= {@link PixelFormat#bytesPerPixel() src_fmt.bytesPerPixel()} * width. - * @throws IllegalArgumentException if <code>strideInBytes</code> is invalid + * @param src_lineStride line stride in byte-size for source, i.e. byte count from one line to the next. + * Must be >= {@link PixelFormat.Composition#bytesPerPixel() src_fmt.comp.bytesPerPixel()} * width + * or {@code zero} for default stride. + * @param dst_bb {@link ByteBuffer} sink + * @param dst_fmt destination {@link PixelFormat} + * @param dst_glOriented if true, the source memory is laid out in OpenGL's coordinate system, <i>origin at bottom left</i>, + * otherwise <i>origin at top left</i>. + * @param dst_lineStride line stride in byte-size for destination, i.e. byte count from one line to the next. + * Must be >= {@link PixelFormat.Composition#bytesPerPixel() dst_fmt.comp.bytesPerPixel()} * width + * or {@code zero} for default stride. + * + * @throws IllegalStateException + * @throws IllegalArgumentException if {@code src_lineStride} or {@code dst_lineStride} is invalid */ - public static void convert32(final PixelSink32 dest32, - final ByteBuffer src_bb, final PixelFormat src_fmt, final boolean src_glOriented, final int width, final int height, int stride_bytes) { - final int src_bpp = src_fmt.bytesPerPixel(); - if( 0 != stride_bytes ) { - if( stride_bytes < src_bpp * width ) { - throw new IllegalArgumentException("Invalid stride "+stride_bytes+", must be greater than bytesPerPixel "+src_bpp+" * width "+width); + public static void convert(final int width, final int height, + final ByteBuffer src_bb, final PixelFormat src_fmt, final boolean src_glOriented, int src_lineStride, + final ByteBuffer dst_bb, final PixelFormat dst_fmt, final boolean dst_glOriented, int dst_lineStride + ) throws IllegalStateException, IllegalArgumentException { + final PixelFormat.Composition src_comp = src_fmt.comp; + final PixelFormat.Composition dst_comp = dst_fmt.comp; + final int src_bpp = src_comp.bytesPerPixel(); + final int dst_bpp = dst_comp.bytesPerPixel(); + + if( 0 != src_lineStride ) { + if( src_lineStride < src_bpp * width ) { + throw new IllegalArgumentException(String.format("Invalid %s stride %d, must be greater than bytesPerPixel %d * width %d", + "source", src_lineStride, src_bpp, width)); } } else { - stride_bytes = src_bpp * width; + src_lineStride = src_bpp * width; + } + if( 0 != dst_lineStride ) { + if( dst_lineStride < dst_bpp * width ) { + throw new IllegalArgumentException(String.format("Invalid %s stride %d, must be greater than bytesPerPixel %d * width %d", + "destination", dst_lineStride, dst_bpp, width)); + } + } else { + dst_lineStride = dst_bpp * width; + } + + // final int src_comp_bitStride = src_comp.bitStride(); + final int dst_comp_bitStride = dst_comp.bitStride(); + final boolean vert_flip = src_glOriented != dst_glOriented; + final boolean fast_copy = src_comp.equals(dst_comp) && 0 == dst_comp_bitStride%8; + if( DEBUG ) { + System.err.println("XXX: size "+width+"x"+height+", fast_copy "+fast_copy); + System.err.println("XXX: SRC fmt "+src_fmt+", "+src_comp+", stride "+src_lineStride+", isGLOrient "+src_glOriented); + System.err.println("XXX: DST fmt "+dst_fmt+", "+dst_comp+", stride "+dst_lineStride+", isGLOrient "+dst_glOriented); } - final PixelFormat dest_fmt = dest32.getPixelformat(); - final boolean vert_flip = src_glOriented != dest32.isGLOriented(); - final boolean fast_copy = src_fmt == dest_fmt && dest_fmt.bytesPerPixel() == 4 ; - // System.err.println("XXX: SRC fmt "+src_fmt+", stride "+stride_bytes+", isGL "+src_glOriented+", "+width+"x"+height); - // System.err.println("XXX: DST fmt "+dest_fmt+", fast_copy "+fast_copy); if( fast_copy ) { // Fast copy for(int y=0; y<height; y++) { - int o = vert_flip ? ( height - 1 - y ) * stride_bytes : y * stride_bytes; + int src_off = vert_flip ? ( height - 1 - y ) * src_lineStride : y * src_lineStride; + int dst_off = dst_lineStride*y; for(int x=0; x<width; x++) { - dest32.store(x, y, getValue32(src_fmt, src_bb, o)); - o += src_bpp; + dst_bb.put(dst_off+0, src_bb.get(src_off+0)); // 1 + if( 2 <= dst_bpp ) { + dst_bb.put(dst_off+1, src_bb.get(src_off+1)); // 2 + if( 3 <= dst_bpp ) { + dst_bb.put(dst_off+2, src_bb.get(src_off+2)); // 3 + if( 4 <= dst_bpp ) { + dst_bb.put(dst_off+3, src_bb.get(src_off+3)); // 4 + } + } + } + src_off += src_bpp; + dst_off += dst_bpp; } } } else { // Conversion - for(int y=0; y<height; y++) { - int o = vert_flip ? ( height - 1 - y ) * stride_bytes : y * stride_bytes; - for(int x=0; x<width; x++) { - dest32.store( x, y, convertToInt32( dest_fmt, src_fmt, src_bb, o)); - o += src_bpp; + final ComponentMap cmap = new ComponentMap(src_fmt.comp, dst_fmt.comp); + + final Bitstream.ByteBufferStream srcBBS = new Bitstream.ByteBufferStream(src_bb); + final Bitstream<ByteBuffer> srcBitStream = new Bitstream<ByteBuffer>(srcBBS, false /* outputMode */); + srcBitStream.setThrowIOExceptionOnEOF(true); + + final Bitstream.ByteBufferStream dstBBS = new Bitstream.ByteBufferStream(dst_bb); + final Bitstream<ByteBuffer> dstBitStream = new Bitstream<ByteBuffer>(dstBBS, true /* outputMode */); + dstBitStream.setThrowIOExceptionOnEOF(true); + + if( DEBUG ) { + System.err.println("XXX: cmap.dst2src "+Arrays.toString(cmap.dst2src)); + System.err.println("XXX: cmap.src2dst "+Arrays.toString(cmap.src2dst)); + System.err.println("XXX: cmap.srcRGBA "+Arrays.toString(cmap.srcRGBA)); + System.err.println("XXX: srcBitStream "+srcBitStream); + System.err.println("XXX: dstBitStream "+dstBitStream); + } + try { + for(int y=0; y<height; y++) { + final int src_off = vert_flip ? ( height - 1 - y ) * src_lineStride * 8 : y * src_lineStride * 8; + // final int dst_off = dst_lineStride*8*y; + srcBitStream.position(src_off); + for(int x=0; x<width; x++) { + convert(cmap, dst_comp, dstBitStream, src_comp, srcBitStream); + } + // srcBitStream.skip(( src_lineStride * 8 ) - ( src_comp_bitStride * width )); + dstBitStream.skip(( dst_lineStride * 8 ) - ( dst_comp_bitStride * width )); + } + } catch(final IOException ioe) { + throw new RuntimeException(ioe); + } + if( DEBUG ) { + System.err.println("XXX: srcBitStream "+srcBitStream); + System.err.println("XXX: dstBitStream "+dstBitStream); + } + } + } + + public static void convert(final ComponentMap cmap, + final PixelFormat.Composition dstComp, + final Bitstream<ByteBuffer> dstBitStream, + final PixelFormat.Composition srcComp, + final Bitstream<ByteBuffer> srcBitStream) throws IllegalStateException, IOException { + final int sCompCount = srcComp.componenCount(); + final int dCompCount = dstComp.componenCount(); + final int[] sc = new int[sCompCount]; + final int[] dcDef = new int[dCompCount]; + final int[] srcCompBitCount = srcComp.componentBitCount(); + final int[] srcCompBitMask = srcComp.componentBitMask(); + final int[] dstCompBitCount = dstComp.componentBitCount(); + + // Fill w/ source values + for(int sIdx=0; sIdx<sCompCount; sIdx++) { + sc[sIdx] = srcBitStream.readBits31(srcCompBitCount[sIdx]) & srcCompBitMask[sIdx]; + } + srcBitStream.skip(srcComp.bitStride() - srcComp.bitsPerPixel()); + + // Cache missing defaults + for(int i=0; i<dCompCount; i++) { + dcDef[i] = dstComp.defaultValue(i, false); + } + + if( 1 == dCompCount && + PixelFormat.CType.Y == dstComp.componentOrder()[0] && + cmap.hasSrcRGB + ) + { + // RGB[A] -> Y conversion + final int r = sc[cmap.srcRGBA[0]]; + final int g = sc[cmap.srcRGBA[1]]; + final int b = sc[cmap.srcRGBA[2]]; + final float rF = srcComp.toFloat(r, cmap.srcRGBA[0], false); + final float gF = srcComp.toFloat(g, cmap.srcRGBA[1], false); + final float bF = srcComp.toFloat(b, cmap.srcRGBA[2], false); + final int a; + final float aF; + /** if( 0 <= cmap.srcRGBA[3] ) { // disable premultiplied-alpha + a = sc[cmap.srcRGBA[3]]; + aF = srcComp.toFloat(a, false, cmap.srcRGBA[3]); + } else */ { + a = 1; + aF = 1f; + } + final float lF = ( rF + gF + bF ) * aF / 3f; + final int v = dstComp.fromFloat(lF, 0, false); + + dstBitStream.writeBits31(dstCompBitCount[0], v); + dstBitStream.skip(dstComp.bitStride() - dstComp.bitsPerPixel()); + if( DEBUG ) { + if( srcBitStream.position() <= 8*4 ) { + System.err.printf("convert: rgb[a] -> Y: rgb 0x%02X 0x%02X 0x%02X 0x%02X -> %f %f %f %f"+ + " -> %f -> dstC 0 0x%08X (%d bits: %s)%n", + r, g, b, a, + rF, gF, bF, aF, + lF, v, dstCompBitCount[0], Bitstream.toBinString(true, v, dstCompBitCount[0]) + ); + } + } + return; + } + + for(int dIdx=0; dIdx<dCompCount; dIdx++) { + int sIdx; + if( 0 <= ( sIdx = cmap.dst2src[dIdx] ) ) { + final float f = srcComp.toFloat(sc[sIdx], sIdx, false); + final int v = dstComp.fromFloat(f, dIdx, false); + dstBitStream.writeBits31(dstCompBitCount[dIdx], v); + if( DEBUG ) { + if( srcBitStream.position() <= 8*4 ) { + System.err.printf("convert: srcC %d: 0x%08X -> %f -> dstC %d 0x%08X (%d bits: %s)%n", + sIdx, sc[sIdx], f, dIdx, v, dstCompBitCount[dIdx], Bitstream.toBinString(true, v, dstCompBitCount[dIdx])); + } + } + } else { + dstBitStream.writeBits31(dstCompBitCount[dIdx], dcDef[dIdx]); + if( DEBUG ) { + if( srcBitStream.position() <= 8*4 ) { + System.err.printf("convert: srcC %d: undef -> dstC %d 0x%08X (%d bits: %s)%n", + sIdx, dIdx, dcDef[dIdx], dstCompBitCount[dIdx], Bitstream.toBinString(true, dcDef[dIdx], dstCompBitCount[dIdx])); + } } } } + dstBitStream.skip(dstComp.bitStride() - dstComp.bitsPerPixel()); + return; } } diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/PixelRectangle.java b/src/nativewindow/classes/javax/media/nativewindow/util/PixelRectangle.java index 96c1f7b33..f4fc99aee 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/util/PixelRectangle.java +++ b/src/nativewindow/classes/javax/media/nativewindow/util/PixelRectangle.java @@ -113,11 +113,11 @@ public interface PixelRectangle { throws IllegalArgumentException, IndexOutOfBoundsException { if( 0 != strideInBytes ) { - if( strideInBytes < pixelformat.bytesPerPixel() * size.getWidth()) { - throw new IllegalArgumentException("Invalid stride "+strideInBytes+", must be greater than bytesPerPixel "+pixelformat.bytesPerPixel()+" * width "+size.getWidth()); + if( strideInBytes < pixelformat.comp.bytesPerPixel() * size.getWidth()) { + throw new IllegalArgumentException("Invalid stride "+strideInBytes+", must be greater than bytesPerPixel "+pixelformat.comp.bytesPerPixel()+" * width "+size.getWidth()); } } else { - strideInBytes = pixelformat.bytesPerPixel() * size.getWidth(); + strideInBytes = pixelformat.comp.bytesPerPixel() * size.getWidth(); } final int reqBytes = strideInBytes * size.getHeight(); if( pixels.limit() < reqBytes ) { @@ -148,7 +148,7 @@ public interface PixelRectangle { synchronized (this) { if( !hashCodeComputed ) { // 31 * x == (x << 5) - x - int hash = 31 + pixelformat.hashCode(); + int hash = pixelformat.comp.hashCode(); hash = ((hash << 5) - hash) + size.hashCode(); hash = ((hash << 5) - hash) + strideInBytes; hash = ((hash << 5) - hash) + ( isGLOriented ? 1 : 0); diff --git a/src/nativewindow/classes/javax/media/nativewindow/util/SurfaceSize.java b/src/nativewindow/classes/javax/media/nativewindow/util/SurfaceSize.java index 601e6dd71..fe1fa3b9d 100644 --- a/src/nativewindow/classes/javax/media/nativewindow/util/SurfaceSize.java +++ b/src/nativewindow/classes/javax/media/nativewindow/util/SurfaceSize.java @@ -105,7 +105,7 @@ public class SurfaceSize implements Comparable<SurfaceSize> { @Override public final int hashCode() { // 31 * x == (x << 5) - x - int hash = 31 + getResolution().hashCode(); + int hash = getResolution().hashCode(); hash = ((hash << 5) - hash) + getBitsPerPixel(); return hash; } diff --git a/src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java b/src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java index deb685b51..10d957186 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java +++ b/src/nativewindow/classes/jogamp/nativewindow/ProxySurfaceImpl.java @@ -28,6 +28,8 @@ package jogamp.nativewindow; +import java.io.PrintStream; + import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeSurface; @@ -279,6 +281,13 @@ public abstract class ProxySurfaceImpl implements ProxySurface { sink.append("WINDOW_INVISIBLE"); needsOr = true; } + if( 0 != ( implBitfield & OPT_UPSTREAM_SURFACELESS ) ) { + if(needsOr) { + sink.append(" | "); + } + sink.append("SURFACELESS"); + needsOr = true; + } sink.append(" ]"); return sink; } @@ -297,6 +306,34 @@ public abstract class ProxySurfaceImpl implements ProxySurface { @Override public final void clearUpstreamOptionBits(final int v) { implBitfield &= ~v; } + public static void dumpHierarchy(final PrintStream out, final ProxySurface s) { + out.println("Surface Hierarchy of "+s.getClass().getName()); + dumpHierarchy(out, s, ""); + out.println(); + } + private static void dumpHierarchy(final PrintStream out, final NativeSurface s, String indentation) { + indentation = indentation + " "; + out.println(indentation+"Surface device "+s.getGraphicsConfiguration().getScreen().getDevice()); + out.println(indentation+"Surface size "+s.getSurfaceWidth()+"x"+s.getSurfaceHeight()+", handle 0x"+Long.toHexString(s.getSurfaceHandle())); + if( s instanceof ProxySurfaceImpl ) { + final ProxySurface ps = (ProxySurface)s; + out.println(indentation+"Upstream options "+ps.getUpstreamOptionBits(null).toString()); + + final UpstreamSurfaceHook psUSH = ps.getUpstreamSurfaceHook(); + if( null != psUSH ) { + out.println(indentation+"Upstream Hook "+psUSH.getClass().getName()); + final NativeSurface upstreamSurface = psUSH.getUpstreamSurface(); + indentation = indentation + " "; + if( null != upstreamSurface ) { + out.println(indentation+"Upstream Hook's Surface "+upstreamSurface.getClass().getName()); + dumpHierarchy(out, upstreamSurface, indentation); + } else { + out.println(indentation+"Upstream Hook's Surface NULL"); + } + } + } + } + @Override public StringBuilder toString(StringBuilder sink) { if(null == sink) { diff --git a/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java b/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java index 881fd56a6..b187921e4 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java +++ b/src/nativewindow/classes/jogamp/nativewindow/SharedResourceToolkitLock.java @@ -33,6 +33,7 @@ import java.util.concurrent.atomic.AtomicInteger; import javax.media.nativewindow.ToolkitLock; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.util.LongObjectHashMap; import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; @@ -63,7 +64,7 @@ public class SharedResourceToolkitLock implements ToolkitLock { if(DEBUG || verbose || handle2Lock.size() > 0 ) { System.err.println("SharedResourceToolkitLock: Shutdown (open: "+handle2Lock.size()+")"); if(DEBUG) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } if( handle2Lock.size() > 0) { dumpOpenDisplayConnections(); diff --git a/src/nativewindow/classes/jogamp/nativewindow/awt/AWTMisc.java b/src/nativewindow/classes/jogamp/nativewindow/awt/AWTMisc.java index b0eda63b6..1dce9218c 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/awt/AWTMisc.java +++ b/src/nativewindow/classes/jogamp/nativewindow/awt/AWTMisc.java @@ -37,6 +37,7 @@ import java.awt.Component; import java.awt.Container; import java.awt.Frame; import java.awt.image.BufferedImage; +import java.nio.ByteBuffer; import java.util.HashMap; import javax.swing.JComponent; @@ -50,6 +51,8 @@ import javax.media.nativewindow.util.PixelFormat; import javax.media.nativewindow.util.PixelFormatUtil; import javax.swing.MenuSelectionManager; +import com.jogamp.nativewindow.awt.DirectDataBufferInt; + import jogamp.nativewindow.jawt.JAWTUtil; public class AWTMisc { @@ -210,25 +213,13 @@ public class AWTMisc { private static synchronized Cursor createCursor(final PixelRectangle pixelrect, final Point hotSpot) { final int width = pixelrect.getSize().getWidth(); final int height = pixelrect.getSize().getHeight(); - final BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); // PixelFormat.BGRA8888 - final PixelFormatUtil.PixelSink32 imgSink = new PixelFormatUtil.PixelSink32() { - public void store(final int x, final int y, final int pixel) { - img.setRGB(x, y, pixel); - } - @Override - public final PixelFormat getPixelformat() { - return PixelFormat.BGRA8888; - } - @Override - public int getStride() { - return width*4; - } - @Override - public final boolean isGLOriented() { - return false; - } - }; - PixelFormatUtil.convert32(imgSink, pixelrect); + // final BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); // PixelFormat.BGRA8888 + final DirectDataBufferInt.BufferedImageInt img = + DirectDataBufferInt.createBufferedImage(width, height, BufferedImage.TYPE_INT_ARGB, + null /* location */, null /* properties */); + final ByteBuffer imgBuffer = img.getDataBuffer().getDataBytes(); + PixelFormatUtil.convert(pixelrect, imgBuffer, PixelFormat.BGRA8888, false /* dst_glOriented */, width*4 /* dst_lineStride */); + final Toolkit toolkit = Toolkit.getDefaultToolkit(); return toolkit.createCustomCursor(img, hotSpot, pixelrect.toString()); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java index cf163bd82..9af74d9f5 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/macosx/OSXUtil.java @@ -31,6 +31,8 @@ import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.Point; +import javax.media.nativewindow.util.Rectangle; +import javax.media.nativewindow.util.RectangleImmutable; import com.jogamp.common.util.Function; import com.jogamp.common.util.FunctionTask; @@ -107,6 +109,58 @@ public class OSXUtil implements ToolkitProperties { return (Insets) GetInsets0(windowOrView); } + /** + * Returns the pixel-scale of the NSScreen, with the highest + * {@link RectangleImmutable#coverage(RectangleImmutable) coverage} of the given rectangle in window units. + * <p> + * If no coverage is detected the pixel-scale of the first NSScreen is returned. + * </p> + * @param r arbitrary rectangle in window units + * @param screenIndexOut storage returning the native screen index containing the given rectangle + */ + public static double GetPixelScale(final RectangleImmutable r, final int[] screenIndexOut) { + if( DEBUG ) { + System.err.printf("GetPixelScale covering %s%n", r.toString()); + } + final int screenCount; + final RectangleImmutable[] screenBounds; + final double[] pixelScales; + { + final double[] sd = GetScreenData0(); + if( 0 != sd.length % 5 ) { + throw new InternalError("GetScreenData0 didn't return multiple of 5 but "+sd.length); + } + screenCount = sd.length / 5; + screenBounds = new RectangleImmutable[screenCount]; + pixelScales = new double[screenCount] ; + for(int i=0; i<screenCount; i++) { + final int j = i*5; + pixelScales[i] = sd[j+0]; + screenBounds[i] = new Rectangle((int)sd[j+1], (int)sd[j+2], (int)sd[j+3], (int)sd[j+4]); + if( DEBUG ) { + System.err.printf("GetPixelScale.Screen[%d]: scale %f, bounds[%f / %f %f x %f]%n", + i, pixelScales[i], sd[j+1], sd[j+2], sd[j+3], sd[j+4]); + } + } + } + double pixelScale = pixelScales[0]; + screenIndexOut[0] = 0; + float maxCoverage = Float.MIN_VALUE; + for(int i=screenCount-1; i>=0; i--) { + final RectangleImmutable sb = screenBounds[i]; + final float coverage = sb.coverage(r); + if( coverage > maxCoverage ) { + maxCoverage = coverage; + screenIndexOut[0] = i; + pixelScale = pixelScales[i]; + } + } + if( DEBUG ) { + System.err.printf("GetPixelScale Result: screen %d, scale %f%n%n", screenIndexOut[0], pixelScale); + } + return pixelScale; + } + public static double GetPixelScale(final int screenIndex) { return GetPixelScale0(screenIndex); } @@ -393,6 +447,7 @@ public class OSXUtil implements ToolkitProperties { private static native boolean isNSWindow0(long object); private static native Object GetLocationOnScreen0(long windowOrView, int src_x, int src_y); private static native Object GetInsets0(long windowOrView); + private static native double[] GetScreenData0(); private static native double GetPixelScale0(int screenIndex); private static native double GetPixelScale1(long windowOrView); private static native long CreateNSWindow0(int x, int y, int width, int height); diff --git a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java index c409b6a39..b3cd977d4 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java +++ b/src/nativewindow/classes/jogamp/nativewindow/windows/GDIUtil.java @@ -31,6 +31,8 @@ import javax.media.nativewindow.util.Point; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.NativeWindowFactory; +import com.jogamp.common.ExceptionUtils; + import jogamp.nativewindow.NWJNILibLoader; import jogamp.nativewindow.Debug; import jogamp.nativewindow.ToolkitProperties; @@ -132,7 +134,7 @@ public class GDIUtil implements ToolkitProperties { SetProcessThreadsAffinityMask0(affinityMask, verbose); } - private static final void dumpStack() { Thread.dumpStack(); } // Callback for JNI + private static final void dumpStack() { ExceptionUtils.dumpStack(System.err); } // Callback for JNI /** Creates WNDCLASSEX instance */ static native boolean CreateWindowClass0(long hInstance, String clazzName, long wndProc, long iconSmallHandle, long iconBigHandle); diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java index 7e61ba6d0..1b3b207f6 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11DummyUpstreamSurfaceHook.java @@ -44,7 +44,7 @@ public class X11DummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize s.setSurfaceHandle(windowHandle); s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); } - s.addUpstreamOptionBits(ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE); + s.addUpstreamOptionBits( ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE ); } finally { device.unlock(); } diff --git a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java index 2414248b4..786be7cd7 100644 --- a/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java +++ b/src/nativewindow/classes/jogamp/nativewindow/x11/X11Util.java @@ -45,6 +45,7 @@ import jogamp.nativewindow.Debug; import jogamp.nativewindow.NWJNILibLoader; import jogamp.nativewindow.ToolkitProperties; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.util.LongObjectHashMap; import com.jogamp.common.util.PropertyAccess; import com.jogamp.nativewindow.x11.X11GraphicsDevice; @@ -196,7 +197,7 @@ public class X11Util implements ToolkitProperties { ", pending (open in creation order): "+pendingDisplayList.size()+ ")"); if(DEBUG) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } if( openDisplayList.size() > 0) { X11Util.dumpOpenDisplayConnections(); @@ -615,7 +616,7 @@ public class X11Util implements ToolkitProperties { } private static final String getCurrentThreadName() { return Thread.currentThread().getName(); } // Callback for JNI - private static final void dumpStack() { Thread.dumpStack(); } // Callback for JNI + private static final void dumpStack() { ExceptionUtils.dumpStack(System.err); } // Callback for JNI private static native boolean initialize0(boolean debug); private static native void shutdown0(); diff --git a/src/nativewindow/native/macosx/OSXmisc.m b/src/nativewindow/native/macosx/OSXmisc.m index 127b329d1..997bafba0 100644 --- a/src/nativewindow/native/macosx/OSXmisc.m +++ b/src/nativewindow/native/macosx/OSXmisc.m @@ -249,6 +249,62 @@ JNIEXPORT jobject JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetInsets0 return res; } +static CGDirectDisplayID GetCGDirectDisplayIDByNSScreen(NSScreen *screen) { + // Mind: typedef uint32_t CGDirectDisplayID; - however, we assume it's 64bit on 64bit ?! + NSDictionary * dict = [screen deviceDescription]; + NSNumber * val = (NSNumber *) [dict objectForKey: @"NSScreenNumber"]; + // [NSNumber integerValue] returns NSInteger which is 32 or 64 bit native size + return (CGDirectDisplayID) [val integerValue]; +} + +/* + * Class: Java_jogamp_nativewindow_macosx_OSXUtil + * Method: GetScreenData0 + * Signature: ()[F + */ +JNIEXPORT jdoubleArray JNICALL Java_jogamp_nativewindow_macosx_OSXUtil_GetScreenData0 + (JNIEnv *env, jclass unused) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + CGFloat pixelScale; + CGDirectDisplayID display; + NSRect dBounds; + NSScreen *screen; + NSArray *screens = [NSScreen screens]; + int sCount = [screens count]; + jdouble res[sCount*5]; + int i,j; + + for(i=0; i<sCount; i++) { + j = i*5; + screen = (NSScreen *) [screens objectAtIndex: i]; + pixelScale = 1.0; // default +NS_DURING + // Available >= 10.7 + pixelScale = [screen backingScaleFactor]; // HiDPI scaling +NS_HANDLER +NS_ENDHANDLER + display = GetCGDirectDisplayIDByNSScreen(screen); + dBounds = CGDisplayBounds (display); // origin top-left + res[j+0] = (jdouble)pixelScale; + res[j+1] = (jdouble)dBounds.origin.x; + res[j+2] = (jdouble)dBounds.origin.y; + res[j+3] = (jdouble)dBounds.size.width; + res[j+4] = (jdouble)dBounds.size.height; + } + + jdoubleArray jniRes = (*env)->NewDoubleArray(env, sCount*5); // x,y,w,h,scale + if (jniRes == NULL) { + NativewindowCommon_throwNewRuntimeException(env, "Could not allocate double array of size %d", sCount*5); + } + (*env)->SetDoubleArrayRegion(env, jniRes, 0, sCount*5, res); + + [pool release]; + + return jniRes; +} + /* * Class: Java_jogamp_nativewindow_macosx_OSXUtil * Method: GetPixelScale0 diff --git a/src/newt/classes/com/jogamp/newt/Window.java b/src/newt/classes/com/jogamp/newt/Window.java index ec6d767fa..c4ca9a554 100644 --- a/src/newt/classes/com/jogamp/newt/Window.java +++ b/src/newt/classes/com/jogamp/newt/Window.java @@ -95,6 +95,17 @@ import javax.media.nativewindow.util.SurfaceSize; * System.setProperty("newt.window.icons", "newt/data/jogamp-16x16.png newt/data/jogamp-32x32.png"); * </pre> * </p> + * + * <a name="lifecycleHeavy"><h5>Use of Lifecycle Heavy functions</h5></a> + * <p> + * Some of the methods specified here are lifecycle-heavy. That is, they are able + * to destroy and/or reattach resources to/from the window. Because of this, the methods + * are <i>not safe</i> to be called from EDT related threads. For example, it is not + * safe for a method in an attached {@link KeyListener} to call {@link #setFullscreen(boolean)} + * on a {@link Window} directly. It is safe, however, for that method to spawn a background + * worker thread which calls the method directly. The documentation for individual methods + * indicates whether or not they are lifecycle-heavy. + * </p> */ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSurface { public static final boolean DEBUG_MOUSE_EVENT = Debug.debug("Window.MouseEvent"); @@ -174,6 +185,7 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur * <p> * The Window can be recreate via {@link #setVisible(boolean) setVisible(true)}. * </p> + * <p>This method is <a href="#lifecycleHeavy">lifecycle heavy</a>.</p> * @see #destroy() * @see #setVisible(boolean) */ @@ -193,6 +205,7 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur /** * Calls {@link #setVisible(boolean, boolean) setVisible(true, visible)}, * i.e. blocks until the window becomes visible. + * <p>This method is <a href="#lifecycleHeavy">lifecycle heavy</a>.</p> * @see #setVisible(boolean, boolean) */ void setVisible(boolean visible); @@ -226,6 +239,7 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur * i.e. {@link javax.media.nativewindow.NativeWindow#getWindowHandle()} returns <code>null</code>.<br> * <code>setVisible(wait, true)</code> shall be repeated when the parent becomes valid. * </p> + * <p>This method is <a href="#lifecycleHeavy">lifecycle heavy</a>.</p> */ void setVisible(boolean wait, boolean visible); @@ -470,6 +484,7 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur * this window is removed from it's list of children.<br> * In case the new parent is not null and a Window, * this window is added to it's list of children.<br></P> + * <p>This method is <a href="#lifecycleHeavy">lifecycle heavy</a>.</p> * * @param newParent The new parent NativeWindow. If null, this Window becomes a top level window. * @param x new top-level position in window units, use -1 for default position. @@ -485,6 +500,7 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur * <p> * Fullscreen mode is established on the {@link #getMainMonitor() main monitor}. * </p> + * <p>This method is <a href="#lifecycleHeavy">lifecycle heavy</a>.</p> * @param fullscreen enable or disable fullscreen mode * @return success * @see #setFullscreen(List) @@ -498,6 +514,7 @@ public interface Window extends NativeWindow, WindowClosingProtocol, ScalableSur * <p> * Disable fullscreen via {@link #setFullscreen(boolean)}. * </p> + * <p>This method is <a href="#lifecycleHeavy">lifecycle heavy</a>.</p> * @param monitors if <code>null</code> fullscreen will be spanned across all {@link MonitorDevice}s, * otherwise across the given list of {@link MonitorDevice}. * @return success diff --git a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java index c470f6840..e890bc640 100644 --- a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java +++ b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java @@ -69,6 +69,7 @@ import jogamp.newt.awt.event.AWTParentWindowAdapter; import jogamp.newt.driver.DriverClearFocus; import jogamp.opengl.awt.AWTTilePainter; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.util.awt.AWTEDTExecutor; import com.jogamp.nativewindow.awt.AWTPrintLifecycle; import com.jogamp.nativewindow.awt.AWTWindowClosingProtocol; @@ -469,7 +470,7 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto determineIfApplet(); if(DEBUG) { System.err.println("NewtCanvasAWT.addNotify.0 - isApplet "+isApplet+", addedOnAWTEDT "+EventQueue.isDispatchThread()+" @ "+currentThreadName()); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } jawtWindow = NewtFactoryAWT.getNativeWindow(NewtCanvasAWT.this, null != newtChild ? newtChild.getRequestedCapabilities() : null); jawtWindow.setShallUseOffscreenLayer(shallUseOffscreenLayer); @@ -493,7 +494,7 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto } else { if(DEBUG) { System.err.println("NewtCanvasAWT.removeNotify.0 - isApplet "+isApplet+" @ "+currentThreadName()); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } componentAdded = false; // Bug 910 awtWindowClosingProtocol.removeClosingListener(); @@ -518,7 +519,7 @@ public class NewtCanvasAWT extends java.awt.Canvas implements WindowClosingProto public final void destroy() { if(DEBUG) { System.err.println("NewtCanvasAWT.destroy() @ "+currentThreadName()); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } AWTEDTExecutor.singleton.invoke(true, new Runnable() { @Override diff --git a/src/newt/classes/jogamp/newt/DefaultEDTUtil.java b/src/newt/classes/jogamp/newt/DefaultEDTUtil.java index ef8ea66b6..4f2087637 100644 --- a/src/newt/classes/jogamp/newt/DefaultEDTUtil.java +++ b/src/newt/classes/jogamp/newt/DefaultEDTUtil.java @@ -43,6 +43,7 @@ import javax.media.nativewindow.NativeWindowException; import jogamp.common.util.locks.LockDebugUtil; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.util.RunnableTask; import com.jogamp.common.util.locks.Lock; import com.jogamp.newt.util.EDTUtil; @@ -144,7 +145,7 @@ public class DefaultEDTUtil implements EDTUtil { public final boolean invokeStop(final boolean wait, final Runnable task) { if(DEBUG) { System.err.println(Thread.currentThread()+": Default-EDT.invokeStop wait "+wait); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return invokeImpl(wait, task, true /* stop */, false /* provokeError */); } @@ -152,7 +153,7 @@ public class DefaultEDTUtil implements EDTUtil { public final boolean invokeAndWaitError(final Runnable task) { if(DEBUG) { System.err.println(Thread.currentThread()+": Default-EDT.invokeAndWaitError"); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return invokeImpl(true /* wait */, task, false /* stop */, true /* provokeError */); } @@ -177,7 +178,7 @@ public class DefaultEDTUtil implements EDTUtil { // drop task .. System.err.println(Thread.currentThread()+": Warning: Default-EDT about (1) to stop, won't enqueue new task: "+edt); if(DEBUG) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return false; } @@ -191,7 +192,7 @@ public class DefaultEDTUtil implements EDTUtil { if( edt.tasks.size()>0 ) { System.err.println(Thread.currentThread()+": Warning: Default-EDT about (2) to stop, task executed. Remaining tasks: "+edt.tasks.size()+" - "+edt); if(DEBUG) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } } @@ -204,7 +205,7 @@ public class DefaultEDTUtil implements EDTUtil { System.err.println(Thread.currentThread()+": Warning: Default-EDT is not running, dropping task. NEDT "+edt); } if(DEBUG) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } return false; diff --git a/src/newt/classes/jogamp/newt/DisplayImpl.java b/src/newt/classes/jogamp/newt/DisplayImpl.java index 84ce45238..c94d7d40e 100644 --- a/src/newt/classes/jogamp/newt/DisplayImpl.java +++ b/src/newt/classes/jogamp/newt/DisplayImpl.java @@ -34,6 +34,7 @@ package jogamp.newt; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.nio.Buffers; import com.jogamp.common.util.IOUtil; import com.jogamp.common.util.ReflectionUtil; @@ -164,7 +165,7 @@ public abstract class DisplayImpl extends Display { final PixelRectangle fpixelrect; if( getNativePointerIconPixelFormat() != pixelrect.getPixelformat() || pixelrect.isGLOriented() ) { // conversion ! - fpixelrect = PixelFormatUtil.convert32(pixelrect, getNativePointerIconPixelFormat(), + fpixelrect = PixelFormatUtil.convert(pixelrect, getNativePointerIconPixelFormat(), 0 /* ddestStride */, false /* isGLOriented */, getNativePointerIconForceDirectNIO() ); if( DEBUG_POINTER_ICON ) { System.err.println("createPointerIconRES.0: Conversion-FMT "+pixelrect+" -> "+fpixelrect); @@ -398,7 +399,7 @@ public abstract class DisplayImpl extends Display { if( DEBUG ) { if ( !res ) { System.err.println("Warning: invokeStop() failed"); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } } @@ -416,7 +417,7 @@ public abstract class DisplayImpl extends Display { if( !_edtUtil.isRunning() ) { // // volatile dbl-checked-locking OK if( DEBUG ) { System.err.println("Info: EDT start "+Thread.currentThread().getName()+", "+this); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } _edtUtil.start(); } @@ -428,7 +429,7 @@ public abstract class DisplayImpl extends Display { } if( DEBUG ) { System.err.println("Warning: invoke(wait "+wait+", ..) on EDT failed .. invoke on current thread "+Thread.currentThread().getName()); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } task.run(); @@ -685,7 +686,7 @@ public abstract class DisplayImpl extends Display { if(null == event) { // Ooops ? System.err.println("Warning: event of eventTask is NULL"); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); return; } dispatchMessage(event); @@ -739,7 +740,7 @@ public abstract class DisplayImpl extends Display { // oops .. we are already dead if(DEBUG) { System.err.println("Warning: EDT already stopped: wait:="+wait+", "+e); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return; } diff --git a/src/newt/classes/jogamp/newt/OffscreenWindow.java b/src/newt/classes/jogamp/newt/OffscreenWindow.java index 749391f1f..a21016402 100644 --- a/src/newt/classes/jogamp/newt/OffscreenWindow.java +++ b/src/newt/classes/jogamp/newt/OffscreenWindow.java @@ -71,7 +71,7 @@ public class OffscreenWindow extends WindowImpl implements MutableSurface { setGraphicsConfiguration(cfg); synchronized(OffscreenWindow.class) { - setWindowHandle(nextWindowHandle++); + setWindowHandle(nextWindowHandle++); // just a marker } visibleChanged(false, true); } diff --git a/src/newt/classes/jogamp/newt/PointerIconImpl.java b/src/newt/classes/jogamp/newt/PointerIconImpl.java index 546a463de..f2b24a3b3 100644 --- a/src/newt/classes/jogamp/newt/PointerIconImpl.java +++ b/src/newt/classes/jogamp/newt/PointerIconImpl.java @@ -154,7 +154,7 @@ public class PointerIconImpl implements PointerIcon { } @Override public final int getStride() { - return size.getWidth() * pixelformat.bytesPerPixel(); + return size.getWidth() * pixelformat.comp.bytesPerPixel(); } @Override public final boolean isGLOriented() { diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java index b62628962..0c4dcd192 100644 --- a/src/newt/classes/jogamp/newt/WindowImpl.java +++ b/src/newt/classes/jogamp/newt/WindowImpl.java @@ -63,6 +63,7 @@ import javax.media.nativewindow.util.RectangleImmutable; import jogamp.nativewindow.SurfaceScaleUtils; import jogamp.nativewindow.SurfaceUpdatedHelper; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.util.ArrayHashSet; import com.jogamp.common.util.IntBitfield; import com.jogamp.common.util.PropertyAccess; @@ -1992,7 +1993,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer protected final void definePosition(final int x, final int y) { if(DEBUG_IMPLEMENTATION) { System.err.println("definePosition: "+this.x+"/"+this.y+" -> "+x+"/"+y); - // Thread.dumpStack(); + // ExceptionUtils.dumpStackTrace(System.err); } autoPosition = false; this.x = x; this.y = y; @@ -2008,7 +2009,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer if(DEBUG_IMPLEMENTATION) { System.err.println("defineSize: win["+this.winWidth+"x"+this.winHeight+" -> "+winWidth+"x"+winHeight+ "], pixel["+this.pixWidth+"x"+this.pixHeight+" -> "+pixWidth+"x"+pixHeight+"]"); - // Thread.dumpStack(); + // ExceptionUtils.dumpStackTrace(System.err); } this.winWidth = winWidth; this.winHeight = winHeight; this.pixWidth = pixWidth; this.pixHeight = pixHeight; @@ -2637,7 +2638,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer final boolean discardTO = QUEUED_EVENT_TO <= System.currentTimeMillis()-e.getWhen(); if(DEBUG_IMPLEMENTATION) { System.err.println("Window.consumeEvent: REPAINT "+Thread.currentThread().getName()+" - queued "+e+", discard-to "+discardTO); - // Thread.dumpStack(); + // ExceptionUtils.dumpStackTrace(System.err); } return discardTO; // discardTO:=true -> consumed } @@ -2653,7 +2654,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer final boolean discardTO = QUEUED_EVENT_TO <= System.currentTimeMillis()-e.getWhen(); if(DEBUG_IMPLEMENTATION) { System.err.println("Window.consumeEvent: RESIZED "+Thread.currentThread().getName()+" - queued "+e+", discard-to "+discardTO); - // Thread.dumpStack(); + // ExceptionUtils.dumpStackTrace(System.err); } return discardTO; // discardTO:=true -> consumed } @@ -3745,7 +3746,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer throw new NativeWindowException(msg); } else if (DEBUG_IMPLEMENTATION) { System.err.println(msg); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return -1; } else if( 0 < remaining ){ @@ -3791,7 +3792,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer throw new NativeWindowException(msg); } else if (DEBUG_IMPLEMENTATION) { System.err.println(msg); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return false; } else { @@ -3851,7 +3852,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } else { System.err.println("Auto position not reached within timeout, has "+getX()+"/"+getY()+", autoPosition "+autoPosition+", remaining "+remaining); } - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } return ok; @@ -3892,7 +3893,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer final WindowClosingMode mode = force ? WindowClosingMode.DISPOSE_ON_CLOSE : defMode; if(DEBUG_IMPLEMENTATION) { System.err.println("Window.windowDestroyNotify(isNativeValid: "+isNativeValid()+", force: "+force+", mode "+defMode+" -> "+mode+") "+getThreadName()+": "+this); - // Thread.dumpStack(); + // ExceptionUtils.dumpStackTrace(System.err); } final boolean destroyed; diff --git a/src/newt/classes/jogamp/newt/driver/android/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/android/DisplayDriver.java index a5f4fc769..fd3beb209 100644 --- a/src/newt/classes/jogamp/newt/driver/android/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/android/DisplayDriver.java @@ -33,6 +33,8 @@ import jogamp.opengl.egl.*; import javax.media.nativewindow.*; +import com.jogamp.opengl.egl.EGL; + public class DisplayDriver extends jogamp.newt.DisplayImpl { static { NEWTJNILibLoader.loadNEWT(); diff --git a/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java index 786ebb31c..908a55604 100644 --- a/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/android/WindowDriver.java @@ -47,12 +47,13 @@ import javax.media.opengl.GLCapabilitiesChooser; import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLException; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.os.AndroidVersion; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; import com.jogamp.newt.MonitorDevice; import com.jogamp.newt.Window; +import com.jogamp.opengl.egl.EGL; -import jogamp.opengl.egl.EGL; import jogamp.opengl.egl.EGLDisplayUtil; import jogamp.opengl.egl.EGLGraphicsConfiguration; import jogamp.opengl.egl.EGLGraphicsConfigurationFactory; @@ -282,7 +283,7 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { protected final boolean canCreateNativeImpl() { Log.d(MD.TAG, "canCreateNativeImpl.0: surfaceHandle ready "+(0!=surfaceHandle)+" - on thread "+Thread.currentThread().getName()); if(Window.DEBUG_IMPLEMENTATION) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } if( isFullscreen() ) { @@ -386,7 +387,7 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { "], pixel["+getSurfaceWidth()+"x"+getSurfaceHeight()+"],"+ " - on thread "+Thread.currentThread().getName()); if(Window.DEBUG_IMPLEMENTATION) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } setupInputListener(false); @@ -557,7 +558,7 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { public final void surfaceChanged(final SurfaceHolder aHolder, final int aFormat, final int aWidth, final int aHeight) { Log.d(MD.TAG, "surfaceChanged: f "+nativeFormat+" -> "+aFormat+", "+aWidth+"x"+aHeight+", current surfaceHandle: 0x"+Long.toHexString(surfaceHandle)+" - on thread "+Thread.currentThread().getName()); if(Window.DEBUG_IMPLEMENTATION) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } if(0!=surfaceHandle && androidFormat != aFormat ) { // re-create @@ -611,7 +612,7 @@ public class WindowDriver extends jogamp.newt.WindowImpl implements Callback2 { public final void surfaceDestroyed(final SurfaceHolder holder) { Log.d(MD.TAG, "surfaceDestroyed - on thread "+Thread.currentThread().getName()); windowDestroyNotify(true); // actually too late .. however .. - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } @Override diff --git a/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java b/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java index 39e68e48c..090fa1653 100644 --- a/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java +++ b/src/newt/classes/jogamp/newt/driver/awt/AWTEDTUtil.java @@ -32,6 +32,7 @@ import java.awt.EventQueue; import javax.media.nativewindow.NativeWindowException; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.util.RunnableTask; import com.jogamp.common.util.awt.AWTEDTExecutor; import com.jogamp.newt.util.EDTUtil; @@ -140,7 +141,7 @@ public class AWTEDTUtil implements EDTUtil { // drop task .. System.err.println(Thread.currentThread()+": Warning: AWT-EDT about (1) to stop, won't enqueue new task: "+nedt); if(DEBUG) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return false; } @@ -161,7 +162,7 @@ public class AWTEDTUtil implements EDTUtil { System.err.println(Thread.currentThread()+": Warning: AWT-EDT is not running, dropping task. NEDT "+nedt); } if(DEBUG) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } return false; diff --git a/src/newt/classes/jogamp/newt/driver/bcm/egl/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/bcm/egl/DisplayDriver.java index ceb337150..6fb93bf97 100644 --- a/src/newt/classes/jogamp/newt/driver/bcm/egl/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/bcm/egl/DisplayDriver.java @@ -38,9 +38,9 @@ import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeWindowException; import jogamp.newt.NEWTJNILibLoader; -import jogamp.opengl.egl.EGL; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; +import com.jogamp.opengl.egl.EGL; public class DisplayDriver extends jogamp.newt.DisplayImpl { diff --git a/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/DisplayDriver.java index 1b67fa755..407668718 100644 --- a/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/DisplayDriver.java @@ -38,13 +38,13 @@ import javax.media.nativewindow.util.PixelFormat; import com.jogamp.common.nio.Buffers; import com.jogamp.common.util.IOUtil; +import com.jogamp.opengl.egl.EGL; import com.jogamp.opengl.util.PNGPixelRect; import jogamp.newt.DisplayImpl; import jogamp.newt.NEWTJNILibLoader; import jogamp.newt.PointerIconImpl; import jogamp.newt.driver.linux.LinuxMouseTracker; -import jogamp.opengl.egl.EGL; import jogamp.opengl.egl.EGLDisplayUtil; public class DisplayDriver extends DisplayImpl { diff --git a/src/newt/classes/jogamp/newt/driver/kd/DisplayDriver.java b/src/newt/classes/jogamp/newt/driver/kd/DisplayDriver.java index e72ddbc11..64e7e698e 100644 --- a/src/newt/classes/jogamp/newt/driver/kd/DisplayDriver.java +++ b/src/newt/classes/jogamp/newt/driver/kd/DisplayDriver.java @@ -37,9 +37,10 @@ package jogamp.newt.driver.kd; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeWindowException; +import com.jogamp.opengl.egl.EGL; + import jogamp.newt.DisplayImpl; import jogamp.newt.NEWTJNILibLoader; -import jogamp.opengl.egl.EGL; import jogamp.opengl.egl.EGLDisplayUtil; public class DisplayDriver extends DisplayImpl { diff --git a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java index afa9786e2..4b8e71571 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/x11/WindowDriver.java @@ -50,6 +50,7 @@ import javax.media.nativewindow.util.Insets; import javax.media.nativewindow.util.InsetsImmutable; import javax.media.nativewindow.util.Point; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.nio.Buffers; import com.jogamp.nativewindow.x11.X11GraphicsDevice; import com.jogamp.nativewindow.x11.X11GraphicsScreen; @@ -424,7 +425,7 @@ public class WindowDriver extends WindowImpl { // Internals only // private static final String getCurrentThreadName() { return Thread.currentThread().getName(); } // Callback for JNI - private static final void dumpStack() { Thread.dumpStack(); } // Callback for JNI + private static final void dumpStack() { ExceptionUtils.dumpStack(System.err); } // Callback for JNI private final <T> T runWithLockedDisplayDevice(final DisplayRunnable<T> action) { return ((DisplayDriver) getScreen().getDisplay()).runWithLockedDisplayDevice(action); diff --git a/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java b/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java index 794e989a6..1b4b43a6e 100644 --- a/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java +++ b/src/newt/classes/jogamp/newt/swt/SWTEDTUtil.java @@ -31,6 +31,7 @@ import javax.media.nativewindow.NativeWindowException; import jogamp.newt.Debug; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.util.RunnableTask; import com.jogamp.newt.util.EDTUtil; @@ -170,7 +171,7 @@ public class SWTEDTUtil implements EDTUtil { // drop task .. if(DEBUG) { System.err.println(Thread.currentThread()+": Warning: SWT-EDT about (1) to stop, won't enqueue new task: "+nedt+", isRunning "+nedt.isRunning+", shouldStop "+nedt.shouldStop); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return false; } @@ -195,7 +196,7 @@ public class SWTEDTUtil implements EDTUtil { System.err.println(Thread.currentThread()+": Warning: SWT-EDT is not running, dropping task. NEDT "+nedt); } if(DEBUG) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } return false; @@ -212,7 +213,7 @@ public class SWTEDTUtil implements EDTUtil { if( swtDisplay.isDisposed() ) { System.err.println(Thread.currentThread()+": Warning: SWT-EDT is about (3) to stop and stopped already, dropping task. "+nedt); if(DEBUG) { - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return false; } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextNewtAWTBug523.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextNewtAWTBug523.java index d3cdf5e95..95bec26fa 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextNewtAWTBug523.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestSharedContextNewtAWTBug523.java @@ -72,6 +72,7 @@ import org.junit.Test; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.nio.Buffers; import com.jogamp.newt.awt.NewtCanvasAWT; import com.jogamp.newt.opengl.GLWindow; @@ -476,7 +477,7 @@ public class TestSharedContextNewtAWTBug523 extends UITestCase { final String errStr = "GL-Error: "+prefix + " on obj 0x"+Integer.toHexString(obj.hashCode())+", OpenGL error: 0x" + Integer.toHexString(glError); if( errorSet.add(errStr) ) { System.err.println(errStr); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } final int status = gl.glCheckFramebufferStatus(GL.GL_FRAMEBUFFER); @@ -484,7 +485,7 @@ public class TestSharedContextNewtAWTBug523 extends UITestCase { final String errStr = "GL-Error: "+prefix + " on obj 0x"+Integer.toHexString(obj.hashCode())+", glCheckFramebufferStatus: 0x" + Integer.toHexString(status); if( errorSet.add(errStr) ) { System.err.println(errStr); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2GLJPanelAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2GLJPanelAWT.java index ae11c9d54..340816a13 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2GLJPanelAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2GLJPanelAWT.java @@ -31,11 +31,16 @@ package com.jogamp.opengl.test.junit.jogl.demos.es2.awt; import java.awt.AWTException; import java.awt.BorderLayout; import java.awt.Dimension; +import java.awt.DisplayMode; +import java.awt.GraphicsDevice; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.lang.reflect.InvocationTargetException; +import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.ScalableSurface; +import javax.media.nativewindow.util.Rectangle; +import javax.media.nativewindow.util.RectangleImmutable; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesImmutable; @@ -45,6 +50,8 @@ import javax.media.opengl.awt.GLJPanel; import javax.swing.JFrame; import javax.swing.SwingUtilities; +import jogamp.common.os.PlatformPropsImpl; + import org.junit.AfterClass; import org.junit.Assert; import org.junit.Assume; @@ -53,6 +60,7 @@ import org.junit.Test; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; +import com.jogamp.common.os.Platform; import com.jogamp.newt.event.KeyEvent; import com.jogamp.newt.event.TraceKeyAdapter; import com.jogamp.newt.event.TraceWindowAdapter; @@ -70,11 +78,13 @@ import com.jogamp.opengl.util.FPSAnimator; public class TestGearsES2GLJPanelAWT extends UITestCase { static Dimension wsize, rwsize=null; static boolean forceES2 = false; + static boolean forceES3 = false; static boolean forceGL3 = false; static boolean forceGLFFP = false; static boolean shallUsePBuffer = false; static boolean shallUseBitmap = false; static boolean useMSAA = false; + static int msaaNumSamples = 4; static int swapInterval = 0; static boolean useAnimator = true; static boolean manualTest = false; @@ -117,6 +127,8 @@ public class TestGearsES2GLJPanelAWT extends UITestCase { protected void runTestGL(final GLCapabilities caps) throws AWTException, InterruptedException, InvocationTargetException { + System.err.println("Requesting: "+caps); + final JFrame frame = new JFrame("Swing GLJPanel"); Assert.assertNotNull(frame); @@ -209,7 +221,23 @@ public class TestGearsES2GLJPanelAWT extends UITestCase { if( e.isAutoRepeat() ) { return; } - if(e.getKeyChar()=='x') { + if(e.getKeyChar()=='p') { + System.err.println(); + final java.awt.Point los = glJPanel.getLocationOnScreen(); + final RectangleImmutable r = new Rectangle(los.x, los.y, glJPanel.getWidth(), glJPanel.getHeight()); + final GraphicsDevice gd = glJPanel.getGraphicsConfiguration().getDevice(); + final DisplayMode dm = gd.getDisplayMode(); + System.err.printf("GetPixelScale: AWT DisplayMode %d x %d pixel-units%n", dm.getWidth(), dm.getHeight()); + System.err.printf("GetPixelScale: NW Screen: %s%n", glJPanel.getNativeSurface().getGraphicsConfiguration().getScreen()); + System.err.printf("GetPixelScale: Panel Bounds: %s window-units%n", r.toString()); + System.err.printf("GetPixelScale: Panel Resolution: %d x %d pixel-units%n", glJPanel.getSurfaceWidth(), glJPanel.getSurfaceHeight()); + if( Platform.OSType.MACOS == PlatformPropsImpl.OS_TYPE ) { + final int[] screenIndexOut = { 0 }; + final double pixelScale = jogamp.nativewindow.macosx.OSXUtil.GetPixelScale(r, screenIndexOut); + System.err.printf("GetPixelScale: PixelScale %f on screen-idx %d%n", pixelScale, screenIndexOut[0]); + } + System.err.println(); + } else if(e.getKeyChar()=='x') { final int[] hadSurfacePixelScale = glJPanel.getCurrentSurfaceScale(new int[2]); final int[] reqSurfacePixelScale; if( hadSurfacePixelScale[0] == ScalableSurface.IDENTITY_PIXELSCALE ) { @@ -302,16 +330,18 @@ public class TestGearsES2GLJPanelAWT extends UITestCase { final GLProfile glp; if(forceGL3) { glp = GLProfile.get(GLProfile.GL3); + } else if(forceES3) { + glp = GLProfile.get(GLProfile.GLES3); } else if(forceES2) { glp = GLProfile.get(GLProfile.GLES2); } else if(forceGLFFP) { glp = GLProfile.getMaxFixedFunc(true); } else { - glp = GLProfile.getGL2ES2(); + glp = GLProfile.getDefault(); } final GLCapabilities caps = new GLCapabilities( glp ); if(useMSAA) { - caps.setNumSamples(4); + caps.setNumSamples(msaaNumSamples); caps.setSampleBuffers(true); } if(shallUsePBuffer) { @@ -406,7 +436,24 @@ public class TestGearsES2GLJPanelAWT extends UITestCase { } @Test - public void test30_GL3() + public void test30_GLES3() + throws AWTException, InterruptedException, InvocationTargetException + { + if( manualTest ) { + return; + } + + if( !GLProfile.isAvailable(GLProfile.GLES3) ) { + System.err.println("GLES3 n/a"); + return; + } + final GLProfile glp = GLProfile.get(GLProfile.GLES3); + final GLCapabilities caps = new GLCapabilities( glp ); + runTestGL(caps); + } + + @Test + public void test40_GL3() throws AWTException, InterruptedException, InvocationTargetException { if( manualTest ) { @@ -447,6 +494,8 @@ public class TestGearsES2GLJPanelAWT extends UITestCase { duration = MiscUtils.atol(args[i], duration); } else if(args[i].equals("-es2")) { forceES2 = true; + } else if(args[i].equals("-es3")) { + forceES3 = true; } else if(args[i].equals("-gl3")) { forceGL3 = true; } else if(args[i].equals("-glFFP")) { @@ -480,7 +529,9 @@ public class TestGearsES2GLJPanelAWT extends UITestCase { i++; swapInterval = MiscUtils.atoi(args[i], swapInterval); } else if(args[i].equals("-msaa")) { + i++; useMSAA = true; + msaaNumSamples = MiscUtils.atoi(args[i], msaaNumSamples); } else if(args[i].equals("-noanim")) { useAnimator = false; } else if(args[i].equals("-pbuffer")) { @@ -503,7 +554,7 @@ public class TestGearsES2GLJPanelAWT extends UITestCase { System.err.println("forceES2 "+forceES2); System.err.println("forceGL3 "+forceGL3); System.err.println("forceGLFFP "+forceGLFFP); - System.err.println("useMSAA "+useMSAA); + System.err.println("useMSAA "+useMSAA+", msaaNumSamples "+msaaNumSamples); System.err.println("useAnimator "+useAnimator); System.err.println("shallUsePBuffer "+shallUsePBuffer); System.err.println("shallUseBitmap "+shallUseBitmap); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2GLJPanelsAWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2GLJPanelsAWT.java index 11d9da780..c22a6fdf8 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2GLJPanelsAWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2GLJPanelsAWT.java @@ -99,7 +99,7 @@ public class TestGearsES2GLJPanelsAWT extends UITestCase { if( initSingleBuffer ) { singleAWTGLPixelBufferProvider = new SingleAWTGLPixelBufferProvider( glp.isGL2ES3() /* allowRowStride */); - singleAWTGLPixelBufferProvider.initSingleton(4, 600, 600, 1, true); + singleAWTGLPixelBufferProvider.initSingleton(null, 4, true, 600, 600, 1); } else { singleAWTGLPixelBufferProvider = null; } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestRandomTiledRendering2GL2NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestRandomTiledRendering2GL2NEWT.java index 546420057..ed20ccd97 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestRandomTiledRendering2GL2NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestRandomTiledRendering2GL2NEWT.java @@ -40,6 +40,7 @@ import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; +import javax.media.nativewindow.util.PixelFormat; import javax.media.opengl.GL; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLCapabilities; @@ -117,8 +118,9 @@ public class TestRandomTiledRendering2GL2NEWT extends UITestCase { @Override public void init(final GLAutoDrawable drawable) { final GL gl = drawable.getGL(); - final GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(gl, 3); - final GLPixelBuffer pixelBuffer = pixelBufferProvider.allocate(gl, pixelAttribs, imageWidth, imageHeight, 1, true, 0); + final PixelFormat.Composition hostPixelComp = pixelBufferProvider.getHostPixelComp(gl.getGLProfile(), 3); + final GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(gl, 3, true); + final GLPixelBuffer pixelBuffer = pixelBufferProvider.allocate(gl, hostPixelComp, pixelAttribs, true, imageWidth, imageHeight, 1, 0); renderer.setImageBuffer(pixelBuffer); if( drawable.isGLOriented() ) { flipVertically[0] = false; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestRandomTiledRendering3GL2AWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestRandomTiledRendering3GL2AWT.java index b128f8691..a9d159684 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestRandomTiledRendering3GL2AWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestRandomTiledRendering3GL2AWT.java @@ -48,6 +48,7 @@ import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; +import javax.media.nativewindow.util.PixelFormat; import javax.media.opengl.GL; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLCapabilities; @@ -136,8 +137,9 @@ public class TestRandomTiledRendering3GL2AWT extends UITestCase { @Override public void init(final GLAutoDrawable drawable) { final GL gl = drawable.getGL(); - final GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(gl, 3); - final GLPixelBuffer pixelBuffer = pixelBufferProvider.allocate(gl, pixelAttribs, imageWidth, imageHeight, 1, true, 0); + final PixelFormat.Composition hostPixelComp = pixelBufferProvider.getHostPixelComp(gl.getGLProfile(), 3); + final GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(gl, 3, true); + final GLPixelBuffer pixelBuffer = pixelBufferProvider.allocate(gl, hostPixelComp, pixelAttribs, true, imageWidth, imageHeight, 1, 0); renderer.setImageBuffer(pixelBuffer); if( drawable.isGLOriented() ) { flipVertically[0] = false; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledRendering1GL2NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledRendering1GL2NEWT.java index 9dee67e5e..1f7016b7c 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledRendering1GL2NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledRendering1GL2NEWT.java @@ -39,6 +39,7 @@ import com.jogamp.opengl.util.texture.TextureIO; import java.io.File; import java.io.IOException; +import javax.media.nativewindow.util.PixelFormat; import javax.media.opengl.GL2; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLCapabilities; @@ -121,8 +122,9 @@ public class TestTiledRendering1GL2NEWT extends UITestCase { final GLPixelBuffer.GLPixelBufferProvider pixelBufferProvider = GLPixelBuffer.defaultProviderWithRowStride; final boolean[] flipVertically = { false }; - final GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(gl, 3); - final GLPixelBuffer pixelBuffer = pixelBufferProvider.allocate(gl, pixelAttribs, imageWidth, imageHeight, 1, true, 0); + final PixelFormat.Composition hostPixelComp = pixelBufferProvider.getHostPixelComp(gl.getGLProfile(), 3); + final GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(gl, 3, true); + final GLPixelBuffer pixelBuffer = pixelBufferProvider.allocate(gl, hostPixelComp, pixelAttribs, true, imageWidth, imageHeight, 1, 0); renderer.setImageBuffer(pixelBuffer); flipVertically[0] = false; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledRendering2NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledRendering2NEWT.java index e979ac966..e792ecaa2 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledRendering2NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/tile/TestTiledRendering2NEWT.java @@ -40,6 +40,8 @@ import com.jogamp.opengl.util.texture.TextureIO; import java.io.File; import java.io.IOException; + +import javax.media.nativewindow.util.PixelFormat; import javax.media.opengl.GL; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLCapabilities; @@ -197,8 +199,9 @@ public class TestTiledRendering2NEWT extends UITestCase { @Override public void init(final GLAutoDrawable drawable) { final GL gl = drawable.getGL(); - final GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(gl, 3); - final GLPixelBuffer pixelBuffer = pixelBufferProvider.allocate(gl, pixelAttribs, imageWidth, imageHeight, 1, true, 0); + final PixelFormat.Composition hostPixelComp = pixelBufferProvider.getHostPixelComp(gl.getGLProfile(), 3); + final GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(gl, 3, true); + final GLPixelBuffer pixelBuffer = pixelBufferProvider.allocate(gl, hostPixelComp, pixelAttribs, true, imageWidth, imageHeight, 1, 0); renderer.setImageBuffer(pixelBuffer); if( drawable.isGLOriented() ) { flipVertically[0] = false; diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestBug817GLReadBufferUtilGLCTXDefFormatTypeES2NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestBug817GLReadBufferUtilGLCTXDefFormatTypeES2NEWT.java index 2eb8b45c3..1a146adb6 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestBug817GLReadBufferUtilGLCTXDefFormatTypeES2NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestBug817GLReadBufferUtilGLCTXDefFormatTypeES2NEWT.java @@ -112,7 +112,7 @@ public class TestBug817GLReadBufferUtilGLCTXDefFormatTypeES2NEWT extends UITestC public void dispose(final GLAutoDrawable drawable) {} public void display(final GLAutoDrawable drawable) { final GLPixelBufferProvider pixelBufferProvider = screenshot.getPixelBufferProvider(); - final GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(drawable.getGL(), readAlpha ? 4 : 3); + final GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(drawable.getGL(), readAlpha ? 4 : 3, true); System.err.println("GLPixelAttributes: "+pixelAttribs); snapshot(displayCount++, null, drawable.getGL(), screenshot, TextureIO.PNG, null); } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGPixelRect01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGPixelRect01NEWT.java index 4a324f594..3f910ed36 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGPixelRect01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPNGPixelRect01NEWT.java @@ -73,9 +73,10 @@ public class TestPNGPixelRect01NEWT extends UITestCase { final GLProfile glp = GLProfile.getGL2ES2(); final PNGPixelRect image = PNGPixelRect.read(istream, destFmt, true /* directBuffer */, 0 /* destMinStrideInBytes */, true /* destIsGLOriented */); Assert.assertNotNull(image); - final GLPixelAttributes glpa = GLPixelAttributes.convert(image.getPixelformat(), glp); - final boolean hasAlpha = 4 == glpa.bytesPerPixel; - System.err.println("PNGPixelRect: "+basename+", "+image+", glpa "+glpa); + System.err.println("PNGPixelRect: "+basename+", "+image); + final GLPixelAttributes glpa = new GLPixelAttributes(glp, image.getPixelformat(), false /* pack */); + final boolean hasAlpha = 4 == glpa.pfmt.comp.bytesPerPixel(); + System.err.println("GLPixelAttributes: "+glpa); final GLReadBufferUtil screenshot = new GLReadBufferUtil(true, false); final GLCapabilities caps = new GLCapabilities(glp); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPixelFormat00NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPixelFormat00NEWT.java new file mode 100644 index 000000000..5550cfcd2 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPixelFormat00NEWT.java @@ -0,0 +1,61 @@ +/** + * 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 com.jogamp.opengl.test.junit.jogl.util.texture; + +import java.io.IOException; +import java.net.MalformedURLException; + +import javax.media.nativewindow.util.PixelFormat; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.FixMethodOrder; +import org.junit.runners.MethodSorters; + +import com.jogamp.opengl.test.junit.util.UITestCase; + +/** + * Testing PixelFormat integrity + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class TestPixelFormat00NEWT extends UITestCase { + @Test + public void test00() throws InterruptedException, IOException, MalformedURLException { + final PixelFormat[] formats = PixelFormat.values(); + + for(int i=0; i<formats.length; i++) { + final PixelFormat pf = formats[i]; + System.err.printf("%02d: %s, %s%n", i, pf, pf.comp); + final PixelFormat pf2 = PixelFormat.valueOf(pf.comp); + Assert.assertEquals(pf, pf2); + } + } + public static void main(final String args[]) { + org.junit.runner.JUnitCore.main(TestPixelFormat00NEWT.class.getName()); + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPixelFormatUtil00NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPixelFormatUtil00NEWT.java index 1b549fa96..6193ad1a7 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPixelFormatUtil00NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPixelFormatUtil00NEWT.java @@ -36,12 +36,14 @@ import javax.media.nativewindow.util.Dimension; import javax.media.nativewindow.util.PixelFormat; import javax.media.nativewindow.util.PixelFormatUtil; import javax.media.nativewindow.util.PixelRectangle; +import javax.media.nativewindow.util.PixelFormat.CType; import org.junit.Assert; import org.junit.Test; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; +import com.jogamp.common.util.Bitstream; import com.jogamp.opengl.test.junit.util.UITestCase; /** @@ -50,142 +52,401 @@ import com.jogamp.opengl.test.junit.util.UITestCase; */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TestPixelFormatUtil00NEWT extends UITestCase { + static final byte undef_val = (byte)0xFF; + static final PixelFormat.Composition comp_val = PixelFormat.RGBA8888.comp; + static final float red___valF; + static final float green_valF; + static final float blue__valF; + static final float alpha_valF; + static final float lum___valF; + static { + // Using am equal stepping of 0x30 = 48 between each RGBA and undefined values, + // dividing 0xff equally by 5 excluding zero. + final byte red___val = (byte)0x30; + final byte green_val = (byte)0x60; + final byte blue__val = (byte)0x90; + final byte alpha_val = (byte)0xC0; + red___valF = comp_val.toFloat(red___val, 0, false); + green_valF = comp_val.toFloat(green_val, 1, false); + blue__valF = comp_val.toFloat(blue__val, 2, false); + alpha_valF = comp_val.toFloat(alpha_val, 3, false); + lum___valF = ( red___valF + green_valF + blue__valF ) / 3f; + } + + @Test + public void testConversion00() throws InterruptedException, IOException, MalformedURLException { + { + final PixelFormat fmt = PixelFormat.RGBA5551; + final PixelFormat.Composition comp = fmt.comp; + System.err.printf("%s, %s:%n", fmt, comp); + final int u16_alpha = comp.encode4CompI8((byte)comp.fromFloat(red___valF, 0, false), + (byte)comp.fromFloat(green_valF, 0, false), + (byte)comp.fromFloat(blue__valF, 0, false), + (byte)comp.fromFloat(alpha_valF, 0, false)); + final int u16_undef = comp.encode4CompI8((byte)comp.fromFloat(red___valF, 0, false), + (byte)comp.fromFloat(green_valF, 0, false), + (byte)comp.fromFloat(blue__valF, 0, false), + undef_val); + System.err.printf(" u16_alpha %s%n", Bitstream.toHexBinString(true, u16_alpha, comp.bitsPerPixel())); + System.err.printf(" u16_undef %s%n", Bitstream.toHexBinString(true, u16_undef, comp.bitsPerPixel())); + { + final byte c4NormI8_alpha = (byte)comp.fromFloat(alpha_valF, 0, false); + final byte c4NormI8_undef = undef_val; + final int compBitShift = 15; + final int compMask = 0x1; + final int v_alpha = ( c4NormI8_alpha & compMask ) << compBitShift ; + final int v_undef = ( c4NormI8_undef & compMask ) << compBitShift ; + System.err.printf(" xx_alpha %s%n", Bitstream.toHexBinString(true, v_alpha, comp.bitsPerPixel())); + System.err.printf(" xx_undef %s%n", Bitstream.toHexBinString(true, v_undef, comp.bitsPerPixel())); + } + } + { + final int r8 = 0x30; + final int g8 = 0x60; + final int b8 = 0x90; + final int a8 = 0xC0; + + final int l1 = 0x1; + final int r5 = 0x6; + final int g6 = 0xC; + final int b5 = 0x6; + + final PixelFormat rgba8888Fmt = PixelFormat.RGBA8888; + final PixelFormat.Composition rgba8888Comp = rgba8888Fmt.comp; + final PixelFormat rgb565Fmt = PixelFormat.RGB565; + final PixelFormat.Composition rgb565Comp = rgb565Fmt.comp; + final PixelFormat lumFmt = PixelFormat.LUMINANCE; + final PixelFormat.Composition lumComp = lumFmt.comp; + System.err.printf("%s, %s -> %s %s%n", rgb565Fmt, rgb565Comp, lumFmt, lumComp); + + { + final float r8f = rgba8888Comp.toFloat(r8, 0, false); + final int r8fi = rgba8888Comp.fromFloat(r8f, 0, false); + final float g8f = rgba8888Comp.toFloat(g8, 1, false); + final int g8fi = rgba8888Comp.fromFloat(g8f, 1, false); + final float b8f = rgba8888Comp.toFloat(b8, 2, false); + final int b8fi = rgba8888Comp.fromFloat(b8f, 2, false); + final float a8f = rgba8888Comp.toFloat(a8, 3, false); + final int a8fi = rgba8888Comp.fromFloat(a8f, 3, false); + + System.err.printf("res00.0.r %s -> %f -> %s%n", Bitstream.toHexBinString(true, r8, 8), r8f, Bitstream.toHexBinString(true, r8fi, 8)); + System.err.printf("res00.0.g %s -> %f -> %s%n", Bitstream.toHexBinString(true, g8, 8), g8f, Bitstream.toHexBinString(true, g8fi, 8)); + System.err.printf("res00.0.b %s -> %f -> %s%n", Bitstream.toHexBinString(true, b8, 8), b8f, Bitstream.toHexBinString(true, b8fi, 8)); + System.err.printf("res00.0.a %s -> %f -> %s%n", Bitstream.toHexBinString(true, a8, 8), a8f, Bitstream.toHexBinString(true, a8fi, 8)); + } + { + final float res00_0 = ( red___valF + green_valF + blue__valF ) / 3f; + final int res00 = rgba8888Comp.fromFloat(res00_0, 0, false); + System.err.printf("res01.0 ( %f + %f + %f ) / 3f = %f -> %s%n", + red___valF, green_valF, blue__valF, res00_0, Bitstream.toHexBinString(true, res00, 8)); + } + { + final float res00_0 = ( red___valF + green_valF + blue__valF ) / 3f; + final int res00 = lumComp.fromFloat(res00_0, 0, false); + System.err.printf("res02.1 ( %f + %f + %f ) / 3f = %f -> %s%n", + red___valF, green_valF, blue__valF, res00_0, Bitstream.toHexBinString(true, res00, 8)); + } + { + // sourceNorm static -> lum + final int rl1 = lumComp.fromFloat(red___valF, 0, false); + final int gl1 = lumComp.fromFloat(green_valF, 0, false); + final int bl1 = lumComp.fromFloat(blue__valF, 0, false); + final float rl2 = lumComp.toFloat(rl1, 0, false); + final float gl2 = lumComp.toFloat(gl1, 0, false); + final float bl2 = lumComp.toFloat(bl1, 0, false); + System.err.printf("res20.l1 ( %s + %s + %s )%n", + Bitstream.toHexBinString(true, rl1, 8), + Bitstream.toHexBinString(true, gl1, 8), + Bitstream.toHexBinString(true, bl1, 8)); + System.err.printf("res20.l2 ( %f + %f + %f )%n", rl2, gl2, bl2); + final float res02_l2_0 = ( rl2 + gl2 + bl2 ) / 3f; + final int res02_l2_x = lumComp.fromFloat(res02_l2_0, 0, false); + System.err.printf("res20.l3 ( %f + %f + %f ) / 3f = %f -> %s%n", + rl2, gl2, bl2, res02_l2_0, Bitstream.toHexBinString(true, res02_l2_x, 8)); + + // rescale lum -> rgb565 + final int r_1 = rgb565Comp.fromFloat(rl2, 0, false); + final int g_1 = rgb565Comp.fromFloat(gl2, 1, false); + final int b_1 = rgb565Comp.fromFloat(bl2, 2, false); + final float r_2 = rgb565Comp.toFloat(r_1, 0, false); + final float g_2 = rgb565Comp.toFloat(g_1, 1, false); + final float b_2 = rgb565Comp.toFloat(b_1, 2, false); + System.err.printf("res20._1 ( %s + %s + %s )%n", + Bitstream.toHexBinString(true, r_1, 8), + Bitstream.toHexBinString(true, g_1, 8), + Bitstream.toHexBinString(true, b_1, 8)); + System.err.printf("res20._2 ( %f + %f + %f )%n", r_2, g_2, b_2); + final float res02__3_0 = ( r_2 + g_2 + b_2 ) / 3f; + final int res02__3_x = lumComp.fromFloat(res02__3_0, 0, false); + System.err.printf("res20._3 ( %f + %f + %f ) / 3f = %f -> %s%n", + r_2, g_2, b_2, res02__3_0, Bitstream.toHexBinString(true, res02__3_x, 8)); + } + { + // sourceNorm static -> lum + // rescale lum -> rgb565 + final float rF = rgb565Comp.toFloat(rescaleComp(lumComp, 0, rgb565Comp, 0, red___valF), 0, false); + final float gF = rgb565Comp.toFloat(rescaleComp(lumComp, 0, rgb565Comp, 1, green_valF), 1, false); + final float bF = rgb565Comp.toFloat(rescaleComp(lumComp, 0, rgb565Comp, 2, blue__valF), 2, false); + final float res01_0 = ( rF + gF + bF ) / 3f; + final int res01 = lumComp.fromFloat(res01_0, 0, false); + System.err.printf("res30.xx ( %f + %f + %f ) / 3f = %f -> %s%n", + rF, gF, bF, res01_0, Bitstream.toHexBinString(true, res01, 8)); + } + { + final float rF = rgb565Comp.toFloat(r5, 0, false); + final float gF = rgb565Comp.toFloat(g6, 1, false); + final float bF = rgb565Comp.toFloat(b5, 2, false); + + final float lF = ( rF + gF + bF ) / 3f; + final int res00 = lumComp.fromFloat(lF, 0, false); + + System.err.printf("res40 ( %f + %f + %f ) / 3f = %s%n", + rF, gF, bF, Bitstream.toHexBinString(true, res00, 8)); + } + } + + } + @Test public void testConversion01_srcS000_BE_TL_destS000_TL() throws InterruptedException, IOException, MalformedURLException { - testPNG00Impl(0 /* srcMinStrideInBytes */, ByteOrder.BIG_ENDIAN, false /* srcIsGLOriented */, - 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); + testConversionImpl(0 /* srcMinStrideInBytes */, ByteOrder.BIG_ENDIAN, false /* srcIsGLOriented */, + 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); } @Test public void testConversion02_srcS000_LE_TL_destS000_TL() throws InterruptedException, IOException, MalformedURLException { - testPNG00Impl(0 /* srcMinStrideInBytes */, ByteOrder.LITTLE_ENDIAN, false /* srcIsGLOriented */, - 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); + testConversionImpl(0 /* srcMinStrideInBytes */, ByteOrder.LITTLE_ENDIAN, false /* srcIsGLOriented */, + 0 /* destMinStrideInBytes */, false /* destIsGLOriented */); } @Test public void testConversion03_srcS000_BE_TL_destS259_TL() throws InterruptedException, IOException, MalformedURLException { - testPNG00Impl(0 /* srcMinStrideInBytes */, ByteOrder.BIG_ENDIAN, false /* srcIsGLOriented */, - 259 /* destMinStrideInBytes */, false /* destIsGLOriented */); + testConversionImpl(0 /* srcMinStrideInBytes */, ByteOrder.BIG_ENDIAN, false /* srcIsGLOriented */, + 259 /* destMinStrideInBytes */, false /* destIsGLOriented */); } @Test public void testConversion04_srcS259_BE_TL_destS259_TL() throws InterruptedException, IOException, MalformedURLException { - testPNG00Impl(259 /* srcMinStrideInBytes */, ByteOrder.BIG_ENDIAN, false /* srcIsGLOriented */, - 259 /* destMinStrideInBytes */, false /* destIsGLOriented */); + testConversionImpl(259 /* srcMinStrideInBytes */, ByteOrder.BIG_ENDIAN, false /* srcIsGLOriented */, + 259 /* destMinStrideInBytes */, false /* destIsGLOriented */); } @Test public void testConversion05_srcS301_BE_TL_destS259_TL() throws InterruptedException, IOException, MalformedURLException { - testPNG00Impl(301 /* srcMinStrideInBytes */, ByteOrder.BIG_ENDIAN, false /* srcIsGLOriented */, - 259 /* destMinStrideInBytes */, false /* destIsGLOriented */); + testConversionImpl(301 /* srcMinStrideInBytes */, ByteOrder.BIG_ENDIAN, false /* srcIsGLOriented */, + 259 /* destMinStrideInBytes */, false /* destIsGLOriented */); } - static final byte red___val = (byte)0x01; - static final byte green_val = (byte)0x02; - static final byte blue__val = (byte)0x03; - static final byte alpha_val = (byte)0x04; - static final byte undef_val = (byte)0xff; - - static final void getComponents(final int srcComps, final PixelFormat fmt, final byte[] components) { + /** + * Note: Fixes bit-rounding errors, i.e. RGBA5551: A 0.6f -> 0x01 -> 1f ... -> RGBA8888: A 0xff + */ + static final float sourceNorm(final PixelFormat.Composition srcComp, final int sIdx, final float f) { + if( sIdx >= 0 && sIdx < srcComp.componenCount() ) { + return srcComp.toFloat(srcComp.fromFloat(f, sIdx, false), sIdx, false); + } else { + return 0f; + } + } + static final byte rescaleComp(final PixelFormat.Composition srcComp, final int sIdx, + final PixelFormat.Composition dstComp, final int dIdx, final float f) { + if( dIdx >= 0 && dIdx < dstComp.componenCount() ) { + return (byte)dstComp.fromFloat(sourceNorm(srcComp, sIdx, f), dIdx, false); + } else { + return (byte)0; + } + } + static final void getComponentData(final PixelFormat srcFmt, final PixelFormat dstFmt, final byte[] components) { + final PixelFormat.Composition srcComp = srcFmt.comp; + final PixelFormat.Composition dstComp = dstFmt.comp; final byte b1, b2, b3, b4; - if( 1 == srcComps ) { + int u16; + if( PixelFormat.LUMINANCE == srcFmt ) { // LUM -> Fmt Conversion - switch(fmt) { + switch(dstFmt) { case LUMINANCE: - b1 = red___val; + b1 = rescaleComp(srcComp, 0, dstComp, 0, lum___valF); b2 = undef_val; b3 = undef_val; b4 = undef_val; break; - case RGB888: - b1 = red___val; - b2 = red___val; - b3 = red___val; + case RGB565: + case BGR565: + u16 = dstComp.encode3CompI8( + rescaleComp(srcComp, 0, dstComp, 0, lum___valF), + rescaleComp(srcComp, 0, dstComp, 1, lum___valF), + rescaleComp(srcComp, 0, dstComp, 2, lum___valF)); + b1 = (byte)( u16 & 0xff ); + b2 = (byte)( ( u16 >>> 8 ) & 0xff ); + b3 = undef_val; b4 = undef_val; break; - case BGR888: - b1 = red___val; - b2 = red___val; - b3 = red___val; + case RGBA5551: + u16 = dstComp.encode4CompI8( + rescaleComp(srcComp, 0, dstComp, 0, lum___valF), + rescaleComp(srcComp, 0, dstComp, 1, lum___valF), + rescaleComp(srcComp, 0, dstComp, 2, lum___valF), + undef_val); + b1 = (byte)( u16 & 0xff ); + b2 = (byte)( ( u16 >>> 8 ) & 0xff ); + b3 = undef_val; b4 = undef_val; break; + case ABGR1555: + u16 = dstComp.encode4CompI8( + undef_val, + rescaleComp(srcComp, 0, dstComp, 0, lum___valF), + rescaleComp(srcComp, 0, dstComp, 1, lum___valF), + rescaleComp(srcComp, 0, dstComp, 2, lum___valF) ); + b1 = (byte)( u16 & 0xff ); + b2 = (byte)( ( u16 >>> 8 ) & 0xff ); + b3 = undef_val; + b4 = undef_val; + break; + case BGRx8888: + case RGBx8888: + case RGB888: + case BGR888: case RGBA8888: - b1 = red___val; - b2 = red___val; - b3 = red___val; + b1 = rescaleComp(srcComp, 0, dstComp, 0, lum___valF); + b2 = rescaleComp(srcComp, 0, dstComp, 1, lum___valF); + b3 = rescaleComp(srcComp, 0, dstComp, 2, lum___valF); b4 = undef_val; break; case ABGR8888: + case ARGB8888: b1 = undef_val; - b2 = red___val; - b3 = red___val; - b4 = red___val; + b2 = rescaleComp(srcComp, 0, dstComp, 1, lum___valF); + b3 = rescaleComp(srcComp, 0, dstComp, 2, lum___valF); + b4 = rescaleComp(srcComp, 0, dstComp, 3, lum___valF); break; case BGRA8888: - b1 = red___val; - b2 = red___val; - b3 = red___val; + b1 = rescaleComp(srcComp, 0, dstComp, 0, lum___valF); + b2 = rescaleComp(srcComp, 0, dstComp, 1, lum___valF); + b3 = rescaleComp(srcComp, 0, dstComp, 2, lum___valF); b4 = undef_val; break; - case ARGB8888: - b1 = undef_val; - b2 = red___val; - b3 = red___val; - b4 = red___val; - break; default: - throw new InternalError("Unhandled format "+fmt); + throw new InternalError("Unhandled format "+dstFmt); } } else { + final int srcIdxR = srcComp.find(CType.R); + final int srcIdxG = srcComp.find(CType.G); + final int srcIdxB = srcComp.find(CType.B); + final int srcIdxA = srcComp.find(CType.A); + final boolean srcHasAlpha = 0 <= srcIdxA; + final boolean srcHasRGB = 0 <= srcIdxR && 0 <= srcIdxG && 0 <= srcIdxB; // 1:1 values - switch(fmt) { + switch(dstFmt) { case LUMINANCE: - if( srcComps > 1 ) { - b1 = ( red___val + green_val+ blue__val ) / 3; + if( srcHasRGB ) { + final float rF = sourceNorm(srcComp, srcIdxR, red___valF); + final float gF = sourceNorm(srcComp, srcIdxG, green_valF); + final float bF = sourceNorm(srcComp, srcIdxB, blue__valF); + b1 = (byte)dstComp.fromFloat( ( rF + gF + bF ) / 3f, 0, false); b2 = undef_val; b3 = undef_val; b4 = undef_val; } else { - b1 = red___val; + b1 = rescaleComp(srcComp, 0, dstComp, 0, red___valF); b2 = undef_val; b3 = undef_val; b4 = undef_val; } break; + case RGB565: + u16 = dstComp.encode3CompI8( + rescaleComp(srcComp, srcIdxR, dstComp, 0, red___valF), + rescaleComp(srcComp, srcIdxG, dstComp, 1, green_valF), + rescaleComp(srcComp, srcIdxB, dstComp, 2, blue__valF)); + b1 = (byte)( u16 & 0xff ); + b2 = (byte)( ( u16 >>> 8 ) & 0xff ); + b3 = undef_val; + b4 = undef_val; + break; + case BGR565: + u16 = dstComp.encode3CompI8( + rescaleComp(srcComp, srcIdxB, dstComp, 0, blue__valF), + rescaleComp(srcComp, srcIdxG, dstComp, 1, green_valF), + rescaleComp(srcComp, srcIdxR, dstComp, 2, red___valF)); + b1 = (byte)( u16 & 0xff ); + b2 = (byte)( ( u16 >>> 8 ) & 0xff ); + b3 = undef_val; + b4 = undef_val; + break; + case RGBA5551: + u16 = dstComp.encode4CompI8( + rescaleComp(srcComp, srcIdxR, dstComp, 0, red___valF), + rescaleComp(srcComp, srcIdxG, dstComp, 1, green_valF), + rescaleComp(srcComp, srcIdxB, dstComp, 2, blue__valF), + srcHasAlpha ? rescaleComp(srcComp, srcIdxA, dstComp, 3, alpha_valF) : undef_val); + b1 = (byte)( u16 & 0xff ); + b2 = (byte)( ( u16 >>> 8 ) & 0xff ); + b3 = undef_val; + b4 = undef_val; + break; + case ABGR1555: + u16 = dstComp.encode4CompI8( + srcHasAlpha ? rescaleComp(srcComp, srcIdxA, dstComp, 0, alpha_valF) : undef_val, + rescaleComp(srcComp, srcIdxB, dstComp, 1, blue__valF), + rescaleComp(srcComp, srcIdxG, dstComp, 2, green_valF), + rescaleComp(srcComp, srcIdxR, dstComp, 3, red___valF) ); + b1 = (byte)( u16 & 0xff ); + b2 = (byte)( ( u16 >>> 8 ) & 0xff ); + b3 = undef_val; + b4 = undef_val; + break; + case RGBx8888: case RGB888: - b1 = red___val; - b2 = green_val; - b3 = blue__val; + b1 = rescaleComp(srcComp, srcIdxR, dstComp, 0, red___valF); + b2 = rescaleComp(srcComp, srcIdxG, dstComp, 1, green_valF); + b3 = rescaleComp(srcComp, srcIdxB, dstComp, 2, blue__valF); b4 = undef_val; break; + case BGRx8888: case BGR888: - b1 = blue__val; - b2 = green_val; - b3 = red___val; + b1 = rescaleComp(srcComp, srcIdxB, dstComp, 0, blue__valF); + b2 = rescaleComp(srcComp, srcIdxG, dstComp, 1, green_valF); + b3 = rescaleComp(srcComp, srcIdxR, dstComp, 2, red___valF); b4 = undef_val; break; case RGBA8888: - b1 = red___val; - b2 = green_val; - b3 = blue__val; - b4 = srcComps > 3 ? alpha_val : undef_val; + b1 = rescaleComp(srcComp, srcIdxR, dstComp, 0, red___valF); + b2 = rescaleComp(srcComp, srcIdxG, dstComp, 1, green_valF); + b3 = rescaleComp(srcComp, srcIdxB, dstComp, 2, blue__valF); + if( srcHasAlpha ) { + b4 = rescaleComp(srcComp, srcIdxA, dstComp, 3, alpha_valF); + } else { + b4 = undef_val; + } break; case ABGR8888: - b1 = srcComps > 3 ? alpha_val : undef_val; - b2 = blue__val; - b3 = green_val; - b4 = red___val; + if( srcHasAlpha ) { + b1 = rescaleComp(srcComp, srcIdxA, dstComp, 0, alpha_valF); + } else { + b1 = undef_val; + } + b2 = rescaleComp(srcComp, srcIdxB, dstComp, 1, blue__valF); + b3 = rescaleComp(srcComp, srcIdxG, dstComp, 2, green_valF); + b4 = rescaleComp(srcComp, srcIdxR, dstComp, 3, red___valF); break; case BGRA8888: - b1 = blue__val; - b2 = green_val; - b3 = red___val; - b4 = srcComps > 3 ? alpha_val : undef_val; + b1 = rescaleComp(srcComp, srcIdxB, dstComp, 0, blue__valF); + b2 = rescaleComp(srcComp, srcIdxG, dstComp, 1, green_valF); + b3 = rescaleComp(srcComp, srcIdxR, dstComp, 2, red___valF); + if( srcHasAlpha ) { + b4 = rescaleComp(srcComp, srcIdxA, dstComp, 3, alpha_valF); + } else { + b4 = undef_val; + } break; case ARGB8888: - b1 = srcComps > 3 ? alpha_val : undef_val; - b2 = red___val; - b3 = green_val; - b4 = blue__val; + if( srcHasAlpha ) { + b1 = rescaleComp(srcComp, srcIdxA, dstComp, 0, alpha_valF); + } else { + b1 = undef_val; + } + b2 = rescaleComp(srcComp, srcIdxR, dstComp, 1, red___valF); + b3 = rescaleComp(srcComp, srcIdxG, dstComp, 2, green_valF); + b4 = rescaleComp(srcComp, srcIdxB, dstComp, 3, blue__valF); break; default: - throw new InternalError("Unhandled format "+fmt); + throw new InternalError("Unhandled format "+dstFmt); } } components[0] = b1; @@ -193,85 +454,120 @@ public class TestPixelFormatUtil00NEWT extends UITestCase { components[2] = b3; components[3] = b4; } - private void testPNG00Impl(final int srcMinStrideInBytes, final ByteOrder srcByteOrder, final boolean srcIsGLOriented, + private void testConversionImpl(final int srcMinStrideInBytes, final ByteOrder srcByteOrder, final boolean srcIsGLOriented, final int destMinStrideInBytes, final boolean destIsGLOriented) throws InterruptedException, IOException, MalformedURLException { System.err.println("Test00: srcMinStrideInBytes "+srcMinStrideInBytes+", srcByteOrder "+srcByteOrder+", srcIsGLOriented "+srcIsGLOriented+ ", destMinStrideInBytes "+destMinStrideInBytes+", destIsGLOriented "+destIsGLOriented); - final PixelFormat[] formats = PixelFormat.values(); + // final PixelFormat[] srcFormats = { PixelFormat.LUMINANCE }; + // final PixelFormat[] dstFormats = { PixelFormat.RGBx8888 }; + // final PixelFormat[] dstFormats = { PixelFormat.RGB5551 }; + // final PixelFormat[] dstFormats = { PixelFormat.RGB888 }; + // final PixelFormat[] srcFormats = { PixelFormat.RGB888 }; + // final PixelFormat[] dstFormats = { PixelFormat.RGB565 }; + final PixelFormat[] srcFormats = PixelFormat.values(); + final PixelFormat[] dstFormats = PixelFormat.values(); final int width = 64, height = 64; - for(int i=0; i<formats.length; i++) { - final PixelFormat srcFmt = formats[i]; - final int srcBpp = srcFmt.bytesPerPixel(); + for(int i=0; i<srcFormats.length; i++) { + final PixelFormat srcFmt = srcFormats[i]; + final int srcBpp = srcFmt.comp.bytesPerPixel(); final int srcStrideBytes = Math.max(srcMinStrideInBytes, width*srcBpp); final ByteBuffer srcPixels = ByteBuffer.allocate(height*srcStrideBytes).order(srcByteOrder); - final byte[] srcComponents = new byte[4]; - getComponents(srcFmt.componentCount, srcFmt, srcComponents); + final byte[] srcData = new byte[4]; + getComponentData(srcFmt, srcFmt, srcData); for(int y=0; y<height; y++) { int o = y*srcStrideBytes; for(int x=0; x<width; x++) { switch(srcFmt) { case LUMINANCE: - srcPixels.put(o++, srcComponents[0]); + srcPixels.put(o++, srcData[0]); + break; + case BGR565: + case RGB565: + case ABGR1555: + case RGBA5551: + srcPixels.put(o++, srcData[0]); + srcPixels.put(o++, srcData[1]); break; case RGB888: case BGR888: - srcPixels.put(o++, srcComponents[0]); - srcPixels.put(o++, srcComponents[1]); - srcPixels.put(o++, srcComponents[2]); + srcPixels.put(o++, srcData[0]); + srcPixels.put(o++, srcData[1]); + srcPixels.put(o++, srcData[2]); break; + case RGBx8888: + case BGRx8888: case RGBA8888: case ABGR8888: case BGRA8888: case ARGB8888: - srcPixels.put(o++, srcComponents[0]); - srcPixels.put(o++, srcComponents[1]); - srcPixels.put(o++, srcComponents[2]); - srcPixels.put(o++, srcComponents[3]); + srcPixels.put(o++, srcData[0]); + srcPixels.put(o++, srcData[1]); + srcPixels.put(o++, srcData[2]); + srcPixels.put(o++, srcData[3]); break; default: throw new InternalError("Unhandled format "+srcFmt); } } } - final PixelRectangle imageSrc = new PixelRectangle.GenericPixelRect(srcFmt, new Dimension(width, height), srcStrideBytes, srcIsGLOriented, srcPixels); + final PixelRectangle imageSrc = new PixelRectangle.GenericPixelRect(srcFmt, new Dimension(width, height), + srcStrideBytes, srcIsGLOriented, srcPixels); + System.err.println("CONVERT["+i+"][*]: Image0 - Orig: "+imageSrc); - testComponents(imageSrc, 0, 0, srcComponents); - testComponents(imageSrc, width-1, height-1, srcComponents); + System.err.printf("Source %s, %s%n", srcFmt, srcFmt.comp); + System.err.printf("Source Data: %s%n", Bitstream.toHexBinString(true, srcData, 0, srcFmt.comp.bytesPerPixel())); + testComponents(imageSrc, 0, 0, srcData, 0); + testComponents(imageSrc, width-1, height-1, srcData, 0); - for(int j=0; j<formats.length; j++) { - final PixelFormat destFmt = formats[j]; - System.err.println("CONVERT["+i+"]["+j+"]: "+srcFmt+" -> "+destFmt); + final int maxDelta = 12; - final int destStrideBytes = Math.max(destMinStrideInBytes, width*destFmt.bytesPerPixel()); + for(int j=0; j<dstFormats.length; j++) { + final PixelFormat destFmt = dstFormats[j]; + System.err.println("CONVERT["+i+"]["+j+"]: "+srcFmt+" -> "+destFmt); + final int destStrideBytes = Math.max(destMinStrideInBytes, width*destFmt.comp.bytesPerPixel()); final byte[] destComponents = new byte[4]; - getComponents(srcFmt.componentCount, destFmt, destComponents); - final PixelRectangle imageConv1 = PixelFormatUtil.convert32(imageSrc, destFmt, destStrideBytes, destIsGLOriented, false /* nio */); - System.err.println("CONVERT["+i+"]["+j+"]: Conv1: "+imageConv1); - testComponents(imageConv1, 0, 0, destComponents); - testComponents(imageConv1, width-1, height-1, destComponents); + getComponentData(srcFmt, destFmt, destComponents); + System.err.printf("Source %s, %s%n", srcFmt, srcFmt.comp); + System.err.printf("Source Data: %s%n", Bitstream.toHexBinString(true, srcData, 0, srcFmt.comp.bytesPerPixel())); + System.err.printf("Dest %s, %s%n", destFmt, destFmt.comp); + System.err.printf("Dest Data: %s%n", Bitstream.toHexBinString(true, destComponents, 0, destFmt.comp.bytesPerPixel())); + final PixelRectangle imageConv1 = PixelFormatUtil.convert(imageSrc, destFmt, destStrideBytes, destIsGLOriented, false /* nio */); + System.err.println("CONVERT["+i+"]["+j+"]: Conv1: "+imageConv1+", maxDelta "+maxDelta); + System.err.printf("Conv1 Data: %s%n", Bitstream.toHexBinString(true, imageConv1.getPixels(), 0, destFmt.comp.bytesPerPixel())); + testComponents(imageConv1, 0, 0, destComponents, maxDelta); + testComponents(imageConv1, width-1, height-1, destComponents, maxDelta); if( PixelFormat.LUMINANCE != srcFmt && PixelFormat.LUMINANCE == destFmt ) { // Cannot convert: RGB* -> LUM -> RGB* System.err.println("CONVERT["+i+"]["+j+"]: Conv2: Dropped due to RGB* -> LUM"); - } else if( srcFmt.componentCount > destFmt.componentCount ) { + } else if( srcFmt.comp.componenCount() > destFmt.comp.componenCount() ) { // Cannot convert back if: src.componentCount > dest.componentCount System.err.println("CONVERT["+i+"]["+j+"]: Conv2: Dropped due to src.componentCount > dest.componentCount"); } else { - final PixelRectangle imageConv2 = PixelFormatUtil.convert32(imageConv1, imageSrc.getPixelformat(), imageSrc.getStride(), imageSrc.isGLOriented(), false /* nio */); - System.err.println("CONVERT["+i+"]["+j+"]: Conv2: "+imageConv2); - testComponents(imageConv2, 0, 0, srcComponents); - testComponents(imageConv2, width-1, height-1, srcComponents); + final PixelRectangle imageConv2 = PixelFormatUtil.convert(imageConv1, imageSrc.getPixelformat(), imageSrc.getStride(), imageSrc.isGLOriented(), false /* nio */); + System.err.println("CONVERT["+i+"]["+j+"]: Conv2: "+imageConv2+", maxDelta "+maxDelta); + System.err.printf("Conv2 Data: %s%n", Bitstream.toHexBinString(true, imageConv2.getPixels(), 0, srcFmt.comp.bytesPerPixel())); + final byte[] destReComponents = new byte[4]; + getComponentData(destFmt, srcFmt, destReComponents); + System.err.printf("DestRe Data: %s%n", Bitstream.toHexBinString(true, destReComponents, 0, srcFmt.comp.bytesPerPixel())); + testComponents(imageConv2, 0, 0, destReComponents, maxDelta); + testComponents(imageConv2, width-1, height-1, destReComponents, maxDelta); + /** + * Due to 'dead' components or value range re-scale, + * identity comparison on byte level is not correct. + * if( imageSrc.getStride() == imageConv1.getStride() ) { Assert.assertEquals(imageSrc.getPixels(), imageConv2.getPixels()); } + */ } } } } - private void dumpComponents(final PixelRectangle image, int x1, int y1, final int w, final int h) { + static void dumpComponents(final PixelRectangle image, int x1, int y1, final int w, final int h) { if( x1 + w >= image.getSize().getWidth() ) { x1 = image.getSize().getWidth() - w; } @@ -280,7 +576,7 @@ public class TestPixelFormatUtil00NEWT extends UITestCase { } System.err.print("PixelsBytes "+x1+"/"+y1+" "+w+"x"+h+":"); final ByteBuffer bb = image.getPixels(); - final int bpp = image.getPixelformat().bytesPerPixel(); + final int bpp = image.getPixelformat().comp.bytesPerPixel(); for(int y = y1; y< y1+h; y++) { System.err.printf("%n[%3d][%3d] ", x1, y); int o = y * image.getStride()+x1*bpp; @@ -311,51 +607,58 @@ public class TestPixelFormatUtil00NEWT extends UITestCase { } System.err.println(); } - private void testComponents(final PixelRectangle image, final int x, final int y, final byte[] components) { + + static final void assertEquals(final int a, final int b, final int maxDelta) { + final int d = Math.abs( a - b ); + Assert.assertTrue(String.format("Not equal: abs(%s - %s) = %d, > %d maxDelta", + Bitstream.toHexBinString(true, a, 8), Bitstream.toHexBinString(true, b, 8), d, maxDelta), + d <= maxDelta); + } + static final boolean equals(final int a, final int b, final int maxDelta) { + final int d = Math.abs( a - b ); + return d <= maxDelta; + } + + /** + * + * @param image actual data + * @param x position in actual data + * @param y position in actual data + * @param expData expected data + * @param maxDelta the maximum delta between expected {@code components} and actual {@code image} data + */ + static void testComponents(final PixelRectangle image, final int x, final int y, final byte[] expData, final int maxDelta) { dumpComponents(image, x, y, 3, 3); + final PixelFormat.Composition imgComp = image.getPixelformat().comp; final ByteBuffer bb = image.getPixels(); - final int bpp = image.getPixelformat().bytesPerPixel(); - int o = y * image.getStride()+x*bpp; - switch(bpp) { - case 1: { - final byte c1 = bb.get(o++); - final boolean equal = c1==components[0]; - System.err.printf("Test [%3d][%3d] exp 0x%02X == has 0x%02X : %b%n", - x, y, components[0], c1, equal ); - Assert.assertEquals(components[0], c1); - } - break; - case 2: { - final byte c1 = bb.get(o++), c2 = bb.get(o++); - final boolean equal = c1==components[0] && c2==components[1]; - System.err.printf("Test [%3d][%3d] exp 0x%02X%02X == has 0x%02X%02X : %b%n", - x, y, components[1], components[0], c2, c1, equal ); - Assert.assertEquals(components[0], c1); - Assert.assertEquals(components[1], c2); - } - break; - case 3: { - final byte c1 = bb.get(o++), c2 = bb.get(o++), c3 = bb.get(o++); - final boolean equal = c1==components[0] && c2==components[1] && c3==components[2]; - System.err.printf("Test [%3d][%3d] exp 0x%02X%02X%02X == has 0x%02X%02X%02X : %b%n", - x, y, components[2], components[1], components[0], c3, c2, c1, equal ); - Assert.assertEquals(components[0], c1); - Assert.assertEquals(components[1], c2); - Assert.assertEquals(components[2], c3); - } - break; - case 4: { - final byte c1 = bb.get(o++), c2 = bb.get(o++), c3 = bb.get(o++), c4 = bb.get(o++); - final boolean equal = c1==components[0] && c2==components[1] && c3==components[2] && c4==components[3]; - System.err.printf("Test [%3d][%3d] exp 0x%02X%02X%02X%02X == has 0x%02X%02X%02X%02X : %b%n", - x, y, components[3], components[2], components[1], components[0], c4, c3, c2, c1, equal ); - Assert.assertEquals(components[0], c1); - Assert.assertEquals(components[1], c2); - Assert.assertEquals(components[2], c3); - Assert.assertEquals(components[3], c4); - } - break; + final int bytesPerPixel = imgComp.bytesPerPixel(); + final int compCount = imgComp.componenCount(); + final int[] compBitCount = imgComp.componentBitCount(); + + final int srcPixOffset = y * image.getStride()+x*bytesPerPixel; + final int bbPos = bb.position(); + bb.position(bbPos+srcPixOffset); + + final long srcPix64 = PixelFormatUtil.getShiftedI64(imgComp.bytesPerPixel(), bb, true); + final int[] srcComponents = new int[compCount]; + final long expPix64 = PixelFormatUtil.getShiftedI64(imgComp.bytesPerPixel(), expData, 0); + final int[] expComponents = new int[compCount]; + boolean equal = true; + for(int i=0; i<compCount; i++) { + srcComponents[i] = imgComp.decodeSingleI64(srcPix64, i); + expComponents[i] = imgComp.decodeSingleI64(expPix64, i); + equal = equal && equals(srcComponents[i], expComponents[i], maxDelta); } + System.err.printf("Test [%3d][%3d] exp ", x, y); + for(int i=0; i<compCount; i++) { System.err.printf("%s ", Bitstream.toHexBinString(true, expComponents[i], compBitCount[i])); } + System.err.printf("==%nTest [%3d][%3d] has ", x, y); + for(int i=0; i<compCount; i++) { System.err.printf("%s ", Bitstream.toHexBinString(true, srcComponents[i], compBitCount[i])); } + System.err.printf(": equal %b%n%n", equal); + for(int i=0; i<compCount; i++) { + assertEquals(srcComponents[i], expComponents[i], maxDelta); + } + + bb.position(bbPos); } public static void main(final String args[]) { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPixelFormatUtil01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPixelFormatUtil01NEWT.java index eba920032..37c8c4494 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPixelFormatUtil01NEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/util/texture/TestPixelFormatUtil01NEWT.java @@ -40,6 +40,7 @@ import org.junit.Test; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; +import com.jogamp.common.util.Bitstream; import com.jogamp.common.util.IOUtil; import com.jogamp.opengl.test.junit.util.UITestCase; import com.jogamp.opengl.util.PNGPixelRect; @@ -86,15 +87,21 @@ public class TestPixelFormatUtil01NEWT extends UITestCase { final PNGPixelRect image1 = PNGPixelRect.read(urlConn.getInputStream(), srcFmt, false /* directBuffer */, destMinStrideInBytes, false /* isGLOriented */); System.err.println("PNGPixelRect - Orig: "+image1); + System.err.printf("Image Data: %s%n", Bitstream.toHexBinString(true, image1.getPixels(), 0, image1.getPixelformat().comp.bytesPerPixel())); + TestPixelFormatUtil00NEWT.dumpComponents(image1, 0, 0, 3, 3); final PixelFormat[] formats = new PixelFormat[] { PixelFormat.RGBA8888, PixelFormat.ABGR8888, PixelFormat.BGRA8888, PixelFormat.ARGB8888 }; for(int i=0; i<formats.length; i++) { final PixelFormat destFmt = formats[i]; System.err.println("CONVERT["+i+"]: "+srcFmt+" -> "+destFmt); - final PixelRectangle imageConv1 = PixelFormatUtil.convert32(image1, destFmt, destMinStrideInBytes, destIsGLOriented, false /* nio */); + final PixelRectangle imageConv1 = PixelFormatUtil.convert(image1, destFmt, destMinStrideInBytes, destIsGLOriented, false /* nio */); System.err.println("PNGPixelRect - Conv1: "+imageConv1); - final PixelRectangle imageConv2 = PixelFormatUtil.convert32(imageConv1, image1.getPixelformat(), image1.getStride(), image1.isGLOriented(), false /* nio */); + System.err.printf("Conv1 Data: %s%n", Bitstream.toHexBinString(true, imageConv1.getPixels(), 0, imageConv1.getPixelformat().comp.bytesPerPixel())); + TestPixelFormatUtil00NEWT.dumpComponents(imageConv1, 0, 0, 3, 3); + final PixelRectangle imageConv2 = PixelFormatUtil.convert(imageConv1, image1.getPixelformat(), image1.getStride(), image1.isGLOriented(), false /* nio */); System.err.println("PNGPixelRect - Conv2: "+imageConv2); + System.err.printf("Conv2 Data: %s%n", Bitstream.toHexBinString(true, imageConv2.getPixels(), 0, imageConv2.getPixelformat().comp.bytesPerPixel())); + TestPixelFormatUtil00NEWT.dumpComponents(imageConv2, 0, 0, 3, 3); Assert.assertEquals(image1.getPixels(), imageConv2.getPixels()); } } diff --git a/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java b/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java index 31d6b887d..c6ceab34e 100644 --- a/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java +++ b/src/test/com/jogamp/opengl/test/junit/util/AWTRobotUtil.java @@ -46,6 +46,7 @@ import javax.media.opengl.GLDrawable; import org.junit.Assert; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.util.awt.AWTEDTExecutor; import com.jogamp.newt.event.WindowEvent; @@ -229,7 +230,7 @@ public class AWTRobotUtil { System.err.println("*** AWTRobotUtil.toFrontAndRequestFocus() UI failure"); System.err.println("*** window: "+window); System.err.println("*** window.hasFocus(): "+window.hasFocus()); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return success; } @@ -442,7 +443,7 @@ public class AWTRobotUtil { } System.err.println("*** gain: "+gain); System.err.println("*** lost: "+lost); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } Assert.assertTrue("Did not gain focus", hasFocus); } |