/* * Encog(tm) Core v2.5 - Java Version * http://www.heatonresearch.com/encog/ * http://code.google.com/p/encog-java/ * Copyright 2008-2010 Heaton Research, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * For more information on Heaton Research copyrights, licenses * and trademarks visit: * http://www.heatonresearch.com/copyright */ package org.encog.engine.opencl.kernels; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import org.encog.engine.EncogEngineError; import org.encog.engine.opencl.EncogCLDevice; import org.encog.engine.util.ResourceLoader; import org.jocl.CL; import org.jocl.Pointer; import org.jocl.Sizeof; import org.jocl.cl_context; import org.jocl.cl_kernel; import org.jocl.cl_mem; import org.jocl.cl_program; /** * Defines a basic OpenCL kernal, as used by Encog. Contains the kernal source * code and a compiled program/kernal. */ public class EncogKernel { /** * The source code for the kernel. */ private String cl; /** * The OpenCL context. */ private final cl_context context; /** * The OpenCL program. */ private cl_program program; /** * The OpenCL kernel. */ private cl_kernel kernel; /** * The device this kernel will run on. */ private final EncogCLDevice device; /** * The name of the source resource. */ private final String sourceName; /** * The size of the local work group. */ private int localWork; /** * The size of the global work group. */ private int globalWork; /** * The name of the function that should be called to execute this kernel, * from inside the OpenCL source code. */ private final String kernelName; /** * Create an Encog OpenCL kernel. The Kernel will be loaded from an embedded * resource. * * @param device * The OpenCL device to use. * @param sourceName * The name of the kernel, from an embedded resource. * @param kernelName * The name of the function, in the kernel, called to start the * kernel. */ public EncogKernel(final EncogCLDevice device, final String sourceName, final String kernelName) { this.sourceName = sourceName; this.context = device.getPlatform().getContext(); this.device = device; this.kernelName = kernelName; this.cl = ResourceLoader.loadString(sourceName); } /** * Compile the kernel with no preprocessor defines. */ public void compile() { compile(new HashMap<String, String>()); } /** * Compile the kernel with a map of preprocessor defines, a collection of * name-value pairs. * * @param options * A map of preprocessor defines. */ public void compile(final Map<String, String> options) { // clear out any old program if (this.program != null) { CL.clReleaseProgram(this.program); CL.clReleaseKernel(this.kernel); } // Create the program from the source code final cl_program program = CL.clCreateProgramWithSource(this.context, 1, new String[] { this.cl }, null, null); if (options.size() > 0) { final StringBuilder builder = new StringBuilder(); for (final Entry<String, String> obj : options.entrySet()) { if (builder.length() > 0) { builder.append(" "); } builder.append("-D "); builder.append(obj.getKey()); builder.append("="); builder.append(obj.getValue()); } CL.clBuildProgram(program, 0, null, builder.toString(), null, null); } else { CL.clBuildProgram(program, 0, null, null, null, null); } // Create the kernel this.kernel = CL.clCreateKernel(program, this.kernelName, null); } /** * Create an array buffer that is read only for floats. * @param array The array to base on. * @return The memory buffer. */ public cl_mem createArrayReadOnly(final float[] array) { return CL.clCreateBuffer(getContext(), CL.CL_MEM_READ_ONLY | CL.CL_MEM_COPY_HOST_PTR, Sizeof.cl_float * array.length, Pointer.to(array), null); } /** * Create an array buffer that is read only for ints. * @param array The array to base on. * @return The memory buffer. */ public cl_mem createArrayReadOnly(final int[] array) { return CL.clCreateBuffer(getContext(), CL.CL_MEM_READ_ONLY | CL.CL_MEM_COPY_HOST_PTR, Sizeof.cl_int * array.length, Pointer.to(array), null); } /** * Create an array buffer that is write only. * @param length The length of the buffer. * @return The memory buffer. */ public cl_mem createFloatArrayWriteOnly(final int length) { return CL.clCreateBuffer(getContext(), CL.CL_MEM_READ_WRITE, Sizeof.cl_float * length, null, null); } /** * @return the cl */ public String getCLSource() { return this.cl; } /** * @return The OpenCL context that this kernel belongs to. */ public cl_context getContext() { return this.context; } /** * @return the device */ public EncogCLDevice getDevice() { return this.device; } /** * @return The size of the global work buffer. */ public int getGlobalWork() { return this.globalWork; } /** * @return The OpenCL kernel. */ public cl_kernel getKernel() { return this.kernel; } /** * @return The size of the local work group. */ public int getLocalWork() { return this.localWork; } /** * @return Suggested max workgroup size. You will very likely crash the GPU * if you go above this. */ public int getMaxWorkGroupSize() { return (int) getWorkGroupLong(CL.CL_KERNEL_WORK_GROUP_SIZE); } /** * @return The OpenCL program that the kernel belongs to. */ public cl_program getProgram() { return this.program; } /** * @return the sourceName */ public String getSourceName() { return this.sourceName; } /** * Get a long param from the device. * * @param param * The param desired. * @return The param value. */ public long getWorkGroupLong(final int param) { final long[] result = new long[1]; final long[] len = new long[1]; CL.clGetKernelWorkGroupInfo(this.kernel, this.device.getDevice(), param, Sizeof.cl_long, Pointer.to(result), len); return result[0]; } /** * Called internally to prepare to execute a kernel. */ public void prepareKernel() { if (this.kernel == null) { throw new EncogEngineError( "Must compile CL kernel before using it."); } } /** * Release this kernel. */ public void release() { if (this.program != null) { CL.clReleaseProgram(this.program); CL.clReleaseKernel(this.kernel); this.program = null; this.kernel = null; } } /** * Release a buffer. * @param mem The buffer to release. */ public void releaseBuffer(final cl_mem mem) { CL.clReleaseMemObject(mem); } /** * Set an argument. * @param num The argument number. * @param mem The memory buffer. */ public void setArg(final int num, final cl_mem mem) { CL.clSetKernelArg(getKernel(), num, Sizeof.cl_mem, Pointer.to(mem)); } /** * @param cl * the cl to set */ public void setCLSource(final String cl) { this.cl = cl; } /** * Set the size of the global work group. * @param globalWork The size of the global work group. */ public void setGlobalWork(final int globalWork) { this.globalWork = globalWork; } /** * Set the size of the local work group. * @param localWork The size of the local work group. */ public void setLocalWork(final int localWork) { this.localWork = localWork; } }