diff options
-rw-r--r-- | src/com/mbien/opencl/CLProgram.java | 38 | ||||
-rw-r--r-- | src/com/mbien/opencl/CLProgramBuilder.java | 156 | ||||
-rw-r--r-- | test/com/mbien/opencl/CLProgramTest.java | 40 |
3 files changed, 213 insertions, 21 deletions
diff --git a/src/com/mbien/opencl/CLProgram.java b/src/com/mbien/opencl/CLProgram.java index 829809de..562df69b 100644 --- a/src/com/mbien/opencl/CLProgram.java +++ b/src/com/mbien/opencl/CLProgram.java @@ -206,6 +206,10 @@ public class CLProgram extends CLObject implements CLResource { */ public CLProgram build(String options, CLDevice... devices) { + if(released) { + throw new CLException("can not build a released program"); + } + if(!kernels.isEmpty()) { //No changes to the program executable are allowed while there are //kernel objects associated with a program object. @@ -214,7 +218,7 @@ public class CLProgram extends CLObject implements CLResource { PointerBuffer deviceIDs = null; int count = 0; - if(devices != null) { + if(devices != null && devices.length != 0) { deviceIDs = PointerBuffer.allocateDirect(devices.length); for (int i = 0; i < devices.length; i++) { deviceIDs.put(i, devices[i].ID); @@ -223,6 +227,11 @@ public class CLProgram extends CLObject implements CLResource { count = devices.length; } + // nvidia driver doesn't like empty strings + if(options != null && options.trim().isEmpty()) { + options = null; + } + // invalidate build status buildStatusMap = null; executable = false; @@ -238,6 +247,13 @@ public class CLProgram extends CLObject implements CLResource { } /** + * Prepares the build for this program by returning a {@link CLProgramBuilder}. + */ + public CLProgramBuilder prepare() { + return new CLProgramBuilder(this); + } + + /** * Creates a kernel with the specified kernel name. */ public CLKernel createCLKernel(String kernelName) { @@ -256,24 +272,6 @@ public class CLProgram extends CLObject implements CLResource { } /** - * Creates n instances of a kernel with the specified kernel name. - */ - /* - public CLKernel[] createCLKernels(String kernelName, int instanceCount) { - - if(released) { - return new CLKernel[0]; - } - - CLKernel[] newKernels = new CLKernel[instanceCount]; - for (int i = 0; i < newKernels.length; i++) { - newKernels[i] = createCLKernel(kernelName); - } - return newKernels; - } - */ - - /** * Creates all kernels of this program and stores them a Map with the kernel name as key. */ public Map<String, CLKernel> createCLKernels() { @@ -596,7 +594,7 @@ public class CLProgram extends CLObject implements CLResource { * This option is ignored for single precision numbers if the device does not support single precision denormalized * numbers i.e. {@link CLDevice.FPConfig#DENORM} is not present in the set returned by {@link CLDevice#getSingleFPConfig()}<br> * This option is ignored for double precision numbers if the device does not support double precision or if it does support - * double precison but {@link CLDevice.FPConfig#DENORM} is not present in the set returned by {@link CLDevice#getDoubleFPConfig()}.<br> + * double precision but {@link CLDevice.FPConfig#DENORM} is not present in the set returned by {@link CLDevice#getDoubleFPConfig()}.<br> * This flag only applies for scalar and vector single precision floating-point variables and computations on * these floating-point variables inside a program. It does not apply to reading from or writing to image objects. */ diff --git a/src/com/mbien/opencl/CLProgramBuilder.java b/src/com/mbien/opencl/CLProgramBuilder.java new file mode 100644 index 00000000..3f7ab07b --- /dev/null +++ b/src/com/mbien/opencl/CLProgramBuilder.java @@ -0,0 +1,156 @@ +package com.mbien.opencl; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + + +/** + * CLProgramBuilder is a helper for building programs with more complex configurations or + * building multiple programs with the same configuration. + * @see CLProgram#prepare() + * @author Michael Bien + */ +public final class CLProgramBuilder { + + private transient CLProgram program; + private final Set<String> optionList = new HashSet<String>(); + private final Set<String> defineList = new HashSet<String>(); + private final Set<CLDevice> deviceList = new HashSet<CLDevice>(); + + public CLProgramBuilder() { } + + public CLProgramBuilder(CLProgram program) { + this.program = program; + } + + public CLProgramBuilder withOption(String option) { + this.optionList.add(option); + return this; + } + + public CLProgramBuilder withOptions(String... options) { + for (String option : options) { + this.optionList.add(option); + } + return this; + } + + public CLProgramBuilder withDefine(String name) { + this.defineList.add(CLProgram.define(name)); + return this; + } + + public CLProgramBuilder withDefines(String... names) { + for (String name : names) { + this.defineList.add(CLProgram.define(name)); + } + return this; + } + + public CLProgramBuilder withDefine(String name, Object value) { + this.defineList.add(CLProgram.define(name, value.toString())); + return this; + } + + public CLProgramBuilder withDefines(Map<String, String> defines) { + for (String name : defines.keySet()) { + defineList.add(CLProgram.define(name, defines.get(name))); + } + return this; + } + + public CLProgramBuilder forDevice(CLDevice device) { + CLDevice[] devices = new CLDevice[]{device}; + for (CLDevice device1 : devices) { + this.deviceList.add(device1); + } + return this; + } + + public CLProgramBuilder forDevices(CLDevice... devices) { + for (CLDevice device : devices) { + this.deviceList.add(device); + } + return this; + } + + /** + * Builds or rebuilds a program. + */ + public CLProgram build() { + return build(program); + } + + /** + * Builds or rebuilds a program. + */ + public CLProgram build(CLProgram program) { + if(program == null) { + throw new NullPointerException("no program has been set"); + } + List<String> setup = new ArrayList<String>(); + setup.addAll(optionList); + setup.addAll(defineList); + String options = CLProgram.optionsOf(setup.toArray(new String[setup.size()])); + CLDevice[] devices = deviceList.toArray(new CLDevice[deviceList.size()]); + return program.build(options, devices); + } + + /** + * Resets this builder's configuration like options, devices and defines. + */ + public CLProgramBuilder reset() { + optionList.clear(); + defineList.clear(); + deviceList.clear(); + return this; + } + + public CLProgram getProgram() { + return program; + } + + /** + * Sets the program which should be build. + */ + public CLProgramBuilder setProgram(CLProgram program) { + this.program = program; + return this; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("CLProgramBuilder"); + sb.append("{optionList=").append(optionList); + sb.append(", defineList=").append(defineList); + sb.append(", deviceList=").append(deviceList); + sb.append('}'); + return sb.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + CLProgramBuilder that = (CLProgramBuilder) o; + + if (defineList != null ? !defineList.equals(that.defineList) : that.defineList != null) return false; + if (deviceList != null ? !deviceList.equals(that.deviceList) : that.deviceList != null) return false; + if (optionList != null ? !optionList.equals(that.optionList) : that.optionList != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = optionList != null ? optionList.hashCode() : 0; + result = 31 * result + (defineList != null ? defineList.hashCode() : 0); + result = 31 * result + (deviceList != null ? deviceList.hashCode() : 0); + return result; + } +} diff --git a/test/com/mbien/opencl/CLProgramTest.java b/test/com/mbien/opencl/CLProgramTest.java index 84e0eed5..95ed5e8c 100644 --- a/test/com/mbien/opencl/CLProgramTest.java +++ b/test/com/mbien/opencl/CLProgramTest.java @@ -8,7 +8,6 @@ import org.junit.Test; import static org.junit.Assert.*; import static java.lang.System.*; import static com.mbien.opencl.CLProgram.CompilerOptions.*; -import static com.mbien.opencl.CLProgram.Status.*; /** * @@ -143,6 +142,45 @@ public class CLProgramTest { } + @Test + public void builderTest() throws IOException { + out.println(" - - - CLProgramTest; builder test - - - "); + + CLContext context = CLContext.create(); + CLProgram program = context.createProgram(getClass().getResourceAsStream("testkernels.cl")); + + // same as program.build() + program.prepare().build(); + + assertTrue(program.isExecutable()); +// program.release(); + + + // complex build + program.prepare().withOption(ENABLE_MAD) + .forDevice(context.getMaxFlopsDevice()) + .withDefine("RADIUS", 5) + .withDefine("ENABLE_FOOBAR") + .build(); + + assertTrue(program.isExecutable()); +// program.release(); + + // reusable builder + CLProgramBuilder builder = new CLProgramBuilder() + .withOption(ENABLE_MAD) + .forDevice(context.getMaxFlopsDevice()) + .withDefine("RADIUS", 5) + .withDefine("ENABLE_FOOBAR"); + + builder.build(program); + + assertTrue(program.isExecutable()); +// program.release(); + + + } + } |