/*! \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 . */ //! \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 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