Jogamp
77da10b4aaa6b983bb809bb1d5cb9cab9a57903f
[jocl.git] / src / com / jogamp / opencl / CLPlatform.java
1 /*
2  * Copyright (c) 2009 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
29 package com.jogamp.opencl;
30
31 import com.jogamp.opencl.llb.CL;
32 import com.jogamp.opencl.impl.CLTLAccessorFactory;
33 import com.jogamp.common.nio.Buffers;
34 import com.jogamp.common.JogampRuntimeException;
35 import com.jogamp.common.nio.PointerBuffer;
36 import com.jogamp.opencl.spi.CLPlatformInfoAccessor;
37 import com.jogamp.opencl.util.CLUtil;
38 import com.jogamp.opencl.llb.impl.CLImpl11;
39 import com.jogamp.opencl.llb.impl.CLImpl12;
40 import com.jogamp.opencl.llb.impl.CLImpl20;
41 import com.jogamp.opencl.spi.CLAccessorFactory;
42 import com.jogamp.opencl.spi.CLInfoAccessor;
43 import com.jogamp.opencl.util.Filter;
44
45 import java.nio.IntBuffer;
46 import java.util.ArrayList;
47 import java.util.Collections;
48 import java.util.HashSet;
49 import java.util.List;
50 import java.util.Map;
51 import java.util.Scanner;
52 import java.util.Set;
53
54 import static com.jogamp.opencl.CLException.*;
55 import static com.jogamp.opencl.llb.CL.*;
56
57 /**
58  * CLPlatfrorm representing a OpenCL implementation (e.g. graphics driver).
59  *
60  * optional eager initialization:
61  * <p><pre>
62  *     if( !CLPlatform.isAvailable() ) {
63  *        return; // abort
64  *     }
65  *     try{
66  *          CLPlatform.initialize();
67  *     }catch(JogampRuntimeException ex) {
68  *          throw new RuntimeException("could not load Java OpenCL Binding");
69  *     }
70  * </pre></p>
71  *
72  * Example initialization:
73  * <p><pre>
74  *     if( !CLPlatform.isAvailable() ) {
75  *        return; // abort
76  *     }
77  *     CLPlatform platform = CLPlatform.getDefault(type(GPU));
78  *
79  *     if(platform == null) {
80  *          throw new RuntimeException("please update your graphics drivers");
81  *     }
82  *
83  *     CLContext context = CLContext.create(platform.getMaxFlopsDevice());
84  *     try {
85  *          // use it
86  *     }finally{
87  *          context.release();
88  *     }
89  * </pre></p>
90  * concurrency:<br/>
91  * CLPlatform is threadsafe.
92  *
93  * @author Michael Bien, et al.
94  * @see #isAvailable()
95  * @see #initialize()
96  * @see #getDefault()
97  * @see #listCLPlatforms()
98  */
99 public class CLPlatform {
100
101     /**
102      * OpenCL platform id for this platform.
103      */
104     public final long ID;
105
106     /**
107      * Version of this OpenCL platform.
108      */
109     public final CLVersion version;
110
111     protected static CL cl;
112     private static CLAccessorFactory defaultFactory;
113     private final CLAccessorFactory factory;
114
115     private Set<String> extensions;
116
117     protected final CLPlatformInfoAccessor info;
118
119     private CLPlatform(final long id) {
120         this(id, null);
121     }
122
123     protected CLPlatform(final long id, final CLAccessorFactory factory) {
124         initialize();
125         this.ID = id;
126         if(factory == null) {
127             this.factory = defaultFactory;
128         }else{
129             this.factory = factory;
130         }
131         this.info = this.factory.createPlatformInfoAccessor(cl, id);
132         this.version = new CLVersion(getInfoString(CL_PLATFORM_VERSION));
133     }
134
135     /**
136      * @returns true if OpenCL is available on this machine,
137      * i.e. all native libraries could be loaded (CL and CL/JNI).
138      */
139     public static boolean isAvailable() { return CLImpl11.isAvailable(); }
140
141     /**
142      * Eagerly initializes JOCL. Subsequent calls do nothing.
143      * @throws JogampRuntimeException if something went wrong in the initialization (e.g. OpenCL lib not found).
144      * @see #isAvailable()
145      */
146     public static void initialize() throws JogampRuntimeException {
147         initialize(null);
148     }
149
150     // keep package private until SPI is stablized
151     /**
152      * Eagerly initializes JOCL. Subsequent calls do nothing.
153      * @param factory CLAccessorFactory used for creating the bindings.
154      * @throws JogampRuntimeException if something went wrong in the initialization (e.g. OpenCL lib not found).
155      * @see #isAvailable()
156      */
157     synchronized static void initialize(final CLAccessorFactory factory) throws JogampRuntimeException {
158         if(cl != null) {
159             return;
160         }
161
162         if(defaultFactory == null) {
163             if(factory == null) {
164                 defaultFactory = new CLTLAccessorFactory();
165             }else{
166                 defaultFactory = factory;
167             }
168         }
169
170         if( !CLImpl11.isAvailable() ) {
171             throw new JogampRuntimeException("JOCL is not available");
172         }
173         cl = new CLImpl11();
174     }
175
176     /**
177      * Returns the default OpenCL platform or null when no platform found.
178      */
179     public static CLPlatform getDefault() {
180         initialize();
181         return latest(listCLPlatforms());
182     }
183
184     /**
185      * Returns the default OpenCL platform or null when no platform found.
186      */
187     public static CLPlatform getDefault(final Filter<CLPlatform>... filter) {
188         final CLPlatform[] platforms = listCLPlatforms(filter);
189         if(platforms.length > 0) {
190             return latest(platforms);
191         }else{
192             return null;
193         }
194     }
195
196     private static CLPlatform latest(final CLPlatform[] platforms) {
197         CLPlatform best = platforms[0];
198         for (final CLPlatform platform : platforms) {
199             if (platform.version.compareTo(best.version) > 0) {
200                 best = platform;
201             }
202         }
203         return best;
204     }
205
206     /**
207      * Lists all available OpenCL implementations.
208      * @throws CLException if something went wrong initializing OpenCL
209      */
210     public static CLPlatform[] listCLPlatforms() {
211         return listCLPlatforms((Filter<CLPlatform>[])null);
212     }
213
214     /**
215      * Lists all available OpenCL implementations. The platforms returned must pass all filters.
216      * @param filter Acceptance filter for the returned platforms.
217      * @throws CLException if something went wrong initializing OpenCL
218      */
219     public static CLPlatform[] listCLPlatforms(final Filter<CLPlatform>... filter) {
220         initialize();
221
222         final IntBuffer ib = Buffers.newDirectIntBuffer(1);
223         // find all available OpenCL platforms
224         int ret = cl.clGetPlatformIDs(0, null, ib);
225         checkForError(ret, "can not enumerate platforms");
226
227         // receive platform ids
228         final PointerBuffer platformId = PointerBuffer.allocateDirect(ib.get(0));
229         ret = cl.clGetPlatformIDs(platformId.capacity(), platformId, null);
230         checkForError(ret, "can not enumerate platforms");
231
232         final List<CLPlatform> platforms = new ArrayList<CLPlatform>();
233
234         for (int i = 0; i < platformId.capacity(); i++) {
235             final CLPlatform platform = new CLPlatform(platformId.get(i));
236             addIfAccepted(platform, platforms, filter);
237         }
238
239         return platforms.toArray(new CLPlatform[platforms.size()]);
240     }
241
242     /**
243      * Returns the low level binding interface to the OpenCL APIs. This interface is always for OpenCL 1.1.
244      */
245     public static CL getLowLevelCLInterface() {
246         initialize();
247         return cl;
248     }
249
250     /**
251      * Returns the low level binding interface to the OpenCL APIs for the specified device. This interface
252      * is the newest one the device supports.
253      */
254     public static CL getLowLevelCLInterfaceForDevice(final long device) {
255         initialize();
256         
257         CLInfoAccessor deviceInfo = defaultFactory.createDeviceInfoAccessor(cl, device);
258         CLVersion version = new CLVersion(deviceInfo.getString(CL_DEVICE_VERSION));
259
260         if(version.isEqual(CLVersion.CL_1_2))
261                 return new CLImpl12();
262
263         if(version.isEqual(CLVersion.CL_2_0))
264                 return new CLImpl20();
265
266         return cl;
267     }
268
269     /**
270      * Hint to allow the implementation to release the resources allocated by the OpenCL compiler.
271      * Calls to {@link CLProgram#build()} after unloadCompiler will reload the compiler if necessary.
272      */
273     public static void unloadCompiler() {
274         initialize();
275         final int ret = cl.clUnloadCompiler();
276         checkForError(ret, "error while sending unload compiler hint");
277     }
278
279     /**
280      * Lists all physical devices available on this platform.
281      * @see #listCLDevices(com.jogamp.opencl.CLDevice.Type...)
282      */
283     public CLDevice[] listCLDevices() {
284         return this.listCLDevices(CLDevice.Type.ALL);
285     }
286
287     /**
288      * Lists all physical devices available on this platform matching the given {@link CLDevice.Type}.
289      */
290     public CLDevice[] listCLDevices(final CLDevice.Type... types) {
291         initialize();
292
293         final List<CLDevice> list = new ArrayList<CLDevice>();
294
295         for(int t = 0; t < types.length; t++) {
296             final CLDevice.Type type = types[t];
297
298             final long[] deviceIDs = info.getDeviceIDs(type.TYPE);
299
300             //add device to list
301             for (int n = 0; n < deviceIDs.length; n++) {
302                 list.add(createDevice(deviceIDs[n]));
303             }
304         }
305
306         return list.toArray(new CLDevice[list.size()]);
307
308     }
309
310     /**
311      * Lists all physical devices available on this platform matching the given {@link Filter}.
312      */
313     public CLDevice[] listCLDevices(final Filter<CLDevice>... filters) {
314         initialize();
315
316         final List<CLDevice> list = new ArrayList<CLDevice>();
317
318         final long[] deviceIDs = info.getDeviceIDs(CL_DEVICE_TYPE_ALL);
319
320         //add device to list
321         for (int n = 0; n < deviceIDs.length; n++) {
322             final CLDevice device = createDevice(deviceIDs[n]);
323             addIfAccepted(device, list, filters);
324         }
325
326         return list.toArray(new CLDevice[list.size()]);
327
328     }
329
330     protected CLDevice createDevice(final long id) {
331         return new CLDevice(this, id);
332     }
333
334     private static <I> void addIfAccepted(final I item, final List<I> list, final Filter<I>[] filters) {
335         if(filters == null) {
336             list.add(item);
337         }else{
338             boolean accepted = true;
339             for (final Filter<I> filter : filters) {
340                 if(!filter.accept(item)) {
341                     accepted = false;
342                     break;
343                 }
344             }
345             if(accepted) {
346                 list.add(item);
347             }
348         }
349     }
350
351     static CLDevice findMaxFlopsDevice(final CLDevice[] devices) {
352         return findMaxFlopsDevice(devices, null);
353     }
354
355     static CLDevice findMaxFlopsDevice(final CLDevice[] devices, final CLDevice.Type type) {
356         initialize();
357
358         CLDevice maxFLOPSDevice = null;
359
360         int maxflops = -1;
361
362         for (int i = 0; i < devices.length; i++) {
363
364             final CLDevice device = devices[i];
365
366             if(type == null || type.equals(device.getType())) {
367
368                 final int maxComputeUnits     = device.getMaxComputeUnits();
369                 final int maxClockFrequency   = device.getMaxClockFrequency();
370                 final int flops = maxComputeUnits*maxClockFrequency;
371
372                 if(flops > maxflops) {
373                     maxflops = flops;
374                     maxFLOPSDevice = device;
375                 }
376             }
377
378         }
379
380         return maxFLOPSDevice;
381     }
382
383
384     /**
385      * Returns the device with maximal FLOPS from this platform.
386      * The device speed is estimated by calculating the product of
387      * MAX_COMPUTE_UNITS and MAX_CLOCK_FREQUENCY.
388      * @see #getMaxFlopsDevice(com.jogamp.opencl.CLDevice.Type...)
389      */
390     public CLDevice getMaxFlopsDevice() {
391         return findMaxFlopsDevice(listCLDevices());
392     }
393
394     /**
395      * Returns the device with maximal FLOPS and the specified type from this platform.
396      * The device speed is estimated by calculating the product of
397      * MAX_COMPUTE_UNITS and MAX_CLOCK_FREQUENCY.
398      */
399     public CLDevice getMaxFlopsDevice(final CLDevice.Type... types) {
400         return findMaxFlopsDevice(listCLDevices(types));
401     }
402
403     /**
404      * Returns the device with maximal FLOPS and the specified type from this platform.
405      * The device speed is estimated by calculating the product of
406      * MAX_COMPUTE_UNITS and MAX_CLOCK_FREQUENCY.
407      */
408     public CLDevice getMaxFlopsDevice(final Filter<CLDevice>... filter) {
409         return findMaxFlopsDevice(listCLDevices(filter));
410     }
411
412     /**
413      * Returns the platform name.
414      */
415     @CLProperty("CL_PLATFORM_NAME")
416     public String getName() {
417         return getInfoString(CL_PLATFORM_NAME);
418     }
419
420     /**
421      * Returns the OpenCL version supported by this platform.
422      */
423     @CLProperty("CL_PLATFORM_VERSION")
424     public CLVersion getVersion() {
425         return version;
426     }
427
428     /**
429      * Returns the OpenCL Specification version supported by this platform.
430      */
431     public String getSpecVersion() {
432         return version.getSpecVersion();
433     }
434
435     /**
436      * @see CLVersion#isAtLeast(com.jogamp.opencl.CLVersion)
437      */
438     public boolean isAtLeast(final CLVersion other) {
439         return version.isAtLeast(other);
440     }
441
442     /**
443      * @see CLVersion#isAtLeast(int, int)
444      */
445     public boolean isAtLeast(final int major, final int minor) {
446         return version.isAtLeast(major, minor);
447     }
448
449     /**
450      * Returns the platform profile.
451      */
452     @CLProperty("CL_PLATFORM_PROFILE")
453     public String getProfile() {
454         return getInfoString(CL_PLATFORM_PROFILE);
455     }
456
457     /**
458      * Returns the platform vendor.
459      */
460     @CLProperty("CL_PLATFORM_VENDOR")
461     public String getVendor() {
462         return getInfoString(CL_PLATFORM_VENDOR);
463     }
464
465     /**
466      * @return true if the vendor is AMD.
467      */
468     public boolean isVendorAMD() {
469         return getVendor().contains("Advanced Micro Devices");
470     }
471     /**
472      * Returns the ICD suffix.
473      */
474     @CLProperty("CL_PLATFORM_ICD_SUFFIX_KHR")
475     public String getICDSuffix() {
476         return getInfoString(CL_PLATFORM_ICD_SUFFIX_KHR);
477     }
478
479     /**
480      * Returns true if the extension is supported on this platform.
481      */
482     public boolean isExtensionAvailable(final String extension) {
483         return getExtensions().contains(extension);
484     }
485
486     /**
487      * Returns all platform extension names as unmodifiable Set.
488      */
489     @CLProperty("CL_PLATFORM_EXTENSIONS")
490     public synchronized Set<String> getExtensions() {
491
492         if(extensions == null) {
493             extensions = new HashSet<String>();
494             final String ext = getInfoString(CL_PLATFORM_EXTENSIONS);
495             final Scanner scanner = new Scanner(ext);
496
497             while(scanner.hasNext())
498                 extensions.add(scanner.next());
499
500             scanner.close();
501             extensions = Collections.unmodifiableSet(extensions);
502         }
503
504         return extensions;
505     }
506
507     /**
508      * Returns a Map of platform properties with the enum names as keys.
509      * @see CLUtil#obtainPlatformProperties(com.jogamp.opencl.CLPlatform)
510      */
511     public Map<String, String> getProperties() {
512         return CLUtil.obtainPlatformProperties(this);
513     }
514
515     /**
516      * Returns a info string in exchange for a key (CL_PLATFORM_*).
517      */
518     public final String getInfoString(final int key) {
519         return info.getString(key);
520     }
521
522     final CLAccessorFactory getAccessorFactory(){
523         return factory;
524     }
525
526     public final CLPlatformInfoAccessor getCLAccessor(){
527         return info;
528     }
529
530     protected CL getCLBinding() {
531         return cl;
532     }
533
534     @Override
535     public String toString() {
536         return getClass().getSimpleName()+" [name: " + getName()
537                          +", vendor: "+getVendor()
538                          +", profile: "+getProfile()
539                          +", version: "+getVersion()+"]";
540     }
541
542     @Override
543     public boolean equals(final Object obj) {
544         if (obj == null) {
545             return false;
546         }
547         if (getClass() != obj.getClass()) {
548             return false;
549         }
550         final CLPlatform other = (CLPlatform) obj;
551         if (this.ID != other.ID) {
552             return false;
553         }
554         return true;
555     }
556
557     @Override
558     public int hashCode() {
559         int hash = 7;
560         hash = 71 * hash + (int) (this.ID ^ (this.ID >>> 32));
561         return hash;
562     }
563
564 }
http://JogAmp.org git info: FAQ, tutorial and man pages.