Commit 75d28e14 authored by schultezub's avatar schultezub
Browse files

* plenty of more work on cllib, too lazy to list everything here...

git-svn-id: https://camplinux.in.tum.de/svn/campvis/trunk@238 bb408c1c-ae56-11e1-83d9-df6b3e0c105e
parent cb525bfa
#include "cldevicemanager.h"
#include "tgt/logmanager.h"
namespace cllib {
const std::string DeviceManager::loggerCat_ = "cllib.DeviceManager";
DeviceManager::DeviceManager() {
cl_uint numPlatforms;
LCL_ERROR(clGetPlatformIDs(0, 0, &numPlatforms));
LINFO("Number of platformIds: " << numPlatforms);
cl_platform_id* platformIds = new cl_platform_id[numPlatforms];
LCL_ERROR(clGetPlatformIDs(numPlatforms, platformIds, 0));
for(cl_uint i=0; i<numPlatforms; ++i) {
_platforms.push_back(new Platform(platformIds[i]));
}
delete[] platformIds;
}
DeviceManager::~DeviceManager() {
for (std::vector<Platform*>::iterator it = _platforms.begin(); it != _platforms.end(); ++it)
delete *it;
}
}
\ No newline at end of file
#ifndef CLDEVICEMANAGER_H__
#define CLDEVICEMANAGER_H__
#include "tgt/tgt_gl.h"
#include "tgt/manager.h"
#include "tgt/singleton.h"
#include "CL/cl.hpp"
#include "cllib/platform.h"
#include "cllib/device.h"
#include <string>
namespace cllib {
class DeviceManager {
public:
DeviceManager();
~DeviceManager();
private:
std::vector<Platform*> _platforms;
static const std::string loggerCat_;
};
}
#endif // CLDEVICEMANAGER_H__
......@@ -8,6 +8,143 @@
namespace cllib {
namespace {
// Code for CLWrapperTraits inspired by the OpenCL C++ binding shipped with the AMD APP SDK.
/**
* Traits for retaining/releasing OpenCL handles.
*/
template<typename T>
struct CLWrapperTraits {};
#if defined(CL_VERSION_1_2)
// OpenCL 1.2 devices do have retain/release.
template <>
struct CLWrapperTraits<cl_device_id>
{
/**
* Retain the device.
* \param device A valid device created using createSubDevices
* \return
* CL_SUCCESS if the function executed successfully.
* CL_INVALID_DEVICE if device was not a valid subdevice
* CL_OUT_OF_RESOURCES
* CL_OUT_OF_HOST_MEMORY
*/
static cl_int retain(cl_device_id device) {
return ::clRetainDevice(device);
}
/**
* Retain the device.
* \param device A valid device created using createSubDevices
* \return
* CL_SUCCESS if the function executed successfully.
* CL_INVALID_DEVICE if device was not a valid subdevice
* CL_OUT_OF_RESOURCES
* CL_OUT_OF_HOST_MEMORY
*/
static cl_int release(cl_device_id device) {
return ::clReleaseDevice(device);
}
};
#else // #if defined(CL_VERSION_1_2)
// OpenCL 1.1 devices do not have retain/release.
template <>
struct CLWrapperTraits<cl_device_id> {
// cl_device_id does not have retain().
static cl_int retain(cl_device_id) {
return CL_SUCCESS;
}
// cl_device_id does not have release().
static cl_int release(cl_device_id) {
return CL_SUCCESS;
}
};
#endif // #if defined(CL_VERSION_1_2)
template <>
struct CLWrapperTraits<cl_platform_id> {
// cl_platform_id does not have retain().
static cl_int retain(cl_platform_id) {
return CL_SUCCESS;
}
// cl_platform_id does not have release().
static cl_int release(cl_platform_id) {
return CL_SUCCESS;
}
};
template <>
struct CLWrapperTraits<cl_context> {
static cl_int retain(cl_context context) {
return ::clRetainContext(context);
}
static cl_int release(cl_context context) {
return ::clReleaseContext(context);
}
};
template <>
struct CLWrapperTraits<cl_command_queue> {
static cl_int retain(cl_command_queue queue) {
return ::clRetainCommandQueue(queue);
}
static cl_int release(cl_command_queue queue) {
return ::clReleaseCommandQueue(queue);
}
};
template <>
struct CLWrapperTraits<cl_mem> {
static cl_int retain(cl_mem memory) {
return ::clRetainMemObject(memory);
}
static cl_int release(cl_mem memory) {
return ::clReleaseMemObject(memory);
}
};
template <>
struct CLWrapperTraits<cl_sampler> {
static cl_int retain(cl_sampler sampler) {
return ::clRetainSampler(sampler);
}
static cl_int release(cl_sampler sampler) {
return ::clReleaseSampler(sampler);
}
};
template <>
struct CLWrapperTraits<cl_program> {
static cl_int retain(cl_program program) {
return ::clRetainProgram(program);
}
static cl_int release(cl_program program) {
return ::clReleaseProgram(program);}
};
template <>
struct CLWrapperTraits<cl_kernel> {
static cl_int retain(cl_kernel kernel) {
return ::clRetainKernel(kernel);
}
static cl_int release(cl_kernel kernel) {
return ::clReleaseKernel(kernel);
}
};
template <>
struct CLWrapperTraits<cl_event> {
static cl_int retain(cl_event event) {
return ::clRetainEvent(event);
}
static cl_int release(cl_event event) {
return ::clReleaseEvent(event);
}
};
}
/**
* Helper function to transform an OpenCL error code to a string.
* \param err OpenCL error code.
......@@ -66,6 +203,98 @@ namespace cllib {
friend std::ostream& operator<<(std::ostream& s, const ClVersion& v);
};
/**
* Wrapper for OpenCL objects that maintain an internal OpenCL ID and regard the internal OpenCL reference counting.
* \sa CLWrapperTraits
*/
template <typename T>
class CLWrapper {
public:
/// Typedef for the type OpenCL id.
typedef T cl_type;
/**
* Default constructor for an object without id.
*/
explicit CLWrapper()
: _id(0)
{ }
/**
* Constructor initializing the internal handle with \a id.
* \param id ID of the internal OpenCL handle.
*/
explicit CLWrapper(const cl_type& id)
: _id(id)
{ }
/**
* Destructor, releases the internal handle.
*/
virtual ~CLWrapper() {
if (_id != 0)
LCL_ERROR(release());
}
/**
* Copy constructor, regards the internal reference counting.
* \param rhs Source object
*/
CLWrapper(const CLWrapper<cl_type>& rhs)
{
_id = rhs._id;
if (_id != 0)
LCL_ERROR(retain());
}
/**
* Assignment operator, regards the internal reference counting.
* \param rhs Source object
* \return *this
*/
CLWrapper<cl_type>& operator=(const CLWrapper<cl_type>& rhs)
{
if (_id != rhs._id) {
if (_id != 0)
LCL_ERROR(release());
_id = rhs._id;
if (_id != 0)
LCL_ERROR(retain());
}
return *this;
}
/**
* Gets the handle to internal OpenCl object.
* \return _id
*/
cl_type getId() const {
return _id;
}
protected:
/**
* Internally retains this object by using CLWrapperTraits<cl_type>.
* \param id Object to retain.
* \return The Error code of the retain function call.
*/
cl_int retain() const {
return CLWrapperTraits<cl_type>::retain(_id);
}
/**
* Internally releases this object by using CLWrapperTraits<cl_type>.
* \return The Error code of the release function call.
*/
cl_int release() const {
return CLWrapperTraits<cl_type>::release(_id);
}
cl_type _id; ///< Handle to internal OpenCL object.
};
}
......
#include "clruntime.h"
#include "tgt/logmanager.h"
namespace cllib {
const std::string CLRuntime::loggerCat_ = "cllib.CLRuntime";
CLRuntime::CLRuntime() {
initPlatforms();
}
CLRuntime::~CLRuntime() {
for (std::vector<Platform*>::iterator it = _platforms.begin(); it != _platforms.end(); ++it)
delete *it;
}
void CLRuntime::initPlatforms() {
// gather OpenCL platforms and create wrapper objects
cl_uint numPlatforms;
LCL_ERROR(clGetPlatformIDs(0, 0, &numPlatforms));
LINFO("Number of platformIds: " << numPlatforms);
cl_platform_id* platformIds = new cl_platform_id[numPlatforms];
LCL_ERROR(clGetPlatformIDs(numPlatforms, platformIds, 0));
for(cl_uint i=0; i<numPlatforms; ++i) {
_platforms.push_back(new Platform(platformIds[i]));
}
delete[] platformIds;
// sort devices into shortcut lists
for (std::vector<Platform*>::const_iterator pit = _platforms.begin(); pit != _platforms.end(); ++pit) {
for (std::vector<Device*>::const_iterator dit = (*pit)->getDevices().begin(); dit != (*pit)->getDevices().end(); ++dit) {
// check for CPU device type
if ((*dit)->getDeviceType() & CL_DEVICE_TYPE_CPU)
_cpuDevices.push_back(*dit);
// check for GPU device type
if ((*dit)->getDeviceType() & CL_DEVICE_TYPE_GPU)
_gpuDevices.push_back(*dit);
}
}
}
const std::vector<Device*> CLRuntime::getCPUDevices() const {
return _cpuDevices;
}
const std::vector<Device*> CLRuntime::getGPUDevices() const {
return _gpuDevices;
}
Context* CLRuntime::createGlSharingContext(const std::vector<ContextProperty>& additionalProperties /*= std::vector<ContextProperty>()*/) const {
Context* toReturn = 0;
std::vector<ContextProperty> properties = Context::generateGlSharingProperties();
properties.insert(properties.end(), additionalProperties.begin(), additionalProperties.end());
for (std::vector<Device*>::const_iterator it = _gpuDevices.begin(); it != _gpuDevices.end(); ++it) {
toReturn = new Context(*it, properties);
if (toReturn->isValid())
return toReturn;
// else
delete toReturn;
toReturn = 0;
}
return 0;
}
}
\ No newline at end of file
#ifndef CLRUNTIME_H__
#define CLRUNTIME_H__
#include "tgt/tgt_gl.h"
#include "tgt/manager.h"
#include "tgt/singleton.h"
#include "cllib/cllib.h"
#include "cllib/context.h"
#include "cllib/device.h"
#include "cllib/platform.h"
#include <string>
namespace cllib {
/**
* Singleton class for managing the OpenCL runtime.
* Gathers all available OpenCL platforms/devices and offers methods to create OpenCL contexts on them.
*/
class CLRuntime {
public:
CLRuntime();
~CLRuntime();
/**
* Tries to create an OpenCL context, which is shared with the current OpenGL context.
* Therefore, it consecutively tries each GPU device until context creation was successful.
* \param additionalProperties Additional properties for the context to create. Do
* \return
*/
Context* createGlSharingContext(const std::vector<ContextProperty>& additionalProperties = std::vector<ContextProperty>()) const;
/**
* Gets the list of all available OpenCL CPU devices.
* \return _cpuDevices
*/
const std::vector<Device*> getCPUDevices() const;
/**
* Gets the list of all available OpenCL GPU devices.
* \return _gpuDevices
*/
const std::vector<Device*> getGPUDevices() const;
private:
/**
* Gathers and inits all available platforms and their devices.
*/
void initPlatforms();
std::vector<Platform*> _platforms; ///< List of all OpenCL platforms and their devices
std::vector<Device*> _cpuDevices; ///< List of all OpenCL CPU devices (just a shortcut to the corresponding devices in _platforms)
std::vector<Device*> _gpuDevices; ///< List of all OpenCL GPU devices (just a shortcut to the corresponding devices in _platforms)
static const std::string loggerCat_;
};
}
#endif // CLRUNTIME_H__
#include "commandqueue.h"
#include "tgt/assert.h"
#include "tgt/logmanager.h"
#include "cllib/context.h"
#include "cllib/device.h"
#include "cllib/event.h"
#include "cllib/kernel.h"
#include "cllib/platform.h"
namespace cllib {
const std::string CommandQueue::loggerCat_ = "cllib.CommandQueue";
CommandQueue::CommandQueue(Context* context, cl_command_queue_properties properties /*= 0*/)
: CLWrapper<cl_command_queue>(0)
, _context(context)
, _device(context->getDevices().front())
, _profilingEnabled((properties & CL_QUEUE_PROFILING_ENABLE) != 0)
{
tgtAssert(_context != 0, "Context must not be 0.");
tgtAssert(_device != 0, "Device must not be 0. Something went terribly wrong, this should should have been asserted earlier.");
cl_int err;
_id = clCreateCommandQueue(_context->getId(), _device->getId(), properties, &err);
LCL_ERROR(err);
}
CommandQueue::CommandQueue(Context* context, Device* device, cl_command_queue_properties properties /*= 0*/)
: CLWrapper<cl_command_queue>(0)
, _context(context)
, _device(device)
, _profilingEnabled((properties & CL_QUEUE_PROFILING_ENABLE) != 0)
{
tgtAssert(_context != 0, "Context must not be 0.");
tgtAssert(_device != 0, "Device must not be 0.");
cl_int err;
_id = clCreateCommandQueue(_context->getId(), _device->getId(), properties, &err);
LCL_ERROR(err);
}
// = getters and setters ==========================================================================
CommandQueue::~CommandQueue() {
if (_id != 0)
clReleaseCommandQueue(_id);
}
const Context* CommandQueue::getContext() const {
return _context;
}
const Device* CommandQueue::getDevice() const {
return _device;
}
// = the interesting stuff :) =====================================================================
void CommandQueue::flush() {
LCL_ERROR(clFlush(_id));
}
void CommandQueue::finish() {
LCL_ERROR(clFinish(_id));
}
Event CommandQueue::enqueueTask(const Kernel* kernel, const EventList& eventsToWaitFor /*= EventList()*/) {
tgtAssert(kernel != 0, "Kernel must not be 0.");
cl_event e;
LCL_ERROR(clEnqueueTask(_id, kernel->getId(), eventsToWaitFor._size, eventsToWaitFor._events, &e));
return Event(e);
}
Event CommandQueue::enqueueKernel(const Kernel* kernel, size_t globalWorkSize, size_t localWorkSize /*= 0*/, size_t offset /*= 0*/, const EventList& eventsToWaitFor /*= EventList()*/) {
tgtAssert(kernel != 0, "Kernel must not be 0.");
tgtAssert(localWorkSize != 0 && localWorkSize > globalWorkSize, "Global work size must be greater than local work size.");
tgtAssert(localWorkSize != 0 && (globalWorkSize % localWorkSize != 0), "Global work size must be a multiple than local work size.");
cl_event e;
LCL_ERROR(clEnqueueNDRangeKernel(
_id,
kernel->getId(),
1,
(offset == 0 ? 0 : &offset),
&globalWorkSize,
(localWorkSize == 0 ? 0 : &localWorkSize),
eventsToWaitFor._size,
eventsToWaitFor._events,
&e));
return Event(e);
}
Event CommandQueue::enqueueKernel(const Kernel* kernel, tgt::svec2 globalWorkSize, tgt::svec2 localWorkSize /*= tgt::svec2::zero*/, tgt::svec2 offset /*= tgt::svec2::zero*/, const EventList& eventsToWaitFor /*= EventList()*/) {
tgtAssert(kernel != 0, "Kernel must not be 0.");
tgtAssert(localWorkSize != tgt::svec2::zero && tgt::hor(tgt::greaterThan(localWorkSize, globalWorkSize)), "Global work size must be greater than local work size.");
tgtAssert(localWorkSize != tgt::svec2::zero && (globalWorkSize.x % localWorkSize.x != 0), "Global work size must be a multiple than local work size.");
tgtAssert(localWorkSize != tgt::svec2::zero && (globalWorkSize.y % localWorkSize.y != 0), "Global work size must be a multiple than local work size.");
cl_event e;
LCL_ERROR(clEnqueueNDRangeKernel(
_id,
kernel->getId(),
2,
(offset == tgt::svec2::zero ? 0 : offset.elem),
globalWorkSize.elem,
(localWorkSize == tgt::svec2::zero ? 0 : localWorkSize.elem),
eventsToWaitFor._size,
eventsToWaitFor._events,
&e));
return Event(e);
}
Event CommandQueue::enqueueKernel(const Kernel* kernel, tgt::svec3 globalWorkSize, tgt::svec3 localWorkSize /*= tgt::svec3::zero*/, tgt::svec3 offset /*= tgt::svec3::zero*/, const EventList& eventsToWaitFor /*= EventList()*/) {
tgtAssert(kernel != 0, "Kernel must not be 0.");
tgtAssert(localWorkSize != tgt::svec3::zero && tgt::hor(tgt::greaterThan(localWorkSize, globalWorkSize)), "Global work size must be greater than local work size.");
tgtAssert(localWorkSize != tgt::svec3::zero && (globalWorkSize.x % localWorkSize.x != 0), "Global work size must be a multiple than local work size.");
tgtAssert(localWorkSize != tgt::svec3::zero && (globalWorkSize.y % localWorkSize.y != 0), "Global work size must be a multiple than local work size.");
tgtAssert(localWorkSize != tgt::svec3::zero && (globalWorkSize.z % localWorkSize.z != 0), "Global work size must be a multiple than local work size.");
cl_event e;
LCL_ERROR(clEnqueueNDRangeKernel(
_id,
kernel->getId(),
3,
(offset == tgt::svec3::zero ? 0 : offset.elem),
globalWorkSize.elem,
(localWorkSize == tgt::svec3::zero ? 0 : localWorkSize.elem),
eventsToWaitFor._size,
eventsToWaitFor._events,
&e));
return Event(e);
}
}
#ifndef COMMANDQUEUE_H__
#define COMMANDQUEUE_H__
#include "tgt/vector.h"
#include "cllib/cllib.h"
#include "cllib/event.h"
#include <vector>
namespace cllib {
class Context;
class Device;
class Kernel;
/**
* Wrapper class for an OpenCL command queue.
*
* \todo OpenCL command queues internally maintain a reference count. We probably should use it here => implement copy constructor/assignment op.
*/
class CommandQueue : public CLWrapper<cl_command_queue> {
public:
/**
* Creates a new command queue for the given OpenCL context and its first device.
* \param context OpenCL context to create the command queue for.
* \param properties Command queue properties bitfield.
*/