summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2013-10-02 01:12:20 +0200
committerSven Gothel <[email protected]>2013-10-02 01:12:20 +0200
commit543c8649f43fdc43028075d7472ad553299271bf (patch)
tree01f0d9e2d94e4a9277c3318b9188fcd95b5f851d
parent00062e490f0b0cc2944a2167f2f00149c8ba352e (diff)
GLJPanel/AWTGLPixelBuffer: Reused BufferedImage didn't account for row-stride (regression of b33bdf41cf53f37203643a8551bf5d94b42a8fab)
SingleAWTGLPixelBufferProvider w/ allowing row-stride reuses the AWTGLPixelBuffer and it's BufferedImage even w/ different width. This leads to distortion if using the BufferedImage unhandled. GLJPanel also set GL_PACK_ROW_LENGTH to pixelBuffer.width, which leads to an 'out-of-bounds' exception if ReadPixels is used w/ panelwidth and panelHeight. ++ Introduce AWTGLPixelBuffer.getAlignedImage(width, height) which returns an aligned BufferedImage while reusing the DataBuffer. GLJPanel fetches a new alignedImage if required. This allows a more efficient single buffer usage as intended, w/o the need of copying data.
-rw-r--r--make/scripts/tests.sh4
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/awt/AWTGLPixelBuffer.java39
-rw-r--r--src/jogl/classes/javax/media/opengl/awt/GLJPanel.java26
3 files changed, 57 insertions, 12 deletions
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh
index 442b12672..068859b55 100644
--- a/make/scripts/tests.sh
+++ b/make/scripts/tests.sh
@@ -296,7 +296,7 @@ function testawtswt() {
#testnoawt com.jogamp.opengl.test.junit.jogl.demos.es1.newt.TestOlympicES1NEWT $*
#testnoawt com.jogamp.opengl.test.junit.jogl.demos.es1.newt.TestRedSquareES1NEWT $*
#testawt com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2AWT $*
-#testawt com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2GLJPanelAWT $*
+testawt com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2GLJPanelAWT $*
#testawt com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2GLJPanelsAWT $*
#testawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NewtCanvasAWT $*
#testawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestLandscapeES2NewtCanvasAWT $*
@@ -332,7 +332,7 @@ function testawtswt() {
#testnoawt com.jogamp.opengl.test.junit.jogl.tile.TestRandomTiledRendering2GL2NEWT $*
#testawt com.jogamp.opengl.test.junit.jogl.tile.TestRandomTiledRendering3GL2AWT $*
#testawt com.jogamp.opengl.test.junit.jogl.tile.TestTiledPrintingGearsAWT $*
-testawt com.jogamp.opengl.test.junit.jogl.tile.TestTiledPrintingGearsSwingAWT $*
+#testawt com.jogamp.opengl.test.junit.jogl.tile.TestTiledPrintingGearsSwingAWT $*
#testawt com.jogamp.opengl.test.junit.jogl.tile.TestTiledPrintingGearsSwingAWT2 $*
#testawt com.jogamp.opengl.test.junit.jogl.tile.TestTiledPrintingGearsNewtAWT $*
#testawt com.jogamp.opengl.test.junit.jogl.tile.TestTiledPrintingNIOImageSwingAWT $*
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 1f5bb6acc..9d2ef6572 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/awt/AWTGLPixelBuffer.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/awt/AWTGLPixelBuffer.java
@@ -28,7 +28,11 @@
package com.jogamp.opengl.util.awt;
import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;
+import java.awt.image.SinglePixelPackedSampleModel;
+import java.awt.image.WritableRaster;
import java.nio.Buffer;
import java.nio.IntBuffer;
@@ -36,7 +40,6 @@ import javax.media.opengl.GL;
import com.jogamp.common.nio.Buffers;
import com.jogamp.opengl.util.GLPixelBuffer;
-import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes;
/**
* AWT {@link GLPixelBuffer} backed by an {@link BufferedImage} of type
@@ -51,6 +54,10 @@ import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes;
* <p>
* See {@link AWTGLPixelBuffer#requiresNewBuffer(GL, int, int, int)} for {@link #allowRowStride} details.
* </p>
+ * <p>
+ * If using <code>allowRowStride == true</code>, user may needs to get the {@link #getAlignedImage(int, int) aligned image}
+ * since {@link #requiresNewBuffer(GL, int, int, int)} will allow different width in this case.
+ * </p>
*/
public class AWTGLPixelBuffer extends GLPixelBuffer {
public static final GLPixelAttributes awtPixelAttributesIntRGBA4 = new GLPixelAttributes(4, GL.GL_BGRA, GL.GL_UNSIGNED_BYTE);
@@ -60,6 +67,7 @@ public class AWTGLPixelBuffer extends GLPixelBuffer {
public final BufferedImage image;
/**
+ *
* @param pixelAttributes the desired {@link GLPixelAttributes}
* @param width in pixels
* @param height in pixels
@@ -68,6 +76,7 @@ public class AWTGLPixelBuffer extends GLPixelBuffer {
* @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(GLPixelAttributes pixelAttributes, int width, int height, int depth, boolean pack, BufferedImage image,
Buffer buffer, boolean allowRowStride) {
@@ -81,6 +90,33 @@ public class AWTGLPixelBuffer extends GLPixelBuffer {
super.dispose();
}
+ /**
+ * Returns a width- and height-aligned image representation sharing data w/ {@link #image}.
+ * @param width
+ * @param height
+ * @return
+ * @throws IllegalArgumentException if requested size exceeds image size
+ */
+ public BufferedImage getAlignedImage(int width, int height) throws IllegalArgumentException {
+ if( width * height > image.getWidth() * image.getHeight() ) {
+ throw new IllegalArgumentException("Requested size exceeds image size: "+width+"x"+height+" > "+image.getWidth()+"x"+image.getHeight());
+ }
+ if( width == image.getWidth() ) {
+ if( height == image.getHeight() ) {
+ return image;
+ }
+ return image.getSubimage(0, 0, width, height);
+ }
+ final ColorModel cm = image.getColorModel();
+ final WritableRaster raster = image.getRaster();
+ final DataBuffer dataBuffer = raster.getDataBuffer();
+ final SinglePixelPackedSampleModel sppsm0 = (SinglePixelPackedSampleModel) raster.getSampleModel();
+ final SinglePixelPackedSampleModel sppsm1 = new SinglePixelPackedSampleModel(dataBuffer.getDataType(),
+ width, height, width /* scanLineStride */, sppsm0.getBitMasks());
+ final WritableRaster raster1 = WritableRaster.createWritableRaster(sppsm1, dataBuffer, null);
+ return new BufferedImage (cm, raster1, cm.isAlphaPremultiplied(), null);
+ }
+
public StringBuilder toString(StringBuilder sb) {
sb = super.toString(sb);
sb.append(", allowRowStride ").append(allowRowStride).append(", image [").append(image.getWidth()).append("x").append(image.getHeight()).append(", ").append(image.toString()).append("]");
@@ -99,6 +135,7 @@ public class AWTGLPixelBuffer extends GLPixelBuffer {
/**
* @param allowRowStride If <code>true</code>, allow row-stride, otherwise not.
* See {@link #getAllowRowStride()} and {@link AWTGLPixelBuffer#requiresNewBuffer(GL, int, int, int)}.
+ * If <code>true</code>, user shall decide whether to use a {@link AWTGLPixelBuffer#getAlignedImage(int, int) width-aligned image}.
*/
public AWTGLPixelBufferProvider(boolean allowRowStride) {
this.allowRowStride = allowRowStride;
diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
index 84d085f76..7002fabb6 100644
--- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
+++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java
@@ -1236,6 +1236,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
private final AWTGLPixelBufferProvider pixelBufferProvider;
private final boolean useSingletonBuffer;
private AWTGLPixelBuffer pixelBuffer;
+ private BufferedImage alignedImage;
// One of these is used to store the read back pixels before storing
// in the BufferedImage
@@ -1255,8 +1256,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
OffscreenBackend(GLProfile glp, AWTGLPixelBufferProvider custom) {
if(null == custom) {
- pixelBufferProvider = glp.isGL2ES3() ? getSingleAWTGLPixelBufferProvider() :
- new AWTGLPixelBufferProvider( false /* allowRowStride */ ) ;
+ pixelBufferProvider = getSingleAWTGLPixelBufferProvider();
} else {
pixelBufferProvider = custom;
}
@@ -1382,6 +1382,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
}
pixelBuffer = null;
}
+ alignedImage = null;
}
@Override
@@ -1389,6 +1390,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
if ( opaque != isOpaque() && !useSingletonBuffer ) {
pixelBuffer.dispose();
pixelBuffer = null;
+ alignedImage = null;
}
}
@@ -1423,6 +1425,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
if( null != pixelBuffer && pixelBuffer.requiresNewBuffer(gl, panelWidth, panelHeight, 0) ) {
pixelBuffer.dispose();
pixelBuffer = null;
+ alignedImage = null;
}
if ( null == pixelBuffer ) {
if (0 >= panelWidth || 0 >= panelHeight ) {
@@ -1439,6 +1442,12 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
if( offscreenDrawable.getWidth() != panelWidth || offscreenDrawable.getHeight() != panelHeight ) {
throw new InternalError("OffscreenDrawable panelSize mismatch (reshape missed): panelSize "+panelWidth+"x"+panelHeight+" != drawable "+offscreenDrawable.getWidth()+"x"+offscreenDrawable.getHeight()+", on thread "+getThreadName());
}
+ if( null == alignedImage || panelWidth != alignedImage.getWidth() || panelHeight != alignedImage.getHeight() ) {
+ alignedImage = pixelBuffer.getAlignedImage(panelWidth, panelHeight);
+ if(DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: alignedImage "+alignedImage.getWidth()+"x"+alignedImage.getHeight()+", pixelBuffer "+pixelBuffer.width+"x"+pixelBuffer.height);
+ }
+ }
final IntBuffer readBackInts;
if( !flipVertical || null != glslTextureRaster ) {
@@ -1475,7 +1484,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
psm.setAlignment(gl, alignment, alignment);
if(gl.isGL2ES3()) {
final GL2ES3 gl2es3 = gl.getGL2ES3();
- gl2es3.glPixelStorei(GL2ES3.GL_PACK_ROW_LENGTH, pixelBuffer.width);
+ gl2es3.glPixelStorei(GL2ES3.GL_PACK_ROW_LENGTH, panelWidth);
gl2es3.glReadBuffer(gl2es3.getDefaultReadBuffer());
}
@@ -1522,12 +1531,12 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
// blitting Note that we could avoid this copy in the cases
// where !offscreenDrawable.isGLOriented(),
// but that's the software rendering path which is very slow anyway.
- final BufferedImage image = pixelBuffer.image;
+ final BufferedImage image = alignedImage;
final int[] src = readBackInts.array();
final int[] dest = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
- final int incr = pixelBuffer.width;
+ final int incr = panelWidth;
int srcPos = 0;
- int destPos = (panelHeight - 1) * pixelBuffer.width;
+ int destPos = (panelHeight - 1) * panelWidth;
for (; destPos >= 0; srcPos += incr, destPos -= incr) {
System.arraycopy(src, srcPos, dest, destPos, incr);
}
@@ -1557,10 +1566,9 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing
public void doPaintComponent(Graphics g) {
helper.invokeGL(offscreenDrawable, offscreenContext, updaterDisplayAction, updaterInitAction);
- if ( null != pixelBuffer ) {
- final BufferedImage image = pixelBuffer.image;
+ if ( null != alignedImage ) {
// Draw resulting image in one shot
- g.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null); // Null ImageObserver since image data is ready.
+ g.drawImage(alignedImage, 0, 0, alignedImage.getWidth(), alignedImage.getHeight(), null); // Null ImageObserver since image data is ready.
}
}