//! \~\file piopencl.h
//! \~\ingroup OpenCL
//! \~\brief
//! \~english OpenCL wrapper classes
//! \~russian Классы-обертки для OpenCL
/*
PIP - Platform Independent Primitives
OpenCL wrapper classes
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 .
*/
//! \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
//! The module provides lightweight wrappers for OpenCL platforms, devices,
//! contexts, programs, kernels and buffers.
//!
//! \~russian
//! Модуль предоставляет легковесные обертки для платформ, устройств,
//! контекстов, программ, ядер и буферов OpenCL.
//!
//! \~\authors
//! \~english
//! Ivan Pelipenko peri4ko@yandex.ru;
//! \~russian
//! Иван Пелипенко peri4ko@yandex.ru;
//!
#ifndef PIOPENCL_H
#define PIOPENCL_H
#include "pip_opencl_export.h"
#include "pivariant.h"
//! \~\ingroup OpenCL
//! \~\brief
//! \~english Entry point for the OpenCL wrapper API.
//! \~russian Точка входа в API-обертку OpenCL.
class PIP_OPENCL_EXPORT PIOpenCL {
public:
struct KernelArg;
struct Device;
struct Platform;
class Context;
class Buffer;
class Program;
class Kernel;
//! \~english List of OpenCL devices.
//! \~russian Список устройств OpenCL.
typedef PIVector DeviceList;
//! \~english Address space qualifier of a kernel argument.
//! \~russian Квалификатор адресного пространства аргумента ядра.
enum AddressQualifier {
AddressGlobal /** \~english Global memory argument \~russian Аргумент в глобальной памяти */,
AddressLocal /** \~english Local memory argument \~russian Аргумент в локальной памяти */,
AddressConstant /** \~english Constant memory argument \~russian Аргумент в константной памяти */,
AddressPrivate /** \~english Private argument \~russian Приватный аргумент */
};
//! \~english Access qualifier of an image or memory argument.
//! \~russian Квалификатор доступа к аргументу изображения или памяти.
enum AccessQualifier {
AccessReadOnly /** \~english Read-only access \~russian Доступ только для чтения */,
AccessWriteOnly /** \~english Write-only access \~russian Доступ только для записи */,
AccessReadWrite /** \~english Read-write access \~russian Доступ для чтения и записи */,
AccessNone /** \~english Access qualifier is not specified \~russian Квалификатор доступа не задан */
};
//! \~english Intended data flow direction for buffers.
//! \~russian Предполагаемое направление обмена данными для буферов.
enum Direction {
Input = 0x01 /** \~english Host-to-device input buffer \~russian Входной буфер host->device */,
Output = 0x02 /** \~english Device-to-host output buffer \~russian Выходной буфер device->host */,
InputOutput = Input | Output /** \~english Bidirectional buffer \~russian Двунаправленный буфер */
};
//! \~english Type qualifier of a kernel argument.
//! \~russian Квалификатор типа аргумента ядра.
enum TypeQualifier {
TypeConst /** \~english Constant argument \~russian Константный аргумент */,
TypeRestrict /** \~english Restricted argument \~russian Аргумент с qualifier `restrict` */,
TypeVolatile /** \~english Volatile argument \~russian Аргумент с qualifier `volatile` */,
TypeNone /** \~english No type qualifier \~russian Квалификатор типа отсутствует */
};
//! \~english Scalar argument type recognized by the wrapper.
//! \~russian Скалярный тип аргумента, распознаваемый оберткой.
enum ArgType {
Char = 1 /** \~english Signed 8-bit integer \~russian Знаковое 8-битное целое */,
UChar /** \~english Unsigned 8-bit integer \~russian Беззнаковое 8-битное целое */,
Short /** \~english Signed 16-bit integer \~russian Знаковое 16-битное целое */,
UShort /** \~english Unsigned 16-bit integer \~russian Беззнаковое 16-битное целое */,
Int /** \~english Signed 32-bit integer \~russian Знаковое 32-битное целое */,
UInt /** \~english Unsigned 32-bit integer \~russian Беззнаковое 32-битное целое */,
Long /** \~english Signed long integer \~russian Знаковое long-целое */,
ULong /** \~english Unsigned long integer \~russian Беззнаковое long-целое */,
Float /** \~english Single-precision floating point \~russian Число с плавающей точкой одинарной точности */,
Double /** \~english Double-precision floating point \~russian Число с плавающей точкой двойной точности */
};
//! \~\brief
//! \~english Reflected description of a kernel argument.
//! \~russian Отраженное описание аргумента ядра.
struct PIP_OPENCL_EXPORT KernelArg {
//! \~english Constructs an empty argument description.
//! \~russian Создает пустое описание аргумента.
KernelArg();
//! \~english Address qualifier reported by OpenCL.
//! \~russian Адресный квалификатор, сообщенный OpenCL.
AddressQualifier address_qualifier;
//! \~english Access qualifier reported by OpenCL.
//! \~russian Квалификатор доступа, сообщенный OpenCL.
AccessQualifier access_qualifier;
//! \~english Intended transfer direction used by this wrapper.
//! \~russian Направление обмена, используемое этой оберткой.
Direction direction;
//! \~english Type qualifier reported by OpenCL.
//! \~russian Квалификатор типа, сообщенный OpenCL.
TypeQualifier type_qualifier;
//! \~english Argument name from kernel metadata.
//! \~russian Имя аргумента из метаданных ядра.
PIString arg_name;
//! \~english Original type name from kernel metadata.
//! \~russian Исходное имя типа из метаданных ядра.
PIString type_name;
//! \~english Base type name without pointer or array suffixes.
//! \~russian Базовое имя типа без указателей и массивных суффиксов.
PIString base_type_name;
//! \~english True when the argument is pointer-like.
//! \~russian True, если аргумент ведет себя как указатель.
bool is_pointer;
//! \~english Wrapper-level scalar type classification.
//! \~russian Классификация скалярного типа на уровне обертки.
ArgType arg_type;
//! \~english Pointer or array depth inferred from the type name.
//! \~russian Глубина указателей или массивов, выведенная из имени типа.
int dims;
private:
friend class Kernel;
void init(void * _k, uint index);
};
//! \~\brief
//! \~english Description of a discovered OpenCL device.
//! \~russian Описание найденного устройства OpenCL.
struct PIP_OPENCL_EXPORT Device {
//! \~english Constructs an invalid device description.
//! \~russian Создает недействительное описание устройства.
Device() {
id = platform_id = 0;
max_compute_units = max_clock_frequency = 0;
max_memory_size = 0;
}
//! \~english Returns true when the native device handle is available.
//! \~russian Возвращает true, если доступен нативный дескриптор устройства.
bool isValid() const { return id != 0; }
//! \~english Returns a short display label with name and device version.
//! \~russian Возвращает краткую строку отображения с именем и версией устройства.
PIString displayText() const { return name.trimmed() + " (" + device_version.trimmed() + ")"; }
//! \~english Native OpenCL device handle.
//! \~russian Нативный дескриптор устройства OpenCL.
void * id;
//! \~english Native platform handle that owns the device.
//! \~russian Нативный дескриптор платформы, которой принадлежит устройство.
void * platform_id;
//! \~english Human-readable device name.
//! \~russian Человекочитаемое имя устройства.
PIString name;
//! \~english Device vendor name.
//! \~russian Имя производителя устройства.
PIString vendor;
//! \~english OpenCL device version string.
//! \~russian Строка версии устройства OpenCL.
PIString device_version;
//! \~english Driver version string.
//! \~russian Строка версии драйвера.
PIString driver_version;
//! \~english Maximum number of compute units.
//! \~russian Максимальное число вычислительных блоков.
int max_compute_units;
//! \~english Maximum clock frequency in MHz.
//! \~russian Максимальная тактовая частота в МГц.
int max_clock_frequency;
//! \~english Global memory size in bytes.
//! \~russian Объем глобальной памяти в байтах.
ullong max_memory_size;
};
//! \~\brief
//! \~english Description of an OpenCL platform and its devices.
//! \~russian Описание платформы OpenCL и ее устройств.
struct PIP_OPENCL_EXPORT Platform {
//! \~english Constructs an invalid platform description.
//! \~russian Создает недействительное описание платформы.
Platform() { id = 0; }
//! \~english Returns true when the native platform handle is available.
//! \~russian Возвращает true, если доступен нативный дескриптор платформы.
bool isValid() const { return id != 0; }
//! \~english Returns a short display label with version and profile.
//! \~russian Возвращает краткую строку отображения с версией и профилем.
PIString displayText() const { return name.trimmed() + " (" + version.trimmed() + ", " + profile.trimmed() + ")"; }
//! \~english Native OpenCL platform handle.
//! \~russian Нативный дескриптор платформы OpenCL.
void * id;
//! \~english Human-readable platform name.
//! \~russian Человекочитаемое имя платформы.
PIString name;
//! \~english Platform vendor name.
//! \~russian Имя производителя платформы.
PIString vendor;
//! \~english Platform profile string.
//! \~russian Строка профиля платформы.
PIString profile;
//! \~english Platform version string.
//! \~russian Строка версии платформы.
PIString version;
//! \~english Reported extension names.
//! \~russian Имена поддерживаемых расширений.
PIStringList extensions;
//! \~english Devices discovered on the platform.
//! \~russian Устройства, найденные на платформе.
PIVector devices;
};
//! \~\brief
//! \~english OpenCL context wrapper that owns created programs and buffers.
//! \~russian Обертка над контекстом OpenCL, владеющая созданными программами и буферами.
class PIP_OPENCL_EXPORT Context {
friend class Buffer;
friend class Program;
friend class Kernel;
public:
//! \~english Destroys the context together with its programs and buffers.
//! \~russian Уничтожает контекст вместе с его программами и буферами.
~Context();
//! \~english Returns the native OpenCL context handle.
//! \~russian Возвращает нативный дескриптор контекста OpenCL.
void * handle();
//! \~english Returns the native command queue handle.
//! \~russian Возвращает нативный дескриптор очереди команд.
void * queue();
//! \~english Creates a context for the given device list.
//! \~russian Создает контекст для заданного списка устройств.
static Context * create(const DeviceList & dl);
//! \~english Creates a context for a single device.
//! \~russian Создает контекст для одного устройства.
static Context * create(const Device & d) { return create(DeviceList() << d); }
//! \~english Creates a context for the first device whose display name contains the given text.
//! \~russian Создает контекст для первого устройства, в строке отображения которого содержится заданный текст.
static Context * create(const PIString & part_name);
//! \~english Builds a program from source and returns null on failure.
//! \~russian Собирает программу из исходного текста и возвращает null при ошибке.
Program * createProgram(const PIString & source, const PIStringList & args = PIStringList(), PIString * error = 0);
//! \~english Creates a buffer bound to a vector container.
//! \~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 Creates a buffer bound to a deque container.
//! \~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 Creates a buffer bound to a two-dimensional vector container.
//! \~russian Создает буфер, связанный с двумерным контейнером-вектором.
template
Buffer * createBuffer(PIOpenCL::Direction dir, PIVector2D & container) {
T def = T();
return createBuffer(dir, &container, Buffer::cVector2D, PIByteArray(&def, sizeof(T)), container.size());
}
//! \~english Creates an unbound buffer with the given element count and clears it to the default value.
//! \~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)
};
//! \~\brief
//! \~english OpenCL buffer wrapper optionally bound to a host container.
//! \~russian Обертка над буфером OpenCL, при необходимости связанная с контейнером host.
class PIP_OPENCL_EXPORT Buffer {
friend class Context;
friend class Kernel;
public:
//! \~english Destroys the buffer object.
//! \~russian Уничтожает объект буфера.
~Buffer();
//! \~english Returns the native OpenCL memory handle.
//! \~russian Возвращает нативный дескриптор памяти OpenCL.
void * handle();
//! \~english Resizes the buffer to another element count.
//! \~russian Изменяет размер буфера на другое число элементов.
bool resize(uint new_elements);
//! \~english Fills the whole buffer with the default element value.
//! \~russian Заполняет весь буфер значением элемента по умолчанию.
void clear();
//! \~english Copies device data back to the bound host container.
//! \~russian Копирует данные с устройства обратно в связанный host-контейнер.
void copyToContainer();
//! \~english Copies the whole buffer to raw host memory.
//! \~russian Копирует весь буфер в сырую память host.
void copyTo(void * data);
//! \~english Copies a subrange of the buffer to raw host memory.
//! \~russian Копирует поддиапазон буфера в сырую память host.
void copyTo(void * data, int elements_count, int elements_offset = 0);
//! \~english Copies data from this buffer to another buffer.
//! \~russian Копирует данные из этого буфера в другой буфер.
void copyTo(Buffer * buffer, int elements_count = -1, int elements_from_offset = 0, int elements_to_offset = 0);
//! \~english Uploads data from the bound host container.
//! \~russian Загружает данные из связанного host-контейнера.
void copyFromContainer();
//! \~english Copies the whole raw host memory block into the buffer.
//! \~russian Копирует весь блок сырой памяти host в буфер.
void copyFrom(void * data);
//! \~english Copies a subrange from raw host memory into the buffer.
//! \~russian Копирует поддиапазон из сырой памяти host в буфер.
void copyFrom(void * data, int elements_count, int elements_offset = 0);
//! \~english Copies data from another buffer into this buffer.
//! \~russian Копирует данные из другого буфера в этот буфер.
void copyFrom(Buffer * buffer, int elements_count = -1, int elements_from_offset = 0, int elements_to_offset = 0);
//! \~english Returns the number of logical elements in the buffer.
//! \~russian Возвращает число логических элементов в буфере.
uint elementsCount() const { return elements; }
private:
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)
};
//! \~\brief
//! \~english Compiled OpenCL program that owns discovered kernels.
//! \~russian Скомпилированная программа OpenCL, владеющая найденными ядрами.
class PIP_OPENCL_EXPORT Program {
friend class Context;
friend class Kernel;
friend class Buffer;
public:
//! \~english Destroys the program and its kernels.
//! \~russian Уничтожает программу и ее ядра.
~Program();
//! \~english Returns the context that created the program.
//! \~russian Возвращает контекст, создавший программу.
Context * context() const { return context_; }
//! \~english Returns the original source code used for compilation.
//! \~russian Возвращает исходный текст, использованный при компиляции.
const PIString & sourceCode() const { return source_; }
//! \~english Returns the kernel at the given index.
//! \~russian Возвращает ядро по заданному индексу.
Kernel * kernel(int index = 0) const { return kernels_[index]; }
//! \~english Returns all kernels created from the program.
//! \~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)
};
//! \~\brief
//! \~english OpenCL kernel wrapper with reflected argument metadata.
//! \~russian Обертка над ядром OpenCL с отраженными метаданными аргументов.
class PIP_OPENCL_EXPORT Kernel {
friend class Program;
friend class Buffer;
public:
//! \~english Returns the program that owns the kernel.
//! \~russian Возвращает программу, которой принадлежит ядро.
Program * program() const { return program_; }
//! \~english Enqueues kernel execution for the configured global ranges.
//! \~russian Помещает выполнение ядра в очередь для настроенных глобальных диапазонов.
bool execute();
//! \~english Waits until the context command queue finishes.
//! \~russian Ожидает завершения очереди команд контекста.
void waitForFinish();
//! \~english Sets one-dimensional execution range.
//! \~russian Устанавливает одномерный диапазон выполнения.
void setExecuteRange(int size) { setExecuteRanges(PIVector() << size); }
//! \~english Sets multi-dimensional execution ranges.
//! \~russian Устанавливает многомерные диапазоны выполнения.
void setExecuteRanges(const PIVector & ranges);
//! \~english Returns the kernel function name.
//! \~russian Возвращает имя функции ядра.
const PIString & name() const { return name_; }
//! \~english Returns reflected descriptions of kernel arguments.
//! \~russian Возвращает отраженные описания аргументов ядра.
const PIVector & args() const { return args_; }
//! \~english Sets a scalar argument by index.
//! \~russian Устанавливает скалярный аргумент по индексу.
template
bool setArgValue(int index, const T & value) {
return setArgValueS(index, PIVariant::fromValue(value));
}
//! \~english Sets a scalar argument by name.
//! \~russian Устанавливает скалярный аргумент по имени.
template
bool setArgValue(const PIString & arg, const T & value) {
return setArgValue(argIndex(arg), value);
}
//! \~english Sets a scalar argument from a %PIVariant value.
//! \~russian Устанавливает скалярный аргумент из значения %PIVariant.
bool setArgValue(const PIString & arg, const PIVariant & value) { return setArgValueS(argIndex(arg), value); }
//! \~english Binds a buffer argument by index.
//! \~russian Привязывает буферный аргумент по индексу.
bool bindArgValue(int index, Buffer * buffer);
//! \~english Binds a buffer 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 Initializes platform and device discovery.
//! \~russian Инициализирует поиск платформ и устройств.
static void init();
//! \~english Returns discovered OpenCL platforms.
//! \~russian Возвращает найденные платформы OpenCL.
static const PIVector & platforms();
//! \~english Returns devices from all discovered platforms.
//! \~russian Возвращает устройства со всех найденных платформ.
static const PIVector devices();
//! \~english Returns a device description for the given native device handle.
//! \~russian Возвращает описание устройства для заданного нативного дескриптора.
static Device deviceByID(void * id);
//! \~english Prepares OpenCL source code before compilation.
//! \~russian Подготавливает исходный текст OpenCL перед компиляцией.
static PIString prepareProgram(const PIString & prog);
private:
static PIString prog_header;
PIOpenCL() { ; }
class PIP_OPENCL_EXPORT Initializer {
public:
Initializer();
static Initializer * instance();
void init();
PIVector platforms_;
bool inited_;
};
};
//! \~english Writes a readable kernel argument description to %PICout.
//! \~russian Выводит читаемое описание аргумента ядра в %PICout.
PIP_OPENCL_EXPORT PICout operator<<(PICout s, const PIOpenCL::KernelArg & v);
#endif // PIOPENCL_H