Files
pip/libs/main/opencl/piopencl.h

655 lines
20 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*! \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 <http://www.gnu.org/licenses/>.
*/
//! \~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<Device> 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<Device> 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<typename T>
Buffer * createBuffer(PIOpenCL::Direction dir, PIVector<T> & container) {
T def = T();
return createBuffer(dir, &container, Buffer::cVector, PIByteArray(&def, sizeof(T)), container.size());
}
//! \~english Create buffer from deque
//! \~russian Создать буфер из deque
template<typename T>
Buffer * createBuffer(PIOpenCL::Direction dir, PIDeque<T> & 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<typename T>
Buffer * createBuffer(PIOpenCL::Direction dir, PIVector2D<T> & container) {
T def = T();
return createBuffer(dir, &container, Buffer::cVector2D, PIByteArray(&def, sizeof(T)), container.size());
}
//! \~english Create buffer for elements
//! \~russian Создать буфер для элементов
template<typename T>
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<Program *> programs_;
PIVector<Buffer *> 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<Kernel *> & kernels() const { return kernels_; }
private:
Program();
void zero();
bool initKernels(PIVector<void *> kerns);
Context * context_;
PIString source_;
PIVector<Kernel *> 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<int>() << size); }
//! \~english Set execution ranges (ND)
//! \~russian Установить диапазоны выполнения (ND)
//! \param ranges Array of sizes per dimension
void setExecuteRanges(const PIVector<int> & ranges);
//! \~english Get kernel name
//! \~russian Получить имя ядра
const PIString & name() const { return name_; }
//! \~english Get kernel arguments
//! \~russian Получить аргументы ядра
const PIVector<KernelArg> & args() const { return args_; }
//! \~english Set argument value by index
//! \~russian Установить значение аргумента по индексу
template<typename T>
bool setArgValue(int index, const T & value) {
return setArgValueS(index, PIVariant::fromValue(value));
}
//! \~english Set argument value by name
//! \~russian Установить значение аргумента по имени
template<typename T>
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<KernelArg> args_;
PIVector<size_t> 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<Platform> & platforms();
//! \~english Get all available devices
//! \~russian Получить все доступные устройства
//! \return Vector of devices
static const PIVector<Device> 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<Platform> 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