#parse("main/Header.vm")
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);
}
#declareInfosGetter("infos", "CL.clGetPlatformInfo")
@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<SizeT> ids, boolean onlyAvailable) {
int nDevs = (int)ids.getValidElements();
CLDevice[] devices;
if (onlyAvailable) {
List<CLDevice> list = new ArrayList<CLDevice>(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, Object> 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<ContextProperties, Object> 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<CLDevice> {
private final List<DeviceFeature> evals;
public DeviceComparator(List<DeviceFeature> 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<DeviceFeature> evals, Collection<CLDevice> devices) {
List<CLDevice> list = new ArrayList<CLDevice>(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<ContextProperties> set) {
return EnumValues.getValue(set);
}
public static EnumSet<ContextProperties> getEnumSet(long v) {
return EnumValues.getEnumSet(v, ContextProperties.class);
}
}
public CLContext createContextFromCurrentGL() {
return createGLCompatibleContext(listAllDevices(true));
}
static Map<ContextProperties, Object> getGLContextProperties(CLPlatform platform) {
Map<ContextProperties, Object> out = new LinkedHashMap<ContextProperties, Object>();
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;
}
/**
#documentCallsFunction("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));
}
/**
#documentCallsFunction("clCreateContext")
* Creates an OpenCL context formed of the provided devices.<br>
* 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, Object> contextProperties, CLDevice... devices) {
int nDevs = devices.length;
if (nDevs == 0) {
throw new IllegalArgumentException("Cannot create a context with no associated device !");
}
Pointer<SizeT> ids = allocateSizeTs(nDevs);
for (int i = 0; i < nDevs; i++) {
ids.setSizeTAtIndex(i, devices[i].getEntity());
}
#declareReusablePtrsAndPErr()
long[] props = getContextProps(contextProperties);
Pointer<SizeT> 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));
#checkPErr();
return new CLContext(this, ids, context);
}
/**
#documentCallsFunction("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<Integer> pCount = allocateInt();
error(CL.clGetDeviceIDs(getEntity(), type.value(), 0, 0, getPeer(pCount)));
int nDevs = pCount.getInt();
if (nDevs <= 0) {
return new CLDevice[0];
}
Pointer<SizeT> 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:
* <ul>
* <li>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).</li>
* <li>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.</li>
* </ul>
*/
@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<String> featuresCheckedForVersion = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
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 <br>
* 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<String>(Arrays.asList(infos.getString(getEntity(), CL_PLATFORM_EXTENSIONS).split("\\s+")));
}
return extensions.toArray(new String[extensions.size()]);
}
private Set<String> 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()));
}
}
}