JOCL v2.6.0-rc-20250722
JOCL, OpenCL® API Binding for Java™ (public API).
CLProgramBuilder.java
Go to the documentation of this file.
1/*
2 * Copyright 2009 - 2010 JogAmp Community. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of JogAmp Community.
27 */
28
29package com.jogamp.opencl;
30
31import com.jogamp.opencl.util.CLBuildConfiguration;
32import com.jogamp.opencl.util.CLBuildListener;
33import com.jogamp.opencl.util.CLProgramConfiguration;
34import java.io.IOException;
35import java.io.ObjectInputStream;
36import java.io.ObjectOutputStream;
37import java.io.Serializable;
38import java.util.ArrayList;
39import java.util.Arrays;
40import java.util.Collections;
41import java.util.Iterator;
42import java.util.LinkedHashMap;
43import java.util.LinkedHashSet;
44import java.util.List;
45import java.util.Map;
46import java.util.Set;
47
48
49/**
50 * CLProgramBuilder is a helper for building programs with more complex configurations or
51 * building multiple programs with similar configurations.
52 * CLProgramBuilder is used to create {@link CLProgramConfiguration}s and {@link CLBuildConfiguration}s.
53 * @see CLProgram#prepare()
54 * @see #createConfiguration()
55 * @see #createConfiguration(com.jogamp.opencl.CLProgram)
56 * @see #loadConfiguration(java.io.ObjectInputStream)
57 * @see #loadConfiguration(java.io.ObjectInputStream, com.jogamp.opencl.CLContext)
58 * @author Michael Bien
59 */
60public final class CLProgramBuilder implements CLProgramConfiguration, Serializable, Cloneable {
61
62 static final long serialVersionUID = 42;
63
64 private static final byte[] NO_BINARIES = new byte[0];
65
66 private transient CLProgram program;
67 private transient Map<CLDevice, byte[]> binariesMap = new LinkedHashMap<CLDevice, byte[]>();
68
69 private String source;
70
71 private final Set<String> optionSet = new LinkedHashSet<String>();
72 private final Set<String> defineSet = new LinkedHashSet<String>();
73
74
75 private CLProgramBuilder() {
76 this(null);
77 }
78
79 private CLProgramBuilder(final CLProgram program) {
80 this(program, null, null);
81 }
82
83 private CLProgramBuilder(final CLProgram program, final String source, final Map<CLDevice, byte[]> map) {
84 this.program = program;
85 this.source = source;
86 if(map != null) {
87 this.binariesMap.putAll(map);
88 }
89 }
90
91 /**
92 * Creates a new CLBuildConfiguration.
93 */
95 return createConfiguration(null);
96 }
97
98 /**
99 * Creates a new CLProgramConfiguration for this program.
100 */
102 return new CLProgramBuilder(program);
103 }
104
105 /**
106 * Loads a CLBuildConfiguration.
107 * @param ois The ObjectInputStream for reading the object.
108 */
109 public static CLBuildConfiguration loadConfiguration(final ObjectInputStream ois) throws IOException, ClassNotFoundException {
110 return (CLBuildConfiguration) ois.readObject();
111 }
112
113 /**
114 * Loads a CLProgramConfiguration containing a CLProgram.
115 * The CLProgram is initialized and ready to be build after this method call.
116 * This method prefers program initialization from binaries if this fails or if
117 * no binaries have been found, it will try to load the program from sources. If
118 * this also fails an appropriate exception will be thrown.
119 * @param ois The ObjectInputStream for reading the object.
120 * @param context The context used for program initialization.
121 */
122 public static CLProgramConfiguration loadConfiguration(final ObjectInputStream ois, final CLContext context) throws IOException, ClassNotFoundException {
123 final CLProgramBuilder config = (CLProgramBuilder) ois.readObject();
124 if(allBinariesAvailable(config)) {
125 try{
126 config.program = context.createProgram(config.binariesMap);
127 }catch(final CLException.CLInvalidBinaryException ex) {
128 if(config.source != null) {
129 config.program = context.createProgram(config.source);
130 }else{
131 throw new IOException("Program configuration contained invalid program binaries and no source.", ex);
132 }
133 }
134 }else if(config.source != null) {
135 config.program = context.createProgram(config.source);
136 }else{
137 throw new IOException("Program configuration did not contain program sources or binaries");
138 }
139 return config;
140 }
141
142 private static boolean allBinariesAvailable(final CLProgramBuilder config) {
143 for (final Map.Entry<CLDevice, byte[]> entry : config.binariesMap.entrySet()) {
144 if(Arrays.equals(NO_BINARIES, entry.getValue())) {
145 return false;
146 }
147 }
148 return config.binariesMap.size() > 0;
149 }
150
151 @Override
152 public void save(final ObjectOutputStream oos) throws IOException {
153 if(program != null) {
154 this.source = program.getSource();
155 if(program.isExecutable()) {
156 binariesMap = program.getBinaries();
157 }
158 }
159 oos.writeObject(this);
160 }
161
162
163 @Override
164 public CLProgramBuilder withOption(final String option) {
165 optionSet.add(option);
166 return this;
167 }
168
169 @Override
170 public CLProgramBuilder withOptions(final String... options) {
171 optionSet.addAll(Arrays.asList(options));
172 return this;
173 }
174
175 @Override
176 public CLProgramBuilder withDefine(final String name) {
177 defineSet.add(CLProgram.define(name));
178 return this;
179 }
180
181 @Override
182 public CLProgramBuilder withDefines(final String... names) {
183 for (final String name : names) {
184 defineSet.add(CLProgram.define(name));
185 }
186 return this;
187 }
188
189 @Override
190 public CLProgramBuilder withDefine(final String name, final Object value) {
191 defineSet.add(CLProgram.define(name, value.toString()));
192 return this;
193 }
194
195 @Override
197 for (final Map.Entry<String, ? extends Object> define : defines.entrySet()) {
198 final String name = define.getKey();
199 final Object value = define.getValue();
200 defineSet.add(CLProgram.define(name, value));
201 }
202 return this;
203 }
204
205 @Override
206 public CLProgramBuilder forDevice(final CLDevice device) {
207 if(!binariesMap.containsKey(device)) {
208 binariesMap.put(device, NO_BINARIES);
209 }
210 return this;
211 }
212
213 @Override
214 public CLProgramBuilder forDevices(final CLDevice... devices) {
215 for (final CLDevice device : devices) {
216 forDevice(device);
217 }
218 return this;
219 }
220
221 @Override
222 public CLProgram build() {
223 return build(program, null);
224 }
225
226 @Override
227 public CLProgram build(final CLBuildListener listener) {
228 return build(program, listener);
229 }
230
231 @Override
232 public CLProgram build(final CLProgram program) {
233 return build(program, null);
234 }
235
236 @Override
237 public CLProgram build(final CLProgram program, final CLBuildListener listener) {
238 if(program == null) {
239 throw new NullPointerException("no program has been set");
240 }
241 final List<String> setup = new ArrayList<String>();
242 setup.addAll(optionSet);
243 setup.addAll(defineSet);
244 final String options = CLProgram.optionsOf(setup.toArray(new String[setup.size()]));
245 final CLDevice[] devices = binariesMap.keySet().toArray(new CLDevice[binariesMap.size()]);
246 return program.build(listener, options, devices);
247 }
248
249 @Override
251 resetOptions();
252 resetDefines();
253 resetDevices();
254 return this;
255 }
256
257 @Override
259 defineSet.clear();
260 return this;
261 }
262
263 @Override
265 binariesMap.clear();
266 return this;
267 }
268
269 @Override
271 optionSet.clear();
272 return this;
273 }
274
275 // format: { platform_suffix, num_binaries, (device_name, length, binaries)+ }
276 private void writeObject(final ObjectOutputStream out) throws IOException {
277 out.defaultWriteObject();
278
279 String suffix = "";
280
281 if(!binariesMap.isEmpty()) {
282 final CLDevice device = binariesMap.keySet().iterator().next();
283 if(device.isICDAvailable())
284 suffix = device.getPlatform().getICDSuffix();
285 }
286
287 // empty string if we have no binaries or no devices specified, or if cl_khr_icd isn't supported
288 out.writeUTF(suffix);
289 out.writeInt(binariesMap.size()); // may be 0
290
291 for (final Map.Entry<CLDevice, byte[]> entry : binariesMap.entrySet()) {
292 final CLDevice device = entry.getKey();
293 final byte[] binaries = entry.getValue();
294
295 out.writeUTF(device.getName());
296 out.writeInt(binaries.length);
297 out.write(binaries);
298 }
299 }
300
301 private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
302 in.defaultReadObject();
303
304 final String suffix = in.readUTF(); // empty string means no suffix was written; just picks first platform
305 CLPlatform platform = null;
306 for (final CLPlatform p : CLPlatform.listCLPlatforms()) {
307 if(suffix.isEmpty() || p.getICDSuffix().equals(suffix)) {
308 platform = p;
309 break;
310 }
311 }
312
313 this.binariesMap = new LinkedHashMap<CLDevice, byte[]>();
314
315 List<CLDevice> devices;
316 if(platform != null) {
317 devices = new ArrayList<CLDevice>(Arrays.asList(platform.listCLDevices()));
318 }else{
319 devices = Collections.emptyList();
320 }
321
322 final int mapSize = in.readInt();
323
324 for (int i = 0; i < mapSize; i++) {
325 final String name = in.readUTF();
326 final int length = in.readInt();
327 final byte[] binaries = new byte[length];
328 in.readFully(binaries);
329
330 for (int d = 0; d < devices.size(); d++) {
331 final CLDevice device = devices.get(d);
332 if(device.getName().equals(name)) {
333 binariesMap.put(device, binaries);
334 devices.remove(d);
335 break;
336 }
337 }
338 }
339 }
340
341 @Override
343 final CLProgramBuilder builder = new CLProgramBuilder();
344 builder.defineSet.addAll(defineSet);
345 builder.optionSet.addAll(optionSet);
346 return builder;
347 }
348
349 @Override
351 final CLProgramBuilder builder = new CLProgramBuilder(program, source, binariesMap);
352 builder.defineSet.addAll(defineSet);
353 builder.optionSet.addAll(optionSet);
354 return builder;
355 }
356
357 @Override
359 return program;
360 }
361
362 @Override
363 public CLProgramBuilder setProgram(final CLProgram program) {
364 this.program = program;
365 return this;
366 }
367
368 @Override
369 public String toString() {
370 final StringBuilder sb = new StringBuilder();
371 sb.append("CLProgramBuilder");
372 sb.append("{options=").append(optionSet);
373 sb.append(", defines=").append(defineSet);
374 sb.append(", devices=").append(binariesMap);
375 sb.append('}');
376 return sb.toString();
377 }
378
379 @Override
380 public boolean equals(final Object o) {
381 if (this == o) return true;
382 if (o == null || getClass() != o.getClass()) return false;
383
384 final CLProgramBuilder that = (CLProgramBuilder) o;
385
386 if (source != null ? !source.equals(that.source) : that.source != null) return false;
387 if (defineSet != null ? !defineSet.equals(that.defineSet) : that.defineSet != null) return false;
388 if (optionSet != null ? !optionSet.equals(that.optionSet) : that.optionSet != null) return false;
389
390 if(binariesMap != null && that.binariesMap != null) {
391 if(binariesMap.size() != that.binariesMap.size()) {
392 return false;
393 }
394 final Iterator<CLDevice> iterator0 = binariesMap.keySet().iterator();
395 final Iterator<CLDevice> iterator1 = that.binariesMap.keySet().iterator();
396 for (int i = 0; i < binariesMap.size(); i++) {
397 final CLDevice device0 = iterator0.next();
398 final CLDevice device1 = iterator1.next();
399 if(!device0.equals(device1) || !Arrays.equals(binariesMap.get(device0), that.binariesMap.get(device1)))
400 return false;
401 }
402 }else if(binariesMap != null || that.binariesMap != null) {
403 return false;
404 }
405
406 return true;
407 }
408
409 @Override
410 public int hashCode() {
411 int result = optionSet != null ? optionSet.hashCode() : 0;
412 result = 31 * result + (defineSet != null ? defineSet.hashCode() : 0);
413 result = 31 * result + (binariesMap != null ? binariesMap.hashCode() : 0);
414 return result;
415 }
416
417}
CLContext is responsible for managing objects such as command-queues, memory, program and kernel obje...
Definition: CLContext.java:79
This object represents an OpenCL device.
Definition: CLDevice.java:53
boolean equals(final Object obj)
Definition: CLDevice.java:725
CLPlatform getPlatform()
Returns the platform for this OpenCL object.
Definition: CLDevice.java:102
boolean isICDAvailable()
Returns isExtensionAvailable("cl_khr_icd").
Definition: CLDevice.java:652
CLException thrown on CL.CL_INVALID_BINARY errors.
Main Exception type for runtime OpenCL errors and failed function calls (e.g.
String getICDSuffix()
Returns the ICD suffix.
CLProgramBuilder is a helper for building programs with more complex configurations or building multi...
CLProgram build(final CLProgram program)
Builds or rebuilds the program.
CLProgram build(final CLBuildListener listener)
Builds or rebuilds a program.
static CLBuildConfiguration createConfiguration()
Creates a new CLBuildConfiguration.
CLProgramBuilder withDefine(final String name, final Object value)
Adds the definition to the build configuration.
CLProgramBuilder withOption(final String option)
Adds the compiler option to the build configuration.
CLProgramConfiguration resetDevices()
Resets this builder's device list.
CLProgramBuilder reset()
Resets this builder's configuration like options, devices and definitions.
static CLProgramConfiguration loadConfiguration(final ObjectInputStream ois, final CLContext context)
Loads a CLProgramConfiguration containing a CLProgram.
CLProgramBuilder forDevices(final CLDevice... devices)
Adds the devices as build target.
CLProgramBuilder clone()
Clones this configuration.
CLProgramConfiguration resetDefines()
Resets this builder's macro definitions.
CLProgramBuilder withDefines(final Map< String, ? extends Object > defines)
CLProgramBuilder setProgram(final CLProgram program)
Sets the program which should be build.
CLProgramConfiguration resetOptions()
Resets this builder's configuration options.
CLProgramBuilder forDevice(final CLDevice device)
Adds the device as build target.
CLProgram getProgram()
Returns the program.
CLProgram build()
Builds or rebuilds a program.
static CLProgramConfiguration createConfiguration(final CLProgram program)
Creates a new CLProgramConfiguration for this program.
CLProgramBuilder withDefine(final String name)
Adds the definition to the build configuration.
CLProgram build(final CLProgram program, final CLBuildListener listener)
Builds or rebuilds the program.
CLProgramBuilder withDefines(final String... names)
Adds the definitions to the build configuration.
void save(final ObjectOutputStream oos)
Saves this configuration to the ObjectOutputStream.
static CLBuildConfiguration loadConfiguration(final ObjectInputStream ois)
Loads a CLBuildConfiguration.
CLProgramBuilder withOptions(final String... options)
Adds the compiler options to the build configuration.
CLProgramBuilder asBuildConfiguration()
Returns a new instance of of this configuration without a CLProgram, program binaries or sources asso...
Represents a OpenCL program executed on one or more CLDevices.
Definition: CLProgram.java:64
static String define(final String name)
Utility method for defining macros as build options (Returns "-D name").
Definition: CLProgram.java:687
boolean isExecutable()
Returns true if the build status 'BUILD_SUCCESS' for at least one device of this program exists.
Definition: CLProgram.java:570
Map< CLDevice, byte[]> getBinaries()
Returns the binaries for this program in an ordered Map containing the device as key and the program ...
Definition: CLProgram.java:624
String getSource()
Returns the source code of this program.
Definition: CLProgram.java:609
CLProgram build()
Builds this program for all devices associated with the context.
Definition: CLProgram.java:226
static String optionsOf(final String... options)
Utility method which builds a properly seperated option string.
Definition: CLProgram.java:674
Configures the mapping process.
Definition: CLMemory.java:402
Configuration representing everything needed to build an OpenCL program.
A callback an application can register to be called when the program executable has been built (succe...
Configuration representing everything needed to build an OpenCL program (program included).