diff options
author | Sven Gothel <[email protected]> | 2011-06-09 00:42:41 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2011-06-09 00:42:41 +0200 |
commit | 423f5bf7f518433edcbf64accaf2cf5252cb4a63 (patch) | |
tree | 15b4278c893adc5f423a22b85b2b97c6b6cda010 /src | |
parent | f6bd208d8ef15769e13cb959e614349fd1e7cae1 (diff) |
GLBuffers fix ; GL imageSizeInBytes fix / unit tests.
- Moved implementation of prev GL imageSizeInBytes(..) -> GLBuffers.sizeof() for all GL profiles
- GLBuffers.*: Added missing formats and types (GL2.1, GL3.3 and GL4.1)
- GLBuffers.sizeof(): Fail fast if format/type is unhandled, or alignment invalid
- Added unit test for GLBuffers.sizeof()
Diffstat (limited to 'src')
-rw-r--r-- | src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java | 412 | ||||
-rw-r--r-- | src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGPUMemSec01NEWT.java | 319 |
2 files changed, 710 insertions, 21 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java b/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java index efe3a7675..f2e742cda 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java +++ b/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java @@ -42,60 +42,145 @@ import com.jogamp.common.nio.Buffers; import javax.media.opengl.GL; import javax.media.opengl.GL2; import javax.media.opengl.GL2ES2; +import javax.media.opengl.GL2GL3; +import javax.media.opengl.GLException; import java.nio.*; /** * Utility routines for dealing with direct buffers. * @author Kenneth Russel + * @author Sven Gothel * @author Michael Bien */ public class GLBuffers extends Buffers { + /** + * @param glType shall be one of + * GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT, GL_SHORT, + * GL_UNSIGNED_INT, GL_INT, GL_HALF_FLOAT, GL_FLOAT, GL_DOUBLE, + * GL_UNSIGNED_BYTE_3_3_2, GL_UNSIGNED_BYTE_2_3_3_REV, + * GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_5_6_5_REV, + * GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_SHORT_4_4_4_4_REV, + * GL_UNSIGNED_SHORT_5_5_5_1, GL_UNSIGNED_SHORT_1_5_5_5_REV, + * GL_UNSIGNED_INT_8_8_8_8, GL_UNSIGNED_INT_8_8_8_8_REV, + * GL_UNSIGNED_INT_10_10_10_2, GL_UNSIGNED_INT_2_10_10_10_REV + * GL_UNSIGNED_INT_24_8, GL_UNSIGNED_INT_10F_11F_11F_REV, + * GL_UNSIGNED_INT_5_9_9_9_REV, GL_FLOAT_32_UNSIGNED_INT_24_8_REV (25) + * @return -1 if glType is unhandled, otherwise the actual value > 0 + */ public static final int sizeOfGLType(int glType) { - switch (glType) { - case GL.GL_UNSIGNED_BYTE: - return SIZEOF_BYTE; + switch (glType) { // 25 case GL.GL_BYTE: + case GL.GL_UNSIGNED_BYTE: + case GL2GL3.GL_UNSIGNED_BYTE_3_3_2: + case GL2GL3.GL_UNSIGNED_BYTE_2_3_3_REV: return SIZEOF_BYTE; - case GL.GL_UNSIGNED_SHORT: - return SIZEOF_SHORT; + case GL.GL_SHORT: + case GL.GL_UNSIGNED_SHORT: + case GL.GL_UNSIGNED_SHORT_5_6_5: + case GL2GL3.GL_UNSIGNED_SHORT_5_6_5_REV: + case GL2GL3.GL_UNSIGNED_SHORT_4_4_4_4: + case GL2GL3.GL_UNSIGNED_SHORT_4_4_4_4_REV: + case GL2GL3.GL_UNSIGNED_SHORT_5_5_5_1: + case GL2GL3.GL_UNSIGNED_SHORT_1_5_5_5_REV: return SIZEOF_SHORT; - case GL.GL_FLOAT: - return SIZEOF_FLOAT; + case GL.GL_FIXED: - return SIZEOF_INT; case GL2ES2.GL_INT: + case GL.GL_UNSIGNED_INT: + case GL2GL3.GL_UNSIGNED_INT_8_8_8_8: + case GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV: + case GL2GL3.GL_UNSIGNED_INT_10_10_10_2: + case GL2GL3.GL_UNSIGNED_INT_2_10_10_10_REV: + case GL2GL3.GL_UNSIGNED_INT_24_8: + case GL2GL3.GL_UNSIGNED_INT_10F_11F_11F_REV: + case GL2GL3.GL_UNSIGNED_INT_5_9_9_9_REV: return SIZEOF_INT; - case GL2ES2.GL_UNSIGNED_INT: - return SIZEOF_INT; + + case GL2GL3.GL_FLOAT_32_UNSIGNED_INT_24_8_REV: + return SIZEOF_LONG; + + case GL.GL_FLOAT: + return SIZEOF_FLOAT; + case GL2.GL_DOUBLE: return SIZEOF_DOUBLE; } return -1; } - + + /** + * @param glType shall be one of + * GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT, GL_SHORT, + * GL_UNSIGNED_INT, GL_INT, GL_HALF_FLOAT, GL_FLOAT, GL_DOUBLE, + * GL_UNSIGNED_BYTE_3_3_2, GL_UNSIGNED_BYTE_2_3_3_REV, + * GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_5_6_5_REV, + * GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_SHORT_4_4_4_4_REV, + * GL_UNSIGNED_SHORT_5_5_5_1, GL_UNSIGNED_SHORT_1_5_5_5_REV, + * GL_UNSIGNED_INT_8_8_8_8, GL_UNSIGNED_INT_8_8_8_8_REV, + * GL_UNSIGNED_INT_10_10_10_2, GL_UNSIGNED_INT_2_10_10_10_REV + * GL_UNSIGNED_INT_24_8, GL_UNSIGNED_INT_10F_11F_11F_REV, + * GL_UNSIGNED_INT_5_9_9_9_REV, GL_FLOAT_32_UNSIGNED_INT_24_8_REV (25) + * @return null if glType is unhandled, otherwise the new Buffer object + */ public static final Buffer newDirectGLBuffer(int glType, int numElements) { switch (glType) { - case GL.GL_UNSIGNED_BYTE: case GL.GL_BYTE: + case GL.GL_UNSIGNED_BYTE: + case GL2GL3.GL_UNSIGNED_BYTE_3_3_2: + case GL2GL3.GL_UNSIGNED_BYTE_2_3_3_REV: return newDirectByteBuffer(numElements); - case GL.GL_UNSIGNED_SHORT: + case GL.GL_SHORT: + case GL.GL_UNSIGNED_SHORT: + case GL.GL_UNSIGNED_SHORT_5_6_5: + case GL2GL3.GL_UNSIGNED_SHORT_5_6_5_REV: + case GL2GL3.GL_UNSIGNED_SHORT_4_4_4_4: + case GL2GL3.GL_UNSIGNED_SHORT_4_4_4_4_REV: + case GL2GL3.GL_UNSIGNED_SHORT_5_5_5_1: + case GL2GL3.GL_UNSIGNED_SHORT_1_5_5_5_REV: return newDirectShortBuffer(numElements); - case GL.GL_FLOAT: - return newDirectFloatBuffer(numElements); + case GL.GL_FIXED: case GL2ES2.GL_INT: - case GL2ES2.GL_UNSIGNED_INT: + case GL.GL_UNSIGNED_INT: + case GL2GL3.GL_UNSIGNED_INT_8_8_8_8: + case GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV: + case GL2GL3.GL_UNSIGNED_INT_10_10_10_2: + case GL2GL3.GL_UNSIGNED_INT_2_10_10_10_REV: + case GL2GL3.GL_UNSIGNED_INT_24_8: + case GL2GL3.GL_UNSIGNED_INT_10F_11F_11F_REV: + case GL2GL3.GL_UNSIGNED_INT_5_9_9_9_REV: return newDirectIntBuffer(numElements); + + case GL2GL3.GL_FLOAT_32_UNSIGNED_INT_24_8_REV: + return newDirectLongBuffer(numElements); + + case GL.GL_FLOAT: + return newDirectFloatBuffer(numElements); + case GL2.GL_DOUBLE: return newDirectDoubleBuffer(numElements); } return null; } + /** + * @param glType shall be one of + * GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT, GL_SHORT, + * GL_UNSIGNED_INT, GL_INT, GL_HALF_FLOAT, GL_FLOAT, GL_DOUBLE, + * GL_UNSIGNED_BYTE_3_3_2, GL_UNSIGNED_BYTE_2_3_3_REV, + * GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_5_6_5_REV, + * GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_SHORT_4_4_4_4_REV, + * GL_UNSIGNED_SHORT_5_5_5_1, GL_UNSIGNED_SHORT_1_5_5_5_REV, + * GL_UNSIGNED_INT_8_8_8_8, GL_UNSIGNED_INT_8_8_8_8_REV, + * GL_UNSIGNED_INT_10_10_10_2, GL_UNSIGNED_INT_2_10_10_10_REV + * GL_UNSIGNED_INT_24_8, GL_UNSIGNED_INT_10F_11F_11F_REV, + * GL_UNSIGNED_INT_5_9_9_9_REV, GL_FLOAT_32_UNSIGNED_INT_24_8_REV (25) + * @return null if glType is unhandled or parent is null or bufLen is 0, otherwise the new Buffer object + */ public static final Buffer sliceGLBuffer(ByteBuffer parent, int bytePos, int byteLen, int glType) { if (parent == null || byteLen == 0) { return null; @@ -104,24 +189,309 @@ public class GLBuffers extends Buffers { parent.limit(bytePos + byteLen); switch (glType) { - case GL.GL_UNSIGNED_BYTE: case GL.GL_BYTE: + case GL.GL_UNSIGNED_BYTE: + case GL2GL3.GL_UNSIGNED_BYTE_3_3_2: + case GL2GL3.GL_UNSIGNED_BYTE_2_3_3_REV: return parent.slice(); - case GL.GL_UNSIGNED_SHORT: + case GL.GL_SHORT: + case GL.GL_UNSIGNED_SHORT: + case GL.GL_UNSIGNED_SHORT_5_6_5: + case GL2GL3.GL_UNSIGNED_SHORT_5_6_5_REV: + case GL2GL3.GL_UNSIGNED_SHORT_4_4_4_4: + case GL2GL3.GL_UNSIGNED_SHORT_4_4_4_4_REV: + case GL2GL3.GL_UNSIGNED_SHORT_5_5_5_1: + case GL2GL3.GL_UNSIGNED_SHORT_1_5_5_5_REV: return parent.asShortBuffer(); - case GL.GL_FLOAT: - return parent.asFloatBuffer(); + case GL.GL_FIXED: - case GL2ES2.GL_INT: + case GL2GL3.GL_INT: case GL2ES2.GL_UNSIGNED_INT: + case GL2GL3.GL_UNSIGNED_INT_8_8_8_8: + case GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV: + case GL2GL3.GL_UNSIGNED_INT_10_10_10_2: + case GL2GL3.GL_UNSIGNED_INT_2_10_10_10_REV: + case GL2GL3.GL_UNSIGNED_INT_24_8: + case GL2GL3.GL_UNSIGNED_INT_10F_11F_11F_REV: + case GL2GL3.GL_UNSIGNED_INT_5_9_9_9_REV: return parent.asIntBuffer(); + + case GL2GL3.GL_FLOAT_32_UNSIGNED_INT_24_8_REV: + return parent.asLongBuffer(); + + case GL.GL_FLOAT: + return parent.asFloatBuffer(); + case GL2.GL_DOUBLE: return parent.asDoubleBuffer(); } return null; } + private static final int glGetInteger(GL gl, int pname, int[] tmp) { + gl.glGetIntegerv(pname, tmp, 0); + return tmp[0]; + } + + /** + * Returns the number of bytes required to read/write a memory buffer via OpenGL + * using the current GL pixel storage state and the given parameters. + * + * <p>This method is security critical, hence it throws an exception (fail-fast) + * in case of an invalid alignment. In case we forgot to handle + * proper values, please contact the maintainer.</p> + * + * @param gl the current GL object + * + * @param tmp a pass through integer array of size >= 1 used to store temp data (performance) + * + * @param bytesPerElement bytes per element + * @param width in pixels + * @param height in pixels + * @param depth in pixels + * @param pack true for read mode GPU -> CPU (pack), otherwise false for write mode CPU -> GPU (unpack) + * @return required minimum size of the buffer in bytes + * @throws GLException if alignment is invalid. Please contact the maintainer if this is our bug. + */ + public static final int sizeof(GL gl, int tmp[], + int bytesPerElement, int width, int height, int depth, + boolean pack) { + int rowLength = 0; + int skipRows = 0; + int skipPixels = 0; + int alignment = 1; + int imageHeight = 0; + int skipImages = 0; + + if (pack) { + alignment = glGetInteger(gl, GL.GL_PACK_ALIGNMENT, tmp); + if(gl.isGL2GL3()) { + rowLength = glGetInteger(gl, GL2GL3.GL_PACK_ROW_LENGTH, tmp); + skipRows = glGetInteger(gl, GL2GL3.GL_PACK_SKIP_ROWS, tmp); + skipPixels = glGetInteger(gl, GL2GL3.GL_PACK_SKIP_PIXELS, tmp); + if (depth > 1) { + imageHeight = glGetInteger(gl, GL2GL3.GL_PACK_IMAGE_HEIGHT, tmp); + skipImages = glGetInteger(gl, GL2GL3.GL_PACK_SKIP_IMAGES, tmp); + } + } + } else { + alignment = glGetInteger(gl, GL.GL_UNPACK_ALIGNMENT, tmp); + if(gl.isGL2GL3 ()) { + rowLength = glGetInteger(gl, GL2GL3.GL_UNPACK_ROW_LENGTH, tmp); + skipRows = glGetInteger(gl, GL2GL3.GL_UNPACK_SKIP_ROWS, tmp); + skipPixels = glGetInteger(gl, GL2GL3.GL_UNPACK_SKIP_PIXELS, tmp); + if (depth > 1) { + imageHeight = glGetInteger(gl, GL2GL3.GL_UNPACK_IMAGE_HEIGHT, tmp); + skipImages = glGetInteger(gl, GL2GL3.GL_UNPACK_SKIP_IMAGES, tmp); + } + } + } + + // Try to deal somewhat correctly with potentially invalid values + width = Math.max(0, width ); + height = Math.max(1, height); // min 1D + depth = Math.max(1, depth ); // min 1 * imageSize + skipRows = Math.max(0, skipRows); + skipPixels = Math.max(0, skipPixels); + alignment = Math.max(1, alignment); + skipImages = Math.max(0, skipImages); + + imageHeight = ( imageHeight > 0 ) ? imageHeight : height; + rowLength = ( rowLength > 0 ) ? rowLength : width; + + int rowLengthInBytes = rowLength * bytesPerElement; + int skipBytes = skipPixels * bytesPerElement; + + switch(alignment) { + case 1: + break; + case 2: + case 4: + case 8: { + // x % 2n == x & (2n - 1) + int remainder = rowLengthInBytes & ( alignment - 1 ); + if (remainder > 0) { + rowLengthInBytes += alignment - remainder; + } + remainder = skipBytes & ( alignment - 1 ); + if (remainder > 0) { + skipBytes += alignment - remainder; + } + } + break; + default: + throw new GLException("Invalid alignment "+alignment+", must be 2**n (1,2,4,8). Pls notify the maintainer in case this is our bug."); + } + + /** + * skipImages, depth, skipPixels and skipRows are static offsets. + * + * skipImages and depth are in multiples of image size. + * + * skipBytes and rowLengthInBytes are aligned + * + * rowLengthInBytes is the aligned byte offset + * from line n to line n+1 at the same x-axis position. + */ + return + skipBytes + // aligned skipPixels * bpp + ( skipImages + depth - 1 ) * imageHeight * rowLengthInBytes + // aligned whole images + ( skipRows + height - 1 ) * rowLengthInBytes + // aligned lines + width * bytesPerElement; // last line + } + + /** + * Returns the number of bytes required to read/write a memory buffer via OpenGL + * using the current GL pixel storage state and the given parameters. + * + * <p>This method is security critical, hence it throws an exception (fail-fast) + * in case either the format, type or alignment is unhandled. In case we forgot to handle + * proper values, please contact the maintainer.</p> + * + * @param gl the current GL object + * + * @param tmp a pass through integer array of size >= 1 used to store temp data (performance) + * + * @param format must be one of + * GL_COLOR_INDEX, GL_STENCIL_INDEX, GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL, + * GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA, GL_LUMINANCE, + * GL_RG, GL_LUMINANCE_ALPHA, + * GL_RGB, GL_BGR, GL_RGBA, GL_BGRA, GL_ABGR_EXT, + * GL_RED_INTEGER, GL_GREEN_INTEGER, GL_BLUE_INTEGER, + * GL_RG_INTEGER, GL_RGB_INTEGER, GL_BGR_INTEGER, + * GL_RGBA_INTEGER, GL_BGRA_INTEGER (24) + * + * @param type must be one of + * GL_BITMAP, + * GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT, GL_SHORT, + * GL_UNSIGNED_INT, GL_INT, GL_HALF_FLOAT, GL_FLOAT, GL_DOUBLE, + * GL_UNSIGNED_BYTE_3_3_2, GL_UNSIGNED_BYTE_2_3_3_REV, + * GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_5_6_5_REV, + * GL_UNSIGNED_SHORT_4_4_4_4, GL_UNSIGNED_SHORT_4_4_4_4_REV, + * GL_UNSIGNED_SHORT_5_5_5_1, GL_UNSIGNED_SHORT_1_5_5_5_REV, + * GL_UNSIGNED_INT_8_8_8_8, GL_UNSIGNED_INT_8_8_8_8_REV, + * GL_UNSIGNED_INT_10_10_10_2, GL_UNSIGNED_INT_2_10_10_10_REV + * GL_UNSIGNED_INT_24_8, GL_UNSIGNED_INT_10F_11F_11F_REV, + * GL_UNSIGNED_INT_5_9_9_9_REV, GL_FLOAT_32_UNSIGNED_INT_24_8_REV (26) + * + * @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 + * @return required minimum size of the buffer in bytes + * @throws GLException if format, type or alignment is not handled. Please contact the maintainer if this is our bug. + */ + public static final int sizeof(GL gl, int tmp[], + int format, int type, int width, int height, int depth, + boolean pack) throws GLException { + int elements = 0; + int esize = 0; + + if (width < 0) return 0; + if (height < 0) return 0; + if (depth < 0) return 0; + + switch (format) /* 24 */ { + case GL2.GL_COLOR_INDEX: + case GL2GL3.GL_STENCIL_INDEX: + case GL2GL3.GL_DEPTH_COMPONENT: + case GL2GL3.GL_DEPTH_STENCIL: + case GL2GL3.GL_RED: + case GL2GL3.GL_RED_INTEGER: + case GL2GL3.GL_GREEN: + case GL2GL3.GL_GREEN_INTEGER: + case GL2GL3.GL_BLUE: + case GL2GL3.GL_BLUE_INTEGER: + case GL.GL_ALPHA: + case GL.GL_LUMINANCE: + elements = 1; + break; + case GL.GL_LUMINANCE_ALPHA: + case GL2GL3.GL_RG: + case GL2GL3.GL_RG_INTEGER: + elements = 2; + break; + case GL.GL_RGB: + case GL2GL3.GL_RGB_INTEGER: + case GL2GL3.GL_BGR: + case GL2GL3.GL_BGR_INTEGER: + elements = 3; + break; + case GL.GL_RGBA: + case GL2GL3.GL_RGBA_INTEGER: + case GL2GL3.GL_BGRA: + case GL2GL3.GL_BGRA_INTEGER: + case GL2.GL_ABGR_EXT: + elements = 4; + break; + /* FIXME ?? + case GL.GL_HILO_NV: + elements = 2; + break; */ + default: + throw new GLException("format 0x"+Integer.toHexString(format)+" not supported [yet], pls notify the maintainer in case this is our bug."); + } + + switch (type) /* 26 */ { + case GL2.GL_BITMAP: + if (GL2.GL_COLOR_INDEX == format || GL2GL3.GL_STENCIL_INDEX == format) { + return (depth * (height * ((width+7)/8))); + } + case GL.GL_BYTE: + case GL.GL_UNSIGNED_BYTE: + esize = 1; + break; + case GL.GL_SHORT: + case GL.GL_UNSIGNED_SHORT: + case GL.GL_HALF_FLOAT: + esize = 2; + break; + case GL2ES2.GL_INT: + case GL.GL_UNSIGNED_INT: + case GL.GL_FLOAT: + esize = 4; + break; + case GL2GL3.GL_DOUBLE: + esize = 8; + break; + + case GL2GL3.GL_UNSIGNED_BYTE_3_3_2: + case GL2GL3.GL_UNSIGNED_BYTE_2_3_3_REV: + esize = 1; + elements = 1; + break; + case GL.GL_UNSIGNED_SHORT_5_6_5: + case GL2GL3.GL_UNSIGNED_SHORT_5_6_5_REV: + case GL2GL3.GL_UNSIGNED_SHORT_4_4_4_4: + case GL2GL3.GL_UNSIGNED_SHORT_4_4_4_4_REV: + case GL2GL3.GL_UNSIGNED_SHORT_5_5_5_1: + case GL2GL3.GL_UNSIGNED_SHORT_1_5_5_5_REV: + esize = 2; + elements = 1; + break; + case GL2GL3.GL_UNSIGNED_INT_8_8_8_8: + case GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV: + case GL2GL3.GL_UNSIGNED_INT_10_10_10_2: + case GL2GL3.GL_UNSIGNED_INT_2_10_10_10_REV: + case GL2GL3.GL_UNSIGNED_INT_24_8: + case GL2GL3.GL_UNSIGNED_INT_10F_11F_11F_REV: + case GL2GL3.GL_UNSIGNED_INT_5_9_9_9_REV: + esize = 4; + elements = 1; + break; + case GL2GL3.GL_FLOAT_32_UNSIGNED_INT_24_8_REV: + esize = 8; + elements = 1; + break; + + default: + throw new GLException("type 0x"+Integer.toHexString(type)+"/"+"format 0x"+Integer.toHexString(format)+" not supported [yet], pls notify the maintainer in case this is our bug."); + } + + return sizeof(gl, tmp, elements * esize, width, height, depth, pack); + } + //---------------------------------------------------------------------- // Conversion routines // diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGPUMemSec01NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGPUMemSec01NEWT.java new file mode 100644 index 000000000..a328a2bac --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestGPUMemSec01NEWT.java @@ -0,0 +1,319 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.test.junit.jogl.acore; + +import com.jogamp.common.nio.Buffers; +import com.jogamp.opengl.util.GLPixelStorageModes; +import com.jogamp.opengl.test.junit.util.NEWTGLContext; +import com.jogamp.opengl.test.junit.util.UITestCase; + +import java.io.IOException; +import java.nio.ByteBuffer; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GL2GL3; +import javax.media.opengl.GLDrawable; +import javax.media.opengl.GLException; +import javax.media.opengl.GLProfile; + +import org.junit.Assert; +import org.junit.Test; + +public class TestGPUMemSec01NEWT extends UITestCase { + static String hexString(int i) { + return "0x"+Integer.toHexString(i); + } + static String exceptionMsg(String pre, int format, int type, int components, int width, int height, int rl1, int rl4, int rl8) { + return pre + + ": fmt "+hexString(format)+", type "+hexString(type)+", comps "+components+ + ", "+width+"x"+height+ + ", rowlenA1 "+rl1+", rowlenA4 "+rl4+", rowlenA8 "+rl8; + } + + static NEWTGLContext.WindowContext createCurrentGLOffscreenWindow(int width, int height) throws GLException, InterruptedException { + final NEWTGLContext.WindowContext winctx = NEWTGLContext.createOffscreenWindow(GLProfile.getGL2ES2(), width, height, true); + final GL _gl = winctx.context.getGL(); + Assert.assertTrue(_gl.isGL2GL3()); + final GL2GL3 gl = _gl.getGL2GL3(); + + Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError()); + + // misc GL setup + gl.glClearColor(1, 1, 1, 1); + gl.glEnable(GL2ES2.GL_DEPTH_TEST); + Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError()); + gl.glViewport(0, 0, width, height); + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError()); + + return winctx; + } + + static int readPixelsCheck(GL gl, int format, int type, int components, int width, int height) throws InterruptedException { + int expectedExceptions = 0; + + final int rowlenA1 = width * components; + + final int rowlenA4 = ( ( width * components + 3 ) / 4 ) * 4 ; + Assert.assertTrue(rowlenA4 % 4 == 0); + + final int rowlenA8 = ( ( width * components + 7 ) / 8 ) * 8 ; + Assert.assertTrue(rowlenA8 % 8 == 0); + + GLPixelStorageModes psm = new GLPixelStorageModes(); + psm.setPackAlignment(gl, 1); + + Exception ee = null; + + // ok size ! + try { + ByteBuffer bb = Buffers.newDirectByteBuffer(height*rowlenA1); + gl.glReadPixels(0, 0, width, height, format, type, bb); + Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError()); + } catch(IndexOutOfBoundsException e) { + ee = e; + } + Assert.assertNull( + exceptionMsg("Unexpected IndexOutOfBoundsException (size ok, alignment 1)", + format, type, components, width, height, rowlenA1, rowlenA4, rowlenA8), ee); + ee = null; + + + // too small -10 ! + try { + ByteBuffer bb = Buffers.newDirectByteBuffer(height*rowlenA1-10); + gl.glReadPixels(0, 0, width, height, format, type, bb); + Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError()); + } catch(IndexOutOfBoundsException e) { + ee = e; + System.err.println( + exceptionMsg("OK Expected IndexOutOfBoundsException (size-10 bytes)", + format, type, components, width, height, rowlenA1, rowlenA4, rowlenA8)+ + ": "+ee.getMessage()); + expectedExceptions++; + } + Assert.assertNotNull( + exceptionMsg("Expected IndexOutOfBoundsException (size-10 bytes)", + format, type, components, width, height, rowlenA1, rowlenA4, rowlenA8), ee); + ee = null; + + // too small size/4 ! + try { + ByteBuffer bb = Buffers.newDirectByteBuffer(height*rowlenA1/4); + gl.glReadPixels(0, 0, width, height, format, type, bb); + Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError()); + } catch(IndexOutOfBoundsException e) { + ee = e; + System.err.println( + exceptionMsg("OK Expected IndexOutOfBoundsException (size/4 bytes)", + format, type, components, width, height, rowlenA1, rowlenA4, rowlenA8)+ + ": "+ee.getMessage()); + expectedExceptions++; + } + Assert.assertNotNull( + exceptionMsg("Expected IndexOutOfBoundsException (size/4 bytes)", + format, type, components, width, height, rowlenA1, rowlenA4, rowlenA8), ee); + ee = null; + + // + // Alignment test + // + psm.setPackAlignment(gl, 4); + + // ok size ! + try { + ByteBuffer bb = Buffers.newDirectByteBuffer(height*rowlenA4); + gl.glReadPixels(0, 0, width, height, format, type, bb); + Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError()); + } catch(IndexOutOfBoundsException e) { + ee = e; + } + Assert.assertNull( + exceptionMsg("Unexpected IndexOutOfBoundsException (size ok, alignment 4)", + format, type, components, width, height, rowlenA1, rowlenA4, rowlenA8), ee); + ee = null; + + // too small if rowlenA1%4 > 0 + try { + ByteBuffer bb = Buffers.newDirectByteBuffer(height*rowlenA1); + gl.glReadPixels(0, 0, width, height, format, type, bb); + Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError()); + } catch(IndexOutOfBoundsException e) { + ee = e; + if(rowlenA1%4>0) { + System.err.println( + exceptionMsg("OK Expected IndexOutOfBoundsException (alignment 4)", + format, type, components, width, height, rowlenA1, rowlenA4, rowlenA8)+ + ": "+ee.getMessage()); + expectedExceptions++; + } + } + if(rowlenA1%4>0) { + Assert.assertNotNull( + exceptionMsg("Expected IndexOutOfBoundsException (alignment 4)", + format, type, components, width, height, rowlenA1, rowlenA4, rowlenA8), ee); + } else { + Assert.assertNull( + exceptionMsg("Unexpected IndexOutOfBoundsException (alignment 4)", + format, type, components, width, height, rowlenA1, rowlenA4, rowlenA8), ee); + } + ee = null; + + psm.setPackAlignment(gl, 8); + + // ok size ! + try { + ByteBuffer bb = Buffers.newDirectByteBuffer(height*rowlenA8); + gl.glReadPixels(0, 0, width, height, format, type, bb); + Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError()); + } catch(IndexOutOfBoundsException e) { + ee = e; + } + Assert.assertNull( + exceptionMsg("Unexpected IndexOutOfBoundsException (size ok, alignment 8)", + format, type, components, width, height, rowlenA1, rowlenA4, rowlenA8), ee); + ee = null; + + // too small if rowlenA1%8 > 0 + try { + ByteBuffer bb = Buffers.newDirectByteBuffer(height*rowlenA1); + gl.glReadPixels(0, 0, width, height, format, type, bb); + Assert.assertEquals(GL.GL_NO_ERROR, gl.glGetError()); + } catch(IndexOutOfBoundsException e) { + ee = e; + if(rowlenA1%8>0) { + System.err.println( + exceptionMsg("OK Expected IndexOutOfBoundsException (alignment 8)", + format, type, components, width, height, rowlenA1, rowlenA4, rowlenA8)+ + ": "+ee.getMessage()); + expectedExceptions++; + } + } + if(rowlenA1%8>0) { + Assert.assertNotNull( + exceptionMsg("Expected IndexOutOfBoundsException (alignment 8)", + format, type, components, width, height, rowlenA1, rowlenA4, rowlenA8), ee); + } else { + Assert.assertNull( + exceptionMsg("Unexpected IndexOutOfBoundsException (alignment 8)", + format, type, components, width, height, rowlenA1, rowlenA4, rowlenA8), ee); + } + ee = null; + + psm.restore(gl); + + return expectedExceptions; + } + + @Test + public void testReadPixels_640x480xREDxUB() throws InterruptedException { + final int width = 640; + final int height= 480; + + // preset .. + final NEWTGLContext.WindowContext winctx = createCurrentGLOffscreenWindow(width, height); + final GLDrawable drawable = winctx.context.getGLDrawable(); + final GL2GL3 gl = winctx.context.getGL().getGL2GL3(); + + // 2 x too small - 0 x alignment + Assert.assertEquals(2, readPixelsCheck(gl, GL2GL3.GL_RED, GL.GL_UNSIGNED_BYTE, 1, width, height)); + + drawable.swapBuffers(); + Thread.sleep(50); + + NEWTGLContext.destroyWindow(winctx); + } + + @Test + public void testReadPixels_640x480xRGBxUB() throws InterruptedException { + final int width = 640; + final int height= 480; + + // preset .. + final NEWTGLContext.WindowContext winctx = createCurrentGLOffscreenWindow(width, height); + final GLDrawable drawable = winctx.context.getGLDrawable(); + final GL2GL3 gl = winctx.context.getGL().getGL2GL3(); + + // 2 x too small - 0 x alignment + Assert.assertEquals(2, readPixelsCheck(gl, GL2GL3.GL_RGB, GL.GL_UNSIGNED_BYTE, 3, width, height)); + + drawable.swapBuffers(); + Thread.sleep(50); + + NEWTGLContext.destroyWindow(winctx); + } + + @Test + public void testReadPixels_102x100xREDxUB() throws InterruptedException { + int wwidth = 640; + int wheight= 480; + int rwidth = 102; + int rheight= 100; + + // preset .. + final NEWTGLContext.WindowContext winctx = createCurrentGLOffscreenWindow(wwidth, wheight); + final GLDrawable drawable = winctx.context.getGLDrawable(); + final GL2GL3 gl = winctx.context.getGL().getGL2GL3(); + + // 2 x too small - 2 x alignment + Assert.assertEquals(4, readPixelsCheck(gl, GL2GL3.GL_RED, GL.GL_UNSIGNED_BYTE, 1, rwidth, rheight)); + + drawable.swapBuffers(); + Thread.sleep(50); + + NEWTGLContext.destroyWindow(winctx); + } + + @Test + public void testReadPixels_102x100xRGBxUB() throws InterruptedException { + final int wwidth = 640; + final int wheight= 480; + final int rwidth = 102; + final int rheight= 100; + + // preset .. + final NEWTGLContext.WindowContext winctx = createCurrentGLOffscreenWindow(wwidth, wheight); + final GLDrawable drawable = winctx.context.getGLDrawable(); + final GL2GL3 gl = winctx.context.getGL().getGL2GL3(); + + // 2 x too small - 2 x alignment + Assert.assertEquals(4, readPixelsCheck(gl, GL2GL3.GL_RGB, GL.GL_UNSIGNED_BYTE, 3, rwidth, rheight)); + + drawable.swapBuffers(); + Thread.sleep(50); + + NEWTGLContext.destroyWindow(winctx); + } + + public static void main(String args[]) throws IOException { + String tstname = TestGPUMemSec01NEWT.class.getName(); + org.junit.runner.JUnitCore.main(tstname); + } +} + |