You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1185 lines
31 KiB
1185 lines
31 KiB
#ifndef OPENCLHELPER_H
|
|
#define OPENCLHELPER_H
|
|
|
|
#define CL_HPP_MINIMUM_OPENCL_VERSION 120
|
|
#define CL_HPP_TARGET_OPENCL_VERSION 120
|
|
|
|
#include <QObject>
|
|
#include <QFile>
|
|
#include <QDebug>
|
|
#include "CL/cl2.hpp"
|
|
#include "ESeverityLevel.h"
|
|
#include "ELogId.h"
|
|
|
|
using namespace cl;
|
|
|
|
class OpenCLHelper : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
private:
|
|
inline void handleError(ESeverityLevel::eSeverityLevel severityLevel,
|
|
ELogID::eLogId logID,
|
|
QString logText,
|
|
bool emitThrow = true) const;
|
|
inline std::vector<Platform> getPlatforms();
|
|
inline std::vector<Device> getDevices(std::vector<Platform> platforms);
|
|
inline QString getDeviceName(const Device& device);
|
|
|
|
public:
|
|
inline Context getContext();
|
|
inline Kernel createKernel(const Context context,
|
|
const QString kernelPath,
|
|
const QString KernelName);
|
|
inline Buffer* array2CLBuffer(const Context &context,
|
|
quint64 size,
|
|
bool read);
|
|
inline Image* frame2CLFrame(const Context& context,
|
|
ImageFormat clFrameFormat,
|
|
QVector<quint64> dimensions, bool read);
|
|
inline CommandQueue createCommandQueue(const Context& context,
|
|
const Device& device,
|
|
const cl_command_queue_properties properties);
|
|
template<typename... Ts>
|
|
inline KernelFunctor<Ts...> createKernelFunctor(const Kernel& kernel);
|
|
inline QVector<Device> getDevicesByContext(const Context& context);
|
|
inline size_t* getMaxGlobalWorkSize(const Kernel& kernel, const Device& device);
|
|
template<typename... Ts>
|
|
inline void runKernelFunctor(KernelFunctor<Ts...>& kernelFunctor,
|
|
EnqueueArgs args,
|
|
Ts... ts);
|
|
signals:
|
|
void sgl_sendLog (ESeverityLevel::eSeverityLevel severityLevel,
|
|
ELogID::eLogId logID,
|
|
QString logText) const;
|
|
|
|
};
|
|
|
|
void OpenCLHelper::handleError(ESeverityLevel::eSeverityLevel severityLevel,
|
|
ELogID::eLogId logID,
|
|
QString logText,
|
|
bool emitThrow) const
|
|
{
|
|
qDebug() << logText;
|
|
}
|
|
|
|
std::vector<Platform> OpenCLHelper::getPlatforms()
|
|
{
|
|
std::vector<Platform> platforms;
|
|
try {
|
|
if (Platform::get(&platforms) == CL_INVALID_VALUE)
|
|
{
|
|
handleError(ESeverityLevel::Alert,
|
|
ELogID::CLPlatformError,
|
|
"(CL_INVALID_VALUE)Error getting CL Platforms");
|
|
}
|
|
} catch (...) {
|
|
throw;
|
|
}
|
|
|
|
/// Removes platforms which are not nvidia or amd based
|
|
try {
|
|
std::vector<Platform> temp(platforms);
|
|
platforms.clear();
|
|
for (auto it = temp.begin(); it != temp.end(); it++)
|
|
{
|
|
string currentPlatformName = it->getInfo<CL_PLATFORM_NAME>();
|
|
handleError(ESeverityLevel::Debug,
|
|
ELogID::CLPlatformInfo,
|
|
"Platform Name: " + QString::fromStdString(currentPlatformName),
|
|
false);
|
|
|
|
if (!(it->getInfo<CL_PLATFORM_NAME>().find("NVIDIA") == string::npos) ||
|
|
!(it->getInfo<CL_PLATFORM_NAME>().find("AMD") == string::npos))
|
|
|
|
{
|
|
platforms.push_back(*it);
|
|
}
|
|
}
|
|
} catch (...) {
|
|
throw;
|
|
}
|
|
|
|
try {
|
|
if (platforms.size() == 0)
|
|
{
|
|
handleError(ESeverityLevel::Alert,
|
|
ELogID::CLPlatformError,
|
|
"No valid NVIDIA or AMD platform available.");
|
|
}
|
|
|
|
} catch (...) {
|
|
throw;
|
|
}
|
|
|
|
|
|
return platforms;
|
|
}
|
|
|
|
std::vector<Device> OpenCLHelper::getDevices(std::vector<Platform> platforms)
|
|
{
|
|
vector<Device> devices;
|
|
try {
|
|
if (platforms.size() == 0)
|
|
{
|
|
handleError(ESeverityLevel::Alert,
|
|
ELogID::CLPlatformError,
|
|
"No valid platforms.");
|
|
}
|
|
|
|
} catch (...) {
|
|
throw;
|
|
}
|
|
|
|
for (auto platform = platforms.begin(); platform != platforms.end(); platform++)
|
|
{
|
|
vector<Device> tempDevices;
|
|
try {
|
|
switch(cl_int err = platform->getDevices(CL_DEVICE_TYPE_GPU, &devices))
|
|
{
|
|
case CL_INVALID_DEVICE_TYPE:
|
|
{
|
|
QString messageText = QString::fromStdString(
|
|
"(CL_INVALID_DEVICE_TYPE) Invalid CL device type (" +
|
|
std::to_string(CL_DEVICE_TYPE_GPU) +
|
|
") while getting devices of platform " +
|
|
platform->getInfo<CL_PLATFORM_NAME>());
|
|
handleError(ESeverityLevel::Alert,
|
|
ELogID::CLPlatformError,
|
|
messageText,
|
|
false);
|
|
break;
|
|
}
|
|
|
|
case CL_INVALID_ARG_VALUE:
|
|
{
|
|
QString messageText = QString::fromStdString(
|
|
"(CL_INVALID_ARG_VALUE) Null device while getting devices of platform " +
|
|
platform->getInfo<CL_PLATFORM_NAME>());
|
|
handleError(ESeverityLevel::Alert,
|
|
ELogID::CLPlatformError,
|
|
messageText,
|
|
false);
|
|
break;
|
|
}
|
|
|
|
case CL_SUCCESS:
|
|
{
|
|
devices.insert(devices.begin(), tempDevices.begin(), tempDevices.end());
|
|
QString logText = "Devices registered successfuly: \"";
|
|
for (auto deviceIt = devices.begin(); deviceIt != devices.end(); deviceIt++)
|
|
{
|
|
logText = logText + QString::fromStdString(deviceIt->getInfo<CL_DEVICE_NAME>() + ",");
|
|
}
|
|
logText = logText + "\"";
|
|
handleError(ESeverityLevel::Debug,
|
|
ELogID::CLPlatformInfo,
|
|
logText,
|
|
false);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
QString messageText = "Unknown error occured while getting devices of platform " +
|
|
QString::fromStdString(platform->getInfo<CL_PLATFORM_NAME>()) +
|
|
". CL error: " +
|
|
QString::number(err);
|
|
break;
|
|
}
|
|
} // end of switch
|
|
} catch (...) {
|
|
throw;
|
|
}
|
|
}
|
|
|
|
return devices;
|
|
}
|
|
|
|
Context OpenCLHelper::getContext()
|
|
{
|
|
static Context* context = nullptr;
|
|
if (context)
|
|
{
|
|
return *context;
|
|
}
|
|
|
|
vector<Platform> allPlatforms;
|
|
try
|
|
{
|
|
allPlatforms = getPlatforms();
|
|
}
|
|
catch(...)
|
|
{
|
|
throw;
|
|
}
|
|
|
|
vector<Device> allDevices;
|
|
try
|
|
{
|
|
allDevices = getDevices(allPlatforms);
|
|
}
|
|
catch(...)
|
|
{
|
|
throw;
|
|
}
|
|
|
|
if (allDevices.size() == 0)
|
|
{
|
|
try
|
|
{
|
|
handleError(ESeverityLevel::Alert,
|
|
ELogID::CLPlatformError,
|
|
"No processing devices found.");
|
|
}
|
|
catch(...)
|
|
{
|
|
throw;
|
|
}
|
|
}
|
|
|
|
cl_int err;
|
|
context = new Context(allDevices, Q_NULLPTR, Q_NULLPTR, Q_NULLPTR, &err);
|
|
try {
|
|
switch (err)
|
|
{
|
|
case CL_INVALID_PROPERTY:
|
|
{
|
|
handleError(ESeverityLevel::Critical,
|
|
ELogID::CLContextError,
|
|
"Error occured while creating CL context: CL_INVALID_PROPERTY");
|
|
break;
|
|
}
|
|
case CL_INVALID_DEVICE_TYPE:
|
|
{
|
|
handleError(ESeverityLevel::Critical,
|
|
ELogID::CLContextError,
|
|
"Error occured while creating CL context: CL_INVALID_DEVICE_TYPE");
|
|
break;
|
|
}
|
|
case CL_DEVICE_NOT_AVAILABLE:
|
|
{
|
|
handleError(ESeverityLevel::Critical,
|
|
ELogID::CLContextError,
|
|
"Error occured while creating CL context: CL_DEVICE_NOT_AVAILABLE");
|
|
break;
|
|
}
|
|
case CL_DEVICE_NOT_FOUND:
|
|
{
|
|
handleError(ESeverityLevel::Critical,
|
|
ELogID::CLContextError,
|
|
"Error occured while creating CL context: CL_DEVICE_NOT_FOUND");
|
|
break;
|
|
}
|
|
case CL_OUT_OF_HOST_MEMORY:
|
|
{
|
|
handleError(ESeverityLevel::Critical,
|
|
ELogID::CLContextError,
|
|
"Error occured while creating CL context: CL_OUT_OF_HOST_MEMORY");
|
|
break;
|
|
}
|
|
case CL_SUCCESS:
|
|
{
|
|
handleError(ESeverityLevel::Debug,
|
|
ELogID::CLContextInfo,
|
|
"CL Context created successfully.",
|
|
false);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
QString logText = "Unknown error while creating CL context. CL error: " + QString::number(err);
|
|
handleError(ESeverityLevel::Critical,
|
|
ELogID::CLContextError,
|
|
logText);
|
|
}
|
|
} // end of switch
|
|
} catch (...) {
|
|
throw;
|
|
}
|
|
|
|
|
|
return *context;
|
|
}
|
|
|
|
Kernel OpenCLHelper::createKernel(const Context context,
|
|
const QString kernelPath,
|
|
const QString kernelName)
|
|
{
|
|
QString kernelFullPath = kernelPath + "/" + kernelName + ".cl";
|
|
|
|
QFile kernelFile(kernelFullPath);
|
|
try {
|
|
if (!kernelFile.open(QIODevice::ReadOnly | QIODevice::Text))
|
|
{
|
|
handleError(ESeverityLevel::Critical,
|
|
ELogID::FileOpenError,
|
|
"Could not open kernel file: " + kernelFullPath);
|
|
}
|
|
} catch (...) {
|
|
}
|
|
|
|
QString kernelSource = kernelFile.readAll();
|
|
cl_int buildError;
|
|
|
|
Program program(context, kernelSource.toStdString(), true, &buildError);
|
|
|
|
try {
|
|
switch (buildError)
|
|
{
|
|
case CL_INVALID_CONTEXT:
|
|
{
|
|
QString logText = " (CL_INVALID_CONTEXT) Error building kernel \"" +
|
|
kernelFullPath +
|
|
"\". Context is not valid.";
|
|
handleError(ESeverityLevel::Critical,
|
|
ELogID::CLKernelBuildError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_INVALID_VALUE:
|
|
{
|
|
QString logText = "(CL_INVALID_VALUE) Error building kernel \"" +
|
|
kernelFullPath +
|
|
"\". Source contains zero entries or any entry contains a tuple with NULL.";
|
|
handleError(ESeverityLevel::Critical,
|
|
ELogID::CLKernelBuildError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_OUT_OF_RESOURCES:
|
|
{
|
|
QString logText = "(CL_OUT_OF_RESOURCES) Error building kernel \"" +
|
|
kernelFullPath +
|
|
"\". Failure to allocate resources on the device.";
|
|
handleError(ESeverityLevel::Critical,
|
|
ELogID::CLKernelBuildError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_OUT_OF_HOST_MEMORY:
|
|
{
|
|
QString logText = "(CL_OUT_OF_HOST_MEMORY) Error building kernel \"" +
|
|
kernelFullPath +
|
|
"\". Failure to allocate resources on the host.";
|
|
handleError(ESeverityLevel::Critical,
|
|
ELogID::CLKernelBuildError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_SUCCESS:
|
|
{
|
|
handleError(ESeverityLevel::Informational,
|
|
ELogID::CLKernelBuilt,
|
|
"Kernel \"" + kernelFullPath + "\" built successfully.",
|
|
false);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
QString logText = "Unknown error occured whild building kernel \"" +
|
|
kernelFullPath +
|
|
"\". Error: " +
|
|
QString::number(buildError);
|
|
handleError(ESeverityLevel::Critical,
|
|
ELogID::CLKernelBuildError,
|
|
logText);
|
|
}
|
|
} // end of switch
|
|
|
|
} catch (...) {
|
|
}
|
|
|
|
// It is considered that there is only one kernel in the program and it's name is known.
|
|
cl_int kernelError;
|
|
Kernel kernel(program, kernelName.toStdString().c_str(), &kernelError);
|
|
|
|
try {
|
|
switch (kernelError)
|
|
{
|
|
case CL_INVALID_PROGRAM:
|
|
{
|
|
QString logText = "(CL_INVALID_PROGRAM) Kernel creation error (" +
|
|
kernelName +
|
|
"): Invalid program object.";
|
|
handleError(ESeverityLevel::Critical,
|
|
ELogID::CLKernelCreationError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_INVALID_PROGRAM_EXECUTABLE:
|
|
{
|
|
QString logText = "(CL_INVALID_PROGRAM_EXECUTABLE) Kernel creation error (" +
|
|
kernelName +
|
|
"): There is no valid built executable.";
|
|
handleError(ESeverityLevel::Critical,
|
|
ELogID::CLKernelCreationError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_INVALID_KERNEL_NAME:
|
|
{
|
|
QString logText = "(CL_INVALID_KERNEL_NAME) Kernel creation error (" +
|
|
kernelName +
|
|
"): Name is not found int the program.";
|
|
handleError(ESeverityLevel::Critical,
|
|
ELogID::CLKernelCreationError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_INVALID_KERNEL_DEFINITION:
|
|
{
|
|
QString logText = "(CL_INVALID_KERNEL_DEFINITION) Kernel creation error (" +
|
|
kernelName +
|
|
"): Invalid kernel definition.";
|
|
handleError(ESeverityLevel::Critical,
|
|
ELogID::CLKernelCreationError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_INVALID_VALUE:
|
|
{
|
|
QString logText = "(CL_INVALID_VALUE) Kernel creation error (" +
|
|
kernelName +
|
|
"): Name is NULL";
|
|
handleError(ESeverityLevel::Critical,
|
|
ELogID::CLKernelCreationError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_OUT_OF_RESOURCES:
|
|
{
|
|
QString logText = "(CL_OUT_OF_RESOURCES) Kernel creation error (" +
|
|
kernelName +
|
|
"): Failure to allocate resources on the device.";
|
|
handleError(ESeverityLevel::Critical,
|
|
ELogID::CLKernelCreationError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_OUT_OF_HOST_MEMORY:
|
|
{
|
|
QString logText = "(CL_OUT_OF_HOST_MEMORY) Kernel creation error (" +
|
|
kernelName +
|
|
"): Failure to allocate resources on the host.";
|
|
handleError(ESeverityLevel::Critical,
|
|
ELogID::CLKernelCreationError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_SUCCESS:
|
|
{
|
|
handleError(ESeverityLevel::Debug,
|
|
ELogID::CLKernelCreated,
|
|
"Kernel created successfully for kernel: " + kernelName,
|
|
false);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
QString logText = "Kernel creation error (" +
|
|
kernelName +
|
|
"): Unknown error: " + QString::number(kernelError);
|
|
handleError(ESeverityLevel::Critical,
|
|
ELogID::CLKernelCreationError,
|
|
logText);
|
|
}
|
|
} //end of switch
|
|
} catch (...) {
|
|
}
|
|
|
|
|
|
return kernel;
|
|
}
|
|
|
|
Buffer* OpenCLHelper::array2CLBuffer(const Context &context,
|
|
quint64 size,
|
|
bool read = true)
|
|
{
|
|
Buffer* buffer = Q_NULLPTR;
|
|
cl_mem_flags clMemFlags = read ? CL_MEM_READ_ONLY : CL_MEM_WRITE_ONLY;
|
|
|
|
cl_int error;
|
|
buffer = new Buffer(context, clMemFlags, size, NULL, &error);
|
|
if(error != 0)
|
|
qDebug() << error;
|
|
|
|
return buffer;
|
|
}
|
|
|
|
Image* OpenCLHelper::frame2CLFrame(const Context &context,
|
|
ImageFormat clFrameFormat,
|
|
QVector<quint64> dimensions,
|
|
bool read = true)
|
|
{
|
|
Image* image = Q_NULLPTR;
|
|
cl_mem_flags clMemFlags = CL_MEM_READ_WRITE;
|
|
|
|
cl_int* error = Q_NULLPTR;
|
|
switch (dimensions.size())
|
|
{
|
|
case 1:
|
|
image = new Image1D(context,
|
|
clMemFlags,
|
|
clFrameFormat,
|
|
dimensions[0],
|
|
error);
|
|
break;
|
|
case 2:
|
|
image = new Image2D(context,
|
|
clMemFlags,
|
|
clFrameFormat,
|
|
dimensions[0],
|
|
dimensions[1],
|
|
0,
|
|
error);
|
|
break;
|
|
case 3:
|
|
image = new Image3D(context,
|
|
clMemFlags,
|
|
clFrameFormat,
|
|
dimensions[0],
|
|
dimensions[1],
|
|
dimensions[2],
|
|
0,
|
|
0,
|
|
error);
|
|
break;
|
|
default:
|
|
try {
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLFrameError,
|
|
"Number of dimenstions is not supported: " + QString::number(dimensions.size()));
|
|
} catch (...) {
|
|
throw;
|
|
}
|
|
}
|
|
|
|
try {
|
|
if (error)
|
|
{
|
|
QString logText;
|
|
switch (*error)
|
|
{
|
|
case CL_INVALID_CONTEXT:
|
|
logText = QString("(CL_INVALID_CONTEXT) The context is not valid ") +
|
|
"while creating CLImage.";
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLFrameError,
|
|
logText);
|
|
break;
|
|
case CL_INVALID_VALUE:
|
|
logText = QString("(CL_INVALID_VALUE) Invalid memory flags ") +
|
|
"while creating CLImage: " + QString::number(clMemFlags);
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLFrameError,
|
|
logText);
|
|
break;
|
|
case CL_INVALID_IMAGE_FORMAT_DESCRIPTOR:
|
|
logText = QString("(CL_INVALID_IMAGE_FORMAT_DESCRIPTOR) Invalid CL frame format ") +
|
|
"while creating CLImage: image_channel_order: " +
|
|
QString::number(clFrameFormat.image_channel_order) +
|
|
" image_channel_data_type: " +
|
|
QString::number(clFrameFormat.image_channel_data_type);
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLFrameError,
|
|
logText);
|
|
break;
|
|
case CL_INVALID_IMAGE_SIZE:
|
|
logText = QString("(CL_INVALID_IMAGE_SIZE) Invalid CL frame size ") +
|
|
"while creating CLImage: ";
|
|
foreach (quint64 dimension, dimensions)
|
|
{
|
|
logText += QString::number(dimension) + ",";
|
|
}
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLFrameError,
|
|
logText);
|
|
break;
|
|
case CL_INVALID_HOST_PTR:
|
|
logText = QString("(CL_INVALID_HOST_PTR) Invalid host pointer ") +
|
|
"while creating CLImage.";
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLFrameError,
|
|
logText);
|
|
break;
|
|
case CL_IMAGE_FORMAT_NOT_SUPPORTED :
|
|
logText = QString("(CL_IMAGE_FORMAT_NOT_SUPPORTED) CL Frame format not supported ") +
|
|
"while creating CLImage: image_channel_order: " +
|
|
QString::number(clFrameFormat.image_channel_order) +
|
|
" image_channel_data_type: " +
|
|
QString::number(clFrameFormat.image_channel_data_type);
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLFrameError,
|
|
logText);
|
|
break;
|
|
case CL_MEM_OBJECT_ALLOCATION_FAILURE:
|
|
logText = QString("(CL_MEM_OBJECT_ALLOCATION_FAILURE) Failed to allocate memory ") +
|
|
"while creating CLImage.";
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLFrameError,
|
|
logText);
|
|
break;
|
|
case CL_INVALID_OPERATION:
|
|
logText = QString("(CL_INVALID_OPERATION) No device in context to support CL frame ") +
|
|
"while creating CLImage.";
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLFrameError,
|
|
logText);
|
|
break;
|
|
case CL_OUT_OF_RESOURCES:
|
|
logText = QString("(CL_OUT_OF_RESOURCES ) Failed to allocate resources on the device") +
|
|
"while creating CLImage.";
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLFrameError,
|
|
logText);
|
|
break;
|
|
case CL_OUT_OF_HOST_MEMORY:
|
|
logText = QString("(CL_OUT_OF_RESOURCES ) Failed to allocate resources on the host") +
|
|
"while creating CLImage.";
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLFrameError,
|
|
logText);
|
|
break;
|
|
default:
|
|
logText = QString("An unknown error occured ") +
|
|
"while creating CLImage.";
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLFrameError,
|
|
logText);
|
|
break;
|
|
} // end of switch
|
|
}
|
|
else
|
|
{
|
|
handleError(ESeverityLevel::Debug,
|
|
ELogID::CLFrameInfo,
|
|
"Frame successfully converted to CL Frame.",
|
|
false);
|
|
}
|
|
} catch (...) {
|
|
throw;
|
|
}
|
|
|
|
return image;
|
|
}
|
|
|
|
template<typename... Ts>
|
|
KernelFunctor<Ts...> OpenCLHelper::createKernelFunctor(const Kernel& kernel)
|
|
{
|
|
QString kernelName = QString::fromStdString(kernel.getInfo<CL_KERNEL_FUNCTION_NAME>());
|
|
|
|
cl_int error;
|
|
KernelFunctor<Ts...> kernelFunctor(kernel.getInfo<CL_KERNEL_PROGRAM>(), kernelName, &error);
|
|
|
|
try {
|
|
switch (error)
|
|
{
|
|
case CL_INVALID_PROGRAM:
|
|
{
|
|
QString logText = "(CL_INVALID_PROGRAM) KernelFunctor creation error (" +
|
|
kernelName +
|
|
"): Invalid program object.";
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelFunctorError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_INVALID_PROGRAM_EXECUTABLE:
|
|
{
|
|
QString logText = "(CL_INVALID_PROGRAM_EXECUTABLE) KernelFunctor creation error (" +
|
|
kernelName +
|
|
"): There is no valid built executable.";
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelFunctorError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_INVALID_KERNEL_NAME:
|
|
{
|
|
QString logText = "(CL_INVALID_KERNEL_NAME) KernelFunctor creation error (" +
|
|
kernelName +
|
|
"): Name is not found int the program.";
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelFunctorError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_INVALID_KERNEL_DEFINITION:
|
|
{
|
|
QString logText = "(CL_INVALID_KERNEL_DEFINITION) KernelFunctor creation error (" +
|
|
kernelName +
|
|
"): Invalid kernel definition.";
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelFunctorError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_INVALID_VALUE:
|
|
{
|
|
QString logText = "(CL_INVALID_VALUE) KernelFunctor creation error (" +
|
|
kernelName +
|
|
"): Name is NULL";
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelFunctorError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_OUT_OF_RESOURCES:
|
|
{
|
|
QString logText = "(CL_OUT_OF_RESOURCES) KernelFunctor creation error (" +
|
|
kernelName +
|
|
"): Failure to allocate resources on the device.";
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelFunctorError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_OUT_OF_HOST_MEMORY:
|
|
{
|
|
QString logText = "(CL_OUT_OF_HOST_MEMORY) KernelFunctor creation error (" +
|
|
kernelName +
|
|
"): Failure to allocate resources on the host.";
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelFunctorError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_SUCCESS:
|
|
{
|
|
handleError(ESeverityLevel::Debug,
|
|
ELogID::CLKernelFunctorCreated,
|
|
"KernelFunctor created successfully for kernel: " + kernelName,
|
|
false);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
QString logText = "KernelFunctor creation error (" +
|
|
kernelName +
|
|
"): Unknown error: " + QString::number(error);
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelFunctorError,
|
|
logText);
|
|
break;
|
|
}
|
|
} // end of switch
|
|
} catch (...) {
|
|
throw;
|
|
}
|
|
|
|
return (kernelFunctor);
|
|
}
|
|
|
|
CommandQueue OpenCLHelper::createCommandQueue(const Context& context,
|
|
const Device& device,
|
|
const cl_command_queue_properties properties = 0)
|
|
{
|
|
cl_int error;
|
|
CommandQueue commandQ(context, properties, &error);
|
|
try {
|
|
switch (error)
|
|
{
|
|
case CL_INVALID_CONTEXT:
|
|
{
|
|
QString logText = QString("(CL_INVALID_CONTEXT) An error occured while creating Queue. ") +
|
|
"Invalid context on device: " +
|
|
QString::fromStdString(device.getInfo<CL_DEVICE_NAME>());
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLCommandQueueCreationError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_INVALID_DEVICE:
|
|
{
|
|
QString logText = QString("(CL_INVALID_DEVICE) An error occured while creating Queue on device. ") +
|
|
"Invalid device or not associated with the provided context: " +
|
|
QString::fromStdString(device.getInfo<CL_DEVICE_NAME>());
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLCommandQueueCreationError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_INVALID_VALUE:
|
|
{
|
|
QString logText = QString("(CL_INVALID_VALUE) An error occured while creating Queue on device. ") +
|
|
"Invalid properties: " + QString::number(properties);
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLCommandQueueCreationError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_INVALID_QUEUE_PROPERTIES:
|
|
{
|
|
QString logText = QString("(CL_INVALID_QUEUE_PROPERTIES) An error occured while creating Queue on device. ") +
|
|
"Properties \"" + QString::number(properties) + "\" " +
|
|
"not supperted by device: " + QString::fromStdString(device.getInfo<CL_DEVICE_NAME>());
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLCommandQueueCreationError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_OUT_OF_RESOURCES:
|
|
{
|
|
QString logText = QString("(CL_OUT_OF_RESOURCES) An error occured while creating Queue on device. ") +
|
|
"Failed to allocate resources on device: " + QString::fromStdString(device.getInfo<CL_DEVICE_NAME>());
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLCommandQueueCreationError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_OUT_OF_HOST_MEMORY:
|
|
{
|
|
QString logText = QString("(CL_OUT_OF_HOST_MEMORY) An error occured while creating Queue on device. ") +
|
|
"Failed to allocate resources on the host.";
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLCommandQueueCreationError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_SUCCESS:
|
|
{
|
|
handleError(ESeverityLevel::Debug,
|
|
ELogID::CLCommandQueueCreated,
|
|
"CL Command Queue created successfully for device: " +
|
|
QString::fromStdString(device.getInfo<CL_DEVICE_NAME>()),
|
|
false);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLCommandQueueCreationError,
|
|
"Unknown error occured while creating command queue on device " +
|
|
QString::fromStdString(device.getInfo<CL_DEVICE_NAME>()) +
|
|
" : " + QString::number(error));
|
|
break;
|
|
}
|
|
} // end of switch
|
|
} catch(...) {
|
|
throw;
|
|
}
|
|
|
|
return commandQ;
|
|
}
|
|
|
|
size_t* OpenCLHelper::getMaxGlobalWorkSize(const Kernel& kernel, const Device& device)
|
|
{
|
|
size_t* maxGlobalWorkSize = new size_t[3];
|
|
QString deviceName;
|
|
try
|
|
{
|
|
deviceName = getDeviceName(device);
|
|
}
|
|
catch (...)
|
|
{
|
|
handleError(ESeverityLevel::Warning,
|
|
ELogID::CLKernelError,
|
|
"An error occured while querying name of a CL device.",
|
|
false);
|
|
deviceName = "UNKNOWN_DEVICE";
|
|
}
|
|
|
|
auto error = kernel.getWorkGroupInfo<decltype (maxGlobalWorkSize)>(device, CL_KERNEL_GLOBAL_WORK_SIZE, &maxGlobalWorkSize);
|
|
|
|
try {
|
|
switch (error)
|
|
{
|
|
case CL_INVALID_DEVICE:
|
|
{
|
|
QString logText =
|
|
"(CL_INVALID_DEVICE) An error occured while querying maximum global work size from device: " +
|
|
deviceName + ". The device is invalid.";
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_INVALID_VALUE:
|
|
{
|
|
QString logText =
|
|
"(CL_INVALID_VALUE) An error occured while querying maximum global work size from device: " +
|
|
deviceName + ". Invlid passed parameters.";
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_INVALID_KERNEL:
|
|
{
|
|
QString logText =
|
|
"(CL_INVALID_KERNEL) An error occured while querying maximum global work size from device: " +
|
|
deviceName + ". Invalid kernel object.";
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_OUT_OF_RESOURCES:
|
|
{
|
|
QString logText =
|
|
"(CL_OUT_OF_RESOURCES) An error occured while querying maximum global work size from device: " +
|
|
deviceName + ". Failed to allocate resources on the device.";
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_OUT_OF_HOST_MEMORY:
|
|
{
|
|
QString logText =
|
|
"(CL_OUT_OF_HOST_MEMORY) An error occured while querying maximum global work size from device: " +
|
|
deviceName + ". Failed to allocate resources on the host.";
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelError,
|
|
logText);
|
|
break;
|
|
}
|
|
case CL_SUCCESS:
|
|
{
|
|
handleError(ESeverityLevel::Debug,
|
|
ELogID::CLKernelInfo,
|
|
"Successfully queried the maximum global work size from device: " + deviceName,
|
|
false);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelError,
|
|
"Unknown error occured while querying the maximum global work size from device: " +
|
|
deviceName);
|
|
break;
|
|
}
|
|
} // end of switch
|
|
} catch (...) {
|
|
throw;
|
|
}
|
|
|
|
return (maxGlobalWorkSize);
|
|
}
|
|
|
|
QString OpenCLHelper::getDeviceName(const Device& device)
|
|
{
|
|
cl_int error;
|
|
auto deviceName = device.getInfo<CL_DEVICE_NAME>(&error);
|
|
try {
|
|
switch (error)
|
|
{
|
|
case CL_INVALID_DEVICE:
|
|
{
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLDeviceError,
|
|
"(CL_INVALID_DEVICE) An error occured while querying name of a CL device.");
|
|
break;
|
|
}
|
|
case CL_INVALID_VALUE:
|
|
{
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLDeviceError,
|
|
"(CL_INVALID_VALUE) An error occured related to passed parameters while querying name of a CL device.");
|
|
break;
|
|
}
|
|
case CL_OUT_OF_RESOURCES:
|
|
{
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLDeviceError,
|
|
QString("(CL_OUT_OF_RESOURCES) An error occured while querying name of a CL device. ") +
|
|
"Failed to allocate resources on the device.");
|
|
break;
|
|
}
|
|
case CL_OUT_OF_HOST_MEMORY:
|
|
{
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLDeviceError,
|
|
QString("(CL_OUT_OF_HOST_MEMORY) An error occured while querying name of a CL device. ") +
|
|
"Failed to allocate resources on the host.");
|
|
break;
|
|
}
|
|
case CL_SUCCESS:
|
|
{
|
|
handleError(ESeverityLevel::Debug,
|
|
ELogID::CLDeviceInfo,
|
|
"Successfully queried the name of a device: " + QString::fromStdString(deviceName),
|
|
false);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLDeviceError,
|
|
"An unknown error occured while quering name of a CL device. error: " + QString::number(error));
|
|
break;
|
|
}
|
|
} // end of switch
|
|
} catch (...) {
|
|
throw;
|
|
}
|
|
|
|
return QString::fromStdString(deviceName);
|
|
}
|
|
|
|
QVector<Device> OpenCLHelper::getDevicesByContext(const Context &context)
|
|
{
|
|
std::vector<Device> devices;
|
|
auto error = context.getInfo<std::vector<Device>>(CL_CONTEXT_DEVICES, &devices);
|
|
|
|
try {
|
|
switch (error)
|
|
{
|
|
case CL_INVALID_CONTEXT:
|
|
{
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLContextError,
|
|
"(CL_INVALID_CONTEXT) An error occured while getting devices from a context.");
|
|
break;
|
|
}
|
|
case CL_INVALID_VALUE:
|
|
{
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLContextError,
|
|
QString("(CL_INVALID_VALUE) An error occured while getting devices from a context.") +
|
|
"Something went wrong with the parsed parameter value.");
|
|
break;
|
|
}
|
|
case CL_OUT_OF_RESOURCES:
|
|
{
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLContextError,
|
|
"(CL_OUT_OF_RESOURCES) An error occured while getting devices from a context.");
|
|
break;
|
|
}
|
|
case CL_OUT_OF_HOST_MEMORY:
|
|
{
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLContextError,
|
|
"(CL_OUT_OF_HOST_MEMORY) An error occured while getting devices from a context.");
|
|
break;
|
|
}
|
|
case CL_SUCCESS:
|
|
{
|
|
handleError(ESeverityLevel::Debug,
|
|
ELogID::CLContextInfo,
|
|
"Devices successfully queried from context.",
|
|
false);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLContextError,
|
|
"Unknown error occured while quering devices from context. error: " + QString::number(error));
|
|
break;
|
|
}
|
|
} // end of switch
|
|
} catch (...)
|
|
{
|
|
throw;
|
|
}
|
|
// qDebug() << "End of kernel functor";
|
|
|
|
return (QVector<Device>::fromStdVector(devices));
|
|
}
|
|
|
|
template<typename... Ts>
|
|
void OpenCLHelper::runKernelFunctor (KernelFunctor<Ts...>& kernelFunctor,
|
|
EnqueueArgs args,
|
|
Ts... ts)
|
|
{
|
|
cl_int error;
|
|
kernelFunctor(args, ts..., error);
|
|
if(error != 0)
|
|
qDebug() << "Error : "<< error;
|
|
try {
|
|
switch(error)
|
|
{
|
|
case CL_INVALID_PROGRAM_EXECUTABLE:
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelRunError,
|
|
"(CL_INVALID_PROGRAM_EXECUTABLE) There is no successfully built program executable.");
|
|
break;
|
|
case CL_INVALID_KERNEL:
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelRunError,
|
|
"(CL_INVALID_KERNEL) Invalid kernel object.");
|
|
break;
|
|
case CL_INVALID_CONTEXT:
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelRunError,
|
|
"(CL_INVALID_CONTEXT) Invalid context associated with the command queue and kernel.");
|
|
break;
|
|
case CL_INVALID_KERNEL_ARGS:
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelRunError,
|
|
"(CL_INVALID_KERNEL_ARGS) Kernel arguments has not been specified.");
|
|
break;
|
|
case CL_INVALID_GLOBAL_WORK_SIZE:
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelRunError,
|
|
"(CL_INVALID_GLOBAL_WORK_SIZE) Invalid global work size specified.");
|
|
break;
|
|
case CL_INVALID_GLOBAL_OFFSET:
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelRunError,
|
|
"(CL_INVALID_GLOBAL_OFFSET) Invalid offset size specified.");
|
|
break;
|
|
case CL_INVALID_WORK_GROUP_SIZE:
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelRunError,
|
|
"(CL_INVALID_WORK_GROUP_SIZE) Work group size mismatch.");
|
|
break;
|
|
case CL_INVALID_WORK_ITEM_SIZE:
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelRunError,
|
|
"(CL_INVALID_WORK_ITEM_SIZE) Work item size mismatch.");
|
|
break;
|
|
case CL_MISALIGNED_SUB_BUFFER_OFFSET:
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelRunError,
|
|
"(CL_MISALIGNED_SUB_BUFFER_OFFSET) Subbuffer offset mismatch.");
|
|
break;
|
|
case CL_INVALID_IMAGE_SIZE:
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelRunError,
|
|
"(CL_INVALID_IMAGE_SIZE) Image dimension not supported by the device.");
|
|
break;
|
|
case CL_OUT_OF_RESOURCES:
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelRunError,
|
|
"(CL_OUT_OF_RESOURCES) Insufficient resources needed to execute the kernel.");
|
|
break;
|
|
case CL_MEM_OBJECT_ALLOCATION_FAILURE:
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelRunError,
|
|
"(CL_MEM_OBJECT_ALLOCATION_FAILURE) Failure to allocate memory.");
|
|
break;
|
|
case CL_INVALID_EVENT_WAIT_LIST:
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelRunError,
|
|
"(CL_INVALID_EVENT_WAIT_LIST) Invalid event objects in events wait list.");
|
|
break;
|
|
case CL_OUT_OF_HOST_MEMORY:
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelRunError,
|
|
"(CL_OUT_OF_HOST_MEMORY) Failure to allocate resources on the host.");
|
|
break;
|
|
case CL_SUCCESS:
|
|
{
|
|
handleError(ESeverityLevel::Debug,
|
|
ELogID::CLKernelRunInfo,
|
|
"Successfully ran the kernel.",
|
|
false);
|
|
break;
|
|
}
|
|
default:
|
|
handleError(ESeverityLevel::Error,
|
|
ELogID::CLKernelRunInfo,
|
|
"There was an unknown error while running the kernel.");
|
|
break;
|
|
} // end of switch
|
|
} catch (...)
|
|
{
|
|
throw;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|