TestOpenCLLibraries.java 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /*
  2. * Copyright (c) 2009-2012 jMonkeyEngine
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are
  7. * met:
  8. *
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. *
  12. * * Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. *
  16. * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
  17. * may be used to endorse or promote products derived from this software
  18. * without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  22. * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  23. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  24. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  25. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  26. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  27. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  28. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  29. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  30. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. */
  32. package jme3test.opencl;
  33. import com.jme3.app.SimpleApplication;
  34. import com.jme3.font.BitmapFont;
  35. import com.jme3.font.BitmapText;
  36. import com.jme3.math.ColorRGBA;
  37. import com.jme3.math.FastMath;
  38. import com.jme3.math.Matrix3f;
  39. import com.jme3.math.Matrix4f;
  40. import com.jme3.opencl.*;
  41. import com.jme3.system.AppSettings;
  42. import com.jme3.util.BufferUtils;
  43. import java.nio.*;
  44. import java.util.Arrays;
  45. import java.util.Objects;
  46. import java.util.Random;
  47. import java.util.logging.Level;
  48. import java.util.logging.Logger;
  49. /**
  50. * Test class for the build in libraries
  51. * @author shaman
  52. */
  53. public class TestOpenCLLibraries extends SimpleApplication {
  54. private static final Logger LOG = Logger.getLogger(TestOpenCLLibraries.class.getName());
  55. public static void main(String[] args){
  56. TestOpenCLLibraries app = new TestOpenCLLibraries();
  57. AppSettings settings = new AppSettings(true);
  58. settings.setOpenCLSupport(true);
  59. settings.setVSync(true);
  60. // settings.setRenderer(AppSettings.JOGL_OPENGL_FORWARD_COMPATIBLE);
  61. app.setSettings(settings);
  62. app.start(); // start the game
  63. }
  64. @Override
  65. public void simpleInitApp() {
  66. BitmapFont fnt = assetManager.loadFont("Interface/Fonts/Default.fnt");
  67. Context clContext = context.getOpenCLContext();
  68. if (clContext == null) {
  69. BitmapText txt = new BitmapText(fnt);
  70. txt.setText("No OpenCL Context created!\nSee output log for details.");
  71. txt.setLocalTranslation(5, settings.getHeight() - 5, 0);
  72. guiNode.attachChild(txt);
  73. return;
  74. }
  75. CommandQueue clQueue = clContext.createQueue(clContext.getDevices().get(0));
  76. StringBuilder str = new StringBuilder();
  77. str.append("OpenCL Context created:\n Platform: ")
  78. .append(clContext.getDevices().get(0).getPlatform().getName())
  79. .append("\n Devices: ").append(clContext.getDevices());
  80. str.append("\nTests:");
  81. str.append("\n Random numbers: ").append(testRandom(clContext, clQueue));
  82. str.append("\n Matrix3f: ").append(testMatrix3f(clContext, clQueue));
  83. str.append("\n Matrix4f: ").append(testMatrix4f(clContext, clQueue));
  84. clQueue.release();
  85. BitmapText txt1 = new BitmapText(fnt);
  86. txt1.setText(str.toString());
  87. txt1.setLocalTranslation(5, settings.getHeight() - 5, 0);
  88. guiNode.attachChild(txt1);
  89. flyCam.setEnabled(false);
  90. inputManager.setCursorVisible(true);
  91. }
  92. private static void assertEquals(byte expected, byte actual, String message) {
  93. if (expected != actual) {
  94. System.err.println(message+": expected="+expected+", actual="+actual);
  95. throw new AssertionError();
  96. }
  97. }
  98. private static void assertEquals(long expected, long actual, String message) {
  99. if (expected != actual) {
  100. System.err.println(message+": expected="+expected+", actual="+actual);
  101. throw new AssertionError();
  102. }
  103. }
  104. private static void assertEquals(double expected, double actual, String message) {
  105. if (Math.abs(expected - actual) >= 0.00001) {
  106. System.err.println(message+": expected="+expected+", actual="+actual);
  107. throw new AssertionError();
  108. }
  109. }
  110. private static void assertEquals(Object expected, Object actual, String message) {
  111. if (!Objects.equals(expected, actual)) {
  112. System.err.println(message+": expected="+expected+", actual="+actual);
  113. throw new AssertionError();
  114. }
  115. }
  116. private boolean testRandom(Context clContext, CommandQueue clQueue) {
  117. try {
  118. //test for doubles
  119. boolean supportsDoubles = clContext.getDevices().get(0).hasDouble();
  120. //create code
  121. String code = ""
  122. + "#import \"Common/OpenCL/Random.clh\"\n"
  123. + "__kernel void TestBool(__global ulong* seeds, __global uchar* results) {\n"
  124. + " results[get_global_id(0)] = randBool(seeds + get_global_id(0)) ? 1 : 0;\n"
  125. + "}\n"
  126. + "__kernel void TestInt(__global ulong* seeds, __global int* results) {\n"
  127. + " results[get_global_id(0)] = randInt(seeds + get_global_id(0));\n"
  128. + "}\n"
  129. + "__kernel void TestIntN(__global ulong* seeds, int n, __global int* results) {\n"
  130. + " results[get_global_id(0)] = randIntN(n, seeds + get_global_id(0));\n"
  131. + "}\n"
  132. + "__kernel void TestLong(__global ulong* seeds, __global long* results) {\n"
  133. + " results[get_global_id(0)] = randLong(seeds + get_global_id(0));\n"
  134. + "}\n"
  135. + "__kernel void TestFloat(__global ulong* seeds, __global float* results) {\n"
  136. + " results[get_global_id(0)] = randFloat(seeds + get_global_id(0));\n"
  137. + "}\n"
  138. + "#ifdef RANDOM_DOUBLES\n"
  139. + "__kernel void TestDouble(__global ulong* seeds, __global double* results) {\n"
  140. + " results[get_global_id(0)] = randDouble(seeds + get_global_id(0));\n"
  141. + "}\n"
  142. + "#endif\n";
  143. if (supportsDoubles) {
  144. code = "#define RANDOM_DOUBLES\n" + code;
  145. }
  146. Program program = clContext.createProgramFromSourceCodeWithDependencies(code, assetManager);
  147. program.build();
  148. int count = 256;
  149. Kernel.WorkSize ws = new Kernel.WorkSize(count);
  150. //create seeds
  151. Random initRandom = new Random();
  152. long[] seeds = new long[count];
  153. Random[] randoms = new Random[count];
  154. for (int i=0; i<count; ++i) {
  155. seeds[i] = initRandom.nextLong();
  156. randoms[i] = new Random(seeds[i]);
  157. seeds[i] = (seeds[i] ^ 0x5DEECE66DL) & ((1L << 48) - 1); //needed because the Random constructor scrambles the initial seed
  158. }
  159. com.jme3.opencl.Buffer seedsBuffer = clContext.createBuffer(8 * count);
  160. ByteBuffer tmpByteBuffer = BufferUtils.createByteBuffer(8 * count);
  161. tmpByteBuffer.asLongBuffer().put(seeds);
  162. seedsBuffer.write(clQueue, tmpByteBuffer);
  163. //test it
  164. ByteBuffer resultByteBuffer = BufferUtils.createByteBuffer(8 * count);
  165. IntBuffer resultIntBuffer = resultByteBuffer.asIntBuffer();
  166. LongBuffer resultLongBuffer = resultByteBuffer.asLongBuffer();
  167. FloatBuffer resultFloatBuffer = resultByteBuffer.asFloatBuffer();
  168. DoubleBuffer resultDoubleBuffer = resultByteBuffer.asDoubleBuffer();
  169. com.jme3.opencl.Buffer resultBuffer = clContext.createBuffer(8 * count);
  170. //boolean
  171. Kernel testBoolKernel = program.createKernel("TestBool");
  172. testBoolKernel.Run1NoEvent(clQueue, ws, seedsBuffer, resultBuffer);
  173. resultByteBuffer.rewind();
  174. resultBuffer.read(clQueue, resultByteBuffer);
  175. for (int i=0; i<count; ++i) {
  176. assertEquals(randoms[i].nextBoolean() ? 1 : 0, resultByteBuffer.get(i), "randBool at i="+i);
  177. }
  178. testBoolKernel.release();
  179. //int
  180. Kernel testIntKernel = program.createKernel("TestInt");
  181. testIntKernel.Run1NoEvent(clQueue, ws, seedsBuffer, resultBuffer);
  182. resultByteBuffer.rewind();
  183. resultBuffer.read(clQueue, resultByteBuffer);
  184. for (int i=0; i<count; ++i) {
  185. assertEquals(randoms[i].nextInt(), resultIntBuffer.get(i), "randInt at i="+i);
  186. }
  187. testIntKernel.release();
  188. //int n
  189. Kernel testIntNKernel = program.createKernel("TestIntN");
  190. testIntNKernel.Run1NoEvent(clQueue, ws, seedsBuffer, 186, resultBuffer);
  191. resultByteBuffer.rewind();
  192. resultBuffer.read(clQueue, resultByteBuffer);
  193. for (int i=0; i<count; ++i) {
  194. assertEquals(randoms[i].nextInt(186), resultIntBuffer.get(i), "randInt at i="+i+" with n="+186);
  195. }
  196. testIntNKernel.Run1NoEvent(clQueue, ws, seedsBuffer, 97357, resultBuffer);
  197. resultByteBuffer.rewind();
  198. resultBuffer.read(clQueue, resultByteBuffer);
  199. for (int i=0; i<count; ++i) {
  200. assertEquals(randoms[i].nextInt(97357), resultIntBuffer.get(i), "randInt at i="+i+" with n="+97357);
  201. }
  202. testIntNKernel.release();
  203. //long
  204. Kernel testLongKernel = program.createKernel("TestLong");
  205. testLongKernel.Run1NoEvent(clQueue, ws, seedsBuffer, resultBuffer);
  206. resultByteBuffer.rewind();
  207. resultBuffer.read(clQueue, resultByteBuffer);
  208. for (int i=0; i<count; ++i) {
  209. assertEquals(randoms[i].nextLong(), resultLongBuffer.get(i), "randLong at i="+i);
  210. }
  211. testLongKernel.release();
  212. //float
  213. Kernel testFloatKernel = program.createKernel("TestFloat");
  214. testFloatKernel.Run1NoEvent(clQueue, ws, seedsBuffer, resultBuffer);
  215. resultByteBuffer.rewind();
  216. resultBuffer.read(clQueue, resultByteBuffer);
  217. for (int i=0; i<count; ++i) {
  218. assertEquals(randoms[i].nextFloat(), resultFloatBuffer.get(i), "randFloat at i="+i);
  219. }
  220. testFloatKernel.release();
  221. //double
  222. if (supportsDoubles) {
  223. Kernel testDoubleKernel = program.createKernel("TestDouble");
  224. testDoubleKernel.Run1NoEvent(clQueue, ws, seedsBuffer, resultBuffer);
  225. resultByteBuffer.rewind();
  226. resultBuffer.read(clQueue, resultByteBuffer);
  227. for (int i=0; i<count; ++i) {
  228. assertEquals(randoms[i].nextDouble(), resultDoubleBuffer.get(i), "randLong at i="+i);
  229. }
  230. testDoubleKernel.release();
  231. }
  232. seedsBuffer.release();
  233. resultBuffer.release();
  234. program.release();
  235. } catch (AssertionError ex) {
  236. LOG.log(Level.SEVERE, "random test failed with an assertion error");
  237. return false;
  238. } catch (Exception ex) {
  239. LOG.log(Level.SEVERE, "random test failed with:", ex);
  240. return false;
  241. }
  242. return true;
  243. }
  244. private boolean testMatrix3f(Context clContext, CommandQueue clQueue) {
  245. try {
  246. String code = ""
  247. + "#import \"Common/OpenCL/Matrix3f.clh\"\n"
  248. + "\n"
  249. + "__kernel void TestMatrix3f_1(__global char* result)\n"
  250. + "{\n"
  251. + " mat3 id = mat3Identity();\n"
  252. + " mat3 m1 = mat3FromRows( (float3)(23,-3,10.4f), (float3)(5,-8,2.22f), (float3)(-1,0,34) );\n"
  253. + " mat3 m1Inv = mat3Invert(m1);\n"
  254. + " mat3 m1Res = mat3Mult(m1, m1Inv);\n"
  255. + " result[0] = mat3Equals(id, m1Res, 0.0001f) ? 1 : 0;\n"
  256. + "}\n"
  257. + "\n"
  258. + "__kernel void TestMatrix3f_2(mat3 m1, float a, mat3 m2, mat3 mRes, __global char* result)\n"
  259. + "{\n"
  260. + " mat3 m = mat3Transpose(m1);\n"
  261. + " m = mat3Add(mat3Scale(m, a), m2);\n"
  262. + " result[0] = mat3Equals(mRes, m, 0.01f) ? 1 : 0;\n"
  263. + "}\n";
  264. Program program = clContext.createProgramFromSourceCodeWithDependencies(code, assetManager);
  265. program.build();
  266. com.jme3.opencl.Buffer buffer = clContext.createBuffer(1);
  267. Kernel testMatrix3fKernel1 = program.createKernel("TestMatrix3f_1");
  268. testMatrix3fKernel1.Run1NoEvent(clQueue, new Kernel.WorkSize(1), buffer);
  269. ByteBuffer bb = buffer.map(clQueue, MappingAccess.MAP_READ_ONLY);
  270. if (bb.get() == 0) {
  271. LOG.severe("Matrix inversion failed");
  272. return false;
  273. }
  274. buffer.unmap(clQueue, bb);
  275. testMatrix3fKernel1.release();
  276. Kernel testMatrix3fKernel2 = program.createKernel("TestMatrix3f_2");
  277. Matrix3f m1 = new Matrix3f(13.24f, -0.234f, 42, 83.23f, -34.2f, 3.2f, 0.25f, -42, 7.64f);
  278. Matrix3f m2 = new Matrix3f(-5.2f, 0.757f, 2.01f, 12.0f, -6, 2, 0.01f, 9, 2.255f);
  279. Matrix3f mRes = new Matrix3f(-31.68f, -165.703f, 1.51f, 12.468f, 62.4f, 86, -83.99f, 2.6f, -13.025f);
  280. testMatrix3fKernel2.Run1NoEvent(clQueue, new Kernel.WorkSize(1), m1, -2.0f, m2, mRes, buffer);
  281. bb = buffer.map(clQueue, MappingAccess.MAP_READ_ONLY);
  282. if (bb.get() == 0) {
  283. LOG.severe("Matrix add, multiply, transpose failed");
  284. return false;
  285. }
  286. buffer.unmap(clQueue, bb);
  287. testMatrix3fKernel2.release();
  288. buffer.release();
  289. } catch (AssertionError ex) {
  290. LOG.log(Level.SEVERE, "matrix3f test failed with an assertion error");
  291. return false;
  292. } catch (Exception ex) {
  293. LOG.log(Level.SEVERE, "matrix3f test failed with:", ex);
  294. return false;
  295. }
  296. return true;
  297. }
  298. private boolean testMatrix4f(Context clContext, CommandQueue clQueue) {
  299. try {
  300. String code = ""
  301. + "#import \"Common/OpenCL/Matrix4f.clh\"\n"
  302. + "\n"
  303. + "__kernel void TestMatrix4f_1(mat4 m1, __global char* result)\n"
  304. + "{\n"
  305. + " mat4 id = mat4Identity();\n"
  306. + " mat4 m1Inv = mat4Invert(m1);\n"
  307. + " mat4 m1Res = mat4Mult(m1, m1Inv);\n"
  308. + " result[0] = mat4Equals(id, m1Res, 0.0001f) ? 1 : 0;\n"
  309. + "}\n"
  310. + "\n"
  311. + "__kernel void TestMatrix4f_2(mat4 m1, float d, mat4 m2, mat4 m3, __global char* result)\n"
  312. + "{\n"
  313. + " float d2 = mat4Determinant(m1);\n"
  314. + " result[0] = fabs(d - d2) < 0.0001f ? 1 : 0;\n"
  315. + " mat4 res = mat4Transpose(m1);\n"
  316. + " result[1] = mat4Equals(res, m2, 0.0001f) ? 1 : 0;\n"
  317. + " res = mat4Adjoint(m1);\n"
  318. + " result[2] = mat4Equals(res, m3, 0.0001f) ? 1 : 0;\n"
  319. + "}\n";
  320. Program program = clContext.createProgramFromSourceCodeWithDependencies(code, assetManager);
  321. program.build();
  322. com.jme3.opencl.Buffer buffer = clContext.createBuffer(3);
  323. Random rand = new Random(1561);
  324. Kernel testMatrix4fKernel1 = program.createKernel("TestMatrix4f_1");
  325. Matrix4f m1 = new Matrix4f();
  326. do {
  327. for (int i=0; i<4; ++i) {
  328. for (int j=0; j<4; ++j) {
  329. m1.set(i, j, rand.nextFloat()*20 - 10);
  330. }
  331. }
  332. } while (FastMath.abs(m1.determinant()) < 0.00001f);
  333. testMatrix4fKernel1.Run1NoEvent(clQueue, new Kernel.WorkSize(1), m1, buffer);
  334. ByteBuffer bb = buffer.map(clQueue, MappingAccess.MAP_READ_ONLY);
  335. if (bb.get() == 0) {
  336. LOG.severe("Matrix inversion failed");
  337. return false;
  338. }
  339. buffer.unmap(clQueue, bb);
  340. testMatrix4fKernel1.release();
  341. Kernel testMatrix4fKernel2 = program.createKernel("TestMatrix4f_2");
  342. for (int i=0; i<4; ++i) {
  343. for (int j=0; j<4; ++j) {
  344. m1.set(i, j, rand.nextFloat()*20 - 10);
  345. }
  346. }
  347. testMatrix4fKernel2.Run1NoEvent(clQueue, new Kernel.WorkSize(1), m1, m1.determinant(), m1.transpose(), m1.adjoint(), buffer);
  348. bb = buffer.map(clQueue, MappingAccess.MAP_READ_ONLY);
  349. if (bb.get() == 0) {
  350. LOG.severe("Matrix determinant computation failed");
  351. return false;
  352. }
  353. if (bb.get() == 0) {
  354. LOG.severe("Matrix transposing failed");
  355. return false;
  356. }
  357. if (bb.get() == 0) {
  358. LOG.severe("Matrix adjoint computation failed");
  359. return false;
  360. }
  361. buffer.unmap(clQueue, bb);
  362. testMatrix4fKernel2.release();
  363. buffer.release();
  364. } catch (AssertionError ex) {
  365. LOG.log(Level.SEVERE, "matrix4f test failed with an assertion error");
  366. return false;
  367. } catch (Exception ex) {
  368. LOG.log(Level.SEVERE, "matrix4f test failed with:", ex);
  369. return false;
  370. }
  371. return true;
  372. }
  373. }