diff options
author | Sven Gothel <[email protected]> | 2013-10-02 01:12:20 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2013-10-02 01:12:20 +0200 |
commit | 543c8649f43fdc43028075d7472ad553299271bf (patch) | |
tree | 01f0d9e2d94e4a9277c3318b9188fcd95b5f851d | |
parent | 00062e490f0b0cc2944a2167f2f00149c8ba352e (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.sh | 4 | ||||
-rw-r--r-- | src/jogl/classes/com/jogamp/opengl/util/awt/AWTGLPixelBuffer.java | 39 | ||||
-rw-r--r-- | src/jogl/classes/javax/media/opengl/awt/GLJPanel.java | 26 |
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. } } |