/* * Created on Thursday, April 28 2011 22:10 */ package com.jogamp.opencl.util; import com.jogamp.opencl.CLContext; import com.jogamp.opencl.CLDevice; import com.jogamp.opencl.CLPlatform; import com.jogamp.opencl.CLResource; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import static java.util.Arrays.*; import static com.jogamp.opencl.CLDevice.Type.*; /** * Utility for organizing multiple {@link CLContext}s. * * @author Michael Bien */ public class CLMultiContext implements CLResource { private final List contexts; private boolean released; private CLMultiContext() { contexts = new ArrayList(); } /** * Creates a multi context with all devices of the specified platforms. */ public static CLMultiContext create(final CLPlatform... platforms) { return create(platforms, ALL); } /** * Creates a multi context with all devices of the specified platforms and types. */ @SuppressWarnings("unchecked") public static CLMultiContext create(final CLPlatform[] platforms, final CLDevice.Type... types) { return create(platforms, CLDeviceFilters.type(types)); } /** * Creates a multi context with all matching devices of the specified platforms. */ @SuppressWarnings("unchecked") public static CLMultiContext create(final CLPlatform[] platforms, final Filter... filters) { if(platforms == null) { throw new NullPointerException("platform list was null"); }else if(platforms.length == 0) { throw new IllegalArgumentException("platform list was empty"); } final List devices = new ArrayList(); for (final CLPlatform platform : platforms) { devices.addAll(asList(platform.listCLDevices(filters))); } return create(devices); } /** * Creates a multi context with the specified devices. * The devices don't have to be from the same platform. */ public static CLMultiContext create(final Collection devices) { if(devices.isEmpty()) { throw new IllegalArgumentException("device list was empty"); } final Map> platformDevicesMap = filterPlatformConflicts(devices); // create contexts final CLMultiContext mc = new CLMultiContext(); for (final Map.Entry> entry : platformDevicesMap.entrySet()) { final List list = entry.getValue(); // one context per device to workaround driver bugs for (final CLDevice device : list) { final CLContext context = CLContext.create(device); mc.contexts.add(context); } } return mc; } /** * Creates a multi context with specified contexts. */ public static CLMultiContext wrap(final CLContext... contexts) { final CLMultiContext mc = new CLMultiContext(); mc.contexts.addAll(asList(contexts)); return mc; } /** * filter devices; don't allow the same device to be used in more than one platform. * example: a CPU available via the AMD and Intel SDKs shouldn't end up in two contexts */ private static Map> filterPlatformConflicts(final Collection devices) { // FIXME: devicename-platform is used as unique device identifier - replace if we have something better final Map> filtered = new HashMap>(); final Map used = new HashMap(); for (final CLDevice device : devices) { final String name = device.getName(); final CLPlatform platform = device.getPlatform(); final CLPlatform usedPlatform = used.get(name); if(usedPlatform == null || platform.equals(usedPlatform)) { if(!filtered.containsKey(platform)) { filtered.put(platform, new ArrayList()); } filtered.get(platform).add(device); used.put(name, platform); } } return filtered; } /** * Releases all contexts. * @see CLContext#release() */ @Override public void release() { if(released) { throw new RuntimeException(getClass().getSimpleName()+" already released"); } released = true; for (final CLContext context : contexts) { context.release(); } contexts.clear(); } public List getContexts() { return Collections.unmodifiableList(contexts); } /** * Returns a list containing all devices used in this multi context. */ public List getDevices() { final List devices = new ArrayList(); for (final CLContext context : contexts) { devices.addAll(asList(context.getDevices())); } return devices; } public boolean isReleased() { return released; } @Override public String toString() { return getClass().getSimpleName()+" [" + contexts.size()+" contexts, " + getDevices().size()+ " devices]"; } }