From: <sp...@us...> - 2010-09-30 17:21:59
|
Revision: 3419 http://java-game-lib.svn.sourceforge.net/java-game-lib/?rev=3419&view=rev Author: spasi Date: 2010-09-30 17:21:50 +0000 (Thu, 30 Sep 2010) Log Message: ----------- Misc GL/CL fixes and additions. Made native calls package private, we can now use them from the high-level API. Added support for "render-to-texture" in the fractal demo. Modified Paths: -------------- trunk/LWJGL/src/java/org/lwjgl/BufferChecks.java trunk/LWJGL/src/java/org/lwjgl/LWJGLUtil.java trunk/LWJGL/src/java/org/lwjgl/PointerWrapperAbstract.java trunk/LWJGL/src/java/org/lwjgl/opencl/APIUtil.java trunk/LWJGL/src/java/org/lwjgl/opencl/CLChecks.java trunk/LWJGL/src/java/org/lwjgl/opencl/CLContext.java trunk/LWJGL/src/java/org/lwjgl/opencl/CLMem.java trunk/LWJGL/src/java/org/lwjgl/opencl/CLProgram.java trunk/LWJGL/src/java/org/lwjgl/opencl/InfoUtilAbstract.java trunk/LWJGL/src/java/org/lwjgl/opencl/InfoUtilFactory.java trunk/LWJGL/src/java/org/lwjgl/opencl/Util.java trunk/LWJGL/src/java/org/lwjgl/test/opencl/gl/DemoFractal.java trunk/LWJGL/src/java/org/lwjgl/test/opencl/gl/Mandelbrot.cl trunk/LWJGL/src/java/org/lwjgl/util/generator/JavaMethodsGenerator.java trunk/LWJGL/src/templates/org/lwjgl/opengl/EXT_direct_state_access.java trunk/LWJGL/src/templates/org/lwjgl/opengl/GL40.java trunk/LWJGL/src/templates/org/lwjgl/opengl/NV_half_float.java Added Paths: ----------- trunk/LWJGL/src/java/org/lwjgl/opencl/api/CLBufferRegion.java trunk/LWJGL/src/java/org/lwjgl/opencl/api/CLImageFormat.java Modified: trunk/LWJGL/src/java/org/lwjgl/BufferChecks.java =================================================================== --- trunk/LWJGL/src/java/org/lwjgl/BufferChecks.java 2010-09-28 21:11:35 UTC (rev 3418) +++ trunk/LWJGL/src/java/org/lwjgl/BufferChecks.java 2010-09-30 17:21:50 UTC (rev 3419) @@ -31,13 +31,7 @@ */ package org.lwjgl; -import java.nio.Buffer; -import java.nio.ByteBuffer; -import java.nio.DoubleBuffer; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.nio.ShortBuffer; -import java.nio.LongBuffer; +import java.nio.*; /** * <p>A class to check buffer boundaries in general. If there is unsufficient space @@ -89,21 +83,21 @@ /** Helper method to ensure an IntBuffer is null-terminated */ public static void checkNullTerminated(IntBuffer buf) { - if ( buf.get(buf.limit() - 1) != 0 ) { + if ( LWJGLUtil.CHECKS && buf.get(buf.limit() - 1) != 0 ) { throw new IllegalArgumentException("Missing null termination"); } } /** Helper method to ensure a LongBuffer is null-terminated */ public static void checkNullTerminated(LongBuffer buf) { - if ( buf.get(buf.limit() - 1) != 0 ) { + if ( LWJGLUtil.CHECKS && buf.get(buf.limit() - 1) != 0 ) { throw new IllegalArgumentException("Missing null termination"); } } /** Helper method to ensure a PointerBuffer is null-terminated */ public static void checkNullTerminated(PointerBuffer buf) { - if ( buf.get(buf.limit() - 1) != 0 ) { + if ( LWJGLUtil.CHECKS && buf.get(buf.limit() - 1) != 0 ) { throw new IllegalArgumentException("Missing null termination"); } } @@ -196,6 +190,41 @@ } } + /** + * Detects the buffer type and performs the corresponding check + * and also returns the buffer position in bytes. + * + * @param buffer the buffer to check + * @param size the size to check + * + * @return the buffer position in bytes + */ + public static int checkBuffer(final Buffer buffer, final int size) { + final int posShift; + if ( buffer instanceof ByteBuffer ) { + BufferChecks.checkBuffer((ByteBuffer)buffer, size); + posShift = 0; + } else if ( buffer instanceof ShortBuffer ) { + BufferChecks.checkBuffer((ShortBuffer)buffer, size); + posShift = 1; + } else if ( buffer instanceof IntBuffer ) { + BufferChecks.checkBuffer((IntBuffer)buffer, size); + posShift = 2; + } else if ( buffer instanceof LongBuffer ) { + BufferChecks.checkBuffer((LongBuffer)buffer, size); + posShift = 4; + } else if ( buffer instanceof FloatBuffer ) { + BufferChecks.checkBuffer((FloatBuffer)buffer, size); + posShift = 2; + } else if ( buffer instanceof DoubleBuffer ) { + BufferChecks.checkBuffer((DoubleBuffer)buffer, size); + posShift = 4; + } else + throw new IllegalArgumentException("Unsupported Buffer type specified: " + buffer.getClass()); + + return buffer.position() << posShift; + } + public static void checkBuffer(ByteBuffer buf, int size) { if ( LWJGLUtil.CHECKS ) { checkBufferSize(buf, size); Modified: trunk/LWJGL/src/java/org/lwjgl/LWJGLUtil.java =================================================================== --- trunk/LWJGL/src/java/org/lwjgl/LWJGLUtil.java 2010-09-28 21:11:35 UTC (rev 3418) +++ trunk/LWJGL/src/java/org/lwjgl/LWJGLUtil.java 2010-09-30 17:21:50 UTC (rev 3419) @@ -32,17 +32,16 @@ package org.lwjgl; import java.io.File; +import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.nio.ByteBuffer; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; -import java.util.ArrayList; -import java.util.List; -import java.util.StringTokenizer; +import java.util.*; - /** * <p> * Internal library methods @@ -488,4 +487,92 @@ return major > major_required || (major == major_required && minor >= minor_required); } -} + /** + * Returns a map of public static final integer fields in the specified classes, to their String representations. + * An optional filter can be specified to only include specific fields. The target map may be null, in which + * case a new map is allocated and returned. + * <p> + * This method is useful when debugging to quickly identify values returned from the AL/GL/CL APIs. + * + * @param filter the filter to use (optional) + * @param target the target map (optional) + * @param tokenClasses an array of classes to get tokens from + * + * @return the token map + */ + + public static Map<Integer, String> getClassTokens(final TokenFilter filter, final Map<Integer, String> target, final Class ... tokenClasses) { + return getClassTokens(filter, target, Arrays.asList(tokenClasses)); + } + + /** + * Returns a map of public static final integer fields in the specified classes, to their String representations. + * An optional filter can be specified to only include specific fields. The target map may be null, in which + * case a new map is allocated and returned. + * <p> + * This method is useful when debugging to quickly identify values returned from the AL/GL/CL APIs. + * + * @param filter the filter to use (optional) + * @param target the target map (optional) + * @param tokenClasses the classes to get tokens from + * + * @return the token map + */ + public static Map<Integer, String> getClassTokens(final TokenFilter filter, Map<Integer, String> target, final Iterable<Class> tokenClasses) { + if ( target == null ) + target = new HashMap<Integer, String>(); + + final int TOKEN_MODIFIERS = Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL; + + for ( final Class tokenClass : tokenClasses ) { + for ( final Field field : tokenClass.getDeclaredFields() ) { + // Get only <public static final int> fields. + if ( (field.getModifiers() & TOKEN_MODIFIERS) == TOKEN_MODIFIERS && field.getType() == int.class ) { + try { + final int value = field.getInt(null); + if ( filter != null && !filter.accept(field, value) ) + continue; + + if ( target.containsKey(value) ) // Print colliding tokens in their hex representation. + target.put(value, toHexString(value)); + else + target.put(value, field.getName()); + } catch (IllegalAccessException e) { + // Ignore + } + } + } + } + + return target; + } + + /** + * Returns a string representation of the integer argument as an + * unsigned integer in base 16. The string will be uppercase + * and will have a leading '0x'. + * + * @param value the integer value + * + * @return the hex string representation + */ + public static String toHexString(final int value) { + return "0x" + Integer.toHexString(value).toUpperCase(); + } + + /** Simple interface for Field filtering. */ + public interface TokenFilter { + + /** + * Should return true if the specified Field passes the filter. + * + * @param field the Field to test + * @param value the integer value of the field + * + * @result true if the Field is accepted + */ + boolean accept(Field field, int value); + + } + +} \ No newline at end of file Modified: trunk/LWJGL/src/java/org/lwjgl/PointerWrapperAbstract.java =================================================================== --- trunk/LWJGL/src/java/org/lwjgl/PointerWrapperAbstract.java 2010-09-28 21:11:35 UTC (rev 3418) +++ trunk/LWJGL/src/java/org/lwjgl/PointerWrapperAbstract.java 2010-09-30 17:21:50 UTC (rev 3419) @@ -63,7 +63,7 @@ */ public final void checkValid() { if ( LWJGLUtil.DEBUG && !isValid() ) - throw new IllegalStateException("This pointer is not valid."); + throw new IllegalStateException("This " + getClass().getSimpleName() + " pointer is not valid."); } public final long getPointer() { Modified: trunk/LWJGL/src/java/org/lwjgl/opencl/APIUtil.java =================================================================== --- trunk/LWJGL/src/java/org/lwjgl/opencl/APIUtil.java 2010-09-28 21:11:35 UTC (rev 3418) +++ trunk/LWJGL/src/java/org/lwjgl/opencl/APIUtil.java 2010-09-30 17:21:50 UTC (rev 3419) @@ -35,18 +35,15 @@ import org.lwjgl.LWJGLUtil; import org.lwjgl.PointerBuffer; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; import java.nio.*; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; -import java.util.*; +import java.util.HashSet; +import java.util.Set; +import java.util.StringTokenizer; -import static org.lwjgl.opencl.CL10.*; - /** * Utility class for OpenCL API calls. - * TODO: Remove useless stuff * * @author spasi */ @@ -356,38 +353,6 @@ return (int)size; } - static String toHexString(final int value) { - return "0x" + Integer.toHexString(value).toUpperCase(); - } - - static void getClassTokens(final Class[] tokenClasses, final Map<Integer, String> target, final TokenFilter filter) { - getClassTokens(Arrays.asList(tokenClasses), target, filter); - } - - static void getClassTokens(final Iterable<Class> tokenClasses, final Map<Integer, String> target, final TokenFilter filter) { - final int TOKEN_MODIFIERS = Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL; - - for ( final Class tokenClass : tokenClasses ) { - for ( final Field field : tokenClass.getDeclaredFields() ) { - // Get only <public static final int> fields. - if ( (field.getModifiers() & TOKEN_MODIFIERS) == TOKEN_MODIFIERS && field.getType() == int.class ) { - try { - final int value = field.getInt(null); - if ( filter != null && !filter.accept(field, value) ) - continue; - - if ( target.containsKey(value) ) // Print colliding tokens in their hex representation. - target.put(value, toHexString(value)); - else - target.put(value, field.getName()); - } catch (IllegalAccessException e) { - // Ignore - } - } - } - } - } - /** * A mutable CharSequence with very large initial length. We can wrap this in a re-usable CharBuffer for decoding. * We cannot subclass CharBuffer because of {@link java.nio.CharBuffer#toString(int,int)}. @@ -451,14 +416,6 @@ } - /** Simple interface for Field filtering */ - interface TokenFilter { - - /** Should return true if the specified Field passes the filter. */ - boolean accept(Field field, int value); - - } - /* ------------------------------------------------------------------------ --------------------------------------------------------------------------- OPENCL API UTILITIES BELOW Modified: trunk/LWJGL/src/java/org/lwjgl/opencl/CLChecks.java =================================================================== --- trunk/LWJGL/src/java/org/lwjgl/opencl/CLChecks.java 2010-09-28 21:11:35 UTC (rev 3418) +++ trunk/LWJGL/src/java/org/lwjgl/opencl/CLChecks.java 2010-09-30 17:21:50 UTC (rev 3419) @@ -68,24 +68,24 @@ final long y = origin.get(1); final long z = origin.get(2); - if ( x < 0 || y < 0 || z < 0 ) + if ( LWJGLUtil.DEBUG && (x < 0 || y < 0 || z < 0) ) throw new IllegalArgumentException("Invalid cl_mem host origin: " + x + ", " + y + ", " + z); final long w = region.get(0); final long h = region.get(1); final long d = region.get(2); - if ( w < 1 || h < 1 || d < 1 ) + if ( LWJGLUtil.DEBUG && (w < 1 || h < 1 || d < 1) ) throw new IllegalArgumentException("Invalid cl_mem rectangle region dimensions: " + w + " x " + h + " x " + d); if ( row_pitch == 0 ) row_pitch = w; - else if ( row_pitch < w ) + else if ( LWJGLUtil.DEBUG && row_pitch < w ) throw new IllegalArgumentException("Invalid host row pitch specified: " + row_pitch); if ( slice_pitch == 0 ) slice_pitch = row_pitch * h; - else if ( slice_pitch < (row_pitch * h) ) + else if ( LWJGLUtil.DEBUG && slice_pitch < (row_pitch * h) ) throw new IllegalArgumentException("Invalid host slice pitch specified: " + slice_pitch); return (int)((z * slice_pitch + y * row_pitch + x) + (w * h * d)); @@ -110,17 +110,17 @@ final long h = region.get(1); final long d = region.get(2); - if ( w < 1 || h < 1 || d < 1 ) + if ( LWJGLUtil.DEBUG && (w < 1 || h < 1 || d < 1) ) throw new IllegalArgumentException("Invalid cl_mem image region dimensions: " + w + " x " + h + " x " + d); if ( row_pitch == 0 ) row_pitch = w; - else if ( row_pitch < w ) + else if ( LWJGLUtil.DEBUG && row_pitch < w ) throw new IllegalArgumentException("Invalid row pitch specified: " + row_pitch); if ( slice_pitch == 0 ) slice_pitch = row_pitch * h; - else if ( slice_pitch < (row_pitch * h) ) + else if ( LWJGLUtil.DEBUG && slice_pitch < (row_pitch * h) ) throw new IllegalArgumentException("Invalid slice pitch specified: " + slice_pitch); return (int)(slice_pitch * d); @@ -138,14 +138,17 @@ * @return the 2D image size in bytes */ static int calculateImage2DSize(final ByteBuffer format, final long w, final long h, long row_pitch) { - if ( LWJGLUtil.CHECKS && (w < 1 || h < 1) ) + if ( !LWJGLUtil.CHECKS ) + return 0; + + if ( LWJGLUtil.DEBUG && (w < 1 || h < 1) ) throw new IllegalArgumentException("Invalid 2D image dimensions: " + w + " x " + h); final int elementSize = getElementSize(format); if ( row_pitch == 0 ) row_pitch = w * elementSize; - else if ( LWJGLUtil.CHECKS && ((row_pitch < w * elementSize) || (row_pitch % elementSize != 0)) ) + else if ( LWJGLUtil.DEBUG && ((row_pitch < w * elementSize) || (row_pitch % elementSize != 0)) ) throw new IllegalArgumentException("Invalid image_row_pitch specified: " + row_pitch); return (int)(row_pitch * h); @@ -164,19 +167,22 @@ * @return the 3D image size in bytes */ static int calculateImage3DSize(final ByteBuffer format, final long w, final long h, final long d, long row_pitch, long slice_pitch) { - if ( LWJGLUtil.CHECKS && (w < 1 || h < 1 || d < 2) ) + if ( !LWJGLUtil.CHECKS ) + return 0; + + if ( LWJGLUtil.DEBUG && (w < 1 || h < 1 || d < 2) ) throw new IllegalArgumentException("Invalid 3D image dimensions: " + w + " x " + h + " x " + d); final int elementSize = getElementSize(format); if ( row_pitch == 0 ) row_pitch = w * elementSize; - else if ( LWJGLUtil.CHECKS && ((row_pitch < w * elementSize) || (row_pitch % elementSize != 0)) ) + else if ( LWJGLUtil.DEBUG && ((row_pitch < w * elementSize) || (row_pitch % elementSize != 0)) ) throw new IllegalArgumentException("Invalid image_row_pitch specified: " + row_pitch); if ( slice_pitch == 0 ) slice_pitch = row_pitch * h; - else if ( LWJGLUtil.CHECKS && ((row_pitch < row_pitch * h) || (slice_pitch % row_pitch != 0)) ) + else if ( LWJGLUtil.DEBUG && ((row_pitch < row_pitch * h) || (slice_pitch % row_pitch != 0)) ) throw new IllegalArgumentException("Invalid image_slice_pitch specified: " + row_pitch); return (int)(slice_pitch * d); @@ -223,7 +229,7 @@ case CL_ARGB: return 4; default: - throw new IllegalArgumentException("Invalid cl_channel_order specified: " + APIUtil.toHexString(channelOrder)); + throw new IllegalArgumentException("Invalid cl_channel_order specified: " + LWJGLUtil.toHexString(channelOrder)); } } @@ -255,7 +261,7 @@ case CL_FLOAT: return 4; default: - throw new IllegalArgumentException("Invalid cl_channel_type specified: " + APIUtil.toHexString(channelType)); + throw new IllegalArgumentException("Invalid cl_channel_type specified: " + LWJGLUtil.toHexString(channelType)); } } Modified: trunk/LWJGL/src/java/org/lwjgl/opencl/CLContext.java =================================================================== --- trunk/LWJGL/src/java/org/lwjgl/opencl/CLContext.java 2010-09-28 21:11:35 UTC (rev 3418) +++ trunk/LWJGL/src/java/org/lwjgl/opencl/CLContext.java 2010-09-30 17:21:50 UTC (rev 3419) @@ -31,6 +31,12 @@ */ package org.lwjgl.opencl; +import org.lwjgl.LWJGLException; +import org.lwjgl.opencl.api.CLImageFormat; +import org.lwjgl.opencl.api.Filter; +import org.lwjgl.opengl.Drawable; + +import java.nio.IntBuffer; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -125,6 +131,100 @@ // ---------------[ UTILITY METHODS ]--------------- /** + * Creates a new CLContext. + * + * @param platform the platform to use + * @param devices the devices to use + * @param errcode_ret the error code result + * + * @return the new CLContext + * + * @throws LWJGLException if an exception occurs while creating the context + */ + public static CLContext create(final CLPlatform platform, final List<CLDevice> devices, final IntBuffer errcode_ret) throws LWJGLException { + return create(platform, devices, null, null, errcode_ret); + } + + /** + * Creates a new CLContext. + * + * @param platform the platform to use + * @param devices the devices to use + * @param pfn_notify the context callback function + * @param errcode_ret the error code result + * + * @return the new CLContext + * + * @throws LWJGLException if an exception occurs while creating the context + */ + public static CLContext create(final CLPlatform platform, final List<CLDevice> devices, final CLContextCallback pfn_notify, final IntBuffer errcode_ret) throws LWJGLException { + return create(platform, devices, pfn_notify, null, errcode_ret); + } + + /** + * Creates a new CLContext. + * + * @param platform the platform to use + * @param devices the devices to use + * @param share_drawable the OpenGL drawable to share objects with + * @param errcode_ret the error code result + * + * @return the new CLContext + * + * @throws LWJGLException if an exception occurs while creating the context + */ + public static CLContext create(final CLPlatform platform, final List<CLDevice> devices, final CLContextCallback pfn_notify, final Drawable share_drawable, final IntBuffer errcode_ret) throws LWJGLException { + return util.create(platform, devices, pfn_notify, share_drawable, errcode_ret); + } + + /** + * Creates a new CLContext. + * + * @param platform the platform to use + * @param device_type the device type to use + * @param errcode_ret the error code result + * + * @return the new CLContext + * + * @throws LWJGLException if an exception occurs while creating the context + */ + public static CLContext createFromType(final CLPlatform platform, final long device_type, final IntBuffer errcode_ret) throws LWJGLException { + return util.createFromType(platform, device_type, null, null, errcode_ret); + } + + /** + * Creates a new CLContext. + * + * @param platform the platform to use + * @param device_type the device type to use + * @param pfn_notify the context callback function + * @param errcode_ret the error code result + * + * @return the new CLContext + * + * @throws LWJGLException if an exception occurs while creating the context + */ + public static CLContext createFromType(final CLPlatform platform, final long device_type, final CLContextCallback pfn_notify, final IntBuffer errcode_ret) throws LWJGLException { + return util.createFromType(platform, device_type, pfn_notify, null, errcode_ret); + } + + /** + * Creates a new CLContext. + * + * @param platform the platform to use + * @param device_type the device type to use + * @param share_drawable the OpenGL drawable to share objects with + * @param errcode_ret the error code result + * + * @return the new CLContext + * + * @throws LWJGLException if an exception occurs while creating the context + */ + public static CLContext createFromType(final CLPlatform platform, final long device_type, final CLContextCallback pfn_notify, final Drawable share_drawable, final IntBuffer errcode_ret) throws LWJGLException { + return util.createFromType(platform, device_type, pfn_notify, share_drawable, errcode_ret); + } + + /** * Returns the integer value of the specified parameter. * * @param param_name the parameter @@ -144,11 +244,25 @@ return util.getInfoDevices(this); } + public List<CLImageFormat> getSupportedImageFormats(final long flags, final int image_type) { + return getSupportedImageFormats(flags, image_type, null); + } + + public List<CLImageFormat> getSupportedImageFormats(final long flags, final int image_type, final Filter<CLImageFormat> filter) { + return util.getSupportedImageFormats(this, flags, image_type, filter); + } + /** CLContext utility methods interface. */ interface CLContextUtil extends InfoUtil<CLContext> { List<CLDevice> getInfoDevices(CLContext context); + CLContext create(CLPlatform platform, List<CLDevice> devices, CLContextCallback pfn_notify, Drawable share_drawable, IntBuffer errcode_ret) throws LWJGLException; + + CLContext createFromType(CLPlatform platform, long device_type, CLContextCallback pfn_notify, Drawable share_drawable, IntBuffer errcode_ret) throws LWJGLException; + + List<CLImageFormat> getSupportedImageFormats(CLContext context, final long flags, final int image_type, Filter<CLImageFormat> filter); + } // -------[ IMPLEMENTATION STUFF BELOW ]------- Modified: trunk/LWJGL/src/java/org/lwjgl/opencl/CLMem.java =================================================================== --- trunk/LWJGL/src/java/org/lwjgl/opencl/CLMem.java 2010-09-28 21:11:35 UTC (rev 3418) +++ trunk/LWJGL/src/java/org/lwjgl/opencl/CLMem.java 2010-09-30 17:21:50 UTC (rev 3419) @@ -31,7 +31,12 @@ */ package org.lwjgl.opencl; +import org.lwjgl.opencl.api.CLBufferRegion; +import org.lwjgl.opencl.api.CLImageFormat; + +import java.nio.Buffer; import java.nio.ByteBuffer; +import java.nio.IntBuffer; /** * This class is a wrapper around a cl_mem pointer. @@ -51,6 +56,52 @@ // ---------------[ UTILITY METHODS ]--------------- /** + * Creates a new 2D image object. + * + * @param context the context on which to create the image object + * @param flags the memory object flags + * @param image_format the image format + * @param image_width the image width + * @param image_height the image height + * @param image_row_pitch the image row pitch + * @param host_ptr the host buffer from which to read image data (optional) + * @param errcode_ret the error code result + * + * @return the new CLMem object + */ + public static CLMem createImage2D(final CLContext context, final long flags, final CLImageFormat image_format, + final long image_width, final long image_height, final long image_row_pitch, + final Buffer host_ptr, final IntBuffer errcode_ret) { + return util.createImage2D(context, flags, image_format, image_width, image_height, image_row_pitch, host_ptr, errcode_ret); + } + + /** + * Creates a new 3D image object. + * + * @param context the context on which to create the image object + * @param flags the memory object flags + * @param image_format the image format + * @param image_width the image width + * @param image_height the image height + * @param image_depth the image depth + * @param image_row_pitch the image row pitch + * @param image_slice_pitch the image slice pitch + * @param host_ptr the host buffer from which to read image data (optional) + * @param errcode_ret the error code result + * + * @return the new CLMem object + */ + public static CLMem createImage3D(final CLContext context, final long flags, final CLImageFormat image_format, + final long image_width, final long image_height, final long image_depth, final long image_row_pitch, final long image_slice_pitch, + final Buffer host_ptr, final IntBuffer errcode_ret) { + return util.createImage3D(context, flags, image_format, image_width, image_height, image_depth, image_row_pitch, image_slice_pitch, host_ptr, errcode_ret); + } + + public CLMem createSubBuffer(final long flags, final int buffer_create_type, final CLBufferRegion buffer_create_info, final IntBuffer errcode_ret) { + return util.createSubBuffer(this, flags, buffer_create_type, buffer_create_info, errcode_ret); + } + + /** * Returns the integer value of the specified parameter. * * @param param_name the parameter @@ -109,6 +160,15 @@ } /** + * Returns the image format. Applicable to image objects only. + * + * @return the parameter value + */ + public CLImageFormat getImageFormat() { + return util.getImageInfoFormat(this); + } + + /** * Returns the image channel order. Applicable to image objects only. * * @return the parameter value @@ -165,10 +225,18 @@ /** CLMem utility methods interface. */ interface CLMemUtil extends InfoUtil<CLMem> { + CLMem createImage2D(CLContext context, long flags, CLImageFormat image_format, long image_width, long image_height, long image_row_pitch, Buffer host_ptr, IntBuffer errcode_ret); + + CLMem createImage3D(CLContext context, long flags, CLImageFormat image_format, long image_width, long image_height, long image_depth, long image_row_pitch, long image_slice_pitch, Buffer host_ptr, IntBuffer errcode_ret); + + CLMem createSubBuffer(CLMem mem, long flags, int buffer_create_type, CLBufferRegion buffer_create_info, IntBuffer errcode_ret); + ByteBuffer getInfoHostBuffer(CLMem mem); long getImageInfoSize(CLMem mem, int param_name); + CLImageFormat getImageInfoFormat(CLMem mem); + int getImageInfoFormat(CLMem mem, int index); int getGLObjectType(CLMem mem); Modified: trunk/LWJGL/src/java/org/lwjgl/opencl/CLProgram.java =================================================================== --- trunk/LWJGL/src/java/org/lwjgl/opencl/CLProgram.java 2010-09-28 21:11:35 UTC (rev 3418) +++ trunk/LWJGL/src/java/org/lwjgl/opencl/CLProgram.java 2010-09-30 17:21:50 UTC (rev 3419) @@ -70,6 +70,15 @@ // ---------------[ UTILITY METHODS ]--------------- /** + * Creates kernel objects for all kernels functions in this program. + * + * @return a CLKernel array + */ + public CLKernel[] createKernelsInProgram() { + return util.createKernelsInProgram(this); + } + + /** * Returns the String value of the specified parameter. * * @param param_name the parameter @@ -168,6 +177,8 @@ /** CLProgram utility methods interface. */ interface CLProgramUtil extends InfoUtil<CLProgram> { + CLKernel[] createKernelsInProgram(CLProgram program); + CLDevice[] getInfoDevices(CLProgram program); ByteBuffer getInfoBinaries(CLProgram program, ByteBuffer target); Modified: trunk/LWJGL/src/java/org/lwjgl/opencl/InfoUtilAbstract.java =================================================================== --- trunk/LWJGL/src/java/org/lwjgl/opencl/InfoUtilAbstract.java 2010-09-28 21:11:35 UTC (rev 3418) +++ trunk/LWJGL/src/java/org/lwjgl/opencl/InfoUtilAbstract.java 2010-09-30 17:21:50 UTC (rev 3419) @@ -31,6 +31,7 @@ */ package org.lwjgl.opencl; +import org.lwjgl.LWJGLUtil; import org.lwjgl.PointerBuffer; import java.nio.ByteBuffer; @@ -112,8 +113,8 @@ object.checkValid(); final int bytes = getSizeRet(object, param_name); - if ( bytes == 0 ) - return ""; + if ( bytes <= 1 ) + return null; final ByteBuffer buffer = APIUtil.getBufferByte(bytes); getInfo(object, param_name, buffer, null); @@ -126,7 +127,7 @@ final PointerBuffer bytes = APIUtil.getBufferPointer(); final int errcode = getInfo(object, param_name, null, bytes); if ( errcode != CL_SUCCESS ) - throw new IllegalArgumentException("Invalid parameter specified: " + APIUtil.toHexString(param_name)); + throw new IllegalArgumentException("Invalid parameter specified: " + LWJGLUtil.toHexString(param_name)); return (int)bytes.get(0); } Modified: trunk/LWJGL/src/java/org/lwjgl/opencl/InfoUtilFactory.java =================================================================== --- trunk/LWJGL/src/java/org/lwjgl/opencl/InfoUtilFactory.java 2010-09-28 21:11:35 UTC (rev 3418) +++ trunk/LWJGL/src/java/org/lwjgl/opencl/InfoUtilFactory.java 2010-09-30 17:21:50 UTC (rev 3419) @@ -32,8 +32,12 @@ package org.lwjgl.opencl; import org.lwjgl.*; +import org.lwjgl.opencl.api.CLBufferRegion; +import org.lwjgl.opencl.api.CLImageFormat; import org.lwjgl.opencl.api.Filter; +import org.lwjgl.opengl.Drawable; +import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.util.ArrayList; @@ -49,7 +53,6 @@ * so that they can be compiled for the generator. * * @author Spasi - * @since 28 \xD3\xE5\xF0 2010 */ final class InfoUtilFactory { @@ -92,6 +95,70 @@ } + /** Custom clCreateContext implementation (reuses APIUtil.getBufferPointer) */ + public CLContext create(final CLPlatform platform, final List<CLDevice> devices, final CLContextCallback pfn_notify, final Drawable share_drawable, final IntBuffer errcode_ret) throws LWJGLException { + final int propertyCount = 2 + (share_drawable == null ? 0 : 4) + 1; + + final PointerBuffer buffer = APIUtil.getBufferPointer(propertyCount + devices.size()); + buffer.put(CL_CONTEXT_PLATFORM).put(platform); + if ( share_drawable != null ) + share_drawable.setCLSharingProperties(buffer); + buffer.put(0); + + buffer.position(propertyCount); // Make sure we're at the right offset, setCLSharingProperties might not use all 4 positions. + for ( CLDevice device : devices ) + buffer.put(device); + + final long function_pointer = CLCapabilities.clCreateContext; + BufferChecks.checkFunctionAddress(function_pointer); + final long user_data = pfn_notify == null || pfn_notify.isCustom() ? 0 : CallbackUtil.createGlobalRef(pfn_notify); + CLContext __result = null; + try { + __result = new CLContext(nclCreateContext(buffer.getBuffer(), 0, devices.size(), buffer.getBuffer(), propertyCount * PointerBuffer.getPointerSize(), pfn_notify == null ? 0 : pfn_notify.getPointer(), user_data, errcode_ret, errcode_ret != null ? errcode_ret.position() : 0, function_pointer), platform); + return __result; + } finally { + CallbackUtil.registerCallback(__result, user_data); + } + } + + public CLContext createFromType(final CLPlatform platform, final long device_type, final CLContextCallback pfn_notify, final Drawable share_drawable, final IntBuffer errcode_ret) throws LWJGLException { + final int propertyCount = 2 + (share_drawable == null ? 0 : 4) + 1; + + final PointerBuffer properties = APIUtil.getBufferPointer(propertyCount); + properties.put(CL_CONTEXT_PLATFORM).put(platform); + if ( share_drawable != null ) + share_drawable.setCLSharingProperties(properties); + properties.put(0); + properties.flip(); + + return clCreateContextFromType(properties, device_type, pfn_notify, errcode_ret); + } + + public List<CLImageFormat> getSupportedImageFormats(final CLContext context, final long flags, final int image_type, final Filter<CLImageFormat> filter) { + final IntBuffer numBuffer = APIUtil.getBufferInt(); + clGetSupportedImageFormats(context, flags, image_type, null, numBuffer); + + final int num_image_formats = numBuffer.get(0); + if ( num_image_formats == 0 ) + return null; + + final ByteBuffer formatBuffer = BufferUtils.createByteBuffer(num_image_formats * CLImageFormat.STRUCT_SIZE); + clGetSupportedImageFormats(context, flags, image_type, formatBuffer, null); + + final List<CLImageFormat> formats = new ArrayList<CLImageFormat>(num_image_formats); + for ( int i = 0; i < num_image_formats; i++ ) { + final int offset = num_image_formats * CLImageFormat.STRUCT_SIZE; + final CLImageFormat format = new CLImageFormat( + formatBuffer.getInt(offset), + formatBuffer.getInt(offset + 4) + ); + if ( filter == null || filter.accept(format) ) + formats.add(format); + } + + return formats.size() == 0 ? null : formats; + } + } static final InfoUtil<CLDevice> CL_DEVICE_UTIL = new CLDeviceUtil(); @@ -106,7 +173,7 @@ case CL_DEVICE_MAX_WORK_ITEM_SIZES: return getInfoInt(device, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS); default: - throw new IllegalArgumentException("Unsupported parameter: " + APIUtil.toHexString(param_name)); + throw new IllegalArgumentException("Unsupported parameter: " + LWJGLUtil.toHexString(param_name)); } } @@ -183,7 +250,7 @@ size = 3; break; default: - throw new IllegalArgumentException("Unsupported parameter: " + APIUtil.toHexString(param_name)); + throw new IllegalArgumentException("Unsupported parameter: " + LWJGLUtil.toHexString(param_name)); } final PointerBuffer buffer = APIUtil.getBufferPointer(size); @@ -215,6 +282,44 @@ return clGetMemObjectInfo(mem, param_name, param_value, param_value_size_ret); } + public CLMem createImage2D(final CLContext context, final long flags, final CLImageFormat image_format, final long image_width, final long image_height, final long image_row_pitch, final Buffer host_ptr, final IntBuffer errcode_ret) { + final ByteBuffer formatBuffer = APIUtil.getBufferByte(2 * 4); + formatBuffer.putInt(0, image_format.getChannelOrder()); + formatBuffer.putInt(4, image_format.getChannelType()); + + final long function_pointer = CLCapabilities.clCreateImage2D; + BufferChecks.checkFunctionAddress(function_pointer); + if ( errcode_ret != null ) + BufferChecks.checkBuffer(errcode_ret, 1); + return new CLMem(nclCreateImage2D(context.getPointer(), flags, formatBuffer, 0, image_width, image_height, image_row_pitch, host_ptr, + host_ptr != null ? BufferChecks.checkBuffer(host_ptr, CLChecks.calculateImage2DSize(formatBuffer, image_width, image_height, image_row_pitch)) : 0, + errcode_ret, errcode_ret != null ? errcode_ret.position() : 0, function_pointer), context); + } + + public CLMem createImage3D(final CLContext context, final long flags, final CLImageFormat image_format, final long image_width, final long image_height, final long image_depth, final long image_row_pitch, final long image_slice_pitch, final Buffer host_ptr, final IntBuffer errcode_ret) { + final ByteBuffer formatBuffer = APIUtil.getBufferByte(2 * 4); + formatBuffer.putInt(0, image_format.getChannelOrder()); + formatBuffer.putInt(4, image_format.getChannelType()); + + final long function_pointer = CLCapabilities.clCreateImage3D; + BufferChecks.checkFunctionAddress(function_pointer); + if ( errcode_ret != null ) + BufferChecks.checkBuffer(errcode_ret, 1); + return new CLMem(nclCreateImage3D(context.getPointer(), flags, formatBuffer, 0, image_width, image_height, image_depth, image_row_pitch, image_slice_pitch, host_ptr, + host_ptr != null ? BufferChecks.checkBuffer(host_ptr, CLChecks.calculateImage3DSize(formatBuffer, image_width, image_height, image_depth, image_row_pitch, image_slice_pitch)) : 0, + errcode_ret, errcode_ret != null ? errcode_ret.position() : 0, function_pointer), context); + } + + public CLMem createSubBuffer(final CLMem mem, final long flags, final int buffer_create_type, final CLBufferRegion buffer_create_info, final IntBuffer errcode_ret) { + final PointerBuffer infoBuffer = APIUtil.getBufferPointer(2); + + infoBuffer.put(buffer_create_info.getOrigin()); + infoBuffer.put(buffer_create_info.getSize()); + + return clCreateSubBuffer(mem, flags, buffer_create_type, infoBuffer.getBuffer(), errcode_ret); + + } + public ByteBuffer getInfoHostBuffer(final CLMem mem) { mem.checkValid(); @@ -242,6 +347,16 @@ return buffer.get(0); } + public CLImageFormat getImageInfoFormat(final CLMem mem) { + mem.checkValid(); + + final ByteBuffer format = APIUtil.getBufferByte(2 * 4); + + clGetImageInfo(mem, CL_IMAGE_FORMAT, format, null); + + return new CLImageFormat(format.getInt(0), format.getInt(4)); + } + public int getImageInfoFormat(final CLMem mem, final int index) { mem.checkValid(); @@ -346,10 +461,28 @@ case CL_PROGRAM_BINARY_SIZES: return getInfoInt(program, CL_PROGRAM_NUM_DEVICES); default: - throw new IllegalArgumentException("Unsupported parameter: " + APIUtil.toHexString(param_name)); + throw new IllegalArgumentException("Unsupported parameter: " + LWJGLUtil.toHexString(param_name)); } } + public CLKernel[] createKernelsInProgram(final CLProgram program) { + final IntBuffer numBuffer = APIUtil.getBufferInt(); + clCreateKernelsInProgram(program, null, numBuffer); + + final int num_kernels = numBuffer.get(0); + if ( num_kernels == 0 ) + return null; + + final PointerBuffer kernelIDs = APIUtil.getBufferPointer(num_kernels); + clCreateKernelsInProgram(program, kernelIDs, null); + + final CLKernel[] kernels = new CLKernel[num_kernels]; + for ( int i = 0; i < num_kernels; i++ ) + kernels[i] = program.getCLKernel(kernelIDs.get(i)); + + return kernels; + } + public CLDevice[] getInfoDevices(final CLProgram program) { program.checkValid(); @@ -413,8 +546,8 @@ program.checkValid(); final int bytes = getBuildSizeRet(program, device, param_name); - if ( bytes == 0 ) - throw new IllegalArgumentException("Invalid parameter specified: " + APIUtil.toHexString(param_name)); + if ( bytes <= 1 ) + return null; final ByteBuffer buffer = APIUtil.getBufferByte(bytes); clGetProgramBuildInfo(program, device, param_name, buffer, null); @@ -435,8 +568,10 @@ private static int getBuildSizeRet(final CLProgram program, final CLDevice device, final int param_name) { final PointerBuffer bytes = APIUtil.getBufferPointer(); final int errcode = clGetProgramBuildInfo(program, device, param_name, null, bytes); + if ( errcode != CL_SUCCESS ) + throw new IllegalArgumentException("Invalid parameter specified: " + LWJGLUtil.toHexString(param_name)); - return errcode == CL_SUCCESS ? (int)bytes.get(0) : 0; + return (int)bytes.get(0); } } Modified: trunk/LWJGL/src/java/org/lwjgl/opencl/Util.java =================================================================== --- trunk/LWJGL/src/java/org/lwjgl/opencl/Util.java 2010-09-28 21:11:35 UTC (rev 3418) +++ trunk/LWJGL/src/java/org/lwjgl/opencl/Util.java 2010-09-30 17:21:50 UTC (rev 3419) @@ -31,8 +31,9 @@ */ package org.lwjgl.opencl; +import org.lwjgl.LWJGLUtil; + import java.lang.reflect.Field; -import java.util.HashMap; import java.util.Map; /** @@ -43,21 +44,12 @@ public final class Util { /** Maps OpenCL error token values to their String representations. */ - private static final Map<Integer, String> CL_ERROR_TOKENS = new HashMap<Integer, String>(64); + private static final Map<Integer, String> CL_ERROR_TOKENS = LWJGLUtil.getClassTokens(new LWJGLUtil.TokenFilter() { + public boolean accept(final Field field, final int value) { + return value < 0; // Currently, all OpenCL errors have negative values. + } + }, null, CL10.class, CL11.class, KHRGLSharing.class, KHRICD.class, APPLEGLSharing.class, EXTDeviceFission.class); - static { - APIUtil.getClassTokens(new Class[] { - CL10.class, CL11.class, - KHRGLSharing.class, KHRICD.class, - APPLEGLSharing.class, - EXTDeviceFission.class, - }, CL_ERROR_TOKENS, new APIUtil.TokenFilter() { - public boolean accept(final Field field, final int value) { - return value < 0; // Currently, all OpenCL errors have negative values. - } - }); - } - private Util() { } @@ -70,7 +62,7 @@ String errname = CL_ERROR_TOKENS.get(errcode); if ( errname == null ) errname = "UNKNOWN"; - throw new OpenCLException("Error Code: " + errname + " (" + APIUtil.toHexString(errcode) + ")"); + throw new OpenCLException("Error Code: " + errname + " (" + LWJGLUtil.toHexString(errcode) + ")"); } } \ No newline at end of file Added: trunk/LWJGL/src/java/org/lwjgl/opencl/api/CLBufferRegion.java =================================================================== --- trunk/LWJGL/src/java/org/lwjgl/opencl/api/CLBufferRegion.java (rev 0) +++ trunk/LWJGL/src/java/org/lwjgl/opencl/api/CLBufferRegion.java 2010-09-30 17:21:50 UTC (rev 3419) @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2002-2010 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT OWNER 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. + */ +package org.lwjgl.opencl.api; + +import org.lwjgl.PointerBuffer; + +/** + * Simple container for cl_buffer_region struct values. + * + * @author Spasi + */ +public final class CLBufferRegion { + + /** The cl_buffer_region struct size in bytes. */ + public static final int STRUCT_SIZE = 2 * PointerBuffer.getPointerSize(); + + private final int origin; + private final int size; + + public CLBufferRegion(final int origin, final int size) { + this.origin = origin; + this.size = size; + } + + public int getOrigin() { + return origin; + } + + public int getSize() { + return size; + } + +} \ No newline at end of file Added: trunk/LWJGL/src/java/org/lwjgl/opencl/api/CLImageFormat.java =================================================================== --- trunk/LWJGL/src/java/org/lwjgl/opencl/api/CLImageFormat.java (rev 0) +++ trunk/LWJGL/src/java/org/lwjgl/opencl/api/CLImageFormat.java 2010-09-30 17:21:50 UTC (rev 3419) @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2002-2010 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * 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. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT OWNER 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. + */ +package org.lwjgl.opencl.api; + +/** + * Simple container for cl_image_format struct values. + * + * @author Spasi + */ +public final class CLImageFormat { + + /** The cl_image_format struct size in bytes. */ + public static final int STRUCT_SIZE = 2 * 4; + + private final int channelOrder; + private final int channelType; + + public CLImageFormat(final int channelOrder, final int channelType) { + this.channelOrder = channelOrder; + this.channelType = channelType; + } + + public int getChannelOrder() { + return channelOrder; + } + + public int getChannelType() { + return channelType; + } + +} \ No newline at end of file Modified: trunk/LWJGL/src/java/org/lwjgl/test/opencl/gl/DemoFractal.java =================================================================== --- trunk/LWJGL/src/java/org/lwjgl/test/opencl/gl/DemoFractal.java 2010-09-28 21:11:35 UTC (rev 3418) +++ trunk/LWJGL/src/java/org/lwjgl/test/opencl/gl/DemoFractal.java 2010-09-30 17:21:50 UTC (rev 3419) @@ -43,18 +43,23 @@ import org.lwjgl.util.ReadableColor; import java.io.*; +import java.nio.ByteBuffer; import java.nio.IntBuffer; +import java.util.HashSet; import java.util.List; +import java.util.Set; import static java.lang.Math.*; import static org.lwjgl.opencl.CL10.*; import static org.lwjgl.opencl.CL10GL.*; import static org.lwjgl.opencl.KHRGLEvent.*; +import static org.lwjgl.opengl.AMDDebugOutput.*; import static org.lwjgl.opengl.ARBCLEvent.*; +import static org.lwjgl.opengl.ARBDebugOutput.*; import static org.lwjgl.opengl.ARBSync.*; import static org.lwjgl.opengl.GL11.*; -import static org.lwjgl.opengl.GL12.*; import static org.lwjgl.opengl.GL15.*; +import static org.lwjgl.opengl.GL20.*; import static org.lwjgl.opengl.GL21.*; /* @@ -118,25 +123,36 @@ // max number of used GPUs private static final int MAX_PARALLELISM_LEVEL = 8; - // max per pixel iterations to compute the fractal - private static final int MAX_ITERATIONS = 500; + private static final int COLOR_MAP_SIZE = 32 * 2 * 4; + private Set<String> params; + private CLContext clContext; private CLCommandQueue[] queues; private CLKernel[] kernels; private CLProgram[] programs; - private CLMem[] pboBuffers; - private IntBuffer pboIDs; + private CLMem[] glBuffers; + private IntBuffer glIDs; + private boolean useTextures; + + // Texture rendering + private int dlist; + private int vsh; + private int fsh; + private int program; + private CLMem[] colorMap; - private IntBuffer[] colorMapBuffer; private final PointerBuffer kernel2DGlobalWorkSize; - private int width; - private int height; + // max per pixel iterations to compute the fractal + private int maxIterations = 500; + private int width = 512; + private int height = 512; + private double minX = -2f; private double minY = -1.2f; private double maxX = 0.6f; @@ -174,135 +190,55 @@ private GLSync glSync; private CLEvent glEvent; - public DemoFractal(int width, int height) { - kernel2DGlobalWorkSize = BufferUtils.createPointerBuffer(2); + public DemoFractal(final String[] args) { + params = new HashSet<String>(); - this.width = width; - this.height = height; - } + for ( int i = 0; i < args.length; i++ ) { + final String arg = args[i]; - private void run() { - long startTime = System.currentTimeMillis() + 5000; - long fps = 0; + if ( arg.charAt(0) != '-' && arg.charAt(0) != '/' ) + throw new IllegalArgumentException("Invalid command-line argument: " + args[i]); - while ( run ) { - if ( !Display.isVisible() ) - Thread.yield(); + final String param = arg.substring(1); - handleIO(); - display(); + if ( "forcePBO".equalsIgnoreCase(param) ) + params.add("forcePBO"); + else if ( "forceCPU".equalsIgnoreCase(param) ) + params.add("forceCPU"); + else if ( "debugGL".equalsIgnoreCase(param) ) + params.add("debugGL"); + else if ( "iterations".equalsIgnoreCase(param) ) { + if ( args.length < i + 1 + 1 ) + throw new IllegalArgumentException("Invalid iterations argument specified."); - Display.update(); - if ( Display.isCloseRequested() ) - break; + try { + this.maxIterations = Integer.parseInt(args[++i]); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Invalid number of iterations specified."); + } + } else if ( "res".equalsIgnoreCase(param) ) { + if ( args.length < i + 2 + 1 ) + throw new IllegalArgumentException("Invalid res argument specified."); - if ( startTime > System.currentTimeMillis() ) { - fps++; - } else { - long timeUsed = 5000 + (startTime - System.currentTimeMillis()); - startTime = System.currentTimeMillis() + 5000; - System.out.println(fps + " frames in 5 seconds = " + (fps / (timeUsed / 1000f))); - fps = 0; - } - } + try { + this.width = Integer.parseInt(args[++i]); + this.height = Integer.parseInt(args[++i]); - CL.destroy(); - Display.destroy(); - } - - private void handleIO() { - if ( Keyboard.getNumKeyboardEvents() != 0 ) { - while ( Keyboard.next() ) { - if ( Keyboard.getEventKeyState() ) - continue; - - final int key = Keyboard.getEventKey(); - - if ( Keyboard.KEY_1 <= key && key <= Keyboard.KEY_8 ) { - int number = key - Keyboard.KEY_1 + 1; - slices = min(number, min(queues.length, MAX_PARALLELISM_LEVEL)); - System.out.println("NEW PARALLELISM LEVEL: " + slices); - buffersInitialized = false; - } else { - switch ( Keyboard.getEventKey() ) { - case Keyboard.KEY_SPACE: - drawSeparator = !drawSeparator; - System.out.println("SEPARATOR DRAWING IS NOW: " + (drawSeparator ? "ON" : "OFF")); - break; - case Keyboard.KEY_D: - doublePrecision = !doublePrecision; - System.out.println("DOUBLE PRECISION IS NOW: " + (doublePrecision ? "ON" : "OFF")); - rebuild = true; - break; - case Keyboard.KEY_HOME: - minX = -2f; - minY = -1.2f; - maxX = 0.6f; - maxY = 1.3f; - break; - case Keyboard.KEY_ESCAPE: - run = false; - break; - } + if ( width < 1 || height < 1 ) + throw new IllegalArgumentException("Invalid res dimensions specified."); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Invalid res dimensions specified."); } } } - while ( Mouse.next() ) { - final int eventBtn = Mouse.getEventButton(); + kernel2DGlobalWorkSize = BufferUtils.createPointerBuffer(2); + } - final int x = Mouse.getX(); - final int y = Mouse.getY(); - - if ( Mouse.isButtonDown(0) && (x != mouseX || y != mouseY) ) { - if ( !dragging ) { - dragging = true; - - dragX = mouseX; - dragY = mouseY; - - dragMinX = minX; - dragMinY = minY; - dragMaxX = maxX; - dragMaxY = maxY; - } - - double offsetX = (x - dragX) * (maxX - minX) / width; - double offsetY = (y - dragY) * (maxY - minY) / height; - - minX = dragMinX - offsetX; - minY = dragMinY - offsetY; - - maxX = dragMaxX - offsetX; - maxY = dragMaxY - offsetY; - } else { - if ( dragging ) - dragging = false; - - if ( eventBtn == -1 ) { - final int dwheel = Mouse.getEventDWheel(); - if ( dwheel != 0 ) { - double scale = dwheel > 0 ? 0.05 : -0.05; - - double deltaX = scale * (maxX - minX); - double deltaY = scale * (maxY - minY); - - // offset for "zoom to cursor" - double offsetX = (x / (double)width - 0.5) * deltaX * 2.0; - double offsetY = (y / (double)height - 0.5) * deltaY * 2.0; - - minX += deltaX + offsetX; - minY += deltaY - offsetY; - - maxX += -deltaX + offsetX; - maxY += -deltaY - offsetY; - } - } - } - - mouseX = x; - mouseY = y; - } + public static void main(String args[]) { + DemoFractal demo = new DemoFractal(args); + demo.init(); + demo.run(); } public void init() { @@ -310,7 +246,8 @@ CL.create(); Display.setDisplayMode(new DisplayMode(width, height)); Display.setTitle("OpenCL Fractal Demo"); - Display.create(); + Display.setSwapInterval(0); + Display.create(new PixelFormat(), new ContextAttribs().withDebug(params.contains("debugGL"))); } catch (LWJGLException e) { throw new RuntimeException(e); } @@ -324,13 +261,12 @@ throw new RuntimeException(e); } - Display.setSwapInterval(0); glDisable(GL_DEPTH_TEST); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); initView(Display.getDisplayMode().getWidth(), Display.getDisplayMode().getHeight()); - initPBO(); + initGLObjects(); glFinish(); setKernelConstants(); @@ -351,48 +287,40 @@ return caps.CL_KHR_gl_sharing; } }; - List<CLDevice> devices = platform.getDevices(CL_DEVICE_TYPE_GPU, glSharingFilter); + int device_type = params.contains("forceCPU") ? CL_DEVICE_TYPE_CPU : CL_DEVICE_TYPE_GPU; + List<CLDevice> devices = platform.getDevices(device_type, glSharingFilter); if ( devices == null ) { - devices = platform.getDevices(CL_DEVICE_TYPE_CPU, glSharingFilter); + device_type = CL_DEVICE_TYPE_CPU; + devices = platform.getDevices(device_type, glSharingFilter); if ( devices == null ) throw new RuntimeException("No OpenCL devices found with KHR_gl_sharing support."); } // Create the context - final PointerBuffer deviceIDs = BufferUtils.createPointerBuffer(devices.size()); - for ( CLDevice device : devices ) - deviceIDs.put(device); - deviceIDs.flip(); + clContext = CLContext.create(platform, devices, new CLContextCallback() { + protected void handleMessage(final String errinfo, final ByteBuffer private_info) { + System.out.println("[CONTEXT MESSAGE] " + errinfo); + } + }, drawable, null); - final PointerBuffer contextProps = BufferUtils.createPointerBuffer(2 + 4 + 1); - contextProps.put(CL_CONTEXT_PLATFORM).put(platform); - - drawable.setCLSharingProperties(contextProps); // Enable GL sharing - - contextProps.put(0); - contextProps.flip(); - clContext = clCreateContext(contextProps, deviceIDs, null, null); - slices = min(devices.size(), MAX_PARALLELISM_LEVEL); // create command queues for every GPU, setup colormap and init kernels queues = new CLCommandQueue[slices]; kernels = new CLKernel[slices]; colorMap = new CLMem[slices]; - colorMapBuffer = new IntBuffer[slices]; for ( int i = 0; i < slices; i++ ) { - colorMapBuffer[i] = BufferUtils.createIntBuffer(32 * 2); - colorMap[i] = clCreateBuffer(clContext, CL_MEM_READ_ONLY, colorMapBuffer[i].capacity() * 4, null); + colorMap[i] = clCreateBuffer(clContext, CL_MEM_READ_ONLY, COLOR_MAP_SIZE, null); colorMap[i].checkValid(); - initColorMap(colorMapBuffer[i], 32, Color.BLUE, Color.GREEN, Color.RED); - // create command queue and upload color map buffer on each used device queues[i] = clCreateCommandQueue(clContext, devices.get(i), CL_QUEUE_PROFILING_ENABLE, null); queues[i].checkValid(); - clEnqueueWriteBuffer(queues[i], colorMap[i], CL_TRUE, 0, colorMapBuffer[i], null, null); // blocking upload + final ByteBuffer colorMapBuffer = clEnqueueMapBuffer(queues[i], colorMap[i], CL_TRUE, CL_MAP_WRITE, 0, COLOR_MAP_SIZE, null, null, null); + initColorMap(colorMapBuffer.asIntBuffer(), 32, Color.BLUE, Color.GREEN, Color.RED); + clEnqueueUnmapMemObject(queues[i], colorMap[i], colorMapBuffer, null, null); } // check if we have 64bit FP support on all devices @@ -411,25 +339,51 @@ // load program(s) programs = new CLProgram[all64bit ? 1 : slices]; - buildPrograms(); - final ContextCapabilities caps = GLContext.getCapabilities(); - System.out.println("OpenGL caps.OpenGL32 = " + caps.OpenGL32); - System.out.println("OpenGL caps.GL_ARB_sync = " + caps.GL_ARB_sync); + if ( !caps.OpenGL20 ) + throw new RuntimeException("OpenGL 2.0 is required to run this demo."); + else if ( device_type == CL_DEVICE_TYPE_CPU && !caps.OpenGL21 ) + throw new RuntimeException("OpenGL 2.1 is required to run this demo."); + + if ( caps.GL_ARB_debug_output ) + glDebugMessageCallbackARB(new ARBDebugOutputCallback()); + else if ( caps.GL_AMD_debug_output ) + glDebugMessageCallbackAMD(new AMDDebugOutputCallback()); + + if ( device_type == CL_DEVICE_TYPE_GPU ) + System.out.println("OpenCL Device Type: GPU (Use -forceCPU to use CPU)"); + else + System.out.println("OpenCL Device Type: CPU"); + for ( int i = 0; i < devices.size(); i++ ) + System.out.println("OpenCL Device #" + (i + 1) + " supports KHR_gl_event = " + CLCapabilities.getDeviceCapabilities(devices.get(i)).CL_KHR_gl_event); + + System.out.println("\nMax Iterations: " + maxIterations + " (Use -iterations <count> to change)"); + System.out.println("Display resolution: " + width + "x" + height + " (Use -res <width> <height> to change)"); + + System.out.println("\nOpenGL caps.GL_ARB_sync = " + caps.GL_ARB_sync); System.out.println("OpenGL caps.GL_ARB_cl_event = " + caps.GL_ARB_cl_event); - for ( int i = 0; i < devices.size(); i++ ) { - System.out.println("Device #" + (i + 1) + " supports KHR_gl_event = " + CLCapabilities.getDeviceCapabilities(devices.get(i)).CL_KHR_gl_event); + + // Use PBO if we're on a CPU implementation + useTextures = device_type == CL_DEVICE_TYPE_GPU && (!caps.OpenGL21 || !params.contains("forcePBO")); + if ( useTextures ) { + System.out.println("\nCL/GL Sharing method: TEXTURES (use -forcePBO to use PBO + DrawPixels)"); + System.out.println("Rendering method: Shader on a fullscreen quad"); + } else { + System.out.println("\nCL/GL Sharing method: PIXEL BUFFER OBJECTS"); + System.out.println("Rendering method: DrawPixels"); } + buildPrograms(); + // Detect GLtoCL synchronization method syncGLtoCL = caps.GL_ARB_cl_event; // GL3.2 or ARB_sync implied if ( syncGLtoCL ) { clEvents = new CLEvent[slices]; clSyncs = new GLSync[slices]; - System.out.println("GL to CL sync: Using OpenCL events"); + System.out.println("\nGL to CL sync: Using OpenCL events"); } else - System.out.println("GL to CL sync: Using clFinish"); + System.out.println("\nGL to CL sync: Using clFinish"); // Detect CLtoGL synchronization method syncCLtoGL = caps.OpenGL32 || caps.GL_ARB_sync; @@ -445,92 +399,57 @@ System.out.println("CL to GL sync: Using OpenGL sync objects"); } else System.out.println("CL to GL sync: Using glFinish"); - } - private void createPrograms() throws IOException { - final String source = getProgramSource("Mandelbrot.cl"); - for ( int i = 0; i < programs.length; i++ ) - programs[i] = clCreateProgramWithSource(clContext, source, null); - } + if ( useTextures ) { + dlist = glGenLists(1); - private String getProgramSource(final String file) throws IOException { - InputStream source = getClass().getResourceAsStream(file); - if ( source == null ) // dev-mode - source = new FileInputStream("... [truncated message content] |