/*! \file piopencl.h
* \ingroup OpenCL
* \~\brief
* \~english OpenCL classes
* \~russian Классы OpenCL
*/
/*
PIP - Platform Independent Primitives
OpenCL wrappers
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
//! \~english OpenCL module
//! \~russian Модуль OpenCL
//! \defgroup OpenCL OpenCL
//! \~\brief
//! \~english OpenCL support
//! \~russian Поддержка OpenCL
//!
//! \~\details
//! \~english \section cmake_module_OpenCL Building with CMake
//! \~russian \section cmake_module_OpenCL Сборка с использованием CMake
//!
//! \~\code
//! find_package(PIP REQUIRED)
//! target_link_libraries([target] PIP::OpenCL)
//! \endcode
//!
//! \~english \par Common
//! \~russian \par Общее
//!
//! \~english
//! These files provides OpenCL classes wrap.
//!
//! \~russian
//! Эти файлы обеспечивают классовую обвязку OpenCL.
//!
//! \~\authors
//! \~english
//! Ivan Pelipenko peri4ko@yandex.ru;
//! Andrey Bychkov work.a.b@yandex.ru;
//! \~russian
//! Иван Пелипенко peri4ko@yandex.ru;
//! Андрей Бычков work.a.b@yandex.ru;
//!
#ifndef PIOPENCL_H
#define PIOPENCL_H
#include "pip_opencl_export.h"
#include "pivariant.h"
//! \~english Main OpenCL wrapper class
//! \~russian Главный класс-обёртка OpenCL
class PIP_OPENCL_EXPORT PIOpenCL {
public:
//! \~english Kernel argument structure
//! \~russian Структура аргумента ядра
struct KernelArg;
//! \~english Device structure
//! \~russian Структура устройства
struct Device;
//! \~english Platform structure
//! \~russian Структура платформы
struct Platform;
//! \~english OpenCL context class
//! \~russian Класс контекста OpenCL
class Context;
//! \~english OpenCL buffer class
//! \~russian Класс буфера OpenCL
class Buffer;
//! \~english OpenCL program class
//! \~russian Класс программы OpenCL
class Program;
//! \~english OpenCL kernel class
//! \~russian Класс ядра OpenCL
class Kernel;
//! \~english List of devices
//! \~russian Список устройств
typedef PIVector DeviceList;
//! \~english Address space qualifiers
//! \~russian Квалификаторы адресного пространства
enum AddressQualifier {
AddressGlobal,
AddressLocal,
AddressConstant,
AddressPrivate,
};
//! \~english Access qualifiers
//! \~russian Квалификаторы доступа
enum AccessQualifier {
AccessReadOnly,
AccessWriteOnly,
AccessReadWrite,
AccessNone,
};
//! \~english Buffer direction
//! \~russian Направление буфера
enum Direction {
Input = 0x01,
Output = 0x02,
InputOutput = Input | Output,
};
//! \~english Type qualifiers
//! \~russian Квалификаторы типа
enum TypeQualifier {
TypeConst,
TypeRestrict,
TypeVolatile,
TypeNone,
};
//! \~english Argument types
//! \~russian Типы аргументов
enum ArgType {
Char = 1,
UChar,
Short,
UShort,
Int,
UInt,
Long,
ULong,
Float,
Double,
};
//! \~english Kernel argument information
//! \~russian Информация об аргументе ядра
struct PIP_OPENCL_EXPORT KernelArg {
//! \~english Default constructor
//! \~russian Конструктор по умолчанию
KernelArg();
//! \~english Address qualifier
//! \~russian Квалификатор адреса
AddressQualifier address_qualifier;
//! \~english Access qualifier
//! \~russian Квалификатор доступа
AccessQualifier access_qualifier;
//! \~english Buffer direction
//! \~russian Направление буфера
Direction direction;
//! \~english Type qualifier
//! \~russian Квалификатор типа
TypeQualifier type_qualifier;
//! \~english Argument name
//! \~russian Имя аргумента
PIString arg_name;
//! \~english Type name
//! \~russian Имя типа
PIString type_name;
//! \~english Base type name
//! \~russian Имя базового типа
PIString base_type_name;
//! \~english Is pointer
//! \~russian Является указателем
bool is_pointer;
//! \~english Argument type
//! \~russian Тип аргумента
ArgType arg_type;
//! \~english Dimensions
//! \~russian Размерности
int dims;
private:
friend class Kernel;
void init(void * _k, uint index);
};
//! \~english OpenCL device information
//! \~russian Информация об устройстве OpenCL
struct PIP_OPENCL_EXPORT Device {
//! \~english Default constructor
//! \~russian Конструктор по умолчанию
Device() {
id = platform_id = 0;
max_compute_units = max_clock_frequency = 0;
max_memory_size = 0;
}
//! \~english Check if device is valid
//! \~russian Проверить устройство на корректность
bool isValid() const { return id != 0; }
//! \~english Get display text
//! \~russian Получить текст для отображения
PIString displayText() const { return name.trimmed() + " (" + device_version.trimmed() + ")"; }
//! \~english Device handle
//! \~russian Дескриптор устройства
void * id;
//! \~english Platform ID
//! \~russian ID платформы
void * platform_id;
//! \~english Device name
//! \~russian Имя устройства
PIString name;
//! \~english Vendor name
//! \~russian Имя производителя
PIString vendor;
//! \~english Device version
//! \~russian Версия устройства
PIString device_version;
//! \~english Driver version
//! \~russian Версия драйвера
PIString driver_version;
//! \~english Maximum compute units
//! \~russian Максимум вычислительных блоков
int max_compute_units;
//! \~english Maximum clock frequency
//! \~russian Максимальная тактовая частота
int max_clock_frequency;
//! \~english Maximum memory size
//! \~russian Максимальный размер памяти
ullong max_memory_size;
};
//! \~english OpenCL platform information
//! \~russian Информация о платформе OpenCL
struct PIP_OPENCL_EXPORT Platform {
//! \~english Default constructor
//! \~russian Конструктор по умолчанию
Platform() { id = 0; }
//! \~english Check if platform is valid
//! \~russian Проверить платформу на корректность
bool isValid() const { return id != 0; }
//! \~english Get display text
//! \~russian Получить текст для отображения
PIString displayText() const { return name.trimmed() + " (" + version.trimmed() + ", " + profile.trimmed() + ")"; }
//! \~english Platform handle
//! \~russian Дескриптор платформы
void * id;
//! \~english Platform name
//! \~russian Имя платформы
PIString name;
//! \~english Vendor name
//! \~russian Имя производителя
PIString vendor;
//! \~english Profile
//! \~russian Профиль
PIString profile;
//! \~english Version
//! \~russian Версия
PIString version;
//! \~english Extensions
//! \~russian Расширения
PIStringList extensions;
//! \~english Available devices
//! \~russian Доступные устройства
PIVector devices;
};
//! \~english OpenCL context for managing devices and resources
//! \~russian Контекст OpenCL для управления устройствами и ресурсами
class PIP_OPENCL_EXPORT Context {
friend class Buffer;
friend class Program;
friend class Kernel;
public:
//! \~english Destructor
//! \~russian Деструктор
~Context();
//! \~english Get context handle
//! \~russian Получить дескриптор контекста
void * handle();
//! \~english Get command queue
//! \~russian Получить очередь команд
void * queue();
//! \~english Create context for device list
//! \~russian Создать контекст для списка устройств
//! \param dl List of devices
//! \return New context or nullptr
static Context * create(const DeviceList & dl);
//! \~english Create context for single device
//! \~russian Создать контекст для одного устройства
//! \param d Device
//! \return New context or nullptr
static Context * create(const Device & d) { return create(DeviceList() << d); }
//! \~english Create context by platform name
//! \~russian Создать контекст по имени платформы
//! \param part_name Platform name pattern
//! \return New context or nullptr
static Context * create(const PIString & part_name);
//! \~english Create program from source
//! \~russian Создать программу из исходного кода
//! \param source OpenCL source code
//! \param args Build arguments
//! \param error Error message output
//! \return New program or nullptr
Program * createProgram(const PIString & source, const PIStringList & args = PIStringList(), PIString * error = 0);
//! \~english Create buffer from vector
//! \~russian Создать буфер из вектора
template
Buffer * createBuffer(PIOpenCL::Direction dir, PIVector & container) {
T def = T();
return createBuffer(dir, &container, Buffer::cVector, PIByteArray(&def, sizeof(T)), container.size());
}
//! \~english Create buffer from deque
//! \~russian Создать буфер из deque
template
Buffer * createBuffer(PIOpenCL::Direction dir, PIDeque & container) {
T def = T();
return createBuffer(dir, &container, Buffer::cDeque, PIByteArray(&def, sizeof(T)), container.size());
}
//! \~english Create buffer from 2D vector
//! \~russian Создать буфер из 2D вектора
template
Buffer * createBuffer(PIOpenCL::Direction dir, PIVector2D & container) {
T def = T();
return createBuffer(dir, &container, Buffer::cVector2D, PIByteArray(&def, sizeof(T)), container.size());
}
//! \~english Create buffer for elements
//! \~russian Создать буфер для элементов
template
Buffer * createBuffer(PIOpenCL::Direction dir, uint elements) {
T def = T();
Buffer * ret = createBuffer(dir, 0, Buffer::cNone, PIByteArray(&def, sizeof(T)), elements);
if (ret) ret->clear();
return ret;
}
private:
Context();
void zero();
void deletePrograms();
void deleteBuffers();
Buffer * createBuffer(PIOpenCL::Direction dir, void * container, int type, PIByteArray def, uint elements);
PIVector programs_;
PIVector buffers_;
PRIVATE_DECLARATION(PIP_OPENCL_EXPORT)
};
//! \~english OpenCL buffer for data storage
//! \~russian Буфер OpenCL для хранения данных
class PIP_OPENCL_EXPORT Buffer {
friend class Context;
friend class Kernel;
public:
//! \~english Destructor
//! \~russian Деструктор
~Buffer();
//! \~english Get buffer handle
//! \~russian Получить дескриптор буфера
void * handle();
//! \~english Resize buffer
//! \~russian Изменить размер буфера
//! \param new_elements New number of elements
//! \return true if successful
bool resize(uint new_elements);
//! \~english Clear buffer
//! \~russian Очистить буфер
void clear();
//! \~english Copy to container
//! \~russian Копировать в контейнер
void copyToContainer();
//! \~english Copy to memory
//! \~russian Копировать в память
void copyTo(void * data);
//! \~english Copy to memory with offset
//! \~russian Копировать в память со смещением
void copyTo(void * data, int elements_count, int elements_offset = 0);
//! \~english Copy to another buffer
//! \~russian Копировать в другой буфер
void copyTo(Buffer * buffer, int elements_count = -1, int elements_from_offset = 0, int elements_to_offset = 0);
//! \~english Copy from container
//! \~russian Копировать из контейнера
void copyFromContainer();
//! \~english Copy from memory
//! \~russian Копировать из памяти
void copyFrom(void * data);
//! \~english Copy from memory with offset
//! \~russian Копировать из памяти со смещением
void copyFrom(void * data, int elements_count, int elements_offset = 0);
//! \~english Copy from another buffer
//! \~russian Копировать из другого буфера
void copyFrom(Buffer * buffer, int elements_count = -1, int elements_from_offset = 0, int elements_to_offset = 0);
//! \~english Get elements count
//! \~russian Получить количество элементов
uint elementsCount() const { return elements; }
private:
//! \~english Container types
//! \~russian Типы контейнеров
enum Container {
cNone,
cVector,
cDeque,
cVector2D,
};
Buffer();
void zero();
bool init();
void * containerData();
static void copy(Buffer * buffer_from, Buffer * buffer_to, int elements_count, int elements_from_offset, int elements_to_offset);
Context * context_;
Direction dir;
Container type;
void * container;
PIByteArray def;
uint elements;
PRIVATE_DECLARATION(PIP_OPENCL_EXPORT)
};
//! \~english OpenCL program containing kernels
//! \~russian Программа OpenCL содержащая ядра
class PIP_OPENCL_EXPORT Program {
friend class Context;
friend class Kernel;
friend class Buffer;
public:
//! \~english Destructor
//! \~russian Деструктор
~Program();
//! \~english Get context
//! \~russian Получить контекст
Context * context() const { return context_; }
//! \~english Get source code
//! \~russian Получить исходный код
const PIString & sourceCode() const { return source_; }
//! \~english Get kernel by index
//! \~russian Получить ядро по индексу
Kernel * kernel(int index = 0) const { return kernels_[index]; }
//! \~english Get all kernels
//! \~russian Получить все ядра
const PIVector & kernels() const { return kernels_; }
private:
Program();
void zero();
bool initKernels(PIVector kerns);
Context * context_;
PIString source_;
PIVector kernels_;
PRIVATE_DECLARATION(PIP_OPENCL_EXPORT)
};
//! \~english OpenCL kernel for execution
//! \~russian Ядро OpenCL для выполнения
class PIP_OPENCL_EXPORT Kernel {
friend class Program;
friend class Buffer;
public:
//! \~english Get parent program
//! \~russian Получить родительскую программу
Program * program() const { return program_; }
//! \~english Execute kernel
//! \~russian Выполнить ядро
//! \return true if successful
bool execute();
//! \~english Wait for execution to finish
//! \~russian Ждать завершения выполнения
void waitForFinish();
//! \~english Set execution range (1D)
//! \~russian Установить диапазон выполнения (1D)
//! \param size Number of work items
void setExecuteRange(int size) { setExecuteRanges(PIVector() << size); }
//! \~english Set execution ranges (ND)
//! \~russian Установить диапазоны выполнения (ND)
//! \param ranges Array of sizes per dimension
void setExecuteRanges(const PIVector & ranges);
//! \~english Get kernel name
//! \~russian Получить имя ядра
const PIString & name() const { return name_; }
//! \~english Get kernel arguments
//! \~russian Получить аргументы ядра
const PIVector & args() const { return args_; }
//! \~english Set argument value by index
//! \~russian Установить значение аргумента по индексу
template
bool setArgValue(int index, const T & value) {
return setArgValueS(index, PIVariant::fromValue(value));
}
//! \~english Set argument value by name
//! \~russian Установить значение аргумента по имени
template
bool setArgValue(const PIString & arg, const T & value) {
return setArgValue(argIndex(arg), value);
}
//! \~english Set variant argument value
//! \~russian Установить значение аргумента variant
bool setArgValue(const PIString & arg, const PIVariant & value) { return setArgValueS(argIndex(arg), value); }
//! \~english Bind buffer to argument
//! \~russian Привязать буфер к аргументу
bool bindArgValue(int index, Buffer * buffer);
//! \~english Bind buffer to argument by name
//! \~russian Привязать буфер к аргументу по имени
bool bindArgValue(const PIString & arg, Buffer * buffer) { return bindArgValue(argIndex(arg), buffer); }
private:
Kernel();
~Kernel();
void zero();
bool init();
bool setArgValueS(int index, const PIVariant & value);
int argIndex(const PIString & an) const;
KernelArg argByName(const PIString & an) const;
Context * context_;
Program * program_;
PIString name_;
PIVector args_;
PIVector dims;
PRIVATE_DECLARATION(PIP_OPENCL_EXPORT)
};
//! \~english Initialize OpenCL
//! \~russian Инициализировать OpenCL
static void init();
//! \~english Get available platforms
//! \~russian Получить доступные платформы
//! \return Vector of platforms
static const PIVector & platforms();
//! \~english Get all available devices
//! \~russian Получить все доступные устройства
//! \return Vector of devices
static const PIVector devices();
//! \~english Get device by ID
//! \~russian Получить устройство по ID
//! \param id Device handle
//! \return Device info
static Device deviceByID(void * id);
//! \~english Prepare program source
//! \~russian Подготовить исходный код программы
//! \param prog Program source
//! \return Prepared source
static PIString prepareProgram(const PIString & prog);
private:
static PIString prog_header;
PIOpenCL() { ; }
//! \~english Initialization helper
//! \~russian Помощник инициализации
class PIP_OPENCL_EXPORT Initializer {
public:
Initializer();
static Initializer * instance();
void init();
PIVector platforms_;
bool inited_;
};
};
//! \~english Output stream operator for KernelArg
//! \~russian Оператор вывода в поток для KernelArg
PIP_OPENCL_EXPORT PICout operator<<(PICout s, const PIOpenCL::KernelArg & v);
#endif // PIOPENCL_H