
com.nativelibs4java.opencl.CLPlatform Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of javacl-core Show documentation
Show all versions of javacl-core Show documentation
JavaCL is an Object-Oriented API that makes the C OpenCL API available to Java in a very natural way.
It hides away the complexity of cross-platform C bindings, has a clean OO design (with generics, Java enums, NIO buffers, fully typed exceptions...), provides high-level features (OpenGL-interop, array reductions) and comes with samples and demos.
For more info, please visit http://code.google.com/p/nativelibs4java/wiki/OpenCL.
The newest version!
/*
* JavaCL - Java API and utilities for OpenCL
* http://javacl.googlecode.com/
*
* Copyright (c) 2009-2013, Olivier Chafik (http://ochafik.com/)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Olivier Chafik nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY OLIVIER CHAFIK AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.nativelibs4java.opencl;
import com.nativelibs4java.opencl.library.OpenGLContextUtils;
import com.nativelibs4java.util.EnumValue;
import com.nativelibs4java.util.EnumValues;
import static com.nativelibs4java.opencl.library.OpenCLLibrary.*;
import static com.nativelibs4java.opencl.library.IOpenCLLibrary.*;
import org.bridj.*;
import org.bridj.ann.*;
import static org.bridj.Pointer.*;
import java.nio.ByteOrder;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.logging.*;
import java.util.concurrent.ConcurrentHashMap;
import static com.nativelibs4java.opencl.JavaCL.*;
import static com.nativelibs4java.opencl.CLException.*;
/**
* OpenCL implementation entry point.
* see {@link JavaCL#listPlatforms() }
* @author Olivier Chafik
*/
public class CLPlatform extends CLAbstractEntity {
CLPlatform(long platform) {
super(platform, true);
}
protected static CLInfoGetter infos = new CLInfoGetter() {
@Override
protected int getInfo(long entity, int infoTypeEnum, long size, Pointer out, Pointer sizeOut) {
return CL.clGetPlatformInfo(entity, infoTypeEnum, size, getPeer(out), getPeer(sizeOut));
}
};
@Override
public String toString() {
return toString(new StringBuilder()).toString();
}
StringBuilder toString(StringBuilder out) {
out.
append(getName()).
append(" {vendor: ").append(getVendor()).
append(", version: ").append(getVersion()).
append(", profile: ").append(getProfile()).
append(", extensions: ").append(Arrays.toString(getExtensions())).
append("}");
return out;
}
@Override
protected void clear() {
}
/**
* Lists all the devices of the platform
* @param onlyAvailable if true, only returns devices that are available
* see {@link CLPlatform#listDevices(CLDevice.Type, boolean) }
*/
public CLDevice[] listAllDevices(boolean onlyAvailable) {
return listDevices(CLDevice.Type.All, onlyAvailable);
}
/**
* Lists all the GPU devices of the platform
* @param onlyAvailable if true, only returns GPU devices that are available
* see {@link CLPlatform#listDevices(CLDevice.Type, boolean) }
*/
public CLDevice[] listGPUDevices(boolean onlyAvailable) {
try {
return listDevices(CLDevice.Type.GPU, onlyAvailable);
} catch (CLException ex) {
if (ex.getCode() == CL_DEVICE_NOT_FOUND) {
return new CLDevice[0];
}
throw new RuntimeException("Unexpected OpenCL error", ex);
}
}
/**
* Lists all the CPU devices of the platform
* @param onlyAvailable if true, only returns CPU devices that are available
* see {@link CLPlatform#listDevices(CLDevice.Type, boolean) }
*/
public CLDevice[] listCPUDevices(boolean onlyAvailable) {
try {
return listDevices(CLDevice.Type.CPU, onlyAvailable);
} catch (CLException ex) {
if (ex.getCode() == CL_DEVICE_NOT_FOUND) {
return new CLDevice[0];
}
throw new RuntimeException("Unexpected OpenCL error", ex);
}
}
private CLDevice[] getDevices(Pointer ids, boolean onlyAvailable) {
int nDevs = (int)ids.getValidElements();
CLDevice[] devices;
if (onlyAvailable) {
List list = new ArrayList(nDevs);
for (int i = 0; i < nDevs; i++) {
CLDevice device = new CLDevice(this, ids.getSizeTAtIndex(i));
if (device.isAvailable()) {
list.add(device);
}
}
devices = list.toArray(new CLDevice[list.size()]);
} else {
devices = new CLDevice[nDevs];
for (int i = 0; i < nDevs; i++) {
devices[i] = new CLDevice(this, ids.getSizeTAtIndex(i));
}
}
return devices;
}
long[] getContextProps(Map contextProperties) {
int nContextProperties = contextProperties == null ? 0 : contextProperties.size();
final long[] properties = new long[(nContextProperties + 1) * 2 + 1];
properties[0] = CL_CONTEXT_PLATFORM;
properties[1] = getEntity();
int iProp = 2;
if (nContextProperties != 0) {
for (Map.Entry e : contextProperties.entrySet()) {
//if (!(v instanceof Number)) throw new IllegalArgumentException("Invalid context property value for '" + e.getKey() + ": " + v);
properties[iProp++] = e.getKey().value();
Object v = e.getValue();
if (v instanceof Number)
properties[iProp++] = ((Number)v).longValue();
else if (v instanceof Pointer)
properties[iProp++] = ((Pointer)v).getPeer();
else
throw new IllegalArgumentException("Cannot convert value " + v + " to a context property value !");
}
}
//properties[iProp] = 0;
return properties;
}
/**
* Enums used to indicate how to choose the best CLDevice.
*/
public enum DeviceFeature {
/**
* Prefer CPU devices (see {@link CLDevice#getType() })
*/
CPU {
Comparable extractValue(CLDevice device) {
return device.getType().contains(CLDevice.Type.CPU) ? 1 : 0;
}
},
/**
* Prefer GPU devices (see {@link CLDevice#getType() })
*/
GPU {
Comparable extractValue(CLDevice device) {
return device.getType().contains(CLDevice.Type.GPU) ? 1 : 0;
}
},
/**
* Prefer Accelerator devices (see {@link CLDevice#getType() })
*/
Accelerator {
Comparable extractValue(CLDevice device) {
return device.getType().contains(CLDevice.Type.Accelerator) ? 1 : 0;
}
},
/**
* Prefer devices with the most compute units (see {@link CLDevice#getMaxComputeUnits() })
*/
MaxComputeUnits {
Comparable extractValue(CLDevice device) {
return device.getMaxComputeUnits();
}
},
/**
* Prefer devices with the same byte ordering as the hosting platform (see {@link CLDevice#getByteOrder() })
*/
NativeEndianness {
Comparable extractValue(CLDevice device) {
return device.getKernelsDefaultByteOrder() == ByteOrder.nativeOrder() ? 1 : 0;
}
},
/**
* Prefer devices that support double-precision float computations (see {@link CLDevice#isDoubleSupported() })
*/
DoubleSupport {
Comparable extractValue(CLDevice device) {
return device.isDoubleSupported() ? 1 : 0;
}
},
/**
* Prefer devices that support images and with the most supported image formats (see {@link CLDevice#hasImageSupport() })
*/
ImageSupport {
Comparable extractValue(CLDevice device) {
return device.hasImageSupport() ? 1 : 0;
}
},
/**
* Prefer devices that support out of order queues (see {@link CLDevice#hasOutOfOrderQueueSupport() })
*/
OutOfOrderQueueSupport {
Comparable extractValue(CLDevice device) {
return device.hasOutOfOrderQueueSupport() ? 1 : 0;
}
},
/**
* Prefer devices with the greatest variety of supported image formats (see {@link CLContext#getSupportedImageFormats(CLMem.Flags, CLMem.ObjectType) })
*/
MostImageFormats {
Comparable extractValue(CLDevice device) {
if (!device.hasImageSupport())
return 0;
// TODO: fix that ugly hack ?
CLContext context = JavaCL.createContext(null, device);
try {
return (Integer)context.getSupportedImageFormats(CLMem.Flags.ReadWrite, CLMem.ObjectType.Image2D).length;
} finally {
context.release();
}
}
};
Comparable extractValue(CLDevice device) {
throw new RuntimeException();
}
}
public static class DeviceComparator implements Comparator {
private final List evals;
public DeviceComparator(List evals) {
this.evals = evals;
}
@Override
public int compare(CLDevice a, CLDevice b) {
for (DeviceFeature eval : evals) {
if (eval == null)
continue;
Comparable va = eval.extractValue(a), vb = eval.extractValue(b);
int c = va.compareTo(vb);
if (c != 0)
return c;
}
return 0;
}
}
public static CLDevice getBestDevice(List evals, Collection devices) {
List list = new ArrayList(devices);
Collections.sort(list, new DeviceComparator(evals));
return !list.isEmpty() ? list.get(list.size() - 1) : null;
}
public CLDevice getBestDevice() {
return getBestDevice(Arrays.asList(DeviceFeature.MaxComputeUnits), Arrays.asList(listAllDevices(true)));
}
/** Bit values for CL_CONTEXT_PROPERTIES */
public enum ContextProperties implements com.nativelibs4java.util.ValuedEnum {
//D3D10Device(CL_CONTEXT_D3D10_DEVICE_KHR),
GLContext(CL_GL_CONTEXT_KHR),
EGLDisplay(CL_EGL_DISPLAY_KHR),
GLXDisplay(CL_GLX_DISPLAY_KHR),
WGLHDC(CL_WGL_HDC_KHR),
Platform(CL_CONTEXT_PLATFORM),
CGLShareGroupApple(CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE),
CGLShareGroup(CL_CGL_SHAREGROUP_KHR);
ContextProperties(long value) { this.value = value; }
long value;
@Override
public long value() { return value; }
public static long getValue(EnumSet set) {
return EnumValues.getValue(set);
}
public static EnumSet getEnumSet(long v) {
return EnumValues.getEnumSet(v, ContextProperties.class);
}
}
public CLContext createContextFromCurrentGL() {
return createGLCompatibleContext(listAllDevices(true));
}
static Map getGLContextProperties(CLPlatform platform) {
Map out = new LinkedHashMap();
if (Platform.isMacOSX()) {
Pointer> context = OpenGLContextUtils.CGLGetCurrentContext();
Pointer> shareGroup = OpenGLContextUtils.CGLGetShareGroup(context);
out.put(ContextProperties.CGLShareGroupApple, shareGroup.getPeer());
} else if (Platform.isWindows()) {
Pointer> context = OpenGLContextUtils.wglGetCurrentContext();
Pointer> dc = OpenGLContextUtils.wglGetCurrentDC();
out.put(ContextProperties.GLContext, context.getPeer());
out.put(ContextProperties.WGLHDC, dc.getPeer());
out.put(ContextProperties.Platform, platform.getEntity());
} else if (Platform.isUnix()) {
Pointer> context = OpenGLContextUtils.glXGetCurrentContext();
Pointer> dc = OpenGLContextUtils.glXGetCurrentDisplay();
out.put(ContextProperties.GLContext, context.getPeer());
out.put(ContextProperties.GLXDisplay, dc.getPeer());
out.put(ContextProperties.Platform, platform.getEntity());
} else
throw new UnsupportedOperationException("Current GL context retrieval not implemented on this platform !");
//out.put(ContextProperties.Platform, platform.getEntity().getPointer());
return out;
}
/**
* Calls clCreateContext.
*/
@Deprecated
public CLContext createGLCompatibleContext(CLDevice... devices) {
for (CLDevice device : devices) {
if (!device.isGLSharingSupported())
continue;
try {
return createContext(getGLContextProperties(this), device);
} catch (Throwable th) {}
}
throw new UnsupportedOperationException("Failed to create an OpenGL-sharing-enabled OpenCL context out of devices " + Arrays.asList(devices));
}
/**
* Calls clCreateContext.
* Creates an OpenCL context formed of the provided devices.
* It is generally not a good idea to create a context with more than one device,
* because much data is shared between all the devices in the same context.
* @param devices devices that are to form the new context
* @return new OpenCL context
*/
public CLContext createContext(Map contextProperties, CLDevice... devices) {
int nDevs = devices.length;
if (nDevs == 0) {
throw new IllegalArgumentException("Cannot create a context with no associated device !");
}
Pointer ids = allocateSizeTs(nDevs);
for (int i = 0; i < nDevs; i++) {
ids.setSizeTAtIndex(i, devices[i].getEntity());
}
ReusablePointers ptrs = ReusablePointers.get();
Pointer pErr = ptrs.pErr;
long[] props = getContextProps(contextProperties);
Pointer propsRef = props == null ? null : pointerToSizeTs(props);
//System.out.println("ERROR CALLBACK " + Long.toHexString(errCb.getPeer()));
long context = CL.clCreateContext(getPeer(propsRef), nDevs, getPeer(ids), 0, 0, getPeer(pErr));
error(pErr.getInt());
;
return new CLContext(this, ids, context);
}
/**
* Calls clGetDeviceIDs.
* List all the devices of the specified types, with only the ones declared as available if onlyAvailable is true.
*/
@SuppressWarnings("deprecation")
public CLDevice[] listDevices(CLDevice.Type type, boolean onlyAvailable) {
Pointer pCount = allocateInt();
error(CL.clGetDeviceIDs(getEntity(), type.value(), 0, 0, getPeer(pCount)));
int nDevs = pCount.getInt();
if (nDevs <= 0) {
return new CLDevice[0];
}
Pointer ids = allocateSizeTs(nDevs);
error(CL.clGetDeviceIDs(getEntity(), type.value(), nDevs, getPeer(ids), 0));
return getDevices(ids, onlyAvailable);
}
/**
* OpenCL profile string. Returns the profile name supported by the implementation. The profile name returned can be one of the following strings:
*
* - FULL_PROFILE if the implementation supports the OpenCL specification (functionality defined as part of the core specification and does not require any extensions to be supported).
* - EMBEDDED_PROFILE if the implementation supports the OpenCL embedded profile. The embedded profile is defined to be a subset for each version of OpenCL. The embedded profile for OpenCL 1.0 is described in section 10.
*
*/
@InfoName("CL_PLATFORM_PROFILE")
public String getProfile() {
return infos.getString(getEntity(), CL_PLATFORM_PROFILE);
}
/**
OpenCL version string. Returns the OpenCL version supported by the implementation. This version string has the following format:
OpenCL<space><major_version.min or_version><space><platform- specific information>
Last Revision Date: 5/16/09 Page 30
The major_version.minor_version value returned will be 1.0.
*/
@InfoName("CL_PLATFORM_VERSION")
public String getVersion() {
return infos.getString(getEntity(), CL_PLATFORM_VERSION);
}
private double versionValue = Double.NaN;
private static final Pattern VERSION_PATTERN = Pattern.compile("OpenCL (\\d+\\.\\d+)\\b.*");
double getVersionValue() {
if (Double.isNaN(versionValue)) {
String versionString = getVersion();
Matcher matcher = VERSION_PATTERN.matcher(versionString);
if (matcher.matches()) {
String str = matcher.group(1);
versionValue = Double.parseDouble(str);
} else {
log(Level.SEVERE, "Failed to parse OpenCL version: '" + versionString + "'");
}
}
return versionValue;
}
void requireMinVersionValue(String feature, double minValue) {
requireMinVersionValue(feature, minValue, Double.NaN);
}
private Set featuresCheckedForVersion = Collections.newSetFromMap(new ConcurrentHashMap());
void requireMinVersionValue(String feature, double minValue, double deprecationValue) {
double value = getVersionValue();
if (value < minValue) {
throw new CLVersionException(feature + " requires OpenCL version " + minValue +
" (detected version is " + value + ")");
} else if (!Double.isNaN(deprecationValue) && featuresCheckedForVersion.add(feature)) {
Level level = null;
if (value < deprecationValue && JavaCL.verbose)
level = Level.INFO;
else if (value >= deprecationValue)
level = Level.WARNING;
if (level != null && shouldLog(level))
log(level, feature + " is deprecated from OpenCL version " + deprecationValue +
" (detected version is " + value + ")");
}
}
/**
* Platform name string.
*/
@InfoName("CL_PLATFORM_NAME")
public String getName() {
return infos.getString(getEntity(), CL_PLATFORM_NAME);
}
/**
* Platform vendor string.
*/
@InfoName("CL_PLATFORM_VENDOR")
public String getVendor() {
return infos.getString(getEntity(), CL_PLATFORM_VENDOR);
}
/**
* Returns a list of extension names
* Extensions defined here must be supported by all devices associated with this platform.
*/
@InfoName("CL_PLATFORM_EXTENSIONS")
public String[] getExtensions() {
if (extensions == null) {
extensions = new LinkedHashSet(Arrays.asList(infos.getString(getEntity(), CL_PLATFORM_EXTENSIONS).split("\\s+")));
}
return extensions.toArray(new String[extensions.size()]);
}
private Set extensions;
public boolean hasExtension(String name) {
getExtensions();
return extensions.contains(name.trim());
}
@InfoName("cl_nv_device_attribute_query")
public boolean isNVDeviceAttributeQuerySupported() {
return hasExtension("cl_nv_device_attribute_query");
}
@InfoName("cl_nv_compiler_options")
public boolean isNVCompilerOptionsSupported() {
return hasExtension("cl_nv_compiler_options");
}
@InfoName("cl_khr_byte_addressable_store")
public boolean isByteAddressableStoreSupported() {
return hasExtension("cl_khr_byte_addressable_store");
}
@InfoName("cl_khr_gl_sharing")
public boolean isGLSharingSupported() {
return hasExtension("cl_khr_gl_sharing") || hasExtension("cl_APPLE_gl_sharing");
}
/**
* Allows the implementation to release the resources allocated by the OpenCL compiler for this platform.
*/
public void unloadPlatformCompiler() {
if (getVersionValue() < 1.2) {
requireMinVersionValue("clUnloadCompiler", 1.1, 1.2);
error(CL.clUnloadCompiler());
} else {
requireMinVersionValue("clUnloadPlatformCompiler", 1.2);
error(CL.clUnloadPlatformCompiler(getEntity()));
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy