Files
pip/libs/main/opencl/piopencl.h
2026-03-07 17:36:36 +03:00

617 lines
27 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 wrapper 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/>.
*/
//! \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;
//! 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"
//! \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<Device> 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<Device> 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<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 Creates a buffer bound to a deque container.
//! \~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 Creates a buffer bound to a two-dimensional vector container.
//! \~russian Создает буфер, связанный с двумерным контейнером-вектором.
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 Creates an unbound buffer with the given element count and clears it to the default value.
//! \~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)
};
//! \~\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<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)
};
//! \~\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<int>() << size); }
//! \~english Sets multi-dimensional execution ranges.
//! \~russian Устанавливает многомерные диапазоны выполнения.
void setExecuteRanges(const PIVector<int> & ranges);
//! \~english Returns the kernel function name.
//! \~russian Возвращает имя функции ядра.
const PIString & name() const { return name_; }
//! \~english Returns reflected descriptions of kernel arguments.
//! \~russian Возвращает отраженные описания аргументов ядра.
const PIVector<KernelArg> & args() const { return args_; }
//! \~english Sets a scalar argument by index.
//! \~russian Устанавливает скалярный аргумент по индексу.
template<typename T>
bool setArgValue(int index, const T & value) {
return setArgValueS(index, PIVariant::fromValue(value));
}
//! \~english Sets a scalar argument by name.
//! \~russian Устанавливает скалярный аргумент по имени.
template<typename T>
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<KernelArg> args_;
PIVector<size_t> 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<Platform> & platforms();
//! \~english Returns devices from all discovered platforms.
//! \~russian Возвращает устройства со всех найденных платформ.
static const PIVector<Device> 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<Platform> 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