From 0a7bf77b8c0765f8a53dc72a8edab8e0496938ff Mon Sep 17 00:00:00 2001
From: Sven Gothel
+ * {@link GLPixelBufferProvider} produces a {@link GLPixelBuffer}.
+ *
+ * You may use {@link #defaultProvider}.
+ *
+ * Being called to gather the initial {@link GLPixelBuffer},
+ * or a new replacement {@link GLPixelBuffer} if {@link GLPixelBuffer#requiresNewBuffer(GL, int, int, int)}.
+ *
+ * The minimum required {@link Buffer#remaining() remaining} byte size equals to
+ * Returns an NIO {@link ByteBuffer}.
+ *
+ * By default the {@link Buffer} is a {@link ByteBuffer}, due to {@link DefProvider#allocate(GL, GLPixelAttributes, int, int, int, boolean, int)}.
+ * However, other {@link GLPixelBufferProvider} may utilize different {@link Buffer} types.
+ *
+ * It is assumed that
+ * The minimum required byte size equals to May be used directly to write the TextureData to file (screenshot).
- * By default the {@link Buffer} is a {@link ByteBuffer}, due to {@link DefPixelBufferProvider#allocate(int, int, int)}.
- * If the {@link PixelBufferProvider} has changed via {@link #setPixelBufferProvider(PixelBufferProvider)}.
- * the {@link Buffer} type maybe different.
- *
+ * Implementation uses an array backed {@link IntBuffer}.
+ *
+ * {@link AWTGLPixelBuffer} can be produced via {@link AWTGLPixelBufferProvider}'s
+ * {@link AWTGLPixelBufferProvider#allocate(GL, GLPixelAttributes, int, int, int, boolean, int) allocate(..)}.
+ *
+ * See {@link AWTGLPixelBuffer#requiresNewBuffer(GL, int, int, int)} for {@link #allowRowStride} details.
+ *
+ * If
+ * If
+ * Returns an array backed {@link IntBuffer} of size minByteSize
, if > 0,
+ * otherwise utilize {@link GLBuffers#sizeof(GL, int[], int, int, int, int, int, boolean)}
+ * to calculate it.
+ * dataFormat
, i.e. {@link GLBuffers#componentCount(int)} if > 0.
+ * @param dataFormat GL data format
+ * @param dataType GL data type
+ */
+ public GLPixelAttributes(int dataFormat, int dataType) {
+ this(0 < dataFormat ? GLBuffers.componentCount(dataFormat) : 0, dataFormat, dataType);
+ }
+ /**
+ * Using user specified source {@link #componentCount}.
+ * @param componentCount source component count
+ * @param dataFormat GL data format
+ * @param dataType GL data type
+ */
+ public GLPixelAttributes(int componentCount, int dataFormat, int dataType) {
+ this.componentCount = componentCount;
+ this.format = dataFormat;
+ this.type = dataType;
+ this.bytesPerPixel = ( 0 < dataFormat && 0 < dataType ) ? GLBuffers.bytesPerPixel(dataFormat, dataType) : 0;
+ }
+ public String toString() {
+ return "PixelAttributes[comp "+componentCount+", fmt 0x"+Integer.toHexString(format)+", type 0x"+Integer.toHexString(type)+", bytesPerPixel "+bytesPerPixel+"]";
+ }
+ }
+
+ /** The {@link GLPixelAttributes}. */
+ public final GLPixelAttributes pixelAttributes;
+ /** Width in pixels. */
+ public final int width;
+ /** Height in pixels. */
+ public final int height;
+ /** Depth in pixels. */
+ public final int depth;
+ /** Data packing direction. If true
for read mode GPU -> CPU, false
for write mode CPU -> GPU. */
+ 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 byteSize
{@link Buffer#remaining()} bytes.
+ * pixelAttributes
, depth
and pack
stays the same!
+ * minByteSize
, if > 0,
+ * otherwise utilize {@link GLBuffers#sizeof(GL, int[], int, int, int, int, int, boolean) GLBuffers.sizeof(..)}
+ * to calculate it.
+ * true
, allow row-stride, otherwise not. See {@link #requiresNewBuffer(GL, int, int, int)}.
+ */
+ public AWTGLPixelBuffer(GLPixelAttributes pixelAttributes, int width, int height, int depth, boolean pack, BufferedImage image,
+ Buffer buffer, boolean allowRowStride) {
+ super(pixelAttributes, width, height, depth, pack, buffer);
+ this.allowRowStride = allowRowStride;
+ this.image = image;
+ }
+
+ /**
+ * {@inheritDoc}
+ * {@link #allowRowStride} = false
,
+ * method returns true
if the new size ≠ current size.
+ * {@link #allowRowStride} = true
, see {@link AWTGLPixelBufferProvider#AWTGLPixelBufferProvider(boolean)},
+ * method returns true
only if the new size > current size. Assuming user utilizes the row-stride
+ * when dealing w/ the data, i.e. {@link GL2GL3#GL_PACK_ROW_LENGTH}.
+ * true
, allow row-stride, otherwise not. See {@link AWTGLPixelBuffer#requiresNewBuffer(GL, int, int, int)}.
+ */
+ public AWTGLPixelBufferProvider(boolean allowRowStride) {
+ this.allowRowStride = allowRowStride;
+ }
+ @Override
+ public GLPixelAttributes getAttributes(GL gl, int componentCount) {
+ return awtPixelAttributesIntRGB;
+ }
+
+ /**
+ * {@inheritDoc}
+ * width*height*{@link Buffers#SIZEOF_INT SIZEOF_INT}.
+ *
+ * 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}
+ * 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 allowRowStride
should be enabled, if possible.
+ *
true
, allow row-stride, otherwise not. See {@link AWTGLPixelBuffer#requiresNewBuffer(GL, int, int, int)}.
+ */
+ public SingleAWTGLPixelBufferProvider(boolean allowRowStride) {
+ super(allowRowStride);
+ }
+
+ /**
+ * {@inheritDoc}
+ * + * Returns an array backed {@link IntBuffer} of size
width*height*{@link Buffers#SIZEOF_INT SIZEOF_INT}. + * + */ + @Override + public AWTGLPixelBuffer allocate(GL gl, GLPixelAttributes pixelAttributes, int width, int height, int depth, boolean pack, int minByteSize) { + if( null == single || single.requiresNewBuffer(gl, width, height, minByteSize) ) { + single = allocateImpl(pixelAttributes, width, height, depth, pack, minByteSize); + } + return single; + } + + private AWTGLPixelBuffer allocateImpl(GLPixelAttributes pixelAttributes, int width, int height, int depth, boolean pack, int minByteSize) { + final BufferedImage image = new BufferedImage(width, height, 4 == pixelAttributes.componentCount ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB); + 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); + } + + /** + * Initializes the single {@link AWTGLPixelBuffer} w/ a given size, if not yet {@link #allocate(GL, GLPixelAttributes, int, int, int, boolean, int) allocated}. + * @return the newly initialized single {@link AWTGLPixelBuffer}, or null if already allocated. + */ + public AWTGLPixelBuffer initSingleton(int width, int height, int depth, boolean pack) { + if( null != single ) { + return null; + } + single = allocateImpl(AWTGLPixelBuffer.awtPixelAttributesIntRGB, width, height, depth, pack, 0); + return single; + } + } +} \ No newline at end of file diff --git a/src/jogl/classes/com/jogamp/opengl/util/awt/AWTGLReadBufferUtil.java b/src/jogl/classes/com/jogamp/opengl/util/awt/AWTGLReadBufferUtil.java index f26fec0d5..0edd53ca1 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/awt/AWTGLReadBufferUtil.java +++ b/src/jogl/classes/com/jogamp/opengl/util/awt/AWTGLReadBufferUtil.java @@ -28,14 +28,11 @@ package com.jogamp.opengl.util.awt; import java.awt.image.BufferedImage; -import java.nio.Buffer; -import java.nio.IntBuffer; import javax.media.opengl.GL; -import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLProfile; import com.jogamp.opengl.util.GLReadBufferUtil; -import com.jogamp.opengl.util.texture.awt.AWTTextureData.AWTPixelBufferProviderInt; /** * {@link GLReadBufferUtil} specialization allowing to @@ -48,25 +45,15 @@ public class AWTGLReadBufferUtil extends GLReadBufferUtil { * * @param alpha */ - public AWTGLReadBufferUtil(boolean alpha) { - super(new AWTPixelBufferProviderInt(), alpha, false); + public AWTGLReadBufferUtil(GLProfile glp, boolean alpha) { + super(new AWTGLPixelBuffer.AWTGLPixelBufferProvider( glp.isGL2GL3() /* allowRowStride */ ), alpha, false); } - /** - * Returns the raw pixel Buffer, filled by {@link #readPixels(GLAutoDrawable, boolean)}. - *- * Due to using {@link AWTPixelBufferProviderInt#allocate(int, int, int)}, - * returns an {@link IntBuffer} instance. - *
- */ - @Override - public Buffer getPixelBuffer() { return readPixelBuffer; } - - public BufferedImage getImage() { return ((AWTPixelBufferProviderInt)pixelBufferProvider).getImage(); } + public AWTGLPixelBuffer getAWTGLPixelBuffer() { return (AWTGLPixelBuffer)this.getPixelBuffer(); } public BufferedImage readPixelsToBufferedImage(GL gl, boolean awtOrientation) { if( readPixels(gl, awtOrientation) ) { - final BufferedImage image = getImage(); + final BufferedImage image = getAWTGLPixelBuffer().image; if( getTextureData().getMustFlipVertically() ) { ImageUtil.flipImageVertically(image); } @@ -78,7 +65,7 @@ public class AWTGLReadBufferUtil extends GLReadBufferUtil { final int[] ioWidth = new int[] { inWidth }; final int[] ioHeight= new int[] { inHeight }; if( readPixels(gl, inX, inY, ioWidth, ioHeight, awtOrientation) ) { - final BufferedImage image = getImage(); + final BufferedImage image = getAWTGLPixelBuffer().image; if( getTextureData().getMustFlipVertically() ) { ImageUtil.flipImageVertically(image); } diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureData.java b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureData.java index 2f0c86255..dec1b43cf 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureData.java +++ b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureData.java @@ -38,14 +38,11 @@ package com.jogamp.opengl.util.texture; import java.nio.Buffer; -import java.nio.ByteBuffer; -import javax.media.opengl.GL; -import javax.media.opengl.GLContext; import javax.media.opengl.GLProfile; -import com.jogamp.common.nio.Buffers; import com.jogamp.opengl.util.GLBuffers; +import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes; /** * Represents the data for an OpenGL texture. This is separated from @@ -62,97 +59,10 @@ public class TextureData { /** ColorSpace of pixel data. */ public static enum ColorSpace { RGB, YCbCr, YCCK, CMYK }; - /** Pixel data attributes. */ - public static class PixelAttributes { - /** Undefinded instance of {@link PixelAttributes}, having format:=0 and type:= 0. */ - public static final PixelAttributes UNDEF = new PixelAttributes(0, 0); - - /** The OpenGL pixel data format */ - public final int format; - /** The OpenGL pixel data type */ - public final int type; - public PixelAttributes(int dataFormat, int dataType) { - this.format = dataFormat; - this.type = dataType; - } - public String toString() { - return "PixelAttributes[fFmt 0x"+Integer.toHexString(format)+", type 0x"+Integer.toHexString(type)+"]"; - } - } - /** Allows user to interface with another toolkit to define {@link PixelAttributes} and memory buffer to produce {@link TextureData}. */ - public static interface PixelBufferProvider { - /** Called first to determine {@link PixelAttributes}. */ - PixelAttributes getAttributes(GL gl, int componentCount); - - /** - * Returns true, if implementation requires a new buffer based on the new size - * and previous aquired {@link #getAttributes(GL, int) attributes} due to pixel alignment, otherwise false. - * @see #allocate(int, int, int) - */ - boolean requiresNewBuffer(int width, int height); - - /** - * Called after {@link #getAttributes(GL, int)} to retrieve the NIO or array backed pixel {@link Buffer}. - *- * Being called to gather the initial {@link Buffer}, if the existing {@link Buffer} size is not sufficient, - * or if {@link #requiresNewBuffer(int, int)} returns false. - *
- *- * Number of components was passed via {@link #getAttributes(GL, int)}. - *
- *- * The returned buffer must have at least
- */ - Buffer allocate(int width, int height, int minByteSize); - - /** Dispose resources. */ - void dispose(); - } - /** - * Default {@link PixelBufferProvider} utilizing best match for {@link PixelAttributes} - * and {@link #allocate(int, int, int) allocating} a {@link ByteBuffer}. - */ - public static class DefPixelBufferProvider implements PixelBufferProvider { - @Override - public PixelAttributes getAttributes(GL gl, int componentCount) { - final GLContext ctx = gl.getContext(); - final int dFormat, dType; - - if(gl.isGL2GL3() && 3 == componentCount) { - dFormat = GL.GL_RGB; - dType = GL.GL_UNSIGNED_BYTE; - } else { - dFormat = ctx.getDefaultPixelDataFormat(); - dType = ctx.getDefaultPixelDataType(); - } - return new TextureData.PixelAttributes(dFormat, dType); - } - @Override - public boolean requiresNewBuffer(int width, int height) { - return false; - } - /** - * {@inheritDoc} - *minByteSize
{@link Buffer#remaining() remaining}. - *- * Returns an NIO {@link ByteBuffer} of
- */ - @Override - public final Buffer allocate(int width, int height, int minByteSize) { - return Buffers.newDirectByteBuffer(minByteSize); - } - - @Override - public void dispose() { - // nop - } - } - protected int width; protected int height; private int border; - protected PixelAttributes pixelAttributes; + protected GLPixelAttributes pixelAttributes; protected int internalFormat; // perhaps inferred from pixelFormat? protected boolean mipmap; // indicates whether mipmaps should be generated // (ignored if mipmaps are supplied from the file) @@ -225,7 +135,7 @@ public class TextureData { boolean mustFlipVertically, Buffer buffer, Flusher flusher) throws IllegalArgumentException { - this(glp, internalFormat, width, height, border, new PixelAttributes(pixelFormat, pixelType), + this(glp, internalFormat, width, height, border, new GLPixelAttributes(pixelFormat, pixelType), mipmap, dataIsCompressed, mustFlipVertically, buffer, flusher); } @@ -273,7 +183,7 @@ public class TextureData { int width, int height, int border, - PixelAttributes pixelAttributes, + GLPixelAttributes pixelAttributes, boolean mipmap, boolean dataIsCompressed, boolean mustFlipVertically, @@ -348,7 +258,7 @@ public class TextureData { boolean mustFlipVertically, Buffer[] mipmapData, Flusher flusher) throws IllegalArgumentException { - this(glp, internalFormat, width, height, border, new PixelAttributes(pixelFormat, pixelType), + this(glp, internalFormat, width, height, border, new GLPixelAttributes(pixelFormat, pixelType), dataIsCompressed, mustFlipVertically, mipmapData, flusher); } @@ -395,7 +305,7 @@ public class TextureData { int width, int height, int border, - PixelAttributes pixelAttributes, + GLPixelAttributes pixelAttributes, boolean dataIsCompressed, boolean mustFlipVertically, Buffer[] mipmapData, @@ -429,7 +339,7 @@ public class TextureData { public void setColorSpace(ColorSpace cs) { pixelCS = cs; } /** Used only by subclasses */ - protected TextureData(GLProfile glp) { this.glProfile = glp; this.pixelAttributes = PixelAttributes.UNDEF; } + protected TextureData(GLProfile glp) { this.glProfile = glp; this.pixelAttributes = GLPixelAttributes.UNDEF; } /** Returns the width in pixels of the texture data. */ public int getWidth() { return width; } @@ -439,8 +349,8 @@ public class TextureData { public int getBorder() { return border; } - /** Returns the intended OpenGL {@link PixelAttributes} of the texture data, i.e. format and type. */ - public PixelAttributes getPixelAttributes() { + /** Returns the intended OpenGL {@link GLPixelAttributes} of the texture data, i.e. format and type. */ + public GLPixelAttributes getPixelAttributes() { return pixelAttributes; } /** Returns the intended OpenGL pixel format of the texture data. */ @@ -495,27 +405,27 @@ public class TextureData { /** Sets the border in pixels of the texture data. */ public void setBorder(int border) { this.border = border; } /** Sets the intended OpenGL pixel format of the texture data. */ - public void setPixelAttributes(PixelAttributes pixelAttributes) { this.pixelAttributes = pixelAttributes; } + public void setPixelAttributes(GLPixelAttributes pixelAttributes) { this.pixelAttributes = pixelAttributes; } /** - * Sets the intended OpenGL pixel format component of {@link PixelAttributes} of the texture data. + * Sets the intended OpenGL pixel format component of {@link GLPixelAttributes} of the texture data. *minByteSize
. - *- * Use {@link #setPixelAttributes(PixelAttributes)}, if setting format and type. + * Use {@link #setPixelAttributes(GLPixelAttributes)}, if setting format and type. *
*/ public void setPixelFormat(int pixelFormat) { if( pixelAttributes.format != pixelFormat ) { - pixelAttributes = new PixelAttributes(pixelFormat, pixelAttributes.type); + pixelAttributes = new GLPixelAttributes(pixelFormat, pixelAttributes.type); } } /** - * Sets the intended OpenGL pixel type component of {@link PixelAttributes} of the texture data. + * Sets the intended OpenGL pixel type component of {@link GLPixelAttributes} of the texture data. *- * Use {@link #setPixelAttributes(PixelAttributes)}, if setting format and type. + * Use {@link #setPixelAttributes(GLPixelAttributes)}, if setting format and type. *
*/ public void setPixelType(int pixelType) { if( pixelAttributes.type != pixelType) { - pixelAttributes = new PixelAttributes(pixelAttributes.format, pixelType); + pixelAttributes = new GLPixelAttributes(pixelAttributes.format, pixelType); } } /** Sets the intended OpenGL internal format of the texture data. */ diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/awt/AWTTextureData.java b/src/jogl/classes/com/jogamp/opengl/util/texture/awt/AWTTextureData.java index 7a0f00edf..d7e825c1d 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/texture/awt/AWTTextureData.java +++ b/src/jogl/classes/com/jogamp/opengl/util/texture/awt/AWTTextureData.java @@ -66,62 +66,10 @@ import javax.media.opengl.GL2GL3; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; -import com.jogamp.common.nio.Buffers; +import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes; import com.jogamp.opengl.util.texture.TextureData; -import com.jogamp.opengl.util.texture.TextureData.PixelBufferProvider; public class AWTTextureData extends TextureData { - public static final PixelAttributes awtPixelAttributesIntRGB = new PixelAttributes(GL.GL_BGRA, GL.GL_UNSIGNED_BYTE); - - /** - * AWT {@link PixelBufferProvider} backed by a {@link BufferedImage} of type - * {@link BufferedImage#TYPE_INT_ARGB} or {@link BufferedImage#TYPE_INT_RGB} - * and {@link #allocate(int, int, int) allocating} am array backed {@link IntBuffer}. - */ - public static final class AWTPixelBufferProviderInt implements PixelBufferProvider { - private BufferedImage image = null; - private int componentCount = 0; - - @Override - public PixelAttributes getAttributes(GL gl, int componentCount) { - this.componentCount = componentCount; - return awtPixelAttributesIntRGB; - } - @Override - public boolean requiresNewBuffer(int width, int height) { - return null == image || image.getWidth() != width || image.getHeight() != height; - } - /** - * {@inheritDoc} - *- * Returns an array backed {@link IntBuffer} of size
width*height*{@link Buffers#SIZEOF_INT SIZEOF_INT}. - * - */ - @Override - public Buffer allocate(int width, int height, int minByteSize) { - image = new BufferedImage(width, height, 4 == componentCount ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB); - final int[] readBackIntBuffer = ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); - return IntBuffer.wrap( readBackIntBuffer ); - } - - @Override - public void dispose() { - if(null != image) { - image.flush(); - image = null; - } - } - - /** Returns the number source components being used as indicated at {@link #allocate(int, int, int)}. */ - public int getComponentCount() { return componentCount; } - - /** Returns the underlying {@link BufferedImage} as allocated via {@link #allocate(int, int, int)}. */ - public BufferedImage getImage() { return image; } - - /** Returns true if an underlying {@link BufferedImage} has been allocated via {@link #allocate(int, int, int)}. */ - public boolean hasImage() { return null != image; } - } - // Mechanism for lazily converting input BufferedImages with custom // ColorModels to standard ones for uploading to OpenGL, as well as // backing off from the optimizations of hoping that either @@ -198,7 +146,7 @@ public class AWTTextureData extends TextureData { } @Override - public PixelAttributes getPixelAttributes() { + public GLPixelAttributes getPixelAttributes() { validatePixelAttributes(); return super.getPixelAttributes(); } @@ -229,7 +177,7 @@ public class AWTTextureData extends TextureData { } private void createFromImage(GLProfile glp, BufferedImage image) { - pixelAttributes = PixelAttributes.UNDEF; // Determine from image + pixelAttributes = GLPixelAttributes.UNDEF; // Determine from image mustFlipVertically = true; width = image.getWidth(); @@ -259,21 +207,21 @@ public class AWTTextureData extends TextureData { if (glp.isGL2GL3()) { switch (image.getType()) { case BufferedImage.TYPE_INT_RGB: - pixelAttributes = new PixelAttributes(GL.GL_BGRA, GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV); + pixelAttributes = new GLPixelAttributes(GL.GL_BGRA, GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV); rowLength = scanlineStride; alignment = 4; expectingGL12 = true; setupLazyCustomConversion(image); break; case BufferedImage.TYPE_INT_ARGB_PRE: - pixelAttributes = new PixelAttributes(GL.GL_BGRA, GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV); + pixelAttributes = new GLPixelAttributes(GL.GL_BGRA, GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV); rowLength = scanlineStride; alignment = 4; expectingGL12 = true; setupLazyCustomConversion(image); break; case BufferedImage.TYPE_INT_BGR: - pixelAttributes = new PixelAttributes(GL.GL_RGBA, GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV); + pixelAttributes = new GLPixelAttributes(GL.GL_RGBA, GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV); rowLength = scanlineStride; alignment = 4; expectingGL12 = true; @@ -284,7 +232,7 @@ public class AWTTextureData extends TextureData { // we can pass the image data directly to OpenGL only if // we have an integral number of pixels in each scanline if ((scanlineStride % 3) == 0) { - pixelAttributes = new PixelAttributes(GL2GL3.GL_BGR, GL.GL_UNSIGNED_BYTE); + pixelAttributes = new GLPixelAttributes(GL2GL3.GL_BGR, GL.GL_UNSIGNED_BYTE); rowLength = scanlineStride / 3; alignment = 1; } else { @@ -304,7 +252,7 @@ public class AWTTextureData extends TextureData { // the necessary byte swapping (FIXME: needs more // investigation) if ((scanlineStride % 4) == 0 && glp.isGL2() && false) { - pixelAttributes = new PixelAttributes(GL2.GL_ABGR_EXT, GL.GL_UNSIGNED_BYTE); + pixelAttributes = new GLPixelAttributes(GL2.GL_ABGR_EXT, GL.GL_UNSIGNED_BYTE); rowLength = scanlineStride / 4; alignment = 4; @@ -320,26 +268,26 @@ public class AWTTextureData extends TextureData { } } case BufferedImage.TYPE_USHORT_565_RGB: - pixelAttributes = new PixelAttributes(GL.GL_RGB, GL.GL_UNSIGNED_SHORT_5_6_5); + pixelAttributes = new GLPixelAttributes(GL.GL_RGB, GL.GL_UNSIGNED_SHORT_5_6_5); rowLength = scanlineStride; alignment = 2; expectingGL12 = true; setupLazyCustomConversion(image); break; case BufferedImage.TYPE_USHORT_555_RGB: - pixelAttributes = new PixelAttributes(GL.GL_BGRA, GL2GL3.GL_UNSIGNED_SHORT_1_5_5_5_REV); + pixelAttributes = new GLPixelAttributes(GL.GL_BGRA, GL2GL3.GL_UNSIGNED_SHORT_1_5_5_5_REV); rowLength = scanlineStride; alignment = 2; expectingGL12 = true; setupLazyCustomConversion(image); break; case BufferedImage.TYPE_BYTE_GRAY: - pixelAttributes = new PixelAttributes(GL.GL_LUMINANCE, GL.GL_UNSIGNED_BYTE); + pixelAttributes = new GLPixelAttributes(GL.GL_LUMINANCE, GL.GL_UNSIGNED_BYTE); rowLength = scanlineStride; alignment = 1; break; case BufferedImage.TYPE_USHORT_GRAY: - pixelAttributes = new PixelAttributes(GL.GL_LUMINANCE, GL.GL_UNSIGNED_SHORT); + pixelAttributes = new GLPixelAttributes(GL.GL_LUMINANCE, GL.GL_UNSIGNED_SHORT); rowLength = scanlineStride; alignment = 2; break; @@ -354,11 +302,11 @@ public class AWTTextureData extends TextureData { default: java.awt.image.ColorModel cm = image.getColorModel(); if (cm.equals(rgbColorModel)) { - pixelAttributes = new PixelAttributes(GL.GL_RGB, GL.GL_UNSIGNED_BYTE); + pixelAttributes = new GLPixelAttributes(GL.GL_RGB, GL.GL_UNSIGNED_BYTE); rowLength = scanlineStride / 3; alignment = 1; } else if (cm.equals(rgbaColorModel)) { - pixelAttributes = new PixelAttributes(GL.GL_RGBA, GL.GL_UNSIGNED_BYTE); + pixelAttributes = new GLPixelAttributes(GL.GL_RGBA, GL.GL_UNSIGNED_BYTE); rowLength = scanlineStride / 4; // FIXME: correct? alignment = 4; } else { @@ -370,7 +318,7 @@ public class AWTTextureData extends TextureData { } else { switch (image.getType()) { case BufferedImage.TYPE_INT_RGB: - pixelAttributes = new PixelAttributes(GL.GL_RGB, GL.GL_UNSIGNED_BYTE); + pixelAttributes = new GLPixelAttributes(GL.GL_RGB, GL.GL_UNSIGNED_BYTE); rowLength = scanlineStride; alignment = 3; expectingGL12 = true; @@ -385,21 +333,21 @@ public class AWTTextureData extends TextureData { case BufferedImage.TYPE_4BYTE_ABGR_PRE: throw new GLException("INT_BGR n.a."); case BufferedImage.TYPE_USHORT_565_RGB: - pixelAttributes = new PixelAttributes(GL.GL_RGB, GL.GL_UNSIGNED_SHORT_5_6_5); + pixelAttributes = new GLPixelAttributes(GL.GL_RGB, GL.GL_UNSIGNED_SHORT_5_6_5); rowLength = scanlineStride; alignment = 2; expectingGL12 = true; setupLazyCustomConversion(image); break; case BufferedImage.TYPE_USHORT_555_RGB: - pixelAttributes = new PixelAttributes(GL.GL_RGBA, GL.GL_UNSIGNED_SHORT_5_5_5_1); + pixelAttributes = new GLPixelAttributes(GL.GL_RGBA, GL.GL_UNSIGNED_SHORT_5_5_5_1); rowLength = scanlineStride; alignment = 2; expectingGL12 = true; setupLazyCustomConversion(image); break; case BufferedImage.TYPE_BYTE_GRAY: - pixelAttributes = new PixelAttributes(GL.GL_LUMINANCE, GL.GL_UNSIGNED_BYTE); + pixelAttributes = new GLPixelAttributes(GL.GL_LUMINANCE, GL.GL_UNSIGNED_BYTE); rowLength = scanlineStride; alignment = 1; break; @@ -416,11 +364,11 @@ public class AWTTextureData extends TextureData { default: java.awt.image.ColorModel cm = image.getColorModel(); if (cm.equals(rgbColorModel)) { - pixelAttributes = new PixelAttributes(GL.GL_RGB, GL.GL_UNSIGNED_BYTE); + pixelAttributes = new GLPixelAttributes(GL.GL_RGB, GL.GL_UNSIGNED_BYTE); rowLength = scanlineStride / 3; alignment = 1; } else if (cm.equals(rgbaColorModel)) { - pixelAttributes = new PixelAttributes(GL.GL_RGBA, GL.GL_UNSIGNED_BYTE); + pixelAttributes = new GLPixelAttributes(GL.GL_RGBA, GL.GL_UNSIGNED_BYTE); rowLength = scanlineStride / 4; // FIXME: correct? alignment = 4; } else { @@ -465,7 +413,7 @@ public class AWTTextureData extends TextureData { } else { throw new RuntimeException("Unexpected DataBuffer type?"); } - pixelAttributes = new PixelAttributes(pixelFormat, pixelType); + pixelAttributes = new GLPixelAttributes(pixelFormat, pixelType); } private void createFromCustom(BufferedImage image) { @@ -524,7 +472,7 @@ public class AWTTextureData extends TextureData { // and knowing we're in the process of doing the fallback code // path, re-infer a vanilla pixel format and type compatible with // OpenGL 1.1 - pixelAttributes = PixelAttributes.UNDEF; + pixelAttributes = GLPixelAttributes.UNDEF; setupLazyCustomConversion(imageForLazyCustomConversion); } diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java index 65bcab100..3f3e88977 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -86,10 +86,11 @@ import jogamp.opengl.awt.Java2D; import jogamp.opengl.util.glsl.GLSLTextureRaster; import com.jogamp.nativewindow.awt.AWTWindowClosingProtocol; import com.jogamp.opengl.FBObject; -import com.jogamp.opengl.util.GLBuffers; +import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes; import com.jogamp.opengl.util.GLPixelStorageModes; -import com.jogamp.opengl.util.texture.TextureData.PixelAttributes; -import com.jogamp.opengl.util.texture.awt.AWTTextureData.AWTPixelBufferProviderInt; +import com.jogamp.opengl.util.awt.AWTGLPixelBuffer; +import com.jogamp.opengl.util.awt.AWTGLPixelBuffer.AWTGLPixelBufferProvider; +import com.jogamp.opengl.util.awt.AWTGLPixelBuffer.SingleAWTGLPixelBufferProvider; /** A lightweight Swing component which provides OpenGL rendering support. Provided for compatibility with Swing user interfaces @@ -133,12 +134,58 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing private static final boolean DEBUG_VIEWPORT = Debug.isPropertyDefined("jogl.debug.GLJPanel.Viewport", true); private static final boolean USE_GLSL_TEXTURE_RASTERIZER = !Debug.isPropertyDefined("jogl.gljpanel.noglsl", true); + /** Indicates whether the Java 2D OpenGL pipeline is requested by user. */ + private static final boolean java2dOGLEnabledByProp; + + /** Indicates whether the Java 2D OpenGL pipeline is enabled, resource-compatible and requested by user. */ + private static final boolean useJava2DGLPipeline; + + /** Indicates whether the Java 2D OpenGL pipeline's usage is error free. */ + private static boolean java2DGLPipelineOK; + + static { + boolean enabled = false; + final String sVal = System.getProperty("sun.java2d.opengl"); + if( null != sVal ) { + enabled = Boolean.valueOf(sVal); + } + java2dOGLEnabledByProp = enabled && !Debug.isPropertyDefined("jogl.gljpanel.noogl", true); + + enabled = false; + if( java2dOGLEnabledByProp ) { + // Force eager initialization of part of the Java2D class since + // otherwise it's likely it will try to be initialized while on + // the Queue Flusher Thread, which is not allowed + if (Java2D.isOGLPipelineResourceCompatible() && Java2D.isFBOEnabled()) { + if( null != Java2D.getShareContext(GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()) ) { + enabled = true; + } + } + } + useJava2DGLPipeline = enabled; + java2DGLPipelineOK = enabled; + if( DEBUG ) { + System.err.println("GLJPanel: java2dOGLEnabledByProp "+java2dOGLEnabledByProp); + System.err.println("GLJPanel: useJava2DGLPipeline "+useJava2DGLPipeline); + System.err.println("GLJPanel: java2DGLPipelineOK "+java2DGLPipelineOK); + } + } + + private static SingleAWTGLPixelBufferProvider singleAWTGLPixelBufferProvider = null; + private static synchronized SingleAWTGLPixelBufferProvider getSingleAWTGLPixelBufferProvider() { + if( null == singleAWTGLPixelBufferProvider ) { + singleAWTGLPixelBufferProvider = new SingleAWTGLPixelBufferProvider( true /* allowRowStride */ ); + } + return singleAWTGLPixelBufferProvider; + } + private GLDrawableHelper helper = new GLDrawableHelper(); private volatile boolean isInitialized; // // Data used for either pbuffers or pixmap-based offscreen surfaces // + private AWTGLPixelBufferProvider customPixelBufferProvider = null; /** Single buffered offscreen caps */ private GLCapabilitiesImmutable offscreenCaps; private GLProfile glProfile; @@ -170,10 +217,9 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing // Used by all backends either directly or indirectly to hook up callbacks private Updater updater = new Updater(); - // Indicates whether the Java 2D OpenGL pipeline is enabled and resource-compatible - private boolean oglPipelineUsable = - Java2D.isOGLPipelineResourceCompatible() && - !Debug.isPropertyDefined("jogl.gljpanel.noogl", true); + private boolean oglPipelineUsable() { + return null == customPixelBufferProvider && useJava2DGLPipeline && java2DGLPipelineOK; + } private AWTWindowClosingProtocol awtWindowClosingProtocol = new AWTWindowClosingProtocol(this, new Runnable() { @@ -183,17 +229,6 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing } }, null); - static { - // Force eager initialization of part of the Java2D class since - // otherwise it's likely it will try to be initialized while on - // the Queue Flusher Thread, which is not allowed - if (Java2D.isOGLPipelineResourceCompatible() && Java2D.isFBOEnabled()) { - Java2D.getShareContext(GraphicsEnvironment. - getLocalGraphicsEnvironment(). - getDefaultScreenDevice()); - } - } - /** Creates a new GLJPanel component with a default set of OpenGL capabilities and using the default OpenGL capabilities selection mechanism. @@ -252,6 +287,23 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing this.setFocusable(true); // allow keyboard input! } + public AWTGLPixelBufferProvider getCustomPixelBufferProvider() { return customPixelBufferProvider; } + + /** + * @param custom custom {@link AWTGLPixelBufferProvider} + * @throws IllegalArgumentException ifcustom
isnull
+ * @throws IllegalStateException if backend is already realized, i.e. this instanced already painted once. + */ + public void setPixelBufferProvider(AWTGLPixelBufferProvider custom) throws IllegalArgumentException, IllegalStateException { + if( null == custom ) { + throw new IllegalArgumentException("Null PixelBufferProvider"); + } + if( null != backend ) { + throw new IllegalStateException("Backend already realized."); + } + customPixelBufferProvider = custom; + } + @Override public final Object getUpstreamWidget() { return this; @@ -629,7 +681,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing to perform OpenGL rendering using the GLJPanel into the same OpenGL drawable as the Swing implementation uses. */ public boolean shouldPreserveColorBufferIfTranslucent() { - return oglPipelineUsable; + return oglPipelineUsable(); } @Override @@ -701,10 +753,10 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing } if ( null == backend ) { - if (oglPipelineUsable) { + if ( oglPipelineUsable() ) { backend = new J2DOGLBackend(); } else { - backend = new OffscreenBackend(); + backend = new OffscreenBackend(glProfile, customPixelBufferProvider); } isInitialized = false; } @@ -922,14 +974,13 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing // backends, both of which rely on reading back the OpenGL frame // buffer and drawing it with a BufferedImage class OffscreenBackend implements Backend { - protected AWTPixelBufferProviderInt pixelBufferProvider = new AWTPixelBufferProviderInt(); - private PixelAttributes pixelAttribs; + private final AWTGLPixelBufferProvider pixelBufferProvider; + private AWTGLPixelBuffer pixelBuffer; + private boolean pixelBufferCheckSize; // One of these is used to store the read back pixels before storing // in the BufferedImage - protected IntBuffer readBackInts; - protected int readBackWidthInPixels; - protected int readBackHeightInPixels; + protected IntBuffer readBackInts; // Implementation using software rendering private GLDrawableImpl offscreenDrawable; @@ -943,6 +994,15 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing // For saving/restoring of OpenGL state during ReadPixels private final GLPixelStorageModes psm = new GLPixelStorageModes(); + OffscreenBackend(GLProfile glp, AWTGLPixelBufferProvider custom) { + if(null == custom) { + pixelBufferProvider = glp.isGL2GL3() ? getSingleAWTGLPixelBufferProvider() : + new AWTGLPixelBufferProvider( true /* allowRowStride */ ); + } else { + pixelBufferProvider = custom; + } + } + @Override public boolean isUsingOwnLifecycle() { return false; } @@ -1049,7 +1109,8 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing @Override public void setOpaque(boolean opaque) { if (opaque != isOpaque()) { - pixelBufferProvider.dispose(); + pixelBuffer.dispose(); + pixelBuffer = null; } } @@ -1076,30 +1137,38 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing alignment = 4; } + final GLPixelAttributes pixelAttribs; + + if( pixelBufferCheckSize ) { + pixelBufferCheckSize = false; + if( null != pixelBuffer && pixelBuffer.requiresNewBuffer(gl, panelWidth, panelHeight, 0) ) { + pixelBuffer.dispose(); + pixelBuffer = null; + } + } + // Must now copy pixels from offscreen context into surface - if ( !pixelBufferProvider.hasImage() ) { + if ( null == pixelBuffer ) { if (0 >= panelWidth || 0 >= panelHeight ) { return; } pixelAttribs = pixelBufferProvider.getAttributes(gl, componentCount); - - final int[] tmp = { 0 }; - final int readPixelSize = GLBuffers.sizeof(gl, tmp, pixelAttribs.format, pixelAttribs.type, panelWidth, panelHeight, 1, true); - final IntBuffer intBuffer = (IntBuffer) pixelBufferProvider.allocate(panelWidth, panelHeight, readPixelSize); - if(!flipVertical || null != glslTextureRaster) { - readBackInts = intBuffer; + pixelBuffer = pixelBufferProvider.allocate(gl, pixelAttribs, panelWidth, panelHeight, 1, true, 0); + if( !flipVertical || null != glslTextureRaster ) { + readBackInts = (IntBuffer) pixelBuffer.buffer; } else { - readBackInts = IntBuffer.allocate(readBackWidthInPixels * readBackHeightInPixels); + readBackInts = IntBuffer.allocate(pixelBuffer.width * pixelBuffer.height); } if(DEBUG) { - final BufferedImage offscreenImage = pixelBufferProvider.getImage(); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: pixelAttribs "+pixelAttribs); + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: pixelBufferProvider 0x"+Integer.toHexString(pixelBufferProvider.hashCode())+", "+pixelBufferProvider.getClass().getSimpleName()); + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: pixelBuffer 0x"+Integer.toHexString(pixelBuffer.hashCode())+", "+pixelBuffer+", alignment "+alignment); System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: flippedVertical "+flipVertical+", glslTextureRaster "+(null!=glslTextureRaster)); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: panelSize "+panelWidth+"x"+panelHeight +", readBackSizeInPixels "+readBackWidthInPixels+"x"+readBackHeightInPixels); - System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: offscreenImage "+offscreenImage.getWidth()+"x"+offscreenImage.getHeight()); + System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: panelSize "+panelWidth+"x"+panelHeight); } - } + } else { + pixelAttribs = pixelBuffer.pixelAttributes; + } if( DEBUG_VIEWPORT ) { int[] vp = new int[] { 0, 0, 0, 0 }; @@ -1111,7 +1180,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing psm.setAlignment(gl, alignment, alignment); if(gl.isGL2GL3()) { final GL2GL3 gl2gl3 = gl.getGL2GL3(); - gl2gl3.glPixelStorei(GL2GL3.GL_PACK_ROW_LENGTH, readBackWidthInPixels); + gl2gl3.glPixelStorei(GL2GL3.GL_PACK_ROW_LENGTH, pixelBuffer.width); gl2gl3.glReadBuffer(gl2gl3.getDefaultReadBuffer()); } @@ -1127,27 +1196,25 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing gl.glBindTexture(GL.GL_TEXTURE_2D, fboTex.getName()); // gl.glClear(GL.GL_DEPTH_BUFFER_BIT); // fboFlipped runs w/o DEPTH! glslTextureRaster.display(gl.getGL2ES2()); - gl.glReadPixels(0, 0, readBackWidthInPixels, readBackHeightInPixels, pixelAttribs.format, pixelAttribs.type, readBackInts); + gl.glReadPixels(0, 0, panelWidth, panelHeight, pixelAttribs.format, pixelAttribs.type, readBackInts); fboFlipped.unbind(gl); } else { - gl.glReadPixels(0, 0, readBackWidthInPixels, readBackHeightInPixels, pixelAttribs.format, pixelAttribs.type, readBackInts); + gl.glReadPixels(0, 0, panelWidth, panelHeight, pixelAttribs.format, pixelAttribs.type, readBackInts); if ( flipVertical ) { // Copy temporary data into raster of BufferedImage for faster // blitting Note that we could avoid this copy in the cases - // where !offscreenContext.offscreenImageNeedsVerticalFlip(), - // but that's the software rendering path which is very slow - // anyway - final BufferedImage offscreenImage = pixelBufferProvider.getImage(); - final Object src = readBackInts.array(); - final Object dest = ((DataBufferInt) offscreenImage.getRaster().getDataBuffer()).getData(); - final int srcIncr = readBackWidthInPixels; - final int destIncr = offscreenImage.getWidth(); + // where !offscreenDrawable.isGLOriented(), + // but that's the software rendering path which is very slow anyway. + final BufferedImage image = pixelBuffer.image; + final int[] src = readBackInts.array(); + final int[] dest = ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); + final int incr = pixelBuffer.width; int srcPos = 0; - int destPos = (offscreenImage.getHeight() - 1) * destIncr; - for (; destPos >= 0; srcPos += srcIncr, destPos -= destIncr) { - System.arraycopy(src, srcPos, dest, destPos, destIncr); + int destPos = (panelHeight - 1) * pixelBuffer.width; + for (; destPos >= 0; srcPos += incr, destPos -= incr) { + System.arraycopy(src, srcPos, dest, destPos, incr); } } } @@ -1164,13 +1231,10 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing public void doPaintComponent(Graphics g) { helper.invokeGL(offscreenDrawable, offscreenContext, updaterDisplayAction, updaterInitAction); - final BufferedImage offscreenImage = pixelBufferProvider.getImage(); - if ( null != offscreenImage ) { + if ( null != pixelBuffer ) { + final BufferedImage image = pixelBuffer.image; // Draw resulting image in one shot - g.drawImage(offscreenImage, 0, 0, - offscreenImage.getWidth(), - offscreenImage.getHeight(), - null /* Null ImageObserver since image data is ready. */); + g.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null); // Null ImageObserver since image data is ready. } } @@ -1201,8 +1265,6 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing } panelWidth = _drawable.getWidth(); panelHeight = _drawable.getHeight(); - readBackWidthInPixels = panelWidth; - readBackHeightInPixels = panelHeight; if( null != glslTextureRaster ) { if( GLContext.CONTEXT_NOT_CURRENT < offscreenContext.makeCurrent() ) { @@ -1216,7 +1278,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing } } - pixelBufferProvider.dispose(); + pixelBufferCheckSize = true; return _drawable.isRealized(); } @@ -1618,7 +1680,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing } isInitialized = false; backend = null; - oglPipelineUsable = false; + java2DGLPipelineOK = false; handleReshape = true; j2dContext.destroy(); j2dContext = null; -- cgit v1.2.3