diff options
Diffstat (limited to 'src/jogl/classes/com/jogamp')
20 files changed, 635 insertions, 281 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/FBObject.java b/src/jogl/classes/com/jogamp/opengl/FBObject.java index 03693a688..ceebe5f45 100644 --- a/src/jogl/classes/com/jogamp/opengl/FBObject.java +++ b/src/jogl/classes/com/jogamp/opengl/FBObject.java @@ -44,6 +44,7 @@ import javax.media.opengl.GLProfile; import jogamp.opengl.Debug; +import com.jogamp.common.ExceptionUtils; import com.jogamp.common.util.PropertyAccess; import com.jogamp.opengl.FBObject.Attachment.Type; @@ -698,10 +699,7 @@ public class FBObject { final int magFilter, final int minFilter, final int wrapS, final int wrapT) { final int dataFormat, dataType; final boolean alpha = hasAlpha(internalFormat); - if( gl.isGLES3() ) { - dataFormat = alpha ? GL.GL_RGBA : GL.GL_RGB; - dataType = GL.GL_UNSIGNED_BYTE; - } else if( gl.isGLES() ) { + if( gl.isGLES() ) { dataFormat = alpha ? GL.GL_RGBA : GL.GL_RGB; dataType = GL.GL_UNSIGNED_BYTE; } else { @@ -1071,7 +1069,7 @@ public class FBObject { vStatus = GL.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; // always incomplete w/o attachments! if(DEBUG) { System.err.println("FBObject.init() END: "+this); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } } @@ -1306,7 +1304,7 @@ public class FBObject { final int glerr = gl.glGetError(); if(DEBUG && GL.GL_NO_ERROR != glerr) { System.err.println("Pre-existing GL error: "+toHexString(glerr)); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } return glerr; } @@ -1520,7 +1518,7 @@ public class FBObject { final TextureAttachment texA = colbuf.getTextureAttachment(); if( samples > 0 ) { removeColorAttachment(attachmentPoint, texA); - if(initializedColorbuf) { + if( initializedColorbuf ) { texA.free(gl); } throw new GLException("Texture2D not supported w/ MSAA. If you have enabled MSAA with exisiting texture attachments, you may want to detach them via detachAllTexturebuffer(gl)."); @@ -1533,9 +1531,9 @@ public class FBObject { if(!ignoreStatus) { updateStatus(gl); - if(!isStatusValid()) { + if( !isStatusValid() ) { detachColorbuffer(gl, attachmentPoint, true); - throw new GLException("attachTexture2D "+texA+" at "+attachmentPoint+" failed "+getStatusString()+", "+this); + throw new GLException("attachTexture2D "+texA+" at "+attachmentPoint+" failed: "+getStatusString()+", "+this); } } } else { @@ -1548,9 +1546,9 @@ public class FBObject { if(!ignoreStatus) { updateStatus(gl); - if(!isStatusValid()) { + if( !isStatusValid() ) { detachColorbuffer(gl, attachmentPoint, true); - throw new GLException("attachColorbuffer "+colA+" at "+attachmentPoint+" failed "+getStatusString()+", "+this); + throw new GLException("attachColorbuffer "+colA+" at "+attachmentPoint+" failed: "+getStatusString()+", "+this); } } } @@ -1796,7 +1794,7 @@ public class FBObject { updateStatus(gl); if( !isStatusValid() ) { detachRenderbuffer(gl, atype, true); - throw new GLException("renderbuffer [attachmentType "+atype+", iformat "+toHexString(internalFormat)+"] failed: "+this.getStatusString()+": "+this.toString()); + throw new GLException("renderbuffer [attachmentType "+atype+", iformat "+toHexString(internalFormat)+"] failed: "+this.getStatusString()+", "+this.toString()); } } @@ -2197,7 +2195,7 @@ public class FBObject { } */ updateStatus(gl); if(!isStatusValid()) { - throw new GLException("detachAllImpl failed "+getStatusString()+", "+this); + throw new GLException("detachAllImpl failed: "+getStatusString()+", "+this); } } } finally { @@ -2306,7 +2304,7 @@ public class FBObject { public final boolean resetSamplingSink(final GL gl) throws GLException { if(DEBUG) { System.err.println("FBObject.resetSamplingSink.0"); - Thread.dumpStack(); + ExceptionUtils.dumpStack(System.err); } if( 0 == samples ) { diff --git a/src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java b/src/jogl/classes/com/jogamp/opengl/GLRendererQuirks.java index 7b5e6b8f1..335bffb80 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. @@ -395,8 +394,36 @@ public class GLRendererQuirks { */ public static final int NeedSharedObjectSync = 20; + /** + * 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 = 21; + /** Return the number of known quirks. */ - public static final int getCount() { return 21; } + public static final int getCount() { return 22; } private static final String[] _names = new String[] { "NoDoubleBufferedPBuffer", "NoDoubleBufferedBitmap", "NoSetSwapInterval", "NoOffscreenBitmap", "NoSetSwapIntervalPostRetarget", "GLSLBuggyDiscard", @@ -405,7 +432,7 @@ public class GLRendererQuirks { "NoFullFBOSupport", "GLSLNonCompliant", "GL4NeedsGL3Request", "GLSharedContextBuggy", "GLES3ViaEGLES2Config", "SingletonEGLDisplayOnly", "NoMultiSamplingBuffers", "BuggyColorRenderbuffer", "NoPBufferWithAccum", - "NeedSharedObjectSync" + "NeedSharedObjectSync", "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(); |