diff options
Diffstat (limited to 'src/com/jogamp/opencl/CLProgramBuilder.java')
-rw-r--r-- | src/com/jogamp/opencl/CLProgramBuilder.java | 325 |
1 files changed, 325 insertions, 0 deletions
diff --git a/src/com/jogamp/opencl/CLProgramBuilder.java b/src/com/jogamp/opencl/CLProgramBuilder.java new file mode 100644 index 00000000..855d9837 --- /dev/null +++ b/src/com/jogamp/opencl/CLProgramBuilder.java @@ -0,0 +1,325 @@ +package com.jogamp.opencl; + +import com.jogamp.opencl.util.CLBuildConfiguration; +import com.jogamp.opencl.util.CLProgramConfiguration; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +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 similar configurations. + * @see CLProgram#prepare() + * @see #createConfiguration() + * @see #createConfiguration(com.jogamp.opencl.CLProgram) + * @see #loadConfiguration(java.io.ObjectInputStream) + * @see #loadConfiguration(java.io.ObjectInputStream, com.jogamp.opencl.CLContext) + * @author Michael Bien + */ +public final class CLProgramBuilder implements CLProgramConfiguration, Serializable { + + static final long serialVersionUID = 42; + + private static final byte[] NO_BINARIES = new byte[0]; + + private transient CLProgram program; + private transient Map<CLDevice, byte[]> binariesMap = new LinkedHashMap<CLDevice, byte[]>(); + + private String source; + + private final Set<String> optionSet = new LinkedHashSet<String>(); + private final Set<String> defineSet = new LinkedHashSet<String>(); + + + private CLProgramBuilder() { + this(null); + } + + private CLProgramBuilder(CLProgram program) { + this(program, null, null); + } + + private CLProgramBuilder(CLProgram program, String source, Map<CLDevice, byte[]> map) { + this.program = program; + this.source = source; + if(map != null) { + this.binariesMap.putAll(map); + } + } + + /** + * Creates a new CLBuildConfiguration. + */ + public static CLBuildConfiguration createConfiguration() { + return createConfiguration(null); + } + + /** + * Creates a new CLProgramConfiguration for this program. + */ + public static CLProgramConfiguration createConfiguration(CLProgram program) { + return new CLProgramBuilder(program); + } + + /** + * Loads a CLBuildConfiguration. + * @param ois The ObjectInputStream for reading the object. + */ + public static CLBuildConfiguration loadConfiguration(ObjectInputStream ois) throws IOException, ClassNotFoundException { + return (CLBuildConfiguration) ois.readObject(); + } + + /** + * Loads a CLProgramConfiguration containing a CLProgram. + * The CLProgram is initialized and ready to be build after this method call. + * This method preferes program initialization from binaries if this fails or if + * no binaries have been found, it will try to load the program from sources. If + * This also fails an appropriate exception will be thrown. + * @param ois The ObjectInputStream for reading the object. + * @param context The context used for program initialization. + */ + public static CLProgramConfiguration loadConfiguration(ObjectInputStream ois, CLContext context) throws IOException, ClassNotFoundException { + CLProgramBuilder config = (CLProgramBuilder) ois.readObject(); + if(config.binariesMap.size() > 0 && config.binariesMap.values().iterator().next().length > 0) { + try{ + config.program = context.createProgram(config.binariesMap); + }catch(CLException.CLInvalidBinaryException ex) { + if(config.source != null) { + config.program = context.createProgram(config.source); + }else{ + throw new IOException("Program configuration contained invalid program binaries and no source.", ex); + } + } + }else if(config.source != null) { + config.program = context.createProgram(config.source); + }else{ + throw new IOException("Program configuration did not contain program sources or binaries"); + } + return config; + } + + @Override + public void save(ObjectOutputStream oos) throws IOException { + if(program != null) { + this.source = program.getSource(); + if(program.isExecutable()) { + binariesMap = program.getBinaries(); + } + } + oos.writeObject(this); + } + + + @Override + public CLProgramBuilder withOption(String option) { + optionSet.add(option); + return this; + } + + @Override + public CLProgramBuilder withOptions(String... options) { + for (String option : options) { + optionSet.add(option); + } + return this; + } + + @Override + public CLProgramBuilder withDefine(String name) { + defineSet.add(CLProgram.define(name)); + return this; + } + + @Override + public CLProgramBuilder withDefines(String... names) { + for (String name : names) { + defineSet.add(CLProgram.define(name)); + } + return this; + } + + @Override + public CLProgramBuilder withDefine(String name, Object value) { + defineSet.add(CLProgram.define(name, value.toString())); + return this; + } + + @Override + public CLProgramBuilder withDefines(Map<String, ? extends Object> defines) { + for (String name : defines.keySet()) { + defineSet.add(CLProgram.define(name, defines.get(name))); + } + return this; + } + + @Override + public CLProgramBuilder forDevice(CLDevice device) { + binariesMap.put(device, NO_BINARIES); + return this; + } + + @Override + public CLProgramBuilder forDevices(CLDevice... devices) { + for (CLDevice device : devices) { + binariesMap.put(device, NO_BINARIES); + } + return this; + } + + @Override + public CLProgram build() { + return build(program); + } + + @Override + public CLProgram build(CLProgram program) { + if(program == null) { + throw new NullPointerException("no program has been set"); + } + List<String> setup = new ArrayList<String>(); + setup.addAll(optionSet); + setup.addAll(defineSet); + String options = CLProgram.optionsOf(setup.toArray(new String[setup.size()])); + CLDevice[] devices = binariesMap.keySet().toArray(new CLDevice[binariesMap.size()]); + return program.build(options, devices); + } + + @Override + public CLProgramBuilder reset() { + resetOptions(); + resetDefines(); + resetDevices(); + return this; + } + + @Override + public CLProgramConfiguration resetDefines() { + defineSet.clear(); + return this; + } + + @Override + public CLProgramConfiguration resetDevices() { + binariesMap.clear(); + return this; + } + + @Override + public CLProgramConfiguration resetOptions() { + optionSet.clear(); + return this; + } + + private void writeObject(ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + out.writeInt(binariesMap.size()); + + for (CLDevice device : binariesMap.keySet()) { + byte[] binaries = binariesMap.get(device); + out.writeLong(device.ID); + out.writeInt(binaries.length); + out.write(binaries); + } + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + this.binariesMap = new LinkedHashMap<CLDevice, byte[]>(); + int mapSize = in.readInt(); + + for (int i = 0; i < mapSize; i++) { + long deviceID = in.readLong(); + int length = in.readInt(); + byte[] binaries = new byte[length]; + in.readFully(binaries); + + CLDevice device = new CLDevice(CLPlatform.getLowLevelCLInterface(), deviceID); + binariesMap.put(device, binaries); + } + } + + @Override + public CLProgramBuilder asBuildConfiguration() { + CLProgramBuilder builder = new CLProgramBuilder(); + builder.defineSet.addAll(defineSet); + builder.optionSet.addAll(optionSet); + return builder; + } + + @Override + public CLProgramBuilder clone() { + CLProgramBuilder builder = new CLProgramBuilder(program, source, binariesMap); + builder.defineSet.addAll(defineSet); + builder.optionSet.addAll(optionSet); + return builder; + } + + public CLProgram getProgram() { + return program; + } + + public CLProgramBuilder setProgram(CLProgram program) { + this.program = program; + return this; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("CLProgramBuilder"); + sb.append("{options=").append(optionSet); + sb.append(", defines=").append(defineSet); + sb.append(", devices=").append(binariesMap); + 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 (source != null ? !source.equals(that.source) : that.source != null) return false; + if (defineSet != null ? !defineSet.equals(that.defineSet) : that.defineSet != null) return false; + if (optionSet != null ? !optionSet.equals(that.optionSet) : that.optionSet != null) return false; + + if(binariesMap != null && that.binariesMap != null) { + if(binariesMap.size() != that.binariesMap.size()) { + return false; + } + Iterator<CLDevice> iterator0 = binariesMap.keySet().iterator(); + Iterator<CLDevice> iterator1 = that.binariesMap.keySet().iterator(); + for (int i = 0; i < binariesMap.size(); i++) { + CLDevice device0 = iterator0.next(); + CLDevice device1 = iterator1.next(); + if(!device0.equals(device1) || !Arrays.equals(binariesMap.get(device0), that.binariesMap.get(device1))) + return false; + } + }else if(binariesMap != null || that.binariesMap != null) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = optionSet != null ? optionSet.hashCode() : 0; + result = 31 * result + (defineSet != null ? defineSet.hashCode() : 0); + result = 31 * result + (binariesMap != null ? binariesMap.hashCode() : 0); + return result; + } + +} |