added dependency resolving and a random number library

define_list_fix
shamanDevel 9 years ago
parent 9a3dce2fb3
commit 44899098e2
  1. 65
      jme3-core/src/main/java/com/jme3/opencl/Context.java
  2. 185
      jme3-core/src/main/resources/Common/OpenCL/Random.clh
  3. 257
      jme3-examples/src/main/java/jme3test/opencl/TestOpenCLLibraries.java

@ -34,6 +34,7 @@ package com.jme3.opencl;
import com.jme3.asset.AssetInfo; import com.jme3.asset.AssetInfo;
import com.jme3.asset.AssetKey; import com.jme3.asset.AssetKey;
import com.jme3.asset.AssetManager; import com.jme3.asset.AssetManager;
import com.jme3.asset.AssetNotFoundException;
import com.jme3.opencl.Image.ImageDescriptor; import com.jme3.opencl.Image.ImageDescriptor;
import com.jme3.opencl.Image.ImageFormat; import com.jme3.opencl.Image.ImageFormat;
import com.jme3.opencl.Image.ImageType; import com.jme3.opencl.Image.ImageType;
@ -43,6 +44,7 @@ import com.jme3.texture.Texture;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.StringReader;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -282,6 +284,52 @@ public abstract class Context extends AbstractOpenCLObject {
*/ */
public abstract Program createProgramFromSourceCode(String sourceCode); public abstract Program createProgramFromSourceCode(String sourceCode);
/**
* Resolves dependencies (using {@code #include } in the source code)
* and delegates the combined source code to
* {@link #createProgramFromSourceCode(java.lang.String) }.
* Important: only absolute paths are allowed.
* @param sourceCode the original source code
* @param assetManager the asset manager to load the files
* @return the created program object
* @throws AssetNotFoundException if a dependency could not be loaded
*/
public Program createProgramFromSourceCodeWithDependencies(String sourceCode, AssetManager assetManager) {
StringBuilder builder = new StringBuilder(sourceCode.length());
BufferedReader reader = new BufferedReader(new StringReader(sourceCode));
try {
buildSourcesRec(reader, builder, assetManager);
} catch (IOException ex) {
throw new AssetNotFoundException("Unable to read a dependency file", ex);
}
return createProgramFromSourceCode(builder.toString());
}
private void buildSourcesRec(BufferedReader reader, StringBuilder builder, AssetManager assetManager) throws IOException {
String ln;
while ((ln = reader.readLine()) != null) {
if (ln.trim().startsWith("#import ")) {
ln = ln.trim().substring(8).trim();
if (ln.startsWith("\"")) {
ln = ln.substring(1);
}
if (ln.endsWith("\"")) {
ln = ln.substring(0, ln.length()-1);
}
AssetInfo info = assetManager.locateAsset(new AssetKey<String>(ln));
if (info == null) {
throw new AssetNotFoundException("Unable to load source file \""+ln+"\"");
}
try (BufferedReader r = new BufferedReader(new InputStreamReader(info.openStream()))) {
builder.append("//-- begin import ").append(ln).append(" --\n");
buildSourcesRec(r, builder, assetManager);
builder.append("//-- end import ").append(ln).append(" --\n");
}
} else {
builder.append(ln).append('\n');
}
}
}
/** /**
* Creates a program object from the provided source code and files. * Creates a program object from the provided source code and files.
* The source code is made up from the specified include string first, * The source code is made up from the specified include string first,
@ -294,14 +342,15 @@ public abstract class Context extends AbstractOpenCLObject {
* <li>Some common OpenCL files used as libraries (Convention: file names end with {@code .clh}</li> * <li>Some common OpenCL files used as libraries (Convention: file names end with {@code .clh}</li>
* <li>One main OpenCL file containing the actual kernels (Convention: file name ends with {@code .cl})</li> * <li>One main OpenCL file containing the actual kernels (Convention: file name ends with {@code .cl})</li>
* </ul> * </ul>
* Note: Files that can't be loaded are skipped.<br>
* *
* The actual creation is handled by {@link #createProgramFromSourceCode(java.lang.String) }. * After the files were combined, additional include statements are resolved
* by {@link #createProgramFromSourceCodeWithDependencies(java.lang.String, com.jme3.asset.AssetManager) }.
* *
* @param assetManager the asset manager used to load the files * @param assetManager the asset manager used to load the files
* @param include an additional include string * @param include an additional include string
* @param resources an array of asset paths pointing to OpenCL source files * @param resources an array of asset paths pointing to OpenCL source files
* @return the new program objects * @return the new program objects
* @throws AssetNotFoundException if a file could not be loaded
*/ */
public Program createProgramFromSourceFilesWithInclude(AssetManager assetManager, String include, String... resources) { public Program createProgramFromSourceFilesWithInclude(AssetManager assetManager, String include, String... resources) {
return createProgramFromSourceFilesWithInclude(assetManager, include, Arrays.asList(resources)); return createProgramFromSourceFilesWithInclude(assetManager, include, Arrays.asList(resources));
@ -319,14 +368,15 @@ public abstract class Context extends AbstractOpenCLObject {
* <li>Some common OpenCL files used as libraries (Convention: file names end with {@code .clh}</li> * <li>Some common OpenCL files used as libraries (Convention: file names end with {@code .clh}</li>
* <li>One main OpenCL file containing the actual kernels (Convention: file name ends with {@code .cl})</li> * <li>One main OpenCL file containing the actual kernels (Convention: file name ends with {@code .cl})</li>
* </ul> * </ul>
* Note: Files that can't be loaded are skipped.<br>
* *
* The actual creation is handled by {@link #createProgramFromSourceCode(java.lang.String) }. * After the files were combined, additional include statements are resolved
* by {@link #createProgramFromSourceCodeWithDependencies(java.lang.String, com.jme3.asset.AssetManager) }.
* *
* @param assetManager the asset manager used to load the files * @param assetManager the asset manager used to load the files
* @param include an additional include string * @param include an additional include string
* @param resources an array of asset paths pointing to OpenCL source files * @param resources an array of asset paths pointing to OpenCL source files
* @return the new program objects * @return the new program objects
* @throws AssetNotFoundException if a file could not be loaded
*/ */
public Program createProgramFromSourceFilesWithInclude(AssetManager assetManager, String include, List<String> resources) { public Program createProgramFromSourceFilesWithInclude(AssetManager assetManager, String include, List<String> resources) {
StringBuilder str = new StringBuilder(); StringBuilder str = new StringBuilder();
@ -334,8 +384,7 @@ public abstract class Context extends AbstractOpenCLObject {
for (String res : resources) { for (String res : resources) {
AssetInfo info = assetManager.locateAsset(new AssetKey<String>(res)); AssetInfo info = assetManager.locateAsset(new AssetKey<String>(res));
if (info == null) { if (info == null) {
LOG.log(Level.WARNING, "unable to load source file ''{0}''", res); throw new AssetNotFoundException("Unable to load source file \""+res+"\"");
continue;
} }
try (BufferedReader reader = new BufferedReader(new InputStreamReader(info.openStream()))) { try (BufferedReader reader = new BufferedReader(new InputStreamReader(info.openStream()))) {
while (true) { while (true) {
@ -349,12 +398,13 @@ public abstract class Context extends AbstractOpenCLObject {
LOG.log(Level.WARNING, "unable to load source file '"+res+"'", ex); LOG.log(Level.WARNING, "unable to load source file '"+res+"'", ex);
} }
} }
return createProgramFromSourceCode(str.toString()); return createProgramFromSourceCodeWithDependencies(str.toString(), assetManager);
} }
/** /**
* Alternative version of {@link #createProgramFromSourceFilesWithInclude(com.jme3.asset.AssetManager, java.lang.String, java.lang.String...) } * Alternative version of {@link #createProgramFromSourceFilesWithInclude(com.jme3.asset.AssetManager, java.lang.String, java.lang.String...) }
* with an empty include string * with an empty include string
* @throws AssetNotFoundException if a file could not be loaded
*/ */
public Program createProgramFromSourceFiles(AssetManager assetManager, String... resources) { public Program createProgramFromSourceFiles(AssetManager assetManager, String... resources) {
return createProgramFromSourceFilesWithInclude(assetManager, "", resources); return createProgramFromSourceFilesWithInclude(assetManager, "", resources);
@ -363,6 +413,7 @@ public abstract class Context extends AbstractOpenCLObject {
/** /**
* Alternative version of {@link #createProgramFromSourceFilesWithInclude(com.jme3.asset.AssetManager, java.lang.String, java.util.List) } * Alternative version of {@link #createProgramFromSourceFilesWithInclude(com.jme3.asset.AssetManager, java.lang.String, java.util.List) }
* with an empty include string * with an empty include string
* @throws AssetNotFoundException if a file could not be loaded
*/ */
public Program createProgramFromSourceFiles(AssetManager assetManager, List<String> resources) { public Program createProgramFromSourceFiles(AssetManager assetManager, List<String> resources) {
return createProgramFromSourceFilesWithInclude(assetManager, "", resources); return createProgramFromSourceFilesWithInclude(assetManager, "", resources);

@ -0,0 +1,185 @@
//This is a port of java.util.Random to OpenCL
//Because not all devices support doubles, the double returning functions
//must be explicit activated with the following preprocessor macro:
//#define RANDOM_DOUBLES
#ifdef RANDOM_DOUBLES
#ifdef cl_khr_fp64
#pragma OPENCL EXTENSION cl_khr_fp64 : enable
#elif defined(cl_amd_fp64)
#pragma OPENCL EXTENSION cl_amd_fp64 : enable
#else
#error "Double precision floating point not supported by OpenCL implementation."
#endif
#endif
inline int randNext(int bits, __global ulong* seed)
{
*seed = (*seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1);
return (int)(*seed >> (48 - bits));
}
/**
* Retrieves the next random integer value.
* The buffer used as seed must be read-write.
* Usage:
* <code>
* __kernel void TestRandom(__global ulong* seeds) {
* // ...
* int i = randInt(seeds + get_global_id(0));
* // ---
* }
* </code>
*/
inline int randInt(__global ulong* seed) {
return randNext(32, seed);
}
/**
* Retrieves the next random integer value between 0 (inclusive) and n (exclusive).
* The buffer used as seed must be read-write.
* Usage:
* <code>
* __kernel void TestRandom(__global ulong* seeds) {
* // ...
* int i = randIntN(n, seeds + get_global_id(0));
* // ---
* }
* </code>
*/
inline int randIntN(int n, __global ulong* seed) {
if (n <= 0)
return 0;
if ((n & -n) == n) // i.e., n is a power of 2
return (int)((n * (long)randNext(31, seed)) >> 31);
int bits, val;
do {
bits = randNext(31, seed);
val = bits % n;
} while (bits - val + (n-1) < 0);
return val;
}
/**
* Retrieves the next random long value.
* The buffer used as seed must be read-write.
* Usage:
* <code>
* __kernel void TestRandom(__global ulong* seeds) {
* // ...
* long l = randLong(seeds + get_global_id(0));
* // ---
* }
* </code>
*/
inline long randLong(__global ulong* seed) {
// it's okay that the bottom word remains signed.
return ((long)(randNext(32, seed)) << 32) + randNext(32, seed);
}
/**
* Retrieves the next random boolean value.
* The buffer used as seed must be read-write.
* Usage:
* <code>
* __kernel void TestRandom(__global ulong* seeds) {
* // ...
* bool b = randBool(seeds + get_global_id(0));
* // ---
* }
* </code>
*/
inline bool randBool(__global ulong* seed) {
return randNext(1, seed) != 0;
}
#ifdef RANDOM_DOUBLES
/**
* Retrieves the next random double value.
* The buffer used as seed must be read-write.
* To use this function, the preprocessor define RANDOM_DOUBLES must be set.
* Usage:
* <code>
* __kernel void TestRandom(__global ulong* seeds) {
* // ...
* double d = randDouble(seeds + get_global_id(0));
* // ---
* }
* </code>
*/
inline double randDouble(__global ulong* seed) {
return (((long)(randNext(26, seed)) << 27) + randNext(27, seed))
/ (double)(1L << 53);
}
#endif
/**
* Retrieves the next random float value.
* The buffer used as seed must be read-write.
* Usage:
* <code>
* __kernel void TestRandom(__global ulong* seeds) {
* // ...
* float f = randFloat(seeds + get_global_id(0));
* // ---
* }
* </code>
*/
inline float randFloat(__global ulong* seed)
{
return randNext(24, seed) / ((float)(1 << 24));
}
/**
* Retrieves the next random float values with a gaussian distribution of mean 0
* and derivation 1.
* The buffer used as seed must be read-write.
* Usage:
* <code>
* __kernel void TestRandom(__global ulong* seeds) {
* // ...
* float2 f2 = randGausianf(seeds + get_global_id(0));
* // ---
* }
* </code>
*/
inline float2 randGaussianf(__global ulong* seed) {
float v1, v2, s;
do {
v1 = 2 * randFloat(seed) - 1; // between -1 and 1
v2 = 2 * randFloat(seed) - 1; // between -1 and 1
s = v1 * v1 + v2 * v2;
} while (s >= 1 || s == 0);
float multiplier = sqrt(-2 * log(s)/s);
return (float2) (v1 * multiplier, v2 * multiplier);
}
#ifdef RANDOM_DOUBLES
/**
* Retrieves the next random double values with a gaussian distribution of mean 0
* and derivation 1.
* The buffer used as seed must be read-write.
* To use this function, the preprocessor define RANDOM_DOUBLES must be set.
* Usage:
* <code>
* __kernel void TestRandom(__global ulong* seeds) {
* // ...
* double2 f2 = randGausian(seeds + get_global_id(0));
* // ---
* }
* </code>
*/
inline double2 randGaussian(__global ulong* seed) {
double v1, v2, s;
do {
v1 = 2 * randDouble(seed) - 1; // between -1 and 1
v2 = 2 * randDouble(seed) - 1; // between -1 and 1
s = v1 * v1 + v2 * v2;
} while (s >= 1 || s == 0);
double multiplier = sqrt(-2 * log(s)/s);
return (double2) (v1 * multiplier, v2 * multiplier);
}
#endif

@ -0,0 +1,257 @@
/*
* Copyright (c) 2009-2012 jMonkeyEngine
* 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 'jMonkeyEngine' 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 jme3test.opencl;
import com.jme3.app.SimpleApplication;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.math.ColorRGBA;
import com.jme3.opencl.*;
import com.jme3.system.AppSettings;
import com.jme3.util.BufferUtils;
import java.nio.*;
import java.util.Arrays;
import java.util.Objects;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Test class for the build in libraries
* @author shaman
*/
public class TestOpenCLLibraries extends SimpleApplication {
private static final Logger LOG = Logger.getLogger(TestOpenCLLibraries.class.getName());
public static void main(String[] args){
TestOpenCLLibraries app = new TestOpenCLLibraries();
AppSettings settings = new AppSettings(true);
settings.setOpenCLSupport(true);
settings.setVSync(true);
// settings.setRenderer(AppSettings.JOGL_OPENGL_FORWARD_COMPATIBLE);
app.setSettings(settings);
app.start(); // start the game
}
@Override
public void simpleInitApp() {
BitmapFont fnt = assetManager.loadFont("Interface/Fonts/Default.fnt");
Context clContext = context.getOpenCLContext();
if (clContext == null) {
BitmapText txt = new BitmapText(fnt);
txt.setText("No OpenCL Context created!\nSee output log for details.");
txt.setLocalTranslation(5, settings.getHeight() - 5, 0);
guiNode.attachChild(txt);
return;
}
CommandQueue clQueue = clContext.createQueue(clContext.getDevices().get(0));
StringBuilder str = new StringBuilder();
str.append("OpenCL Context created:\n Platform: ")
.append(clContext.getDevices().get(0).getPlatform().getName())
.append("\n Devices: ").append(clContext.getDevices());
str.append("\nTests:");
str.append("\n Random numbers: ").append(testRandom(clContext, clQueue));
clQueue.release();
BitmapText txt1 = new BitmapText(fnt);
txt1.setText(str.toString());
txt1.setLocalTranslation(5, settings.getHeight() - 5, 0);
guiNode.attachChild(txt1);
flyCam.setEnabled(false);
inputManager.setCursorVisible(true);
}
private static void assertEquals(byte expected, byte actual, String message) {
if (expected != actual) {
System.err.println(message+": expected="+expected+", actual="+actual);
throw new AssertionError();
}
}
private static void assertEquals(long expected, long actual, String message) {
if (expected != actual) {
System.err.println(message+": expected="+expected+", actual="+actual);
throw new AssertionError();
}
}
private static void assertEquals(double expected, double actual, String message) {
if (Math.abs(expected - actual) >= 0.00001) {
System.err.println(message+": expected="+expected+", actual="+actual);
throw new AssertionError();
}
}
private static void assertEquals(Object expected, Object actual, String message) {
if (!Objects.equals(expected, actual)) {
System.err.println(message+": expected="+expected+", actual="+actual);
throw new AssertionError();
}
}
private boolean testRandom(Context clContext, CommandQueue clQueue) {
try {
//test for doubles
boolean supportsDoubles = clContext.getDevices().get(0).hasDouble();
//create code
String code = ""
+ "#import \"Common/OpenCL/Random.clh\"\n"
+ "__kernel void TestBool(__global ulong* seeds, __global uchar* results) {\n"
+ " results[get_global_id(0)] = randBool(seeds + get_global_id(0)) ? 1 : 0;\n"
+ "}\n"
+ "__kernel void TestInt(__global ulong* seeds, __global int* results) {\n"
+ " results[get_global_id(0)] = randInt(seeds + get_global_id(0));\n"
+ "}\n"
+ "__kernel void TestIntN(__global ulong* seeds, int n, __global int* results) {\n"
+ " results[get_global_id(0)] = randIntN(n, seeds + get_global_id(0));\n"
+ "}\n"
+ "__kernel void TestLong(__global ulong* seeds, __global long* results) {\n"
+ " results[get_global_id(0)] = randLong(seeds + get_global_id(0));\n"
+ "}\n"
+ "__kernel void TestFloat(__global ulong* seeds, __global float* results) {\n"
+ " results[get_global_id(0)] = randFloat(seeds + get_global_id(0));\n"
+ "}\n"
+ "#ifdef RANDOM_DOUBLES\n"
+ "__kernel void TestDouble(__global ulong* seeds, __global double* results) {\n"
+ " results[get_global_id(0)] = randDouble(seeds + get_global_id(0));\n"
+ "}\n"
+ "#endif\n";
if (supportsDoubles) {
code = "#define RANDOM_DOUBLES\n" + code;
}
Program program = clContext.createProgramFromSourceCodeWithDependencies(code, assetManager);
program.build();
int count = 256;
Kernel.WorkSize ws = new Kernel.WorkSize(count);
//create seeds
Random initRandom = new Random();
long[] seeds = new long[count];
Random[] randoms = new Random[count];
for (int i=0; i<count; ++i) {
seeds[i] = initRandom.nextLong();
randoms[i] = new Random(seeds[i]);
seeds[i] = (seeds[i] ^ 0x5DEECE66DL) & ((1L << 48) - 1); //needed because the Random constructor scrambles the initial seed
}
com.jme3.opencl.Buffer seedsBuffer = clContext.createBuffer(8 * count);
ByteBuffer tmpByteBuffer = BufferUtils.createByteBuffer(8 * count);
tmpByteBuffer.asLongBuffer().put(seeds);
seedsBuffer.write(clQueue, tmpByteBuffer);
//test it
ByteBuffer resultByteBuffer = BufferUtils.createByteBuffer(8 * count);
IntBuffer resultIntBuffer = resultByteBuffer.asIntBuffer();
LongBuffer resultLongBuffer = resultByteBuffer.asLongBuffer();
FloatBuffer resultFloatBuffer = resultByteBuffer.asFloatBuffer();
DoubleBuffer resultDoubleBuffer = resultByteBuffer.asDoubleBuffer();
com.jme3.opencl.Buffer resultBuffer = clContext.createBuffer(8 * count);
//boolean
Kernel testBoolKernel = program.createKernel("TestBool");
testBoolKernel.Run1NoEvent(clQueue, ws, seedsBuffer, resultBuffer);
resultByteBuffer.rewind();
resultBuffer.read(clQueue, resultByteBuffer);
for (int i=0; i<count; ++i) {
assertEquals(randoms[i].nextBoolean() ? 1 : 0, resultByteBuffer.get(i), "randBool at i="+i);
}
testBoolKernel.release();
//int
Kernel testIntKernel = program.createKernel("TestInt");
testIntKernel.Run1NoEvent(clQueue, ws, seedsBuffer, resultBuffer);
resultByteBuffer.rewind();
resultBuffer.read(clQueue, resultByteBuffer);
for (int i=0; i<count; ++i) {
assertEquals(randoms[i].nextInt(), resultIntBuffer.get(i), "randInt at i="+i);
}
testIntKernel.release();
//int n
Kernel testIntNKernel = program.createKernel("TestIntN");
testIntNKernel.Run1NoEvent(clQueue, ws, seedsBuffer, 186, resultBuffer);
resultByteBuffer.rewind();
resultBuffer.read(clQueue, resultByteBuffer);
for (int i=0; i<count; ++i) {
assertEquals(randoms[i].nextInt(186), resultIntBuffer.get(i), "randInt at i="+i+" with n="+186);
}
testIntNKernel.Run1NoEvent(clQueue, ws, seedsBuffer, 97357, resultBuffer);
resultByteBuffer.rewind();
resultBuffer.read(clQueue, resultByteBuffer);
for (int i=0; i<count; ++i) {
assertEquals(randoms[i].nextInt(97357), resultIntBuffer.get(i), "randInt at i="+i+" with n="+97357);
}
testIntNKernel.release();
//long
Kernel testLongKernel = program.createKernel("TestLong");
testLongKernel.Run1NoEvent(clQueue, ws, seedsBuffer, resultBuffer);
resultByteBuffer.rewind();
resultBuffer.read(clQueue, resultByteBuffer);
for (int i=0; i<count; ++i) {
assertEquals(randoms[i].nextLong(), resultLongBuffer.get(i), "randLong at i="+i);
}
testLongKernel.release();
//float
Kernel testFloatKernel = program.createKernel("TestFloat");
testFloatKernel.Run1NoEvent(clQueue, ws, seedsBuffer, resultBuffer);
resultByteBuffer.rewind();
resultBuffer.read(clQueue, resultByteBuffer);
for (int i=0; i<count; ++i) {
assertEquals(randoms[i].nextFloat(), resultFloatBuffer.get(i), "randFloat at i="+i);
}
testFloatKernel.release();
//double
if (supportsDoubles) {
Kernel testDoubleKernel = program.createKernel("TestDouble");
testDoubleKernel.Run1NoEvent(clQueue, ws, seedsBuffer, resultBuffer);
resultByteBuffer.rewind();
resultBuffer.read(clQueue, resultByteBuffer);
for (int i=0; i<count; ++i) {
assertEquals(randoms[i].nextDouble(), resultDoubleBuffer.get(i), "randLong at i="+i);
}
testDoubleKernel.release();
}
seedsBuffer.release();
resultBuffer.release();
program.release();
} catch (AssertionError ex) {
LOG.log(Level.SEVERE, "kernel test failed with an assertion error");
return false;
} catch (Exception ex) {
LOG.log(Level.SEVERE, "kernel test failed with:", ex);
return false;
}
return true;
}
}
Loading…
Cancel
Save