/*########################################################################################################################### # Copyright (c) 1997-2012 Ufasoft http://ufasoft.com mailto:support@ufasoft.com # # # # This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License # # as published by the Free Software Foundation; either version 3, or (at your option) any later version. # # # # # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied # # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License along with this program; # # If not, see # ###########################################################################################################################*/ #include #include "ext-opencl.h" #pragma comment(lib, "opencl") namespace Ext { namespace Cl { void ClCheck(cl_int rc) { if (rc != CL_SUCCESS) throw OpenclException(MAKE_HRESULT(SEVERITY_ERROR, FACILITY_OPENCL, -rc)); } vector Platform::GetAll() { cl_uint n; int rc = ::clGetPlatformIDs(0, 0, &n); if (rc == CL_PLATFORM_NOT_FOUND_KHR) return vector(); // OpenCL not installed ClCheck(rc); cl_platform_id *p = (cl_platform_id*)alloca(n*sizeof(cl_platform_id)); ClCheck(::clGetPlatformIDs(n, p, 0)); return vector(p, p+n); } String Platform::get_Vendor() const { size_t size; ClCheck(::clGetPlatformInfo(Id, CL_PLATFORM_VENDOR, 0, 0, &size)); char *p = (char*)alloca(size); ClCheck(::clGetPlatformInfo(Id, CL_PLATFORM_VENDOR, size, p, 0)); return String(p); } vector Platform::GetDevices(cl_device_type typ) const { cl_uint n; ClCheck(::clGetDeviceIDs(Id, typ, 0, 0, &n)); cl_device_id *p = (cl_device_id*)alloca(n*sizeof(cl_device_id)); ClCheck(::clGetDeviceIDs(Id, typ, n, p, 0)); return vector(p, p+n); } Blob Device::GetInfo(cl_device_info pname) const { size_t size; ClCheck(::clGetDeviceInfo(Id, pname, 0, 0, &size)); Blob r(0, size); ClCheck(::clGetDeviceInfo(Id, pname, r.Size, r.data(), 0)); return r; } NDRange::NDRange(int n) : m_globalSize(1) , m_localSize(1) { m_global[0] = n; m_local[0] = DEFAULT_WORK_GROUP_SIZE; } ExecutionStatus Event::get_Status() { cl_int r; ClCheck(::clGetEventInfo(_self, CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof r, &r, 0)); return ExecutionStatus(r); } int Event::get_RefCount() { cl_uint r; ClCheck(::clGetEventInfo(_self, CL_EVENT_REFERENCE_COUNT, sizeof r, &r, 0)); return r; } void Event::SetCallback(void (CL_CALLBACK *pfn)(cl_event, cl_int, void *), void *userData) { ClCheck(::clSetEventCallback(_self, CL_COMPLETE, pfn, userData)); } void Wait(const Event& ev) { ClCheck(::clWaitForEvents(1, &ev.m_h)); } Event CommandQueue::Enqueue(const Kernel& kernel, const NDRange& range) { Event ev; ClCheck(::clEnqueueNDRangeKernel(_self, kernel, range.m_globalSize, 0, &range.m_global[0], &range.m_local[0], 0, 0, &ev.m_h)); return ev; } Event CommandQueue::Enqueue(const Kernel& kernel) { Event ev; ClCheck(::clEnqueueTask(_self, kernel, 0, 0, &ev.m_h)); return ev; } Event CommandQueue::EnqueueRead(const Buffer& buffer, void *p, size_t cb) { Event ev; ClCheck(::clEnqueueReadBuffer(_self, buffer, false, 0, cb, p, 0, 0, &ev.m_h)); return ev; } Event CommandQueue::EnqueueWrite(const Buffer& buffer, const void *p, size_t cb) { Event ev; ClCheck(::clEnqueueWriteBuffer(_self, buffer, false, 0, cb, p, 0, 0, &ev.m_h)); return ev; } Event CommandQueue::EnqueueMarker() { Event ev; ClCheck(::clEnqueueMarker(_self, &ev.m_h)); return ev; } void CommandQueue::EnqueueBarrier() { ClCheck(::clEnqueueBarrier(_self)); } Context::~Context() { } void Context::Create(const CContextProps& props, const Device& dev) { cl_context_properties *p = (cl_context_properties*)alloca((props.size()*2+1)*sizeof(cl_context_properties)); int i = 0; for (auto it=props.begin(); it!=props.end(); ++it, i+=2) { p[i] = it->first; p[i+1] = it->second; } p[i] = 0; cl_int rc; OutRef() = ::clCreateContext(p, 1, &dev.Id, 0, 0, &rc); if (!m_h) ClCheck(rc); } void Context::CreateFromType(const CContextProps& props, cl_device_type typ) { cl_context_properties *p = (cl_context_properties*)alloca((props.size()*2+1)*sizeof(cl_context_properties)); int i = 0; for (auto it=props.begin(); it!=props.end(); ++it, i+=2) { p[i] = it->first; p[i+1] = it->second; } p[i] = 0; cl_int rc; OutRef() = ::clCreateContextFromType(p, typ, 0, 0, &rc); if (!m_h) ClCheck(rc); } CommandQueue Context::CreateCommandQueue(const Device& dev, cl_command_queue_properties prop) { CommandQueue r; cl_int rc; r.OutRef() = ::clCreateCommandQueue(_self, dev.Id, prop, &rc); if (!r.m_h) ClCheck(rc); return r; } Buffer Context::CreateBuffer(void *p, size_t size, cl_mem_flags flags) { Buffer r; cl_int rc; r.OutRef() = ::clCreateBuffer(_self, flags, size, p, &rc); if (!r.m_h) ClCheck(rc); return r; } vector Context::get_Devices() const { cl_uint n; ClCheck(::clGetContextInfo(_self, CL_CONTEXT_NUM_DEVICES, sizeof n, &n, 0)); cl_device_id *p = (cl_device_id*)alloca(n*sizeof(cl_device_id)); ClCheck(::clGetContextInfo(_self, CL_CONTEXT_DEVICES, n*sizeof(cl_device_id), p, 0)); return vector(p, p+n); } void Program::CreateFromSources(Context& ctx, const vector& ss) { Ctx = &ctx; vector pp; for (int i=0; i buf(size); ClCheck(::clGetProgramBuildInfo(_self, dev.Id, CL_PROGRAM_BUILD_LOG, size, &buf[0], 0)); throw BuildException(MAKE_HRESULT(SEVERITY_ERROR, FACILITY_OPENCL, -rc), &buf[0]); } } Kernel Program::CreateKernel(RCString name) { Kernel r; cl_int rc; r.OutRef() = ::clCreateKernel(_self, name, &rc); if (!r.m_h) ClCheck(rc); return r; } vector Program::get_Binaries() { vector r; cl_uint n; ClCheck(::clGetProgramInfo(_self, CL_PROGRAM_NUM_DEVICES, sizeof(n), &n, 0)); if (n) { vector vId(n); vector vSize(n); ClCheck(::clGetProgramInfo(_self, CL_PROGRAM_DEVICES, sizeof(cl_device_id)*n, &vId[0], 0)); ClCheck(::clGetProgramInfo(_self, CL_PROGRAM_BINARY_SIZES, sizeof(size_t)*n, &vSize[0], 0)); r.resize(n); vector vp(n); for (int i=0; i