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/jogl/classes/com/jogamp/opengl/util | |
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/jogl/classes/com/jogamp/opengl/util')
-rw-r--r-- | src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java | 412 |
1 files changed, 391 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 // |