diff --git a/.appveyor.yml b/.appveyor.yml index f1c9b99..44ca24b 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -10,6 +10,10 @@ configuration: #- Debug - Release +skip_commits: + files: + - '**/*.md' + before_build: - git clone --depth=1 https://github.com/KhronosGroup/OpenCL-Headers external/OpenCL-Headers - git clone --depth=1 https://github.com/KhronosGroup/OpenCL-ICD-Loader external/opencl-icd-loader diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..e60eabd --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,82 @@ +name: build + +on: + push: + paths-ignore: + - '**/*.md' + pull_request: + branches: + - main + +env: + BUILD_TYPE: RelWithDebInfo + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Check Tabs + run: | + if git grep -n $'\t' samples/*.cpp samples/*.h tutorials/*.cpp tutorials/*.h; then echo 'Please replace tabs with spaces in source files.'; false; fi + + - name: Check Whitespace + run: | + if git grep -n '[[:blank:]]$' samples/*.cpp samples/*.h tutorials/*.cpp tutorials/*.h; then echo 'Please remove trailing whitespace from source files.'; false; fi + + build: + needs: check + + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + ext: [YES, NO] + + runs-on: ${{matrix.os}} + + steps: + - uses: actions/checkout@v3 + + - name: Get Ubuntu OpenGL Dependencies + if: matrix.os == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y libglfw3-dev + + - name: Get OpenCL Headers + uses: actions/checkout@v3 + with: + repository: KhronosGroup/OpenCL-Headers + path: external/OpenCL-Headers + + - name: Get OpenCL ICD Loader + uses: actions/checkout@v3 + with: + repository: KhronosGroup/OpenCL-ICD-Loader + path: external/opencl-icd-loader + + - name: Get OpenCL Extension Loader + if: matrix.ext == 'YES' + uses: actions/checkout@v3 + with: + repository: bashbaug/opencl-extension-loader + path: external/opencl-extension-loader + + - name: Create Build Directory + run: cmake -E make_directory ${{runner.workspace}}/build + + - name: Run CMake + shell: bash + working-directory: ${{runner.workspace}}/build + run: cmake -DOpenCL_INCLUDE_DIRS=$GITHUB_WORKSPACE/external/OpenCL-Headers -DCMAKE_BUILD_TYPE=$BUILD_TYPE $GITHUB_WORKSPACE + + - name: Build + working-directory: ${{runner.workspace}}/build + shell: bash + run: cmake --build . --parallel --config $BUILD_TYPE + + #- name: Test + # working-directory: ${{runner.workspace}}/build + # shell: bash + # run: ctest -C $BUILD_TYPE diff --git a/CMakeLists.txt b/CMakeLists.txt index 8be375e..f421ce2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,21 +32,33 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON) project(SimpleOpenCLSamples VERSION 1.0) +option(SAMPLES_ENABLE_EXCEPTIONS "Enable Exceptions for OpenCL Errors") + set(OpenCL_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/OpenCL-Headers CACHE PATH "Path to OpenCL Headers") find_package(OpenCL) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) include_directories(${OpenCL_INCLUDE_DIR}) +add_subdirectory(external/OpenCL-Headers) add_subdirectory(external/opencl-icd-loader) set_target_properties(OpenCL PROPERTIES FOLDER "OpenCL-ICD-Loader") +set_target_properties(cllayerinfo PROPERTIES FOLDER "OpenCL-ICD-Loader") set(OpenCL_LIBRARIES OpenCL) +if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/external/opencl-extension-loader) + add_subdirectory(external/opencl-extension-loader) +else() + message(STATUS "OpenCL Extension Loader is not found.") +endif() + if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) enable_testing() endif() +add_subdirectory(layers) add_subdirectory(samples) +add_subdirectory(tutorials) if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/install" CACHE PATH "Install Path" FORCE) diff --git a/README.md b/README.md index 4cfd667..935110f 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,14 @@ # Simple OpenCLTM Samples +[![build](https://github.com/bashbaug/SimpleOpenCLSamples/workflows/build/badge.svg?branch=main)](https://github.com/bashbaug/SimpleOpenCLSamples/actions?query=workflow%3Abuild+branch%3Amain) + This repo contains simple OpenCL samples that demonstrate how to build OpenCL applications using only the Khronos-provided headers and libs. All samples have been tested on Windows and Linux. +Most of the samples are written in C and C++ using the OpenCL C++ bindings. +A few of the samples have been ported to Python using [PyOpenCL](https://pypi.org/project/pyopencl/). + ## Code Structure @@ -13,7 +18,9 @@ LICENSE License information CMakeLists.txt Top-level CMakefile external/ External Projects (headers and libs) include/ Include Files (OpenCL C++ bindings) -samples/ Samples +layers/ Sample Layers +samples/ Sample Applications +tutorials/ Tutorials ``` ## How to Build the Samples @@ -28,6 +35,10 @@ OpenCL ICD Loader: git clone https://github.com/KhronosGroup/opencl-icd-loader external/opencl-icd-loader +Many samples that use extensions additionally require the OpenCL Extension Loader: + + git clone https://github.com/bashbaug/opencl-extension-loader external/opencl-extension-loader + After satisfying the external dependencies create build files using CMake. For example: mkdir build && cd build @@ -48,10 +59,21 @@ implementations as well. ## Further Reading -* [Environment Setup for Ubuntu 18.04](docs/env/ubuntu/18.04.md) +* [Environment Setup for Ubuntu 22.04](docs/env/ubuntu/22.04.md) * [OpenCLPapers](https://github.com/bashbaug/OpenCLPapers) -* [OpenCL Specs](https://www.khronos.org/registry/OpenCL/specs/) -* [OpenCL Return Codes](https://streamhpc.com/blog/2013-04-28/opencl-error-codes/) +* [OpenCL Specs](https://registry.khronos.org/OpenCL/) +* [OpenCL Error Codes](https://registry.khronos.org/OpenCL/specs/3.0-unified/html/OpenCL_API.html#error_codes) + +## A Note About Error Checking + +For brevity, most samples do not include error checking. This means that a +sample may crash or incorrectly report success if an OpenCL error occurs. By +defining the CMake variable `SAMPLES_ENABLE_EXCEPTIONS` many samples can instead +throw an exception if an OpenCL error occurs. + +Tools like the [OpenCL Intercept Layer](https://github.com/intel/opencl-intercept-layer) +can also be useful to detect when an OpenCL error occurs and to identify the +cause of the error. ## License @@ -62,6 +84,11 @@ Notes: [Khronos OpenCL-CLHPP Repo](https://github.com/KhronosGroup/OpenCL-CLHPP), and is licensed under the [Khronos(tm) License](https://github.com/KhronosGroup/OpenCL-CLHPP/blob/master/LICENSE.txt). +* The samples use [popl](https://github.com/badaix/popl) for its options +parsing, which is licensed under the MIT License. +* The samples use [stb](https://github.com/nothings/stb) for image reading and + writing, which is dual-licensed under a public domain license and the MIT + license. --- OpenCL and the OpenCL logo are trademarks of Apple Inc. used by permission by Khronos. diff --git a/docs/env/ubuntu/18.04.md b/docs/env/ubuntu/18.04.md index d935ca8..c7f5190 100644 --- a/docs/env/ubuntu/18.04.md +++ b/docs/env/ubuntu/18.04.md @@ -34,7 +34,7 @@ OpenCL applications generally link against an OpenCL Installable Compute Device ### AMD -TODO +AMD supports OpenCL through their ROCm platform. Installation instructions are [here](https://rocmdocs.amd.com/en/latest/Installation_Guide/Installation-Guide.html#ubuntu). ### Intel Intel's OpenCL support is provided through the NEO compute runtime, available as a PPA. diff --git a/docs/env/ubuntu/19.04.md b/docs/env/ubuntu/19.04.md index d935ca8..5f2b835 100644 --- a/docs/env/ubuntu/19.04.md +++ b/docs/env/ubuntu/19.04.md @@ -34,7 +34,7 @@ OpenCL applications generally link against an OpenCL Installable Compute Device ### AMD -TODO +AMD provides official support for LTS releases only. ### Intel Intel's OpenCL support is provided through the NEO compute runtime, available as a PPA. diff --git a/docs/env/ubuntu/19.10.md b/docs/env/ubuntu/19.10.md index f26406d..7beb08a 100644 --- a/docs/env/ubuntu/19.10.md +++ b/docs/env/ubuntu/19.10.md @@ -34,7 +34,7 @@ OpenCL applications generally link against an OpenCL Installable Compute Device ### AMD -TODO +AMD provides official support for LTS releases only. ### Intel Intel's OpenCL support is provided through the NEO compute runtime, available as a PPA. diff --git a/docs/env/ubuntu/20.04.md b/docs/env/ubuntu/20.04.md index e025a9b..c7026fd 100644 --- a/docs/env/ubuntu/20.04.md +++ b/docs/env/ubuntu/20.04.md @@ -36,7 +36,7 @@ OpenCL applications generally link against an OpenCL Installable Compute Device ### AMD Compute Runtime -TODO +AMD supports OpenCL through their ROCm platform. Installation instructions are [here](https://rocmdocs.amd.com/en/latest/Installation_Guide/Installation-Guide.html#ubuntu). ### Intel Compute Runtime diff --git a/docs/env/ubuntu/22.04.md b/docs/env/ubuntu/22.04.md new file mode 100644 index 0000000..396c27d --- /dev/null +++ b/docs/env/ubuntu/22.04.md @@ -0,0 +1,82 @@ +# Ubuntu 22.04 Setup Instructions + +## Verify Hardware Support + +Most modern GPUs support OpenCL. For integrated graphics devices (iGPUs), use `lscpu` to get the processor SKU. Detailed information for Intel SKUs is available from [ark.intel.com](ark.intel.com). Detailed information for AMD processors is available from [AMD's product page](https://www.amd.com/en/products/specifications/processors). + +## Build Dependencies + +OCL Headers: + +```bash +sudo apt install opencl-c-headers opencl-clhpp-headers +``` + +The OpenCL API has its own set of header files; the above command installs both C and C++ headers files. The C header can be found in ``; the C++ header is in ``. + +OCL ICD Loader: + +```bash +sudo apt install ocl-icd-opencl-dev +``` + +OpenCL applications generally link against an OpenCL Installable Compute Device (ICD) loader instead of a specific OpenCL implementation; see [https://github.com/bashbaug/OpenCLPapers/blob/master/OpenCLOnLinux.asciidoc](https://github.com/bashbaug/OpenCLPapers/blob/master/OpenCLOnLinux.asciidoc) for more information about this system. + +## Runtime Dependencies + +OpenCL requires a compute runtime to manage the interaction between the OpenCL API and the GPU. + +### OCL ICD Loader + +```bash +sudo apt install ocl-icd-libopencl1 +``` + +OpenCL applications generally link against an OpenCL Installable Compute Device (ICD) loader instead of a specific OpenCL implementation; see [https://github.com/bashbaug/OpenCLPapers/blob/master/OpenCLOnLinux.asciidoc](https://github.com/bashbaug/OpenCLPapers/blob/master/OpenCLOnLinux.asciidoc) for more information about this system. + +### AMD Compute Runtime + +AMD supports OpenCL through their ROCm platform. Installation instructions are [here](https://rocmdocs.amd.com/en/latest/Installation_Guide/Installation-Guide.html#ubuntu). + +### Intel Compute Runtime + +Intel's OpenCL support is provided through the NEO compute runtime. Download packages from the project's [GitHub releases page](https://github.com/intel/compute-runtime/releases). + +### Nvidia Compute Runtime + +Nvidia provides OpenCL support through their proprietary driver, available from the [graphics-drivers PPA](https://launchpad.net/~graphics-drivers/+archive/ubuntu/ppa). + +```bash +sudo add-apt-repository ppa:graphics-drivers/ppa +sudo apt update +sudo apt install nvidia-graphics-drivers- +``` + +### Configure Permissions + +```bash +sudo usermod -a -G video $USER +sudo usermod -a -G render $USER +``` + +Users running OpenCL applications on a GPU require additional permissions granted by the groups above. + +## Verification + +The `clinfo` utility can be used to verify the environment has been properly configured. + +```bash +$ sudo apt install clinfo +$ clinfo + +``` + +## Troubleshooting + +If `clinfo` indicates there are 0 supported platforms: + +1. Verify your host has OpenCL-capable hardware attached +2. Verify clinfo is running as a user with appropriate group membership +3. Verify new group membership has been applied (this may require logout or reboot) +4. Verify the correct compute runtime is installed +5. Check the kernel log (`sudo dmesg`) for related errors diff --git a/include/CL/opencl.hpp b/include/CL/opencl.hpp index 2567073..1c43ae0 100644 --- a/include/CL/opencl.hpp +++ b/include/CL/opencl.hpp @@ -16,9 +16,8 @@ /*! \file * - * \brief C++ bindings for OpenCL 1.0 (rev 48), OpenCL 1.1 (rev 33), - * OpenCL 1.2 (rev 15), OpenCL 2.0 (rev 29), OpenCL 2.1 (rev 17), - * and OpenCL 2.2 (V2.2-11). + * \brief C++ bindings for OpenCL 1.0, OpenCL 1.1, OpenCL 1.2, + * OpenCL 2.0, OpenCL 2.1, OpenCL 2.2, and OpenCL 3.0. * \author Lee Howes and Bruce Merry * * Derived from the OpenCL 1.x C++ bindings written by @@ -61,10 +60,10 @@ * For many large applications C++ is the language of choice and so it seems * reasonable to define C++ bindings for OpenCL. * - * The interface is contained with a single C++ header file \em cl2.hpp and all + * The interface is contained with a single C++ header file \em opencl.hpp and all * definitions are contained within the namespace \em cl. There is no additional * requirement to include \em cl.h and to use either the C++ or original C - * bindings; it is enough to simply include \em cl2.hpp. + * bindings; it is enough to simply include \em opencl.hpp. * * The bindings themselves are lightweight and correspond closely to the * underlying C API. Using the C++ bindings introduces no additional execution @@ -73,7 +72,7 @@ * There are numerous compatibility, portability and memory management * fixes in the new header as well as additional OpenCL 2.0 features. * As a result the header is not directly backward compatible and for this - * reason we release it as cl2.hpp rather than a new version of cl.hpp. + * reason we release it as opencl.hpp rather than a new version of cl.hpp. * * * \section compatibility Compatibility @@ -145,26 +144,26 @@ * - CL_HPP_NO_STD_STRING * * Do not use the standard library string class. cl::string is not - * defined and may be defined by the user before cl2.hpp is + * defined and may be defined by the user before opencl.hpp is * included. * * - CL_HPP_NO_STD_VECTOR * * Do not use the standard library vector class. cl::vector is not - * defined and may be defined by the user before cl2.hpp is + * defined and may be defined by the user before opencl.hpp is * included. * * - CL_HPP_NO_STD_ARRAY * * Do not use the standard library array class. cl::array is not - * defined and may be defined by the user before cl2.hpp is + * defined and may be defined by the user before opencl.hpp is * included. * * - CL_HPP_NO_STD_UNIQUE_PTR * * Do not use the standard library unique_ptr class. cl::pointer and * the cl::allocate_pointer functions are not defined and may be - * defined by the user before cl2.hpp is included. + * defined by the user before opencl.hpp is included. * * - CL_HPP_ENABLE_DEVICE_FISSION * @@ -215,7 +214,7 @@ #define CL_HPP_ENABLE_EXCEPTIONS #define CL_HPP_TARGET_OPENCL_VERSION 200 - #include + #include #include #include #include @@ -435,8 +434,8 @@ /* Detect which version to target */ #if !defined(CL_HPP_TARGET_OPENCL_VERSION) -# pragma message("opencl.hpp: CL_HPP_TARGET_OPENCL_VERSION is not defined. It will default to 220 (OpenCL 2.2)") -# define CL_HPP_TARGET_OPENCL_VERSION 220 +# pragma message("opencl.hpp: CL_HPP_TARGET_OPENCL_VERSION is not defined. It will default to 300 (OpenCL 3.0)") +# define CL_HPP_TARGET_OPENCL_VERSION 300 #endif #if CL_HPP_TARGET_OPENCL_VERSION != 100 && \ CL_HPP_TARGET_OPENCL_VERSION != 110 && \ @@ -445,9 +444,9 @@ CL_HPP_TARGET_OPENCL_VERSION != 210 && \ CL_HPP_TARGET_OPENCL_VERSION != 220 && \ CL_HPP_TARGET_OPENCL_VERSION != 300 -# pragma message("opencl.hpp: CL_HPP_TARGET_OPENCL_VERSION is not a valid value (100, 110, 120, 200, 210, 220 or 300). It will be set to 220") +# pragma message("opencl.hpp: CL_HPP_TARGET_OPENCL_VERSION is not a valid value (100, 110, 120, 200, 210, 220 or 300). It will be set to 300 (OpenCL 3.0).") # undef CL_HPP_TARGET_OPENCL_VERSION -# define CL_HPP_TARGET_OPENCL_VERSION 220 +# define CL_HPP_TARGET_OPENCL_VERSION 300 #endif /* Forward target OpenCL version to C headers if necessary */ @@ -549,19 +548,19 @@ // Define deprecated prefixes and suffixes to ensure compilation // in case they are not pre-defined -#if !defined(CL_EXT_PREFIX__VERSION_1_1_DEPRECATED) -#define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED -#endif // #if !defined(CL_EXT_PREFIX__VERSION_1_1_DEPRECATED) -#if !defined(CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED) -#define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED -#endif // #if !defined(CL_EXT_PREFIX__VERSION_1_1_DEPRECATED) - -#if !defined(CL_EXT_PREFIX__VERSION_1_2_DEPRECATED) -#define CL_EXT_PREFIX__VERSION_1_2_DEPRECATED -#endif // #if !defined(CL_EXT_PREFIX__VERSION_1_2_DEPRECATED) -#if !defined(CL_EXT_SUFFIX__VERSION_1_2_DEPRECATED) -#define CL_EXT_SUFFIX__VERSION_1_2_DEPRECATED -#endif // #if !defined(CL_EXT_PREFIX__VERSION_1_2_DEPRECATED) +#if !defined(CL_API_PREFIX__VERSION_1_1_DEPRECATED) +#define CL_API_PREFIX__VERSION_1_1_DEPRECATED +#endif // #if !defined(CL_API_PREFIX__VERSION_1_1_DEPRECATED) +#if !defined(CL_API_SUFFIX__VERSION_1_1_DEPRECATED) +#define CL_API_SUFFIX__VERSION_1_1_DEPRECATED +#endif // #if !defined(CL_API_PREFIX__VERSION_1_1_DEPRECATED) + +#if !defined(CL_API_PREFIX__VERSION_1_2_DEPRECATED) +#define CL_API_PREFIX__VERSION_1_2_DEPRECATED +#endif // #if !defined(CL_API_PREFIX__VERSION_1_2_DEPRECATED) +#if !defined(CL_API_SUFFIX__VERSION_1_2_DEPRECATED) +#define CL_API_SUFFIX__VERSION_1_2_DEPRECATED +#endif // #if !defined(CL_API_PREFIX__VERSION_1_2_DEPRECATED) #if !defined(CL_CALLBACK) #define CL_CALLBACK @@ -970,6 +969,11 @@ static inline cl_int errHandler (cl_int err, const char * errStr = NULL) #define __CLONE_KERNEL_ERR CL_HPP_ERR_STR_(clCloneKernel) #endif // CL_HPP_TARGET_OPENCL_VERSION >= 210 +#if defined(cl_khr_command_buffer) +#define __GET_COMMAND_BUFFER_INFO_KHR_ERR CL_HPP_ERR_STR_(clGetCommandBufferInfoKHR) +#define __FINALIZE_COMMAND_BUFFER_KHR_ERR CL_HPP_ERR_STR_(clFinalizeCommandBufferKHR) +#endif // cl_khr_command_buffer + #endif // CL_HPP_USER_OVERRIDE_ERROR_STRINGS //! \endcond @@ -1318,13 +1322,20 @@ inline cl_int getInfoHelper(Func f, cl_uint name, T* param, int, typename T::cl_ F(cl_kernel_arg_info, CL_KERNEL_ARG_NAME, string) \ F(cl_kernel_arg_info, CL_KERNEL_ARG_TYPE_QUALIFIER, cl_kernel_arg_type_qualifier) \ \ + F(cl_kernel_work_group_info, CL_KERNEL_GLOBAL_WORK_SIZE, cl::detail::size_t_array) \ + \ + F(cl_device_info, CL_DEVICE_LINKER_AVAILABLE, cl_bool) \ + F(cl_device_info, CL_DEVICE_IMAGE_MAX_BUFFER_SIZE, size_type) \ + F(cl_device_info, CL_DEVICE_IMAGE_MAX_ARRAY_SIZE, size_type) \ F(cl_device_info, CL_DEVICE_PARENT_DEVICE, cl::Device) \ + F(cl_device_info, CL_DEVICE_PARTITION_MAX_SUB_DEVICES, cl_uint) \ F(cl_device_info, CL_DEVICE_PARTITION_PROPERTIES, cl::vector) \ F(cl_device_info, CL_DEVICE_PARTITION_TYPE, cl::vector) \ F(cl_device_info, CL_DEVICE_REFERENCE_COUNT, cl_uint) \ - F(cl_device_info, CL_DEVICE_PREFERRED_INTEROP_USER_SYNC, size_type) \ + F(cl_device_info, CL_DEVICE_PREFERRED_INTEROP_USER_SYNC, cl_bool) \ F(cl_device_info, CL_DEVICE_PARTITION_AFFINITY_DOMAIN, cl_device_affinity_domain) \ F(cl_device_info, CL_DEVICE_BUILT_IN_KERNELS, string) \ + F(cl_device_info, CL_DEVICE_PRINTF_BUFFER_SIZE, size_type) \ \ F(cl_image_info, CL_IMAGE_ARRAY_SIZE, size_type) \ F(cl_image_info, CL_IMAGE_NUM_MIP_LEVELS, cl_uint) \ @@ -1344,7 +1355,14 @@ inline cl_int getInfoHelper(Func f, cl_uint name, T* param, int, typename T::cl_ F(cl_device_info, CL_DEVICE_PREFERRED_PLATFORM_ATOMIC_ALIGNMENT, cl_uint) \ F(cl_device_info, CL_DEVICE_PREFERRED_GLOBAL_ATOMIC_ALIGNMENT, cl_uint) \ F(cl_device_info, CL_DEVICE_PREFERRED_LOCAL_ATOMIC_ALIGNMENT, cl_uint) \ + F(cl_device_info, CL_DEVICE_IMAGE_PITCH_ALIGNMENT, cl_uint) \ + F(cl_device_info, CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_READ_WRITE_IMAGE_ARGS, cl_uint ) \ + F(cl_device_info, CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE, size_type ) \ + F(cl_device_info, CL_DEVICE_GLOBAL_VARIABLE_PREFERRED_TOTAL_SIZE, size_type ) \ F(cl_profiling_info, CL_PROFILING_COMMAND_COMPLETE, cl_ulong) \ + F(cl_kernel_exec_info, CL_KERNEL_EXEC_INFO_SVM_FINE_GRAIN_SYSTEM, cl_bool) \ + F(cl_kernel_exec_info, CL_KERNEL_EXEC_INFO_SVM_PTRS, void**) \ F(cl_command_queue_info, CL_QUEUE_SIZE, cl_uint) \ F(cl_mem_info, CL_MEM_USES_SVM_POINTER, cl_bool) \ F(cl_program_build_info, CL_PROGRAM_BUILD_GLOBAL_VARIABLE_TOTAL_SIZE, size_type) \ @@ -1360,17 +1378,17 @@ inline cl_int getInfoHelper(Func f, cl_uint name, T* param, int, typename T::cl_ F(cl_program_info, CL_PROGRAM_IL_KHR, cl::vector) #define CL_HPP_PARAM_NAME_INFO_2_1_(F) \ - F(cl_platform_info, CL_PLATFORM_HOST_TIMER_RESOLUTION, size_type) \ + F(cl_platform_info, CL_PLATFORM_HOST_TIMER_RESOLUTION, cl_ulong) \ F(cl_program_info, CL_PROGRAM_IL, cl::vector) \ - F(cl_kernel_info, CL_KERNEL_MAX_NUM_SUB_GROUPS, size_type) \ - F(cl_kernel_info, CL_KERNEL_COMPILE_NUM_SUB_GROUPS, size_type) \ F(cl_device_info, CL_DEVICE_MAX_NUM_SUB_GROUPS, cl_uint) \ F(cl_device_info, CL_DEVICE_IL_VERSION, string) \ F(cl_device_info, CL_DEVICE_SUB_GROUP_INDEPENDENT_FORWARD_PROGRESS, cl_bool) \ F(cl_command_queue_info, CL_QUEUE_DEVICE_DEFAULT, cl::DeviceCommandQueue) \ F(cl_kernel_sub_group_info, CL_KERNEL_MAX_SUB_GROUP_SIZE_FOR_NDRANGE, size_type) \ F(cl_kernel_sub_group_info, CL_KERNEL_SUB_GROUP_COUNT_FOR_NDRANGE, size_type) \ - F(cl_kernel_sub_group_info, CL_KERNEL_LOCAL_SIZE_FOR_SUB_GROUP_COUNT, cl::detail::size_t_array) + F(cl_kernel_sub_group_info, CL_KERNEL_LOCAL_SIZE_FOR_SUB_GROUP_COUNT, cl::detail::size_t_array) \ + F(cl_kernel_sub_group_info, CL_KERNEL_MAX_NUM_SUB_GROUPS, size_type) \ + F(cl_kernel_sub_group_info, CL_KERNEL_COMPILE_NUM_SUB_GROUPS, size_type) #define CL_HPP_PARAM_NAME_INFO_2_2_(F) \ F(cl_program_info, CL_PROGRAM_SCOPE_GLOBAL_CTORS_PRESENT, cl_bool) \ @@ -1383,7 +1401,7 @@ inline cl_int getInfoHelper(Func f, cl_uint name, T* param, int, typename T::cl_ F(cl_device_info, CL_DEVICE_REFERENCE_COUNT_EXT , cl_uint) \ F(cl_device_info, CL_DEVICE_PARTITION_STYLE_EXT, cl::vector) -#define CL_HPP_PARAM_NAME_CL_KHR_EXTENDED_VERSIONING_SHARED_(F) \ +#define CL_HPP_PARAM_NAME_CL_KHR_EXTENDED_VERSIONING_CL3_SHARED_(F) \ F(cl_platform_info, CL_PLATFORM_NUMERIC_VERSION_KHR, cl_version_khr) \ F(cl_platform_info, CL_PLATFORM_EXTENSIONS_WITH_VERSION_KHR, cl::vector) \ \ @@ -1392,7 +1410,7 @@ inline cl_int getInfoHelper(Func f, cl_uint name, T* param, int, typename T::cl_ F(cl_device_info, CL_DEVICE_ILS_WITH_VERSION_KHR, cl::vector) \ F(cl_device_info, CL_DEVICE_BUILT_IN_KERNELS_WITH_VERSION_KHR, cl::vector) -#define CL_HPP_PARAM_NAME_CL_KHR_EXTENDED_VERSIONING_UNIQUE_(F) \ +#define CL_HPP_PARAM_NAME_CL_KHR_EXTENDED_VERSIONING_KHRONLY_(F) \ F(cl_device_info, CL_DEVICE_OPENCL_C_NUMERIC_VERSION_KHR, cl_version_khr) #define CL_HPP_PARAM_NAME_INFO_3_0_(F) \ @@ -1411,15 +1429,20 @@ inline cl_int getInfoHelper(Func f, cl_uint name, T* param, int, typename T::cl_ F(cl_device_info, CL_DEVICE_WORK_GROUP_COLLECTIVE_FUNCTIONS_SUPPORT, cl_bool) \ F(cl_device_info, CL_DEVICE_GENERIC_ADDRESS_SPACE_SUPPORT, cl_bool) \ F(cl_device_info, CL_DEVICE_OPENCL_C_FEATURES, cl::vector) \ + F(cl_device_info, CL_DEVICE_DEVICE_ENQUEUE_CAPABILITIES, cl_device_device_enqueue_capabilities) \ F(cl_device_info, CL_DEVICE_PIPE_SUPPORT, cl_bool) \ + F(cl_device_info, CL_DEVICE_LATEST_CONFORMANCE_VERSION_PASSED, string) \ \ F(cl_command_queue_info, CL_QUEUE_PROPERTIES_ARRAY, cl::vector) \ F(cl_mem_info, CL_MEM_PROPERTIES, cl::vector) \ F(cl_pipe_info, CL_PIPE_PROPERTIES, cl::vector) \ F(cl_sampler_info, CL_SAMPLER_PROPERTIES, cl::vector) -// TODO: Add this to CL_HPP_PARAM_NAME_INFO_3_0_ once CL_DEVICE_DEVICE_ENQUEUE_CAPABILITIES is in the headers! -// F(cl_device_info, CL_DEVICE_DEVICE_ENQUEUE_CAPABILITIES, cl_device_device_enqueue_capabilities) \ +#define CL_HPP_PARAM_NAME_CL_INTEL_COMMAND_QUEUE_FAMILIES_(F) \ + F(cl_device_info, CL_DEVICE_QUEUE_FAMILY_PROPERTIES_INTEL, cl::vector) \ + \ + F(cl_command_queue_info, CL_QUEUE_FAMILY_INTEL, cl_uint) \ + F(cl_command_queue_info, CL_QUEUE_INDEX_INTEL, cl_uint) template @@ -1452,17 +1475,8 @@ CL_HPP_PARAM_NAME_INFO_2_2_(CL_HPP_DECLARE_PARAM_TRAITS_) #endif // CL_HPP_TARGET_OPENCL_VERSION >= 220 #if CL_HPP_TARGET_OPENCL_VERSION >= 300 CL_HPP_PARAM_NAME_INFO_3_0_(CL_HPP_DECLARE_PARAM_TRAITS_) -// TODO: Remove this when the headers are updated! -#if defined(CL_DEVICE_DEVICE_ENQUEUE_SUPPORT) -CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_DEVICE_ENQUEUE_SUPPORT, cl_bool) -#endif // CL_DEVICE_DEVICE_ENQUEUE_SUPPORT -// TODO: Move this into CL_HPP_PARAM_NAME_INFO_3_0_ when the headers are updated! -#if defined(CL_DEVICE_DEVICE_ENQUEUE_CAPABILITIES) -CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_DEVICE_ENQUEUE_CAPABILITIES, cl_device_device_enqueue_capabilities) -#endif // CL_DEVICE_DEVICE_ENQUEUE_CAPABILITIES #endif // CL_HPP_TARGET_OPENCL_VERSION >= 300 - #if defined(CL_HPP_USE_CL_SUB_GROUPS_KHR) && CL_HPP_TARGET_OPENCL_VERSION < 210 CL_HPP_PARAM_NAME_INFO_SUBGROUP_KHR_(CL_HPP_DECLARE_PARAM_TRAITS_) #endif // #if defined(CL_HPP_USE_CL_SUB_GROUPS_KHR) && CL_HPP_TARGET_OPENCL_VERSION < 210 @@ -1500,11 +1514,56 @@ CL_HPP_PARAM_NAME_DEVICE_FISSION_(CL_HPP_DECLARE_PARAM_TRAITS_); #if defined(cl_khr_extended_versioning) #if CL_HPP_TARGET_OPENCL_VERSION < 300 -CL_HPP_PARAM_NAME_CL_KHR_EXTENDED_VERSIONING_SHARED_(CL_HPP_DECLARE_PARAM_TRAITS_); +CL_HPP_PARAM_NAME_CL_KHR_EXTENDED_VERSIONING_CL3_SHARED_(CL_HPP_DECLARE_PARAM_TRAITS_) #endif // CL_HPP_TARGET_OPENCL_VERSION < 300 -CL_HPP_PARAM_NAME_CL_KHR_EXTENDED_VERSIONING_UNIQUE_(CL_HPP_DECLARE_PARAM_TRAITS_); +CL_HPP_PARAM_NAME_CL_KHR_EXTENDED_VERSIONING_KHRONLY_(CL_HPP_DECLARE_PARAM_TRAITS_) #endif // cl_khr_extended_versioning +#if defined(cl_khr_device_uuid) +using uuid_array = array; +using luid_array = array; +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_UUID_KHR, uuid_array) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DRIVER_UUID_KHR, uuid_array) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_LUID_VALID_KHR, cl_bool) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_LUID_KHR, luid_array) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_NODE_MASK_KHR, cl_uint) +#endif + +#if defined(cl_khr_pci_bus_info) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_PCI_BUS_INFO_KHR, cl_device_pci_bus_info_khr) +#endif + +#if defined(cl_khr_integer_dot_product) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_INTEGER_DOT_PRODUCT_CAPABILITIES_KHR, cl_device_integer_dot_product_capabilities_khr) +#endif + +#if defined(cl_khr_command_buffer) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_COMMAND_BUFFER_CAPABILITIES_KHR, cl_device_command_buffer_capabilities_khr) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_COMMAND_BUFFER_REQUIRED_QUEUE_PROPERTIES_KHR, cl_command_queue_properties) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_command_buffer_info_khr, CL_COMMAND_BUFFER_QUEUES_KHR, cl::vector) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_command_buffer_info_khr, CL_COMMAND_BUFFER_NUM_QUEUES_KHR, cl_uint) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_command_buffer_info_khr, CL_COMMAND_BUFFER_REFERENCE_COUNT_KHR, cl_uint) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_command_buffer_info_khr, CL_COMMAND_BUFFER_STATE_KHR, cl_command_buffer_state_khr) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_command_buffer_info_khr, CL_COMMAND_BUFFER_PROPERTIES_ARRAY_KHR, cl::vector) +#endif // cl_khr_command_buffer + +#if defined(cl_khr_external_memory) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_platform_info, CL_PLATFORM_EXTERNAL_MEMORY_IMPORT_HANDLE_TYPES_KHR, cl::vector) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_EXTERNAL_MEMORY_IMPORT_HANDLE_TYPES_KHR, cl::vector) +#endif // cl_khr_external_memory + +#if defined(cl_khr_semaphore) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_platform_info, CL_PLATFORM_SEMAPHORE_TYPES_KHR, cl::vector) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_SEMAPHORE_TYPES_KHR, cl::vector) +#endif // cl_khr_external_memory + +#if defined(cl_khr_external_semaphore) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_platform_info, CL_PLATFORM_SEMAPHORE_IMPORT_HANDLE_TYPES_KHR, cl::vector) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_platform_info, CL_PLATFORM_SEMAPHORE_EXPORT_HANDLE_TYPES_KHR, cl::vector) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_SEMAPHORE_IMPORT_HANDLE_TYPES_KHR, cl::vector) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_SEMAPHORE_EXPORT_HANDLE_TYPES_KHR, cl::vector) +#endif // cl_khr_external_semaphore + #ifdef CL_PLATFORM_ICD_SUFFIX_KHR CL_HPP_DECLARE_PARAM_TRAITS_(cl_platform_info, CL_PLATFORM_ICD_SUFFIX_KHR, string) #endif @@ -1512,7 +1571,6 @@ CL_HPP_DECLARE_PARAM_TRAITS_(cl_platform_info, CL_PLATFORM_ICD_SUFFIX_KHR, strin #ifdef CL_DEVICE_PROFILING_TIMER_OFFSET_AMD CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_PROFILING_TIMER_OFFSET_AMD, cl_ulong) #endif - #ifdef CL_DEVICE_GLOBAL_FREE_MEMORY_AMD CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_GLOBAL_FREE_MEMORY_AMD, vector) #endif @@ -1550,6 +1608,15 @@ CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_COMPUTE_UNITS_BITFIELD_AR #ifdef CL_DEVICE_JOB_SLOTS_ARM CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_JOB_SLOTS_ARM, cl_uint) #endif +#ifdef CL_DEVICE_SCHEDULING_CONTROLS_CAPABILITIES_ARM +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_SCHEDULING_CONTROLS_CAPABILITIES_ARM, cl_bitfield) +#endif +#ifdef CL_KERNEL_EXEC_INFO_WORKGROUP_BATCH_SIZE_ARM +CL_HPP_DECLARE_PARAM_TRAITS_(cl_kernel_exec_info, CL_KERNEL_EXEC_INFO_WORKGROUP_BATCH_SIZE_ARM, cl_uint) +#endif +#ifdef CL_KERNEL_EXEC_INFO_WORKGROUP_BATCH_SIZE_MODIFIER_ARM +CL_HPP_DECLARE_PARAM_TRAITS_(cl_kernel_exec_info, CL_KERNEL_EXEC_INFO_WORKGROUP_BATCH_SIZE_MODIFIER_ARM, cl_int) +#endif #ifdef CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, cl_uint) @@ -1573,6 +1640,20 @@ CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV, c CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_INTEGRATED_MEMORY_NV, cl_bool) #endif +#if defined(cl_intel_command_queue_families) +CL_HPP_PARAM_NAME_CL_INTEL_COMMAND_QUEUE_FAMILIES_(CL_HPP_DECLARE_PARAM_TRAITS_) +#endif // cl_intel_command_queue_families + +#if defined(cl_intel_device_attribute_query) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_IP_VERSION_INTEL, cl_uint) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_ID_INTEL, cl_uint) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_NUM_SLICES_INTEL, cl_uint) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_NUM_SUB_SLICES_PER_SLICE_INTEL, cl_uint) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_NUM_EUS_PER_SUB_SLICE_INTEL, cl_uint) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_NUM_THREADS_PER_EU_INTEL, cl_uint) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_FEATURE_CAPABILITIES_INTEL, cl_device_feature_capabilities_intel) +#endif // cl_intel_device_attribute_query + // Convenience functions template @@ -1741,6 +1822,16 @@ struct ReferenceHandler { return ::clReleaseEvent(event); } }; +#if defined(cl_khr_command_buffer) +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_command_buffer_khr cmdbuf) + { return ::clRetainCommandBufferKHR(cmdbuf); } + static cl_int release(cl_command_buffer_khr cmdbuf) + { return ::clReleaseCommandBufferKHR(cmdbuf); } +}; +#endif // cl_khr_command_buffer #if CL_HPP_TARGET_OPENCL_VERSION >= 120 && CL_HPP_MINIMUM_OPENCL_VERSION < 120 // Extracts version number with major in the upper 16 bits, minor in the lower 16 @@ -1904,8 +1995,9 @@ class Wrapper #if CL_HPP_TARGET_OPENCL_VERSION >= 120 #if CL_HPP_MINIMUM_OPENCL_VERSION < 120 if (device != NULL) { - int version = getDevicePlatformVersion(device); - if(version > ((1 << 16) + 1)) { + cl_platform_id platform = getDevicePlatform(device); + cl_uint version = getPlatformVersion(platform); + if (version >= 0x10002) { retVal = true; } } @@ -2097,6 +2189,9 @@ struct ImageFormat : public cl_image_format image_channel_data_type = type; } + //! \brief Copy constructor. + ImageFormat(const ImageFormat &other) { *this = other; } + //! \brief Assignment operator. ImageFormat& operator = (const ImageFormat& rhs) { @@ -2350,7 +2445,7 @@ class Device : public detail::Wrapper const cl_device_partition_property_ext * /* properties */, cl_uint /*num_entries*/, cl_device_id * /*out_devices*/, - cl_uint * /*num_devices*/ ) CL_EXT_SUFFIX__VERSION_1_1; + cl_uint * /*num_devices*/ ) CL_API_SUFFIX__VERSION_1_1; static PFN_clCreateSubDevicesEXT pfn_clCreateSubDevicesEXT = NULL; CL_HPP_INIT_CL_EXT_FCN_PTR_(clCreateSubDevicesEXT); @@ -2760,8 +2855,8 @@ CL_HPP_DEFINE_STATIC_MEMBER_ cl_int Platform::default_error_ = CL_SUCCESS; * Unload the OpenCL compiler. * \note Deprecated for OpenCL 1.2. Use Platform::unloadCompiler instead. */ -inline CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_int -UnloadCompiler() CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; +inline CL_API_PREFIX__VERSION_1_1_DEPRECATED cl_int +UnloadCompiler() CL_API_SUFFIX__VERSION_1_1_DEPRECATED; inline cl_int UnloadCompiler() { @@ -2851,7 +2946,7 @@ class Context */ Context( const vector& devices, - cl_context_properties* properties = NULL, + const cl_context_properties* properties = NULL, void (CL_CALLBACK * notifyFptr)( const char *, const void *, @@ -2880,9 +2975,13 @@ class Context } } + /*! \brief Constructs a context including a specific device. + * + * Wraps clCreateContext(). + */ Context( const Device& device, - cl_context_properties* properties = NULL, + const cl_context_properties* properties = NULL, void (CL_CALLBACK * notifyFptr)( const char *, const void *, @@ -2912,7 +3011,7 @@ class Context */ Context( cl_device_type type, - cl_context_properties* properties = NULL, + const cl_context_properties* properties = NULL, void (CL_CALLBACK * notifyFptr)( const char *, const void *, @@ -3278,7 +3377,7 @@ class Event : public detail::Wrapper */ cl_int setCallback( cl_int type, - void (CL_CALLBACK * pfn_notify)(cl_event, cl_int, void *), + void (CL_CALLBACK * pfn_notify)(cl_event, cl_int, void *), void * user_data = NULL) { return detail::errHandler( @@ -3467,7 +3566,7 @@ class Memory : public detail::Wrapper * value - not the Memory class instance. */ cl_int setDestructorCallback( - void (CL_CALLBACK * pfn_notify)(cl_mem, void *), + void (CL_CALLBACK * pfn_notify)(cl_mem, void *), void * user_data = NULL) { return detail::errHandler( @@ -4058,7 +4157,7 @@ class Buffer : public Memory } return result; - } + } #endif // CL_HPP_TARGET_OPENCL_VERSION >= 110 }; @@ -4474,12 +4573,11 @@ class Image1D : public Image cl_int* err = NULL) { cl_int error; - cl_image_desc desc = - { - CL_MEM_OBJECT_IMAGE1D, - width, - 0, 0, 0, 0, 0, 0, 0, 0 - }; + + cl_image_desc desc = {0}; + desc.image_type = CL_MEM_OBJECT_IMAGE1D; + desc.image_width = width; + object_ = ::clCreateImage( context(), flags, @@ -4562,13 +4660,12 @@ class Image1DBuffer : public Image cl_int* err = NULL) { cl_int error; - cl_image_desc desc = - { - CL_MEM_OBJECT_IMAGE1D_BUFFER, - width, - 0, 0, 0, 0, 0, 0, 0, - buffer() - }; + + cl_image_desc desc = {0}; + desc.image_type = CL_MEM_OBJECT_IMAGE1D_BUFFER; + desc.image_width = width; + desc.buffer = buffer(); + object_ = ::clCreateImage( context(), flags, @@ -4648,15 +4745,13 @@ class Image1DArray : public Image cl_int* err = NULL) { cl_int error; - cl_image_desc desc = - { - CL_MEM_OBJECT_IMAGE1D_ARRAY, - width, - 0, 0, // height, depth (unused) - arraySize, - rowPitch, - 0, 0, 0, 0 - }; + + cl_image_desc desc = {0}; + desc.image_type = CL_MEM_OBJECT_IMAGE1D_ARRAY; + desc.image_width = width; + desc.image_array_size = arraySize; + desc.image_row_pitch = rowPitch; + object_ = ::clCreateImage( context(), flags, @@ -4751,7 +4846,8 @@ class Image2D : public Image #if CL_HPP_TARGET_OPENCL_VERSION >= 120 && CL_HPP_MINIMUM_OPENCL_VERSION < 120 // Run-time decision based on the actual platform { - cl_uint version = detail::getContextPlatformVersion(context()); + cl_platform_id platform = detail::getContextPlatform(context()); + cl_uint version = detail::getPlatformVersion(platform); useCreateImage = (version >= 0x10002); // OpenCL 1.2 or above } #elif CL_HPP_TARGET_OPENCL_VERSION >= 120 @@ -4763,15 +4859,12 @@ class Image2D : public Image #if CL_HPP_TARGET_OPENCL_VERSION >= 120 if (useCreateImage) { - cl_image_desc desc = - { - CL_MEM_OBJECT_IMAGE2D, - width, - height, - 0, 0, // depth, array size (unused) - row_pitch, - 0, 0, 0, 0 - }; + cl_image_desc desc = {0}; + desc.image_type = CL_MEM_OBJECT_IMAGE2D; + desc.image_width = width; + desc.image_height = height; + desc.image_row_pitch = row_pitch; + object_ = ::clCreateImage( context(), flags, @@ -4817,17 +4910,13 @@ class Image2D : public Image { cl_int error; - cl_image_desc desc = - { - CL_MEM_OBJECT_IMAGE2D, - width, - height, - 0, 0, // depth, array size (unused) - row_pitch, - 0, 0, 0, - // Use buffer as input to image - sourceBuffer() - }; + cl_image_desc desc = {0}; + desc.image_type = CL_MEM_OBJECT_IMAGE2D; + desc.image_width = width; + desc.image_height = height; + desc.image_row_pitch = row_pitch; + desc.buffer = sourceBuffer(); + object_ = ::clCreateImage( context(), 0, // flags inherited from buffer @@ -4881,19 +4970,16 @@ class Image2D : public Image // Update only the channel order. // Channel format inherited from source. sourceFormat.image_channel_order = order; - cl_image_desc desc = - { - CL_MEM_OBJECT_IMAGE2D, - sourceWidth, - sourceHeight, - 0, 0, // depth (unused), array size (unused) - sourceRowPitch, - 0, // slice pitch (unused) - sourceNumMIPLevels, - sourceNumSamples, - // Use buffer as input to image - sourceImage() - }; + + cl_image_desc desc = {0}; + desc.image_type = CL_MEM_OBJECT_IMAGE2D; + desc.image_width = sourceWidth; + desc.image_height = sourceHeight; + desc.image_row_pitch = sourceRowPitch; + desc.num_mip_levels = sourceNumMIPLevels; + desc.num_samples = sourceNumSamples; + desc.buffer = sourceImage(); + object_ = ::clCreateImage( context(), 0, // flags should be inherited from mem_object @@ -4973,7 +5059,7 @@ class Image2D : public Image * \see Memory * \note Deprecated for OpenCL 1.2. Please use ImageGL instead. */ -class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED Image2DGL : public Image2D +class CL_API_PREFIX__VERSION_1_1_DEPRECATED Image2DGL : public Image2D { public: /*! \brief Constructs an Image2DGL in a specified context, from a given @@ -5056,7 +5142,7 @@ class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED Image2DGL : public Image2D return *this; } -} CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; +} CL_API_SUFFIX__VERSION_1_1_DEPRECATED; #endif // CL_USE_DEPRECATED_OPENCL_1_1_APIS #if CL_HPP_TARGET_OPENCL_VERSION >= 120 @@ -5079,17 +5165,15 @@ class Image2DArray : public Image cl_int* err = NULL) { cl_int error; - cl_image_desc desc = - { - CL_MEM_OBJECT_IMAGE2D_ARRAY, - width, - height, - 0, // depth (unused) - arraySize, - rowPitch, - slicePitch, - 0, 0, 0 - }; + + cl_image_desc desc = {0}; + desc.image_type = CL_MEM_OBJECT_IMAGE2D_ARRAY; + desc.image_width = width; + desc.image_height = height; + desc.image_array_size = arraySize; + desc.image_row_pitch = rowPitch; + desc.image_slice_pitch = slicePitch; + object_ = ::clCreateImage( context(), flags, @@ -5182,7 +5266,8 @@ class Image3D : public Image #if CL_HPP_TARGET_OPENCL_VERSION >= 120 && CL_HPP_MINIMUM_OPENCL_VERSION < 120 // Run-time decision based on the actual platform { - cl_uint version = detail::getContextPlatformVersion(context()); + cl_platform_id platform = detail::getContextPlatform(context()); + cl_uint version = detail::getPlatformVersion(platform); useCreateImage = (version >= 0x10002); // OpenCL 1.2 or above } #elif CL_HPP_TARGET_OPENCL_VERSION >= 120 @@ -5194,17 +5279,14 @@ class Image3D : public Image #if CL_HPP_TARGET_OPENCL_VERSION >= 120 if (useCreateImage) { - cl_image_desc desc = - { - CL_MEM_OBJECT_IMAGE3D, - width, - height, - depth, - 0, // array size (unused) - row_pitch, - slice_pitch, - 0, 0, 0 - }; + cl_image_desc desc = {0}; + desc.image_type = CL_MEM_OBJECT_IMAGE3D; + desc.image_width = width; + desc.image_height = height; + desc.image_depth = depth; + desc.image_row_pitch = row_pitch; + desc.image_slice_pitch = slice_pitch; + object_ = ::clCreateImage( context(), flags, @@ -6186,6 +6268,23 @@ class Kernel : public detail::Wrapper sizeof(void*)*(1 + sizeof...(Ts)), pointerList.data())); } + + template + cl_int setExecInfo(cl_kernel_exec_info param_name, const T& val) + { + return detail::errHandler( + ::clSetKernelExecInfo( + object_, + param_name, + sizeof(T), + &val)); + } + + template + cl_int setExecInfo(typename detail::param_traits::param_type& val) + { + return setExecInfo(name, val); + } #endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 200 #if CL_HPP_TARGET_OPENCL_VERSION >= 210 @@ -6665,6 +6764,7 @@ class Program : public detail::Wrapper void* data = NULL) const { cl_device_id deviceID = device(); + cl_int buildError = ::clBuildProgram( object_, 1, @@ -6691,7 +6791,6 @@ class Program : public detail::Wrapper notifyFptr, data); - return detail::buildErrHandler(buildError, __BUILD_PROGRAM_ERR, getBuildInfo()); } @@ -6845,9 +6944,9 @@ class Program : public detail::Wrapper * on a callback stack associated with program. The registered user callback * functions are called in the reverse order in which they were registered. */ - CL_EXT_PREFIX__VERSION_2_2_DEPRECATED cl_int setReleaseCallback( + CL_API_PREFIX__VERSION_2_2_DEPRECATED cl_int setReleaseCallback( void (CL_CALLBACK * pfn_notify)(cl_program program, void * user_data), - void * user_data = NULL) CL_EXT_SUFFIX__VERSION_2_2_DEPRECATED + void * user_data = NULL) CL_API_SUFFIX__VERSION_2_2_DEPRECATED { return detail::errHandler( ::clSetProgramReleaseCallback( @@ -7040,6 +7139,93 @@ inline Kernel::Kernel(const Program& program, const char* name, cl_int* err) } +#if defined(cl_khr_command_buffer) + +/*! \class CommandBuffer + * \brief CommandBuffer interface for cl_command_buffer_khr. + */ +class CommandBuffer : public detail::Wrapper +{ +public: + CommandBuffer() {} + + /*! \brief Constructor from cl_command_queue - takes ownership. + * + * \param retainObject will cause the constructor to retain its cl object. + * Defaults to false to maintain compatibility with + * earlier versions. + */ + explicit CommandBuffer(cl_command_buffer_khr cmdbuf, bool retainObject = false) : + detail::Wrapper(cmdbuf, retainObject) { } + + // TODO: other overloads! + + CommandBuffer& operator = (const cl_command_buffer_khr& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + CommandBuffer(const CommandBuffer& cmdbuf) : detail::Wrapper(cmdbuf) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + CommandBuffer& operator = (const CommandBuffer& cmdbuf) + { + detail::Wrapper::operator=(cmdbuf); + return *this; + } + + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + CommandBuffer(CommandBuffer&& cmdbuf) CL_HPP_NOEXCEPT_ : detail::Wrapper(std::move(cmdbuf)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + CommandBuffer& operator = (CommandBuffer &&cmdbuf) + { + detail::Wrapper::operator=(std::move(cmdbuf)); + return *this; + } + + template + cl_int getInfo(cl_command_buffer_info_khr name, T* param) const + { + return detail::errHandler( + detail::getInfo( + &::clGetCommandBufferInfoKHR, object_, name, param), + __GET_COMMAND_BUFFER_INFO_KHR_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_command_buffer_info_khr, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + cl_int finalize(void) + { + return detail::errHandler( + ::clFinalizeCommandBufferKHR(object_), + __FINALIZE_COMMAND_BUFFER_KHR_ERR); + } +}; // CommandBuffer + +#endif // cl_khr_command_buffer + enum class QueueProperties : cl_command_queue_properties { None = 0, @@ -7142,7 +7328,8 @@ class CommandQueue : public detail::Wrapper #if CL_HPP_TARGET_OPENCL_VERSION >= 200 && CL_HPP_MINIMUM_OPENCL_VERSION < 200 // Run-time decision based on the actual platform { - cl_uint version = detail::getContextPlatformVersion(context()); + cl_platform_id platform = detail::getDevicePlatform(device()); + cl_uint version = detail::getPlatformVersion(platform); useWithProperties = (version >= 0x20000); // OpenCL 2.0 or above } #elif CL_HPP_TARGET_OPENCL_VERSION >= 200 @@ -7208,7 +7395,8 @@ class CommandQueue : public detail::Wrapper #if CL_HPP_TARGET_OPENCL_VERSION >= 200 && CL_HPP_MINIMUM_OPENCL_VERSION < 200 // Run-time decision based on the actual platform { - cl_uint version = detail::getContextPlatformVersion(context()); + cl_platform_id platform = detail::getDevicePlatform(device()); + cl_uint version = detail::getPlatformVersion(platform); useWithProperties = (version >= 0x20000); // OpenCL 2.0 or above } #elif CL_HPP_TARGET_OPENCL_VERSION >= 200 @@ -7273,7 +7461,8 @@ class CommandQueue : public detail::Wrapper #if CL_HPP_TARGET_OPENCL_VERSION >= 200 && CL_HPP_MINIMUM_OPENCL_VERSION < 200 // Run-time decision based on the actual platform { - cl_uint version = detail::getContextPlatformVersion(context()); + cl_platform_id platform = detail::getDevicePlatform(devices[0]()); + cl_uint version = detail::getPlatformVersion(platform); useWithProperties = (version >= 0x20000); // OpenCL 2.0 or above } #elif CL_HPP_TARGET_OPENCL_VERSION >= 200 @@ -7340,7 +7529,8 @@ class CommandQueue : public detail::Wrapper #if CL_HPP_TARGET_OPENCL_VERSION >= 200 && CL_HPP_MINIMUM_OPENCL_VERSION < 200 // Run-time decision based on the actual platform { - cl_uint version = detail::getContextPlatformVersion(context()); + cl_platform_id platform = detail::getDevicePlatform(devices[0]()); + cl_uint version = detail::getPlatformVersion(platform); useWithProperties = (version >= 0x20000); // OpenCL 2.0 or above } #elif CL_HPP_TARGET_OPENCL_VERSION >= 200 @@ -7391,7 +7581,8 @@ class CommandQueue : public detail::Wrapper #if CL_HPP_TARGET_OPENCL_VERSION >= 200 && CL_HPP_MINIMUM_OPENCL_VERSION < 200 // Run-time decision based on the actual platform { - cl_uint version = detail::getContextPlatformVersion(context()); + cl_platform_id platform = detail::getDevicePlatform(device()); + cl_uint version = detail::getPlatformVersion(platform); useWithProperties = (version >= 0x20000); // OpenCL 2.0 or above } #elif CL_HPP_TARGET_OPENCL_VERSION >= 200 @@ -7442,7 +7633,8 @@ class CommandQueue : public detail::Wrapper #if CL_HPP_TARGET_OPENCL_VERSION >= 200 && CL_HPP_MINIMUM_OPENCL_VERSION < 200 // Run-time decision based on the actual platform { - cl_uint version = detail::getContextPlatformVersion(context()); + cl_platform_id platform = detail::getDevicePlatform(device()); + cl_uint version = detail::getPlatformVersion(platform); useWithProperties = (version >= 0x20000); // OpenCL 2.0 or above } #elif CL_HPP_TARGET_OPENCL_VERSION >= 200 @@ -8193,7 +8385,7 @@ class CommandQueue : public detail::Wrapper { cl_event tmp; cl_int err = detail::errHandler(::clEnqueueSVMMap( - object_, blocking, flags, static_cast(container.data()), container.size(), + object_, blocking, flags, static_cast(container.data()), container.size()*sizeof(T), (events != NULL) ? (cl_uint)events->size() : 0, (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL, (event != NULL) ? &tmp : NULL), @@ -8552,10 +8744,10 @@ class CommandQueue : public detail::Wrapper } #if defined(CL_USE_DEPRECATED_OPENCL_1_2_APIS) - CL_EXT_PREFIX__VERSION_1_2_DEPRECATED cl_int enqueueTask( + CL_API_PREFIX__VERSION_1_2_DEPRECATED cl_int enqueueTask( const Kernel& kernel, const vector* events = NULL, - Event* event = NULL) const CL_EXT_SUFFIX__VERSION_1_2_DEPRECATED + Event* event = NULL) const CL_API_SUFFIX__VERSION_1_2_DEPRECATED { cl_event tmp; cl_int err = detail::errHandler( @@ -8612,8 +8804,8 @@ class CommandQueue : public detail::Wrapper * Deprecated APIs for 1.2 */ #if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - CL_EXT_PREFIX__VERSION_1_1_DEPRECATED - cl_int enqueueMarker(Event* event = NULL) const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED + CL_API_PREFIX__VERSION_1_1_DEPRECATED + cl_int enqueueMarker(Event* event = NULL) const CL_API_SUFFIX__VERSION_1_1_DEPRECATED { cl_event tmp; cl_int err = detail::errHandler( @@ -8628,8 +8820,8 @@ class CommandQueue : public detail::Wrapper return err; } - CL_EXT_PREFIX__VERSION_1_1_DEPRECATED - cl_int enqueueWaitForEvents(const vector& events) const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED + CL_API_PREFIX__VERSION_1_1_DEPRECATED + cl_int enqueueWaitForEvents(const vector& events) const CL_API_SUFFIX__VERSION_1_1_DEPRECATED { return detail::errHandler( ::clEnqueueWaitForEvents( @@ -8765,8 +8957,8 @@ typedef CL_API_ENTRY cl_int (CL_API_CALL *PFN_clEnqueueReleaseD3D10ObjectsKHR)( * Deprecated APIs for 1.2 */ #if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) - CL_EXT_PREFIX__VERSION_1_1_DEPRECATED - cl_int enqueueBarrier() const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED + CL_API_PREFIX__VERSION_1_1_DEPRECATED + cl_int enqueueBarrier() const CL_API_SUFFIX__VERSION_1_1_DEPRECATED { return detail::errHandler( ::clEnqueueBarrier(object_), @@ -10277,6 +10469,8 @@ namespace compatibility { #undef __CLONE_KERNEL_ERR #undef __GET_HOST_TIMER_ERR #undef __GET_DEVICE_AND_HOST_TIMER_ERR +#undef __GET_COMMAND_BUFFER_INFO_KHR_ERR +#undef __FINALIZE_COMMAND_BUFFER_KHR_ERR #endif //CL_HPP_USER_OVERRIDE_ERROR_STRINGS diff --git a/include/layer_util.hpp b/include/layer_util.hpp new file mode 100644 index 0000000..d826cec --- /dev/null +++ b/include/layer_util.hpp @@ -0,0 +1,136 @@ +/* +// Copyright (c) 2022 Ben Ashbaugh +// +// SPDX-License-Identifier: MIT +*/ +#pragma once + +#include + +#include +#include +#include + +template +cl_int writeParamToMemory( + size_t param_value_size, + T param, + size_t* param_value_size_ret, + T* pointer) +{ + if (pointer != nullptr) { + if (param_value_size < sizeof(param)) { + return CL_INVALID_VALUE; + } + *pointer = param; + } + + if (param_value_size_ret != nullptr) { + *param_value_size_ret = sizeof(param); + } + + return CL_SUCCESS; +} + +template +cl_int writeVectorToMemory( + size_t param_value_size, + const std::vector& param, + size_t *param_value_size_ret, + T* pointer ) +{ + size_t size = param.size() * sizeof(T); + + if (pointer != nullptr) { + if (param_value_size < size) { + return CL_INVALID_VALUE; + } + memcpy(pointer, param.data(), size); + } + + if (param_value_size_ret != nullptr) { + *param_value_size_ret = size; + } + + return CL_SUCCESS; +} + +static inline cl_int writeStringToMemory( + size_t param_value_size, + const char* param, + size_t* param_value_size_ret, + char* pointer ) +{ + size_t size = strlen(param) + 1; + + if (pointer != nullptr) { + if (param_value_size < size) { + return CL_INVALID_VALUE; + } + strcpy(pointer, param); + } + + if (param_value_size_ret != nullptr) { + *param_value_size_ret = size; + } + + return CL_SUCCESS; +} + +static cl_uint getOpenCLVersionFromString( + const char* str) +{ + cl_uint major = 0; + cl_uint minor = 0; + + // The device version string has the form: + // OpenCL . + const char* prefix = "OpenCL "; + size_t sz = strlen(prefix); + if (strlen(str) > sz && + strncmp(str, prefix, sz) == 0) { + const char* check = str + sz; + while (isdigit(check[0])) { + major *= 10; + major += check[0] - '0'; + ++check; + } + if (check[0] == '.') { + ++check; + } + while (isdigit(check[0])) { + minor *= 10; + minor += check[0] - '0'; + ++check; + } + } + + return (major << 16) | minor; +} + +static inline bool checkStringForExtension( + const char* str, + const char* extensionName ) +{ + bool supported = false; + + if (extensionName && !strchr(extensionName, ' ')) { + const char* start = str; + while (true) { + const char* where = strstr(start, extensionName); + if (!where) { + break; + } + const char* terminator = where + strlen(extensionName); + if (where == start || *(where - 1) == ' ') { + if (*terminator == ' ' || *terminator == '\0') { + supported = true; + break; + } + } + start = terminator; + } + } + + return supported; +} diff --git a/include/popl/popl.hpp b/include/popl/popl.hpp new file mode 100644 index 0000000..23cbb12 --- /dev/null +++ b/include/popl/popl.hpp @@ -0,0 +1,1257 @@ +/*** + ____ __ ____ __ + ( _ \ / \( _ \( ) + ) __/( O )) __// (_/\ + (__) \__/(__) \____/ + version 1.2.0 + https://github.com/badaix/popl + + This file is part of popl (program options parser lib) + Copyright (C) 2015-2018 Johannes Pohl + + This software may be modified and distributed under the terms + of the MIT license. See the LICENSE file for details. +***/ + +/// checked with clang-tidy: +/// run-clang-tidy-3.8.py -header-filter='.*' -checks='*,-misc-definitions-in-headers,-google-readability-braces-around-statements,-readability-braces-around-statements,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-google-build-using-namespace,-google-build-using-namespace' + +#ifndef POPL_HPP +#define POPL_HPP + +#ifndef NOMINMAX +#define NOMINMAX +#endif // NOMINMAX + +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace popl +{ + +#define POPL_VERSION "1.2.0" + + +/// Option's argument type +/** + * Switch has "no" argument + * Value has "required" argument + * Implicit has "optional" argument + */ +enum class Argument +{ + no = 0, // option never takes an argument + required, // option always requires an argument + optional // option may take an argument +}; + + +/// Option's attribute +/** + * inactive: Option is not set and will not be parsed + * hidden: Option is active, but will not show up in the help message + * required: Option must be set on the command line. Otherwise an exception will be thrown + * optional: Option must not be set. Default attribute. + * advanced: Option is advanced and will only show up in the advanced help message + * expoert: Option is expert and will only show up in the expert help message + */ +enum class Attribute +{ + inactive = 0, + hidden = 1, + required = 2, + optional = 3, + advanced = 4, + expert = 5 +}; + + +/// Option name type. Used in invalid_option exception. +/** + * unspecified: not specified + * short_name: The option's short name + * long_name: The option's long name + */ +enum class OptionName +{ + unspecified, + short_name, + long_name +}; + + +/// Abstract Base class for Options +/** + * Base class for Options + * holds just configuration data, no runtime data. + * Option is not bound to a special type "T" + */ +class Option +{ +friend class OptionParser; +public: + /// Construct an Option + /// @param short_name the options's short name. Must be empty or one character. + /// @param long_name the option's long name. Can be empty. + /// @param description the Option's description that will be shown in the help message + Option(const std::string& short_name, const std::string& long_name, std::string description); + + /// Destructor + virtual ~Option() = default; + + /// default copy constructor + Option(const Option&) = default; + + /// default move constructor + Option(Option&&) = default; + + /// default assignement operator + Option& operator=(const Option&) = default; + + /// default move assignement operator + Option& operator=(Option&&) = default; + + /// Get the Option's short name + /// @return character of the options's short name or 0 if no short name is defined + char short_name() const; + + /// Get the Option's long name + /// @return the long name of the Option. Empty string if no long name is defined + std::string long_name() const; + + /// Get the Option's long or short name + /// @param what_name the option's name to return + /// @param what_hyphen preced the returned name with (double-)hypen + /// @return the requested name of the Option. Empty string if not defined. + std::string name(OptionName what_name, bool with_hypen = false) const; + + /// Get the Option's description + /// @return the description + std::string description() const; + + /// Get the Option's default value + /// @param out stream to write the default value to + /// @return true if a default value is available, false if not + virtual bool get_default(std::ostream& out) const = 0; + + /// Set the Option's attribute + /// @param attribute + void set_attribute(const Attribute& attribute); + + /// Get the Option's attribute + /// @return the Options's attribute + Attribute attribute() const; + + /// Get the Option's argument type + /// @return argument type (no, required, optional) + virtual Argument argument_type() const = 0; + + /// Check how often the Option is set on command line + /// @return the Option's count on command line + virtual size_t count() const = 0; + + /// Check if the Option is set + /// @return true if set at least once + virtual bool is_set() const = 0; + +protected: + /// Parse the command line option and fill the internal data structure + /// @param what_name short or long option name + /// @param value the value as given on command line + virtual void parse(OptionName what_name, const char* value) = 0; + + /// Clear the internal data structure + virtual void clear() = 0; + + std::string short_name_; + std::string long_name_; + std::string description_; + Attribute attribute_; +}; + + + + +/// Value option with optional default value +/** + * Value option with optional default value + * If set, it requires an argument + */ +template +class Value : public Option +{ +public: + /// Construct an Value Option + /// @param short_name the option's short name. Must be empty or one character. + /// @param long_name the option's long name. Can be empty. + /// @param description the Option's description that will be shown in the help message + Value(const std::string& short_name, const std::string& long_name, const std::string& description); + + /// Construct an Value Option + /// @param short_name the option's short name. Must be empty or one character. + /// @param long_name the option's long name. Can be empty. + /// @param description the Option's description that will be shown in the help message + /// @param default_val the Option's default value + /// @param assign_to pointer to a variable to assign the parsed command line value to + Value(const std::string& short_name, const std::string& long_name, const std::string& description, const T& default_val, T* assign_to = nullptr); + + size_t count() const override; + bool is_set() const override; + + /// Assign the last parsed command line value to "var" + /// @param var pointer to the variable where is value is written to + void assign_to(T* var); + + /// Manually set the Option's value. Deletes current value(s) + /// @param value the new value of the option + void set_value(const T& value); + + /// Get the Option's value. Will throw if option at index idx is not available + /// @param idx the zero based index of the value (if set multiple times) + /// @return the Option's value at index "idx" + T value(size_t idx = 0) const; + + /// Set the Option's default value + /// @param value the default value if not specified on command line + void set_default(const T& value); + + /// Check if the Option has a default value + /// @return true if the Option has a default value + bool has_default() const; + + /// Get the Option's default value. Will throw if no default is set. + /// @return the Option's default value + T get_default() const; + bool get_default(std::ostream& out) const override; + + Argument argument_type() const override; + +protected: + void parse(OptionName what_name, const char* value) override; + std::unique_ptr default_; + + virtual void update_reference(); + virtual void add_value(const T& value); + void clear() override; + + T* assign_to_; + std::vector values_; +}; + + + + +/// Value option with implicit default value +/** + * Value option with implicit default value + * If set, an argument is optional + * -without argument it carries the implicit default value + * -with argument it carries the explicit value + */ +template +class Implicit : public Value +{ +public: + Implicit(const std::string& short_name, const std::string& long_name, const std::string& description, const T& implicit_val, T* assign_to = nullptr); + + Argument argument_type() const override; + +protected: + void parse(OptionName what_name, const char* value) override; +}; + + + + +/// Value option without value +/** + * Value option without value + * Does not require an argument + * Can be either set or not set + */ +class Switch : public Value +{ +public: + Switch(const std::string& short_name, const std::string& long_name, const std::string& description, bool* assign_to = nullptr); + + void set_default(const bool& value) = delete; + Argument argument_type() const override; + +protected: + void parse(OptionName what_name, const char* value) override; +}; + + + + +using Option_ptr = std::shared_ptr