From 0247649d0f5e56367bcffb80c9bea9f0b80f7e2d Mon Sep 17 00:00:00 2001 From: Cittadhammo <82962905+cittadhammo@users.noreply.github.com> Date: Mon, 27 Jan 2025 09:28:32 +0000 Subject: [PATCH 1/8] add type for star with Janus cosmological law of interaction with constants of proportionality --- README.md | 25 + imgui.ini | 6 +- includes/CL/cl.h | 1235 +++ includes/CL/cl.hpp | 12906 +++++++++++++++++++++++++ includes/CL/cl_ext.h | 334 + includes/CL/cl_gl.h | 162 + includes/CL/cl_gl_ext.h | 69 + includes/CL/cl_platform.h | 1278 +++ includes/CL/lib/OpenCL.lib | Bin 0 -> 25870 bytes includes/CL/lib/libOpenCL.so | Bin 0 -> 27424 bytes includes/CL/opencl.h | 54 + includes/Computer.hpp | 9 +- includes/Menu.hpp | 4 +- shaders/compute/cl_compute_shader.cl | 49 +- sources/Computer.cpp | 42 +- sources/Menu.cpp | 11 + 16 files changed, 16154 insertions(+), 30 deletions(-) create mode 100644 includes/CL/cl.h create mode 100644 includes/CL/cl.hpp create mode 100644 includes/CL/cl_ext.h create mode 100644 includes/CL/cl_gl.h create mode 100644 includes/CL/cl_gl_ext.h create mode 100644 includes/CL/cl_platform.h create mode 100644 includes/CL/lib/OpenCL.lib create mode 100644 includes/CL/lib/libOpenCL.so create mode 100644 includes/CL/opencl.h diff --git a/README.md b/README.md index b910eb1..33ff485 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,28 @@ +``` +./build/Galaxy_simulation +``` +to run the built + +``` +bash unix_run.sh +``` +to built + +error 0: install libglew-dev + +error 1 : https://stackoverflow.com/questions/56858213/how-to-create-nvidia-opencl-project/57017982#57017982 + +https://github.com/ProjectPhysX/OpenCL-Wrapper/tree/master/src/OpenCL and put the file in the incldes with good folders + + + +error 2: that was useful +``` +sudo apt-get install freeglut3-dev +``` +from https://askubuntu.com/questions/96087/how-to-install-opengl-glut-libraries + + # ๐ŸŒŒ Galaxy simulation ![Release](https://img.shields.io/badge/Release-v4.0-blueviolet) diff --git a/imgui.ini b/imgui.ini index d387f38..d3f266a 100644 --- a/imgui.ini +++ b/imgui.ini @@ -1,6 +1,6 @@ [Window][InvisibleWindow] Pos=0,0 -Size=1920,1080 +Size=1440,810 Collapsed=0 [Window][Menu] @@ -30,9 +30,9 @@ Collapsed=0 [Window][Simulation settings (F1 to hide)] Pos=51,51 -Size=273,734 +Size=275,909 Collapsed=0 [Docking][Data] -DockSpace ID=0xF442860A Window=0xD8117908 Pos=0,0 Size=1920,1080 CentralNode=1 Selected=0x18B8C0DE +DockSpace ID=0xF442860A Window=0xD8117908 Pos=0,0 Size=1440,810 CentralNode=1 Selected=0x18B8C0DE diff --git a/includes/CL/cl.h b/includes/CL/cl.h new file mode 100644 index 0000000..4026cbb --- /dev/null +++ b/includes/CL/cl.h @@ -0,0 +1,1235 @@ +/******************************************************************************* + * Copyright (c) 2008 - 2012 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Materials. + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + ******************************************************************************/ + +#ifndef __OPENCL_CL_H +#define __OPENCL_CL_H + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************/ + +typedef struct _cl_platform_id * cl_platform_id; +typedef struct _cl_device_id * cl_device_id; +typedef struct _cl_context * cl_context; +typedef struct _cl_command_queue * cl_command_queue; +typedef struct _cl_mem * cl_mem; +typedef struct _cl_program * cl_program; +typedef struct _cl_kernel * cl_kernel; +typedef struct _cl_event * cl_event; +typedef struct _cl_sampler * cl_sampler; + +typedef cl_uint cl_bool; /* WARNING! Unlike cl_ types in cl_platform.h, cl_bool is not guaranteed to be the same size as the bool in kernels. */ +typedef cl_ulong cl_bitfield; +typedef cl_bitfield cl_device_type; +typedef cl_uint cl_platform_info; +typedef cl_uint cl_device_info; +typedef cl_bitfield cl_device_fp_config; +typedef cl_uint cl_device_mem_cache_type; +typedef cl_uint cl_device_local_mem_type; +typedef cl_bitfield cl_device_exec_capabilities; +typedef cl_bitfield cl_command_queue_properties; +typedef intptr_t cl_device_partition_property; +typedef cl_bitfield cl_device_affinity_domain; + +typedef intptr_t cl_context_properties; +typedef cl_uint cl_context_info; +typedef cl_uint cl_command_queue_info; +typedef cl_uint cl_channel_order; +typedef cl_uint cl_channel_type; +typedef cl_bitfield cl_mem_flags; +typedef cl_uint cl_mem_object_type; +typedef cl_uint cl_mem_info; +typedef cl_bitfield cl_mem_migration_flags; +typedef cl_uint cl_image_info; +typedef cl_uint cl_buffer_create_type; +typedef cl_uint cl_addressing_mode; +typedef cl_uint cl_filter_mode; +typedef cl_uint cl_sampler_info; +typedef cl_bitfield cl_map_flags; +typedef cl_uint cl_program_info; +typedef cl_uint cl_program_build_info; +typedef cl_uint cl_program_binary_type; +typedef cl_int cl_build_status; +typedef cl_uint cl_kernel_info; +typedef cl_uint cl_kernel_arg_info; +typedef cl_uint cl_kernel_arg_address_qualifier; +typedef cl_uint cl_kernel_arg_access_qualifier; +typedef cl_bitfield cl_kernel_arg_type_qualifier; +typedef cl_uint cl_kernel_work_group_info; +typedef cl_uint cl_event_info; +typedef cl_uint cl_command_type; +typedef cl_uint cl_profiling_info; + + +typedef struct _cl_image_format { + cl_channel_order image_channel_order; + cl_channel_type image_channel_data_type; +} cl_image_format; + +typedef struct _cl_image_desc { + cl_mem_object_type image_type; + size_t image_width; + size_t image_height; + size_t image_depth; + size_t image_array_size; + size_t image_row_pitch; + size_t image_slice_pitch; + cl_uint num_mip_levels; + cl_uint num_samples; + cl_mem buffer; +} cl_image_desc; + +typedef struct _cl_buffer_region { + size_t origin; + size_t size; +} cl_buffer_region; + + +/******************************************************************************/ + +/* Error Codes */ +#define CL_SUCCESS 0 +#define CL_DEVICE_NOT_FOUND -1 +#define CL_DEVICE_NOT_AVAILABLE -2 +#define CL_COMPILER_NOT_AVAILABLE -3 +#define CL_MEM_OBJECT_ALLOCATION_FAILURE -4 +#define CL_OUT_OF_RESOURCES -5 +#define CL_OUT_OF_HOST_MEMORY -6 +#define CL_PROFILING_INFO_NOT_AVAILABLE -7 +#define CL_MEM_COPY_OVERLAP -8 +#define CL_IMAGE_FORMAT_MISMATCH -9 +#define CL_IMAGE_FORMAT_NOT_SUPPORTED -10 +#define CL_BUILD_PROGRAM_FAILURE -11 +#define CL_MAP_FAILURE -12 +#define CL_MISALIGNED_SUB_BUFFER_OFFSET -13 +#define CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST -14 +#define CL_COMPILE_PROGRAM_FAILURE -15 +#define CL_LINKER_NOT_AVAILABLE -16 +#define CL_LINK_PROGRAM_FAILURE -17 +#define CL_DEVICE_PARTITION_FAILED -18 +#define CL_KERNEL_ARG_INFO_NOT_AVAILABLE -19 + +#define CL_INVALID_VALUE -30 +#define CL_INVALID_DEVICE_TYPE -31 +#define CL_INVALID_PLATFORM -32 +#define CL_INVALID_DEVICE -33 +#define CL_INVALID_CONTEXT -34 +#define CL_INVALID_QUEUE_PROPERTIES -35 +#define CL_INVALID_COMMAND_QUEUE -36 +#define CL_INVALID_HOST_PTR -37 +#define CL_INVALID_MEM_OBJECT -38 +#define CL_INVALID_IMAGE_FORMAT_DESCRIPTOR -39 +#define CL_INVALID_IMAGE_SIZE -40 +#define CL_INVALID_SAMPLER -41 +#define CL_INVALID_BINARY -42 +#define CL_INVALID_BUILD_OPTIONS -43 +#define CL_INVALID_PROGRAM -44 +#define CL_INVALID_PROGRAM_EXECUTABLE -45 +#define CL_INVALID_KERNEL_NAME -46 +#define CL_INVALID_KERNEL_DEFINITION -47 +#define CL_INVALID_KERNEL -48 +#define CL_INVALID_ARG_INDEX -49 +#define CL_INVALID_ARG_VALUE -50 +#define CL_INVALID_ARG_SIZE -51 +#define CL_INVALID_KERNEL_ARGS -52 +#define CL_INVALID_WORK_DIMENSION -53 +#define CL_INVALID_WORK_GROUP_SIZE -54 +#define CL_INVALID_WORK_ITEM_SIZE -55 +#define CL_INVALID_GLOBAL_OFFSET -56 +#define CL_INVALID_EVENT_WAIT_LIST -57 +#define CL_INVALID_EVENT -58 +#define CL_INVALID_OPERATION -59 +#define CL_INVALID_GL_OBJECT -60 +#define CL_INVALID_BUFFER_SIZE -61 +#define CL_INVALID_MIP_LEVEL -62 +#define CL_INVALID_GLOBAL_WORK_SIZE -63 +#define CL_INVALID_PROPERTY -64 +#define CL_INVALID_IMAGE_DESCRIPTOR -65 +#define CL_INVALID_COMPILER_OPTIONS -66 +#define CL_INVALID_LINKER_OPTIONS -67 +#define CL_INVALID_DEVICE_PARTITION_COUNT -68 + +/* OpenCL Version */ +#define CL_VERSION_1_0 1 +#define CL_VERSION_1_1 1 +#define CL_VERSION_1_2 1 + +/* cl_bool */ +#define CL_FALSE 0 +#define CL_TRUE 1 +#define CL_BLOCKING CL_TRUE +#define CL_NON_BLOCKING CL_FALSE + +/* cl_platform_info */ +#define CL_PLATFORM_PROFILE 0x0900 +#define CL_PLATFORM_VERSION 0x0901 +#define CL_PLATFORM_NAME 0x0902 +#define CL_PLATFORM_VENDOR 0x0903 +#define CL_PLATFORM_EXTENSIONS 0x0904 + +/* cl_device_type - bitfield */ +#define CL_DEVICE_TYPE_DEFAULT (1 << 0) +#define CL_DEVICE_TYPE_CPU (1 << 1) +#define CL_DEVICE_TYPE_GPU (1 << 2) +#define CL_DEVICE_TYPE_ACCELERATOR (1 << 3) +#define CL_DEVICE_TYPE_CUSTOM (1 << 4) +#define CL_DEVICE_TYPE_ALL 0xFFFFFFFF + +/* cl_device_info */ +#define CL_DEVICE_TYPE 0x1000 +#define CL_DEVICE_VENDOR_ID 0x1001 +#define CL_DEVICE_MAX_COMPUTE_UNITS 0x1002 +#define CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS 0x1003 +#define CL_DEVICE_MAX_WORK_GROUP_SIZE 0x1004 +#define CL_DEVICE_MAX_WORK_ITEM_SIZES 0x1005 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR 0x1006 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT 0x1007 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT 0x1008 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG 0x1009 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT 0x100A +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE 0x100B +#define CL_DEVICE_MAX_CLOCK_FREQUENCY 0x100C +#define CL_DEVICE_ADDRESS_BITS 0x100D +#define CL_DEVICE_MAX_READ_IMAGE_ARGS 0x100E +#define CL_DEVICE_MAX_WRITE_IMAGE_ARGS 0x100F +#define CL_DEVICE_MAX_MEM_ALLOC_SIZE 0x1010 +#define CL_DEVICE_IMAGE2D_MAX_WIDTH 0x1011 +#define CL_DEVICE_IMAGE2D_MAX_HEIGHT 0x1012 +#define CL_DEVICE_IMAGE3D_MAX_WIDTH 0x1013 +#define CL_DEVICE_IMAGE3D_MAX_HEIGHT 0x1014 +#define CL_DEVICE_IMAGE3D_MAX_DEPTH 0x1015 +#define CL_DEVICE_IMAGE_SUPPORT 0x1016 +#define CL_DEVICE_MAX_PARAMETER_SIZE 0x1017 +#define CL_DEVICE_MAX_SAMPLERS 0x1018 +#define CL_DEVICE_MEM_BASE_ADDR_ALIGN 0x1019 +#define CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE 0x101A +#define CL_DEVICE_SINGLE_FP_CONFIG 0x101B +#define CL_DEVICE_GLOBAL_MEM_CACHE_TYPE 0x101C +#define CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE 0x101D +#define CL_DEVICE_GLOBAL_MEM_CACHE_SIZE 0x101E +#define CL_DEVICE_GLOBAL_MEM_SIZE 0x101F +#define CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE 0x1020 +#define CL_DEVICE_MAX_CONSTANT_ARGS 0x1021 +#define CL_DEVICE_LOCAL_MEM_TYPE 0x1022 +#define CL_DEVICE_LOCAL_MEM_SIZE 0x1023 +#define CL_DEVICE_ERROR_CORRECTION_SUPPORT 0x1024 +#define CL_DEVICE_PROFILING_TIMER_RESOLUTION 0x1025 +#define CL_DEVICE_ENDIAN_LITTLE 0x1026 +#define CL_DEVICE_AVAILABLE 0x1027 +#define CL_DEVICE_COMPILER_AVAILABLE 0x1028 +#define CL_DEVICE_EXECUTION_CAPABILITIES 0x1029 +#define CL_DEVICE_QUEUE_PROPERTIES 0x102A +#define CL_DEVICE_NAME 0x102B +#define CL_DEVICE_VENDOR 0x102C +#define CL_DRIVER_VERSION 0x102D +#define CL_DEVICE_PROFILE 0x102E +#define CL_DEVICE_VERSION 0x102F +#define CL_DEVICE_EXTENSIONS 0x1030 +#define CL_DEVICE_PLATFORM 0x1031 +#define CL_DEVICE_DOUBLE_FP_CONFIG 0x1032 +/* 0x1033 reserved for CL_DEVICE_HALF_FP_CONFIG */ +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF 0x1034 +#define CL_DEVICE_HOST_UNIFIED_MEMORY 0x1035 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR 0x1036 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT 0x1037 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_INT 0x1038 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG 0x1039 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT 0x103A +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE 0x103B +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF 0x103C +#define CL_DEVICE_OPENCL_C_VERSION 0x103D +#define CL_DEVICE_LINKER_AVAILABLE 0x103E +#define CL_DEVICE_BUILT_IN_KERNELS 0x103F +#define CL_DEVICE_IMAGE_MAX_BUFFER_SIZE 0x1040 +#define CL_DEVICE_IMAGE_MAX_ARRAY_SIZE 0x1041 +#define CL_DEVICE_PARENT_DEVICE 0x1042 +#define CL_DEVICE_PARTITION_MAX_SUB_DEVICES 0x1043 +#define CL_DEVICE_PARTITION_PROPERTIES 0x1044 +#define CL_DEVICE_PARTITION_AFFINITY_DOMAIN 0x1045 +#define CL_DEVICE_PARTITION_TYPE 0x1046 +#define CL_DEVICE_REFERENCE_COUNT 0x1047 +#define CL_DEVICE_PREFERRED_INTEROP_USER_SYNC 0x1048 +#define CL_DEVICE_PRINTF_BUFFER_SIZE 0x1049 +#define CL_DEVICE_IMAGE_PITCH_ALIGNMENT 0x104A +#define CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT 0x104B + +/* cl_device_fp_config - bitfield */ +#define CL_FP_DENORM (1 << 0) +#define CL_FP_INF_NAN (1 << 1) +#define CL_FP_ROUND_TO_NEAREST (1 << 2) +#define CL_FP_ROUND_TO_ZERO (1 << 3) +#define CL_FP_ROUND_TO_INF (1 << 4) +#define CL_FP_FMA (1 << 5) +#define CL_FP_SOFT_FLOAT (1 << 6) +#define CL_FP_CORRECTLY_ROUNDED_DIVIDE_SQRT (1 << 7) + +/* cl_device_mem_cache_type */ +#define CL_NONE 0x0 +#define CL_READ_ONLY_CACHE 0x1 +#define CL_READ_WRITE_CACHE 0x2 + +/* cl_device_local_mem_type */ +#define CL_LOCAL 0x1 +#define CL_GLOBAL 0x2 + +/* cl_device_exec_capabilities - bitfield */ +#define CL_EXEC_KERNEL (1 << 0) +#define CL_EXEC_NATIVE_KERNEL (1 << 1) + +/* cl_command_queue_properties - bitfield */ +#define CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE (1 << 0) +#define CL_QUEUE_PROFILING_ENABLE (1 << 1) + +/* cl_context_info */ +#define CL_CONTEXT_REFERENCE_COUNT 0x1080 +#define CL_CONTEXT_DEVICES 0x1081 +#define CL_CONTEXT_PROPERTIES 0x1082 +#define CL_CONTEXT_NUM_DEVICES 0x1083 + +/* cl_context_properties */ +#define CL_CONTEXT_PLATFORM 0x1084 +#define CL_CONTEXT_INTEROP_USER_SYNC 0x1085 + +/* cl_device_partition_property */ +#define CL_DEVICE_PARTITION_EQUALLY 0x1086 +#define CL_DEVICE_PARTITION_BY_COUNTS 0x1087 +#define CL_DEVICE_PARTITION_BY_COUNTS_LIST_END 0x0 +#define CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN 0x1088 + +/* cl_device_affinity_domain */ +#define CL_DEVICE_AFFINITY_DOMAIN_NUMA (1 << 0) +#define CL_DEVICE_AFFINITY_DOMAIN_L4_CACHE (1 << 1) +#define CL_DEVICE_AFFINITY_DOMAIN_L3_CACHE (1 << 2) +#define CL_DEVICE_AFFINITY_DOMAIN_L2_CACHE (1 << 3) +#define CL_DEVICE_AFFINITY_DOMAIN_L1_CACHE (1 << 4) +#define CL_DEVICE_AFFINITY_DOMAIN_NEXT_PARTITIONABLE (1 << 5) + +/* cl_command_queue_info */ +#define CL_QUEUE_CONTEXT 0x1090 +#define CL_QUEUE_DEVICE 0x1091 +#define CL_QUEUE_REFERENCE_COUNT 0x1092 +#define CL_QUEUE_PROPERTIES 0x1093 + +/* cl_mem_flags - bitfield */ +#define CL_MEM_READ_WRITE (1 << 0) +#define CL_MEM_WRITE_ONLY (1 << 1) +#define CL_MEM_READ_ONLY (1 << 2) +#define CL_MEM_USE_HOST_PTR (1 << 3) +#define CL_MEM_ALLOC_HOST_PTR (1 << 4) +#define CL_MEM_COPY_HOST_PTR (1 << 5) +/* reserved (1 << 6) */ +#define CL_MEM_HOST_WRITE_ONLY (1 << 7) +#define CL_MEM_HOST_READ_ONLY (1 << 8) +#define CL_MEM_HOST_NO_ACCESS (1 << 9) + +/* cl_mem_migration_flags - bitfield */ +#define CL_MIGRATE_MEM_OBJECT_HOST (1 << 0) +#define CL_MIGRATE_MEM_OBJECT_CONTENT_UNDEFINED (1 << 1) + +/* cl_channel_order */ +#define CL_R 0x10B0 +#define CL_A 0x10B1 +#define CL_RG 0x10B2 +#define CL_RA 0x10B3 +#define CL_RGB 0x10B4 +#define CL_RGBA 0x10B5 +#define CL_BGRA 0x10B6 +#define CL_ARGB 0x10B7 +#define CL_INTENSITY 0x10B8 +#define CL_LUMINANCE 0x10B9 +#define CL_Rx 0x10BA +#define CL_RGx 0x10BB +#define CL_RGBx 0x10BC +#define CL_DEPTH 0x10BD +#define CL_DEPTH_STENCIL 0x10BE + +/* cl_channel_type */ +#define CL_SNORM_INT8 0x10D0 +#define CL_SNORM_INT16 0x10D1 +#define CL_UNORM_INT8 0x10D2 +#define CL_UNORM_INT16 0x10D3 +#define CL_UNORM_SHORT_565 0x10D4 +#define CL_UNORM_SHORT_555 0x10D5 +#define CL_UNORM_INT_101010 0x10D6 +#define CL_SIGNED_INT8 0x10D7 +#define CL_SIGNED_INT16 0x10D8 +#define CL_SIGNED_INT32 0x10D9 +#define CL_UNSIGNED_INT8 0x10DA +#define CL_UNSIGNED_INT16 0x10DB +#define CL_UNSIGNED_INT32 0x10DC +#define CL_HALF_FLOAT 0x10DD +#define CL_FLOAT 0x10DE +#define CL_UNORM_INT24 0x10DF + +/* cl_mem_object_type */ +#define CL_MEM_OBJECT_BUFFER 0x10F0 +#define CL_MEM_OBJECT_IMAGE2D 0x10F1 +#define CL_MEM_OBJECT_IMAGE3D 0x10F2 +#define CL_MEM_OBJECT_IMAGE2D_ARRAY 0x10F3 +#define CL_MEM_OBJECT_IMAGE1D 0x10F4 +#define CL_MEM_OBJECT_IMAGE1D_ARRAY 0x10F5 +#define CL_MEM_OBJECT_IMAGE1D_BUFFER 0x10F6 + +/* cl_mem_info */ +#define CL_MEM_TYPE 0x1100 +#define CL_MEM_FLAGS 0x1101 +#define CL_MEM_SIZE 0x1102 +#define CL_MEM_HOST_PTR 0x1103 +#define CL_MEM_MAP_COUNT 0x1104 +#define CL_MEM_REFERENCE_COUNT 0x1105 +#define CL_MEM_CONTEXT 0x1106 +#define CL_MEM_ASSOCIATED_MEMOBJECT 0x1107 +#define CL_MEM_OFFSET 0x1108 + +/* cl_image_info */ +#define CL_IMAGE_FORMAT 0x1110 +#define CL_IMAGE_ELEMENT_SIZE 0x1111 +#define CL_IMAGE_ROW_PITCH 0x1112 +#define CL_IMAGE_SLICE_PITCH 0x1113 +#define CL_IMAGE_WIDTH 0x1114 +#define CL_IMAGE_HEIGHT 0x1115 +#define CL_IMAGE_DEPTH 0x1116 +#define CL_IMAGE_ARRAY_SIZE 0x1117 +#define CL_IMAGE_BUFFER 0x1118 +#define CL_IMAGE_NUM_MIP_LEVELS 0x1119 +#define CL_IMAGE_NUM_SAMPLES 0x111A + +/* cl_addressing_mode */ +#define CL_ADDRESS_NONE 0x1130 +#define CL_ADDRESS_CLAMP_TO_EDGE 0x1131 +#define CL_ADDRESS_CLAMP 0x1132 +#define CL_ADDRESS_REPEAT 0x1133 +#define CL_ADDRESS_MIRRORED_REPEAT 0x1134 + +/* cl_filter_mode */ +#define CL_FILTER_NEAREST 0x1140 +#define CL_FILTER_LINEAR 0x1141 + +/* cl_sampler_info */ +#define CL_SAMPLER_REFERENCE_COUNT 0x1150 +#define CL_SAMPLER_CONTEXT 0x1151 +#define CL_SAMPLER_NORMALIZED_COORDS 0x1152 +#define CL_SAMPLER_ADDRESSING_MODE 0x1153 +#define CL_SAMPLER_FILTER_MODE 0x1154 + +/* cl_map_flags - bitfield */ +#define CL_MAP_READ (1 << 0) +#define CL_MAP_WRITE (1 << 1) +#define CL_MAP_WRITE_INVALIDATE_REGION (1 << 2) + +/* cl_program_info */ +#define CL_PROGRAM_REFERENCE_COUNT 0x1160 +#define CL_PROGRAM_CONTEXT 0x1161 +#define CL_PROGRAM_NUM_DEVICES 0x1162 +#define CL_PROGRAM_DEVICES 0x1163 +#define CL_PROGRAM_SOURCE 0x1164 +#define CL_PROGRAM_BINARY_SIZES 0x1165 +#define CL_PROGRAM_BINARIES 0x1166 +#define CL_PROGRAM_NUM_KERNELS 0x1167 +#define CL_PROGRAM_KERNEL_NAMES 0x1168 + +/* cl_program_build_info */ +#define CL_PROGRAM_BUILD_STATUS 0x1181 +#define CL_PROGRAM_BUILD_OPTIONS 0x1182 +#define CL_PROGRAM_BUILD_LOG 0x1183 +#define CL_PROGRAM_BINARY_TYPE 0x1184 + +/* cl_program_binary_type */ +#define CL_PROGRAM_BINARY_TYPE_NONE 0x0 +#define CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT 0x1 +#define CL_PROGRAM_BINARY_TYPE_LIBRARY 0x2 +#define CL_PROGRAM_BINARY_TYPE_EXECUTABLE 0x4 + +/* cl_build_status */ +#define CL_BUILD_SUCCESS 0 +#define CL_BUILD_NONE -1 +#define CL_BUILD_ERROR -2 +#define CL_BUILD_IN_PROGRESS -3 + +/* cl_kernel_info */ +#define CL_KERNEL_FUNCTION_NAME 0x1190 +#define CL_KERNEL_NUM_ARGS 0x1191 +#define CL_KERNEL_REFERENCE_COUNT 0x1192 +#define CL_KERNEL_CONTEXT 0x1193 +#define CL_KERNEL_PROGRAM 0x1194 +#define CL_KERNEL_ATTRIBUTES 0x1195 + +/* cl_kernel_arg_info */ +#define CL_KERNEL_ARG_ADDRESS_QUALIFIER 0x1196 +#define CL_KERNEL_ARG_ACCESS_QUALIFIER 0x1197 +#define CL_KERNEL_ARG_TYPE_NAME 0x1198 +#define CL_KERNEL_ARG_TYPE_QUALIFIER 0x1199 +#define CL_KERNEL_ARG_NAME 0x119A + +/* cl_kernel_arg_address_qualifier */ +#define CL_KERNEL_ARG_ADDRESS_GLOBAL 0x119B +#define CL_KERNEL_ARG_ADDRESS_LOCAL 0x119C +#define CL_KERNEL_ARG_ADDRESS_CONSTANT 0x119D +#define CL_KERNEL_ARG_ADDRESS_PRIVATE 0x119E + +/* cl_kernel_arg_access_qualifier */ +#define CL_KERNEL_ARG_ACCESS_READ_ONLY 0x11A0 +#define CL_KERNEL_ARG_ACCESS_WRITE_ONLY 0x11A1 +#define CL_KERNEL_ARG_ACCESS_READ_WRITE 0x11A2 +#define CL_KERNEL_ARG_ACCESS_NONE 0x11A3 + +/* cl_kernel_arg_type_qualifer */ +#define CL_KERNEL_ARG_TYPE_NONE 0 +#define CL_KERNEL_ARG_TYPE_CONST (1 << 0) +#define CL_KERNEL_ARG_TYPE_RESTRICT (1 << 1) +#define CL_KERNEL_ARG_TYPE_VOLATILE (1 << 2) + +/* cl_kernel_work_group_info */ +#define CL_KERNEL_WORK_GROUP_SIZE 0x11B0 +#define CL_KERNEL_COMPILE_WORK_GROUP_SIZE 0x11B1 +#define CL_KERNEL_LOCAL_MEM_SIZE 0x11B2 +#define CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE 0x11B3 +#define CL_KERNEL_PRIVATE_MEM_SIZE 0x11B4 +#define CL_KERNEL_GLOBAL_WORK_SIZE 0x11B5 + +/* cl_event_info */ +#define CL_EVENT_COMMAND_QUEUE 0x11D0 +#define CL_EVENT_COMMAND_TYPE 0x11D1 +#define CL_EVENT_REFERENCE_COUNT 0x11D2 +#define CL_EVENT_COMMAND_EXECUTION_STATUS 0x11D3 +#define CL_EVENT_CONTEXT 0x11D4 + +/* cl_command_type */ +#define CL_COMMAND_NDRANGE_KERNEL 0x11F0 +#define CL_COMMAND_TASK 0x11F1 +#define CL_COMMAND_NATIVE_KERNEL 0x11F2 +#define CL_COMMAND_READ_BUFFER 0x11F3 +#define CL_COMMAND_WRITE_BUFFER 0x11F4 +#define CL_COMMAND_COPY_BUFFER 0x11F5 +#define CL_COMMAND_READ_IMAGE 0x11F6 +#define CL_COMMAND_WRITE_IMAGE 0x11F7 +#define CL_COMMAND_COPY_IMAGE 0x11F8 +#define CL_COMMAND_COPY_IMAGE_TO_BUFFER 0x11F9 +#define CL_COMMAND_COPY_BUFFER_TO_IMAGE 0x11FA +#define CL_COMMAND_MAP_BUFFER 0x11FB +#define CL_COMMAND_MAP_IMAGE 0x11FC +#define CL_COMMAND_UNMAP_MEM_OBJECT 0x11FD +#define CL_COMMAND_MARKER 0x11FE +#define CL_COMMAND_ACQUIRE_GL_OBJECTS 0x11FF +#define CL_COMMAND_RELEASE_GL_OBJECTS 0x1200 +#define CL_COMMAND_READ_BUFFER_RECT 0x1201 +#define CL_COMMAND_WRITE_BUFFER_RECT 0x1202 +#define CL_COMMAND_COPY_BUFFER_RECT 0x1203 +#define CL_COMMAND_USER 0x1204 +#define CL_COMMAND_BARRIER 0x1205 +#define CL_COMMAND_MIGRATE_MEM_OBJECTS 0x1206 +#define CL_COMMAND_FILL_BUFFER 0x1207 +#define CL_COMMAND_FILL_IMAGE 0x1208 + +/* command execution status */ +#define CL_COMPLETE 0x0 +#define CL_RUNNING 0x1 +#define CL_SUBMITTED 0x2 +#define CL_QUEUED 0x3 + +/* cl_buffer_create_type */ +#define CL_BUFFER_CREATE_TYPE_REGION 0x1220 + +/* cl_profiling_info */ +#define CL_PROFILING_COMMAND_QUEUED 0x1280 +#define CL_PROFILING_COMMAND_SUBMIT 0x1281 +#define CL_PROFILING_COMMAND_START 0x1282 +#define CL_PROFILING_COMMAND_END 0x1283 + +/********************************************************************************************************/ + +/* Platform API */ +extern CL_API_ENTRY cl_int CL_API_CALL +clGetPlatformIDs(cl_uint /* num_entries */, + cl_platform_id * /* platforms */, + cl_uint * /* num_platforms */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetPlatformInfo(cl_platform_id /* platform */, + cl_platform_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +/* Device APIs */ +extern CL_API_ENTRY cl_int CL_API_CALL +clGetDeviceIDs(cl_platform_id /* platform */, + cl_device_type /* device_type */, + cl_uint /* num_entries */, + cl_device_id * /* devices */, + cl_uint * /* num_devices */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetDeviceInfo(cl_device_id /* device */, + cl_device_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clCreateSubDevices(cl_device_id /* in_device */, + const cl_device_partition_property * /* properties */, + cl_uint /* num_devices */, + cl_device_id * /* out_devices */, + cl_uint * /* num_devices_ret */) CL_API_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clRetainDevice(cl_device_id /* device */) CL_API_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clReleaseDevice(cl_device_id /* device */) CL_API_SUFFIX__VERSION_1_2; + +/* Context APIs */ +extern CL_API_ENTRY cl_context CL_API_CALL +clCreateContext(const cl_context_properties * /* properties */, + cl_uint /* num_devices */, + const cl_device_id * /* devices */, + void (CL_CALLBACK * /* pfn_notify */)(const char *, const void *, size_t, void *), + void * /* user_data */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_context CL_API_CALL +clCreateContextFromType(const cl_context_properties * /* properties */, + cl_device_type /* device_type */, + void (CL_CALLBACK * /* pfn_notify*/ )(const char *, const void *, size_t, void *), + void * /* user_data */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clRetainContext(cl_context /* context */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clReleaseContext(cl_context /* context */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetContextInfo(cl_context /* context */, + cl_context_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +/* Command Queue APIs */ +extern CL_API_ENTRY cl_command_queue CL_API_CALL +clCreateCommandQueue(cl_context /* context */, + cl_device_id /* device */, + cl_command_queue_properties /* properties */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clRetainCommandQueue(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clReleaseCommandQueue(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetCommandQueueInfo(cl_command_queue /* command_queue */, + cl_command_queue_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +#ifdef CL_USE_DEPRECATED_OPENCL_1_0_APIS +#ifndef NVCL_SUPPRESS_USE_DEPRECATED_OPENCL_1_0_APIS_WARNING +#warning CL_USE_DEPRECATED_OPENCL_1_0_APIS is defined. These APIs are unsupported and untested in OpenCL 1.1! +#endif +/* + * WARNING: + * This API introduces mutable state into the OpenCL implementation. It has been REMOVED + * to better facilitate thread safety. The 1.0 API is not thread safe. It is not tested by the + * OpenCL 1.1 conformance test, and consequently may not work or may not work dependably. + * It is likely to be non-performant. Use of this API is not advised. Use at your own risk. + * + * Software developers previously relying on this API are instructed to set the command queue + * properties when creating the queue, instead. + */ +extern CL_API_ENTRY cl_int CL_API_CALL +clSetCommandQueueProperty(cl_command_queue /* command_queue */, + cl_command_queue_properties /* properties */, + cl_bool /* enable */, + cl_command_queue_properties * /* old_properties */) CL_EXT_SUFFIX__VERSION_1_0_DEPRECATED; +#endif /* CL_USE_DEPRECATED_OPENCL_1_0_APIS */ + +/* Memory Object APIs */ +extern CL_API_ENTRY cl_mem CL_API_CALL +clCreateBuffer(cl_context /* context */, + cl_mem_flags /* flags */, + size_t /* size */, + void * /* host_ptr */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_mem CL_API_CALL +clCreateSubBuffer(cl_mem /* buffer */, + cl_mem_flags /* flags */, + cl_buffer_create_type /* buffer_create_type */, + const void * /* buffer_create_info */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_1; + +extern CL_API_ENTRY cl_mem CL_API_CALL +clCreateImage(cl_context /* context */, + cl_mem_flags /* flags */, + const cl_image_format * /* image_format */, + const cl_image_desc * /* image_desc */, + void * /* host_ptr */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clRetainMemObject(cl_mem /* memobj */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clReleaseMemObject(cl_mem /* memobj */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetSupportedImageFormats(cl_context /* context */, + cl_mem_flags /* flags */, + cl_mem_object_type /* image_type */, + cl_uint /* num_entries */, + cl_image_format * /* image_formats */, + cl_uint * /* num_image_formats */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetMemObjectInfo(cl_mem /* memobj */, + cl_mem_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetImageInfo(cl_mem /* image */, + cl_image_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clSetMemObjectDestructorCallback( cl_mem /* memobj */, + void (CL_CALLBACK * /*pfn_notify*/)( cl_mem /* memobj */, void* /*user_data*/), + void * /*user_data */ ) CL_API_SUFFIX__VERSION_1_1; + +/* Sampler APIs */ +extern CL_API_ENTRY cl_sampler CL_API_CALL +clCreateSampler(cl_context /* context */, + cl_bool /* normalized_coords */, + cl_addressing_mode /* addressing_mode */, + cl_filter_mode /* filter_mode */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clRetainSampler(cl_sampler /* sampler */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clReleaseSampler(cl_sampler /* sampler */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetSamplerInfo(cl_sampler /* sampler */, + cl_sampler_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +/* Program Object APIs */ +extern CL_API_ENTRY cl_program CL_API_CALL +clCreateProgramWithSource(cl_context /* context */, + cl_uint /* count */, + const char ** /* strings */, + const size_t * /* lengths */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_program CL_API_CALL +clCreateProgramWithBinary(cl_context /* context */, + cl_uint /* num_devices */, + const cl_device_id * /* device_list */, + const size_t * /* lengths */, + const unsigned char ** /* binaries */, + cl_int * /* binary_status */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_program CL_API_CALL +clCreateProgramWithBuiltInKernels(cl_context /* context */, + cl_uint /* num_devices */, + const cl_device_id * /* device_list */, + const char * /* kernel_names */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clRetainProgram(cl_program /* program */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clReleaseProgram(cl_program /* program */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clBuildProgram(cl_program /* program */, + cl_uint /* num_devices */, + const cl_device_id * /* device_list */, + const char * /* options */, + void (CL_CALLBACK * /* pfn_notify */)(cl_program /* program */, void * /* user_data */), + void * /* user_data */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clCompileProgram(cl_program /* program */, + cl_uint /* num_devices */, + const cl_device_id * /* device_list */, + const char * /* options */, + cl_uint /* num_input_headers */, + const cl_program * /* input_headers */, + const char ** /* header_include_names */, + void (CL_CALLBACK * /* pfn_notify */)(cl_program /* program */, void * /* user_data */), + void * /* user_data */) CL_API_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_program CL_API_CALL +clLinkProgram(cl_context /* context */, + cl_uint /* num_devices */, + const cl_device_id * /* device_list */, + const char * /* options */, + cl_uint /* num_input_programs */, + const cl_program * /* input_programs */, + void (CL_CALLBACK * /* pfn_notify */)(cl_program /* program */, void * /* user_data */), + void * /* user_data */, + cl_int * /* errcode_ret */ ) CL_API_SUFFIX__VERSION_1_2; + + +extern CL_API_ENTRY cl_int CL_API_CALL +clUnloadPlatformCompiler(cl_platform_id /* platform */) CL_API_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetProgramInfo(cl_program /* program */, + cl_program_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetProgramBuildInfo(cl_program /* program */, + cl_device_id /* device */, + cl_program_build_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +/* Kernel Object APIs */ +extern CL_API_ENTRY cl_kernel CL_API_CALL +clCreateKernel(cl_program /* program */, + const char * /* kernel_name */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clCreateKernelsInProgram(cl_program /* program */, + cl_uint /* num_kernels */, + cl_kernel * /* kernels */, + cl_uint * /* num_kernels_ret */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clRetainKernel(cl_kernel /* kernel */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clReleaseKernel(cl_kernel /* kernel */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clSetKernelArg(cl_kernel /* kernel */, + cl_uint /* arg_index */, + size_t /* arg_size */, + const void * /* arg_value */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetKernelInfo(cl_kernel /* kernel */, + cl_kernel_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetKernelArgInfo(cl_kernel /* kernel */, + cl_uint /* arg_indx */, + cl_kernel_arg_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetKernelWorkGroupInfo(cl_kernel /* kernel */, + cl_device_id /* device */, + cl_kernel_work_group_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +/* Event Object APIs */ +extern CL_API_ENTRY cl_int CL_API_CALL +clWaitForEvents(cl_uint /* num_events */, + const cl_event * /* event_list */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetEventInfo(cl_event /* event */, + cl_event_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_event CL_API_CALL +clCreateUserEvent(cl_context /* context */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_1; + +extern CL_API_ENTRY cl_int CL_API_CALL +clRetainEvent(cl_event /* event */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clReleaseEvent(cl_event /* event */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clSetUserEventStatus(cl_event /* event */, + cl_int /* execution_status */) CL_API_SUFFIX__VERSION_1_1; + +extern CL_API_ENTRY cl_int CL_API_CALL +clSetEventCallback( cl_event /* event */, + cl_int /* command_exec_callback_type */, + void (CL_CALLBACK * /* pfn_notify */)(cl_event, cl_int, void *), + void * /* user_data */) CL_API_SUFFIX__VERSION_1_1; + +/* Profiling APIs */ +extern CL_API_ENTRY cl_int CL_API_CALL +clGetEventProfilingInfo(cl_event /* event */, + cl_profiling_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +/* Flush and Finish APIs */ +extern CL_API_ENTRY cl_int CL_API_CALL +clFlush(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clFinish(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; + +/* Enqueued Commands APIs */ +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueReadBuffer(cl_command_queue /* command_queue */, + cl_mem /* buffer */, + cl_bool /* blocking_read */, + size_t /* offset */, + size_t /* size */, + void * /* ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueReadBufferRect(cl_command_queue /* command_queue */, + cl_mem /* buffer */, + cl_bool /* blocking_read */, + const size_t * /* buffer_offset */, + const size_t * /* host_offset */, + const size_t * /* region */, + size_t /* buffer_row_pitch */, + size_t /* buffer_slice_pitch */, + size_t /* host_row_pitch */, + size_t /* host_slice_pitch */, + void * /* ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_1; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueWriteBuffer(cl_command_queue /* command_queue */, + cl_mem /* buffer */, + cl_bool /* blocking_write */, + size_t /* offset */, + size_t /* size */, + const void * /* ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueWriteBufferRect(cl_command_queue /* command_queue */, + cl_mem /* buffer */, + cl_bool /* blocking_write */, + const size_t * /* buffer_offset */, + const size_t * /* host_offset */, + const size_t * /* region */, + size_t /* buffer_row_pitch */, + size_t /* buffer_slice_pitch */, + size_t /* host_row_pitch */, + size_t /* host_slice_pitch */, + const void * /* ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_1; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueFillBuffer(cl_command_queue /* command_queue */, + cl_mem /* buffer */, + const void * /* pattern */, + size_t /* pattern_size */, + size_t /* offset */, + size_t /* size */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueCopyBuffer(cl_command_queue /* command_queue */, + cl_mem /* src_buffer */, + cl_mem /* dst_buffer */, + size_t /* src_offset */, + size_t /* dst_offset */, + size_t /* size */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueCopyBufferRect(cl_command_queue /* command_queue */, + cl_mem /* src_buffer */, + cl_mem /* dst_buffer */, + const size_t * /* src_origin */, + const size_t * /* dst_origin */, + const size_t * /* region */, + size_t /* src_row_pitch */, + size_t /* src_slice_pitch */, + size_t /* dst_row_pitch */, + size_t /* dst_slice_pitch */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_1; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueReadImage(cl_command_queue /* command_queue */, + cl_mem /* image */, + cl_bool /* blocking_read */, + const size_t * /* origin[3] */, + const size_t * /* region[3] */, + size_t /* row_pitch */, + size_t /* slice_pitch */, + void * /* ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueWriteImage(cl_command_queue /* command_queue */, + cl_mem /* image */, + cl_bool /* blocking_write */, + const size_t * /* origin[3] */, + const size_t * /* region[3] */, + size_t /* input_row_pitch */, + size_t /* input_slice_pitch */, + const void * /* ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueFillImage(cl_command_queue /* command_queue */, + cl_mem /* image */, + const void * /* fill_color */, + const size_t * /* origin[3] */, + const size_t * /* region[3] */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueCopyImage(cl_command_queue /* command_queue */, + cl_mem /* src_image */, + cl_mem /* dst_image */, + const size_t * /* src_origin[3] */, + const size_t * /* dst_origin[3] */, + const size_t * /* region[3] */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueCopyImageToBuffer(cl_command_queue /* command_queue */, + cl_mem /* src_image */, + cl_mem /* dst_buffer */, + const size_t * /* src_origin[3] */, + const size_t * /* region[3] */, + size_t /* dst_offset */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueCopyBufferToImage(cl_command_queue /* command_queue */, + cl_mem /* src_buffer */, + cl_mem /* dst_image */, + size_t /* src_offset */, + const size_t * /* dst_origin[3] */, + const size_t * /* region[3] */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY void * CL_API_CALL +clEnqueueMapBuffer(cl_command_queue /* command_queue */, + cl_mem /* buffer */, + cl_bool /* blocking_map */, + cl_map_flags /* map_flags */, + size_t /* offset */, + size_t /* size */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY void * CL_API_CALL +clEnqueueMapImage(cl_command_queue /* command_queue */, + cl_mem /* image */, + cl_bool /* blocking_map */, + cl_map_flags /* map_flags */, + const size_t * /* origin[3] */, + const size_t * /* region[3] */, + size_t * /* image_row_pitch */, + size_t * /* image_slice_pitch */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueUnmapMemObject(cl_command_queue /* command_queue */, + cl_mem /* memobj */, + void * /* mapped_ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueMigrateMemObjects(cl_command_queue /* command_queue */, + cl_uint /* num_mem_objects */, + const cl_mem * /* mem_objects */, + cl_mem_migration_flags /* flags */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueNDRangeKernel(cl_command_queue /* command_queue */, + cl_kernel /* kernel */, + cl_uint /* work_dim */, + const size_t * /* global_work_offset */, + const size_t * /* global_work_size */, + const size_t * /* local_work_size */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueTask(cl_command_queue /* command_queue */, + cl_kernel /* kernel */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueNativeKernel(cl_command_queue /* command_queue */, + void (CL_CALLBACK * /*user_func*/)(void *), + void * /* args */, + size_t /* cb_args */, + cl_uint /* num_mem_objects */, + const cl_mem * /* mem_list */, + const void ** /* args_mem_loc */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueMarkerWithWaitList(cl_command_queue /* command_queue */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueBarrierWithWaitList(cl_command_queue /* command_queue */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_2; + + +/* Extension function access + * + * Returns the extension function address for the given function name, + * or NULL if a valid function can not be found. The client must + * check to make sure the address is not NULL, before using or + * calling the returned function address. + */ +extern CL_API_ENTRY void * CL_API_CALL +clGetExtensionFunctionAddressForPlatform(cl_platform_id /* platform */, + const char * /* func_name */) CL_API_SUFFIX__VERSION_1_2; + + +/* Deprecated OpenCL 1.1 APIs */ +extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_mem CL_API_CALL +clCreateImage2D(cl_context /* context */, + cl_mem_flags /* flags */, + const cl_image_format * /* image_format */, + size_t /* image_width */, + size_t /* image_height */, + size_t /* image_row_pitch */, + void * /* host_ptr */, + cl_int * /* errcode_ret */) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; + +extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_mem CL_API_CALL +clCreateImage3D(cl_context /* context */, + cl_mem_flags /* flags */, + const cl_image_format * /* image_format */, + size_t /* image_width */, + size_t /* image_height */, + size_t /* image_depth */, + size_t /* image_row_pitch */, + size_t /* image_slice_pitch */, + void * /* host_ptr */, + cl_int * /* errcode_ret */) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; + +extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_int CL_API_CALL +clEnqueueMarker(cl_command_queue /* command_queue */, + cl_event * /* event */) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; + +extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_int CL_API_CALL +clEnqueueWaitForEvents(cl_command_queue /* command_queue */, + cl_uint /* num_events */, + const cl_event * /* event_list */) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; + +extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_int CL_API_CALL +clEnqueueBarrier(cl_command_queue /* command_queue */) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; + +extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_int CL_API_CALL +clUnloadCompiler(void) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; + +extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED void * CL_API_CALL +clGetExtensionFunctionAddress(const char * /* func_name */) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; + +#ifdef __cplusplus +} +#endif + +#endif /* __OPENCL_CL_H */ + diff --git a/includes/CL/cl.hpp b/includes/CL/cl.hpp new file mode 100644 index 0000000..3b456b7 --- /dev/null +++ b/includes/CL/cl.hpp @@ -0,0 +1,12906 @@ +/******************************************************************************* + * Copyright (c) 2008-2015 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Materials. + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + ******************************************************************************/ + +/*! \file + * + * \brief C++ bindings for OpenCL 1.0 (rev 48), OpenCL 1.1 (rev 33) and + * OpenCL 1.2 (rev 15) + * \author Benedict R. Gaster, Laurent Morichetti and Lee Howes + * + * Additions and fixes from: + * Brian Cole, March 3rd 2010 and April 2012 + * Matt Gruenke, April 2012. + * Bruce Merry, February 2013. + * Tom Deakin and Simon McIntosh-Smith, July 2013 + * + * \version 1.2.7 + * \date January 2015 + * + * Optional extension support + * + * cl + * cl_ext_device_fission + * #define USE_CL_DEVICE_FISSION + */ + +/*! \mainpage + * \section intro Introduction + * 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 cl.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 cl.hpp. + * + * The bindings themselves are lightweight and correspond closely to the + * underlying C API. Using the C++ bindings introduces no additional execution + * overhead. + * + * For detail documentation on the bindings see: + * + * The OpenCL C++ Wrapper API 1.2 (revision 09) + * http://www.khronos.org/registry/cl/specs/opencl-cplusplus-1.2.pdf + * + * \section example Example + * + * The following example shows a general use case for the C++ + * bindings, including support for the optional exception feature and + * also the supplied vector and string classes, see following sections for + * decriptions of these features. + * + * \code + * #define __CL_ENABLE_EXCEPTIONS + * + * #if defined(__APPLE__) || defined(__MACOSX) + * #include + * #else + * #include + * #endif + * #include + * #include + * #include + * + * const char * helloStr = "__kernel void " + * "hello(void) " + * "{ " + * " " + * "} "; + * + * int + * main(void) + * { + * cl_int err = CL_SUCCESS; + * try { + * + * std::vector platforms; + * cl::Platform::get(&platforms); + * if (platforms.size() == 0) { + * std::cout << "Platform size 0\n"; + * return -1; + * } + * + * cl_context_properties properties[] = + * { CL_CONTEXT_PLATFORM, (cl_context_properties)(platforms[0])(), 0}; + * cl::Context context(CL_DEVICE_TYPE_CPU, properties); + * + * std::vector devices = context.getInfo(); + * + * cl::Program::Sources source(1, + * std::make_pair(helloStr,strlen(helloStr))); + * cl::Program program_ = cl::Program(context, source); + * program_.build(devices); + * + * cl::Kernel kernel(program_, "hello", &err); + * + * cl::Event event; + * cl::CommandQueue queue(context, devices[0], 0, &err); + * queue.enqueueNDRangeKernel( + * kernel, + * cl::NullRange, + * cl::NDRange(4,4), + * cl::NullRange, + * NULL, + * &event); + * + * event.wait(); + * } + * catch (cl::Error err) { + * std::cerr + * << "ERROR: " + * << err.what() + * << "(" + * << err.err() + * << ")" + * << std::endl; + * } + * + * return EXIT_SUCCESS; + * } + * + * \endcode + * + */ +#ifndef CL_HPP_ +#define CL_HPP_ + +#ifdef _WIN32 + +#include + +#if defined(USE_DX_INTEROP) +#include +#include +#endif +#endif // _WIN32 + +#if defined(_MSC_VER) +#include +#endif // _MSC_VER + +// +#if defined(USE_CL_DEVICE_FISSION) +#include +#endif + +#if defined(__APPLE__) || defined(__MACOSX) +#include +#else +#include +#endif // !__APPLE__ + +#if (_MSC_VER >= 1700) || (__cplusplus >= 201103L) +#define CL_HPP_RVALUE_REFERENCES_SUPPORTED +#define CL_HPP_CPP11_ATOMICS_SUPPORTED +#include +#endif + +#if (__cplusplus >= 201103L) +#define CL_HPP_NOEXCEPT noexcept +#else +#define CL_HPP_NOEXCEPT +#endif + + +// To avoid accidentally taking ownership of core OpenCL types +// such as cl_kernel constructors are made explicit +// under OpenCL 1.2 +#if defined(CL_VERSION_1_2) && !defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) +#define __CL_EXPLICIT_CONSTRUCTORS explicit +#else // #if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) +#define __CL_EXPLICIT_CONSTRUCTORS +#endif // #if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + +// 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_CALLBACK) +#define CL_CALLBACK +#endif //CL_CALLBACK + +#include +#include +#include + +#if defined(__CL_ENABLE_EXCEPTIONS) +#include +#endif // #if defined(__CL_ENABLE_EXCEPTIONS) + +#if !defined(__NO_STD_VECTOR) +#include +#endif + +#if !defined(__NO_STD_STRING) +#include +#endif + +#if defined(__ANDROID__) || defined(linux) || defined(__APPLE__) || defined(__MACOSX) +#include +#endif // linux + +#include + + +/*! \namespace cl + * + * \brief The OpenCL C++ bindings are defined within this namespace. + * + */ +namespace cl { + +class Memory; + +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) +#define __INIT_CL_EXT_FCN_PTR(name) \ + if(!pfn_##name) { \ + pfn_##name = (PFN_##name) \ + clGetExtensionFunctionAddress(#name); \ + if(!pfn_##name) { \ + } \ + } +#endif // #if defined(CL_VERSION_1_1) + +#if defined(CL_VERSION_1_2) +#define __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, name) \ + if(!pfn_##name) { \ + pfn_##name = (PFN_##name) \ + clGetExtensionFunctionAddressForPlatform(platform, #name); \ + if(!pfn_##name) { \ + } \ + } +#endif // #if defined(CL_VERSION_1_1) + +class Program; +class Device; +class Context; +class CommandQueue; +class Memory; +class Buffer; + +#if defined(__CL_ENABLE_EXCEPTIONS) +/*! \brief Exception class + * + * This may be thrown by API functions when __CL_ENABLE_EXCEPTIONS is defined. + */ +class Error : public std::exception +{ +private: + cl_int err_; + const char * errStr_; +public: + /*! \brief Create a new CL error exception for a given error code + * and corresponding message. + * + * \param err error code value. + * + * \param errStr a descriptive string that must remain in scope until + * handling of the exception has concluded. If set, it + * will be returned by what(). + */ + Error(cl_int err, const char * errStr = NULL) : err_(err), errStr_(errStr) + {} + + ~Error() throw() {} + + /*! \brief Get error string associated with exception + * + * \return A memory pointer to the error message string. + */ + virtual const char * what() const throw () + { + if (errStr_ == NULL) { + return "empty"; + } + else { + return errStr_; + } + } + + /*! \brief Get error code associated with exception + * + * \return The error code. + */ + cl_int err(void) const { return err_; } +}; + +#define __ERR_STR(x) #x +#else +#define __ERR_STR(x) NULL +#endif // __CL_ENABLE_EXCEPTIONS + + +namespace detail +{ +#if defined(__CL_ENABLE_EXCEPTIONS) +static inline cl_int errHandler ( + cl_int err, + const char * errStr = NULL) +{ + if (err != CL_SUCCESS) { + throw Error(err, errStr); + } + return err; +} +#else +static inline cl_int errHandler (cl_int err, const char * errStr = NULL) +{ + (void) errStr; // suppress unused variable warning + return err; +} +#endif // __CL_ENABLE_EXCEPTIONS +} + + + +//! \cond DOXYGEN_DETAIL +#if !defined(__CL_USER_OVERRIDE_ERROR_STRINGS) +#define __GET_DEVICE_INFO_ERR __ERR_STR(clGetDeviceInfo) +#define __GET_PLATFORM_INFO_ERR __ERR_STR(clGetPlatformInfo) +#define __GET_DEVICE_IDS_ERR __ERR_STR(clGetDeviceIDs) +#define __GET_PLATFORM_IDS_ERR __ERR_STR(clGetPlatformIDs) +#define __GET_CONTEXT_INFO_ERR __ERR_STR(clGetContextInfo) +#define __GET_EVENT_INFO_ERR __ERR_STR(clGetEventInfo) +#define __GET_EVENT_PROFILE_INFO_ERR __ERR_STR(clGetEventProfileInfo) +#define __GET_MEM_OBJECT_INFO_ERR __ERR_STR(clGetMemObjectInfo) +#define __GET_IMAGE_INFO_ERR __ERR_STR(clGetImageInfo) +#define __GET_SAMPLER_INFO_ERR __ERR_STR(clGetSamplerInfo) +#define __GET_KERNEL_INFO_ERR __ERR_STR(clGetKernelInfo) +#if defined(CL_VERSION_1_2) +#define __GET_KERNEL_ARG_INFO_ERR __ERR_STR(clGetKernelArgInfo) +#endif // #if defined(CL_VERSION_1_2) +#define __GET_KERNEL_WORK_GROUP_INFO_ERR __ERR_STR(clGetKernelWorkGroupInfo) +#define __GET_PROGRAM_INFO_ERR __ERR_STR(clGetProgramInfo) +#define __GET_PROGRAM_BUILD_INFO_ERR __ERR_STR(clGetProgramBuildInfo) +#define __GET_COMMAND_QUEUE_INFO_ERR __ERR_STR(clGetCommandQueueInfo) + +#define __CREATE_CONTEXT_ERR __ERR_STR(clCreateContext) +#define __CREATE_CONTEXT_FROM_TYPE_ERR __ERR_STR(clCreateContextFromType) +#define __GET_SUPPORTED_IMAGE_FORMATS_ERR __ERR_STR(clGetSupportedImageFormats) + +#define __CREATE_BUFFER_ERR __ERR_STR(clCreateBuffer) +#define __COPY_ERR __ERR_STR(cl::copy) +#define __CREATE_SUBBUFFER_ERR __ERR_STR(clCreateSubBuffer) +#define __CREATE_GL_BUFFER_ERR __ERR_STR(clCreateFromGLBuffer) +#define __CREATE_GL_RENDER_BUFFER_ERR __ERR_STR(clCreateFromGLBuffer) +#define __GET_GL_OBJECT_INFO_ERR __ERR_STR(clGetGLObjectInfo) +#if defined(CL_VERSION_1_2) +#define __CREATE_IMAGE_ERR __ERR_STR(clCreateImage) +#define __CREATE_GL_TEXTURE_ERR __ERR_STR(clCreateFromGLTexture) +#define __IMAGE_DIMENSION_ERR __ERR_STR(Incorrect image dimensions) +#endif // #if defined(CL_VERSION_1_2) +#define __CREATE_SAMPLER_ERR __ERR_STR(clCreateSampler) +#define __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR __ERR_STR(clSetMemObjectDestructorCallback) + +#define __CREATE_USER_EVENT_ERR __ERR_STR(clCreateUserEvent) +#define __SET_USER_EVENT_STATUS_ERR __ERR_STR(clSetUserEventStatus) +#define __SET_EVENT_CALLBACK_ERR __ERR_STR(clSetEventCallback) +#define __WAIT_FOR_EVENTS_ERR __ERR_STR(clWaitForEvents) + +#define __CREATE_KERNEL_ERR __ERR_STR(clCreateKernel) +#define __SET_KERNEL_ARGS_ERR __ERR_STR(clSetKernelArg) +#define __CREATE_PROGRAM_WITH_SOURCE_ERR __ERR_STR(clCreateProgramWithSource) +#define __CREATE_PROGRAM_WITH_BINARY_ERR __ERR_STR(clCreateProgramWithBinary) +#if defined(CL_VERSION_1_2) +#define __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR __ERR_STR(clCreateProgramWithBuiltInKernels) +#endif // #if defined(CL_VERSION_1_2) +#define __BUILD_PROGRAM_ERR __ERR_STR(clBuildProgram) +#if defined(CL_VERSION_1_2) +#define __COMPILE_PROGRAM_ERR __ERR_STR(clCompileProgram) +#define __LINK_PROGRAM_ERR __ERR_STR(clLinkProgram) +#endif // #if defined(CL_VERSION_1_2) +#define __CREATE_KERNELS_IN_PROGRAM_ERR __ERR_STR(clCreateKernelsInProgram) + +#define __CREATE_COMMAND_QUEUE_ERR __ERR_STR(clCreateCommandQueue) +#define __SET_COMMAND_QUEUE_PROPERTY_ERR __ERR_STR(clSetCommandQueueProperty) +#define __ENQUEUE_READ_BUFFER_ERR __ERR_STR(clEnqueueReadBuffer) +#define __ENQUEUE_READ_BUFFER_RECT_ERR __ERR_STR(clEnqueueReadBufferRect) +#define __ENQUEUE_WRITE_BUFFER_ERR __ERR_STR(clEnqueueWriteBuffer) +#define __ENQUEUE_WRITE_BUFFER_RECT_ERR __ERR_STR(clEnqueueWriteBufferRect) +#define __ENQEUE_COPY_BUFFER_ERR __ERR_STR(clEnqueueCopyBuffer) +#define __ENQEUE_COPY_BUFFER_RECT_ERR __ERR_STR(clEnqueueCopyBufferRect) +#define __ENQUEUE_FILL_BUFFER_ERR __ERR_STR(clEnqueueFillBuffer) +#define __ENQUEUE_READ_IMAGE_ERR __ERR_STR(clEnqueueReadImage) +#define __ENQUEUE_WRITE_IMAGE_ERR __ERR_STR(clEnqueueWriteImage) +#define __ENQUEUE_COPY_IMAGE_ERR __ERR_STR(clEnqueueCopyImage) +#define __ENQUEUE_FILL_IMAGE_ERR __ERR_STR(clEnqueueFillImage) +#define __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR __ERR_STR(clEnqueueCopyImageToBuffer) +#define __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR __ERR_STR(clEnqueueCopyBufferToImage) +#define __ENQUEUE_MAP_BUFFER_ERR __ERR_STR(clEnqueueMapBuffer) +#define __ENQUEUE_MAP_IMAGE_ERR __ERR_STR(clEnqueueMapImage) +#define __ENQUEUE_UNMAP_MEM_OBJECT_ERR __ERR_STR(clEnqueueUnMapMemObject) +#define __ENQUEUE_NDRANGE_KERNEL_ERR __ERR_STR(clEnqueueNDRangeKernel) +#define __ENQUEUE_TASK_ERR __ERR_STR(clEnqueueTask) +#define __ENQUEUE_NATIVE_KERNEL __ERR_STR(clEnqueueNativeKernel) +#if defined(CL_VERSION_1_2) +#define __ENQUEUE_MIGRATE_MEM_OBJECTS_ERR __ERR_STR(clEnqueueMigrateMemObjects) +#endif // #if defined(CL_VERSION_1_2) + +#define __ENQUEUE_ACQUIRE_GL_ERR __ERR_STR(clEnqueueAcquireGLObjects) +#define __ENQUEUE_RELEASE_GL_ERR __ERR_STR(clEnqueueReleaseGLObjects) + + +#define __RETAIN_ERR __ERR_STR(Retain Object) +#define __RELEASE_ERR __ERR_STR(Release Object) +#define __FLUSH_ERR __ERR_STR(clFlush) +#define __FINISH_ERR __ERR_STR(clFinish) +#define __VECTOR_CAPACITY_ERR __ERR_STR(Vector capacity error) + +/** + * CL 1.2 version that uses device fission. + */ +#if defined(CL_VERSION_1_2) +#define __CREATE_SUB_DEVICES __ERR_STR(clCreateSubDevices) +#else +#define __CREATE_SUB_DEVICES __ERR_STR(clCreateSubDevicesEXT) +#endif // #if defined(CL_VERSION_1_2) + +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) +#define __ENQUEUE_MARKER_ERR __ERR_STR(clEnqueueMarker) +#define __ENQUEUE_WAIT_FOR_EVENTS_ERR __ERR_STR(clEnqueueWaitForEvents) +#define __ENQUEUE_BARRIER_ERR __ERR_STR(clEnqueueBarrier) +#define __UNLOAD_COMPILER_ERR __ERR_STR(clUnloadCompiler) +#define __CREATE_GL_TEXTURE_2D_ERR __ERR_STR(clCreateFromGLTexture2D) +#define __CREATE_GL_TEXTURE_3D_ERR __ERR_STR(clCreateFromGLTexture3D) +#define __CREATE_IMAGE2D_ERR __ERR_STR(clCreateImage2D) +#define __CREATE_IMAGE3D_ERR __ERR_STR(clCreateImage3D) +#endif // #if defined(CL_VERSION_1_1) + +#endif // __CL_USER_OVERRIDE_ERROR_STRINGS +//! \endcond + +/** + * CL 1.2 marker and barrier commands + */ +#if defined(CL_VERSION_1_2) +#define __ENQUEUE_MARKER_WAIT_LIST_ERR __ERR_STR(clEnqueueMarkerWithWaitList) +#define __ENQUEUE_BARRIER_WAIT_LIST_ERR __ERR_STR(clEnqueueBarrierWithWaitList) +#endif // #if defined(CL_VERSION_1_2) + +#if !defined(__USE_DEV_STRING) && !defined(__NO_STD_STRING) +typedef std::string STRING_CLASS; +#elif !defined(__USE_DEV_STRING) + +/*! \class string + * \brief Simple string class, that provides a limited subset of std::string + * functionality but avoids many of the issues that come with that class. + + * \note Deprecated. Please use std::string as default or + * re-define the string class to match the std::string + * interface by defining STRING_CLASS + */ +class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED string CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED +{ +private: + ::size_t size_; + char * str_; +public: + //! \brief Constructs an empty string, allocating no memory. + string(void) : size_(0), str_(NULL) + { + } + + /*! \brief Constructs a string populated from an arbitrary value of + * specified size. + * + * An extra '\0' is added, in case none was contained in str. + * + * \param str the initial value of the string instance. Note that '\0' + * characters receive no special treatment. If NULL, + * the string is left empty, with a size of 0. + * + * \param size the number of characters to copy from str. + */ + string(const char * str, ::size_t size) : + size_(size), + str_(NULL) + { + if( size > 0 ) { + str_ = new char[size_+1]; + if (str_ != NULL) { + memcpy(str_, str, size_ * sizeof(char)); + str_[size_] = '\0'; + } + else { + size_ = 0; + } + } + } + + /*! \brief Constructs a string populated from a null-terminated value. + * + * \param str the null-terminated initial value of the string instance. + * If NULL, the string is left empty, with a size of 0. + */ + string(const char * str) : + size_(0), + str_(NULL) + { + if( str ) { + size_= ::strlen(str); + } + if( size_ > 0 ) { + str_ = new char[size_ + 1]; + if (str_ != NULL) { + memcpy(str_, str, (size_ + 1) * sizeof(char)); + } + } + } + + void resize( ::size_t n ) + { + if( size_ == n ) { + return; + } + if (n == 0) { + if( str_ ) { + delete [] str_; + } + str_ = NULL; + size_ = 0; + } + else { + char *newString = new char[n + 1]; + ::size_t copySize = n; + if( size_ < n ) { + copySize = size_; + } + size_ = n; + + if(str_) { + memcpy(newString, str_, (copySize + 1) * sizeof(char)); + } + if( copySize < size_ ) { + memset(newString + copySize, 0, size_ - copySize); + } + newString[size_] = '\0'; + + delete [] str_; + str_ = newString; + } + } + + const char& operator[] ( ::size_t pos ) const + { + return str_[pos]; + } + + char& operator[] ( ::size_t pos ) + { + return str_[pos]; + } + + /*! \brief Copies the value of another string to this one. + * + * \param rhs the string to copy. + * + * \returns a reference to the modified instance. + */ + string& operator=(const string& rhs) + { + if (this == &rhs) { + return *this; + } + + if( str_ != NULL ) { + delete [] str_; + str_ = NULL; + size_ = 0; + } + + if (rhs.size_ == 0 || rhs.str_ == NULL) { + str_ = NULL; + size_ = 0; + } + else { + str_ = new char[rhs.size_ + 1]; + size_ = rhs.size_; + + if (str_ != NULL) { + memcpy(str_, rhs.str_, (size_ + 1) * sizeof(char)); + } + else { + size_ = 0; + } + } + + return *this; + } + + /*! \brief Constructs a string by copying the value of another instance. + * + * \param rhs the string to copy. + */ + string(const string& rhs) : + size_(0), + str_(NULL) + { + *this = rhs; + } + + //! \brief Destructor - frees memory used to hold the current value. + ~string() + { + delete[] str_; + str_ = NULL; + } + + //! \brief Queries the length of the string, excluding any added '\0's. + ::size_t size(void) const { return size_; } + + //! \brief Queries the length of the string, excluding any added '\0's. + ::size_t length(void) const { return size(); } + + /*! \brief Returns a pointer to the private copy held by this instance, + * or "" if empty/unset. + */ + const char * c_str(void) const { return (str_) ? str_ : "";} +}; +typedef cl::string STRING_CLASS; +#endif // #elif !defined(__USE_DEV_STRING) + +#if !defined(__USE_DEV_VECTOR) && !defined(__NO_STD_VECTOR) +#define VECTOR_CLASS std::vector +#elif !defined(__USE_DEV_VECTOR) +#define VECTOR_CLASS cl::vector + +#if !defined(__MAX_DEFAULT_VECTOR_SIZE) +#define __MAX_DEFAULT_VECTOR_SIZE 10 +#endif + +/*! \class vector + * \brief Fixed sized vector implementation that mirroring + * + * \note Deprecated. Please use std::vector as default or + * re-define the vector class to match the std::vector + * interface by defining VECTOR_CLASS + + * \note Not recommended for use with custom objects as + * current implementation will construct N elements + * + * std::vector functionality. + * \brief Fixed sized vector compatible with std::vector. + * + * \note + * This differs from std::vector<> not just in memory allocation, + * but also in terms of when members are constructed, destroyed, + * and assigned instead of being copy constructed. + * + * \param T type of element contained in the vector. + * + * \param N maximum size of the vector. + */ +template +class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED vector +{ +private: + T data_[N]; + unsigned int size_; + +public: + //! \brief Constructs an empty vector with no memory allocated. + vector() : + size_(static_cast(0)) + {} + + //! \brief Deallocates the vector's memory and destroys all of its elements. + ~vector() + { + clear(); + } + + //! \brief Returns the number of elements currently contained. + unsigned int size(void) const + { + return size_; + } + + /*! \brief Empties the vector of all elements. + * \note + * This does not deallocate memory but will invoke destructors + * on contained elements. + */ + void clear() + { + while(!empty()) { + pop_back(); + } + } + + /*! \brief Appends an element after the last valid element. + * Calling this on a vector that has reached capacity will throw an + * exception if exceptions are enabled. + */ + void push_back (const T& x) + { + if (size() < N) { + new (&data_[size_]) T(x); + size_++; + } else { + detail::errHandler(CL_MEM_OBJECT_ALLOCATION_FAILURE, __VECTOR_CAPACITY_ERR); + } + } + + /*! \brief Removes the last valid element from the vector. + * Calling this on an empty vector will throw an exception + * if exceptions are enabled. + */ + void pop_back(void) + { + if (size_ != 0) { + --size_; + data_[size_].~T(); + } else { + detail::errHandler(CL_MEM_OBJECT_ALLOCATION_FAILURE, __VECTOR_CAPACITY_ERR); + } + } + + /*! \brief Constructs with a value copied from another. + * + * \param vec the vector to copy. + */ + vector(const vector& vec) : + size_(vec.size_) + { + if (size_ != 0) { + assign(vec.begin(), vec.end()); + } + } + + /*! \brief Constructs with a specified number of initial elements. + * + * \param size number of initial elements. + * + * \param val value of initial elements. + */ + vector(unsigned int size, const T& val = T()) : + size_(0) + { + for (unsigned int i = 0; i < size; i++) { + push_back(val); + } + } + + /*! \brief Overwrites the current content with that copied from another + * instance. + * + * \param rhs vector to copy. + * + * \returns a reference to this. + */ + vector& operator=(const vector& rhs) + { + if (this == &rhs) { + return *this; + } + + if (rhs.size_ != 0) { + assign(rhs.begin(), rhs.end()); + } else { + clear(); + } + + return *this; + } + + /*! \brief Tests equality against another instance. + * + * \param vec the vector against which to compare. + */ + bool operator==(vector &vec) + { + if (size() != vec.size()) { + return false; + } + + for( unsigned int i = 0; i < size(); ++i ) { + if( operator[](i) != vec[i] ) { + return false; + } + } + return true; + } + + //! \brief Conversion operator to T*. + operator T* () { return data_; } + + //! \brief Conversion operator to const T*. + operator const T* () const { return data_; } + + //! \brief Tests whether this instance has any elements. + bool empty (void) const + { + return size_==0; + } + + //! \brief Returns the maximum number of elements this instance can hold. + unsigned int max_size (void) const + { + return N; + } + + //! \brief Returns the maximum number of elements this instance can hold. + unsigned int capacity () const + { + return N; + } + + //! \brief Resizes the vector to the given size + void resize(unsigned int newSize, T fill = T()) + { + if (newSize > N) + { + detail::errHandler(CL_MEM_OBJECT_ALLOCATION_FAILURE, __VECTOR_CAPACITY_ERR); + } + else + { + while (size_ < newSize) + { + new (&data_[size_]) T(fill); + size_++; + } + while (size_ > newSize) + { + --size_; + data_[size_].~T(); + } + } + } + + /*! \brief Returns a reference to a given element. + * + * \param index which element to access. * + * \note + * The caller is responsible for ensuring index is >= 0 and < size(). + */ + T& operator[](int index) + { + return data_[index]; + } + + /*! \brief Returns a const reference to a given element. + * + * \param index which element to access. + * + * \note + * The caller is responsible for ensuring index is >= 0 and < size(). + */ + const T& operator[](int index) const + { + return data_[index]; + } + + /*! \brief Assigns elements of the vector based on a source iterator range. + * + * \param start Beginning iterator of source range + * \param end Enditerator of source range + * + * \note + * Will throw an exception if exceptions are enabled and size exceeded. + */ + template + void assign(I start, I end) + { + clear(); + while(start != end) { + push_back(*start); + start++; + } + } + + /*! \class iterator + * \brief Const iterator class for vectors + */ + class iterator + { + private: + const vector *vec_; + int index_; + + /** + * Internal iterator constructor to capture reference + * to the vector it iterates over rather than taking + * the vector by copy. + */ + iterator (const vector &vec, int index) : + vec_(&vec) + { + if( !vec.empty() ) { + index_ = index; + } else { + index_ = -1; + } + } + + public: + iterator(void) : + index_(-1), + vec_(NULL) + { + } + + iterator(const iterator& rhs) : + vec_(rhs.vec_), + index_(rhs.index_) + { + } + + ~iterator(void) {} + + static iterator begin(const cl::vector &vec) + { + iterator i(vec, 0); + + return i; + } + + static iterator end(const cl::vector &vec) + { + iterator i(vec, vec.size()); + + return i; + } + + bool operator==(iterator i) + { + return ((vec_ == i.vec_) && + (index_ == i.index_)); + } + + bool operator!=(iterator i) + { + return (!(*this==i)); + } + + iterator& operator++() + { + ++index_; + return *this; + } + + iterator operator++(int) + { + iterator retVal(*this); + ++index_; + return retVal; + } + + iterator& operator--() + { + --index_; + return *this; + } + + iterator operator--(int) + { + iterator retVal(*this); + --index_; + return retVal; + } + + const T& operator *() const + { + return (*vec_)[index_]; + } + }; + + iterator begin(void) + { + return iterator::begin(*this); + } + + iterator begin(void) const + { + return iterator::begin(*this); + } + + iterator end(void) + { + return iterator::end(*this); + } + + iterator end(void) const + { + return iterator::end(*this); + } + + T& front(void) + { + return data_[0]; + } + + T& back(void) + { + return data_[size_]; + } + + const T& front(void) const + { + return data_[0]; + } + + const T& back(void) const + { + return data_[size_-1]; + } +} CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; +#endif // #if !defined(__USE_DEV_VECTOR) && !defined(__NO_STD_VECTOR) + + + + + +namespace detail { +#define __DEFAULT_NOT_INITIALIZED 1 +#define __DEFAULT_BEING_INITIALIZED 2 +#define __DEFAULT_INITIALIZED 4 + + /* + * Compare and exchange primitives are needed for handling of defaults + */ + +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED + inline int compare_exchange(std::atomic * dest, int exchange, int comparand) +#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED + inline int compare_exchange(volatile int * dest, int exchange, int comparand) +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED + { +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED + std::atomic_compare_exchange_strong(dest, &comparand, exchange); + return comparand; +#elif _MSC_VER + return (int)(_InterlockedCompareExchange( + (volatile long*)dest, + (long)exchange, + (long)comparand)); +#else // !_MSC_VER && !CL_HPP_CPP11_ATOMICS_SUPPORTED + return (__sync_val_compare_and_swap( + dest, + comparand, + exchange)); +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED + } + + inline void fence() { +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED + std::atomic_thread_fence(std::memory_order_seq_cst); +#elif _MSC_VER // !CL_HPP_CPP11_ATOMICS_SUPPORTED + _ReadWriteBarrier(); +#else // !_MSC_VER && !CL_HPP_CPP11_ATOMICS_SUPPORTED + __sync_synchronize(); +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED + } +} // namespace detail + + +/*! \brief class used to interface between C++ and + * OpenCL C calls that require arrays of size_t values, whose + * size is known statically. + */ +template +class size_t +{ +private: + ::size_t data_[N]; + +public: + //! \brief Initialize size_t to all 0s + size_t() + { + for( int i = 0; i < N; ++i ) { + data_[i] = 0; + } + } + + ::size_t& operator[](int index) + { + return data_[index]; + } + + const ::size_t& operator[](int index) const + { + return data_[index]; + } + + //! \brief Conversion operator to T*. + operator ::size_t* () { return data_; } + + //! \brief Conversion operator to const T*. + operator const ::size_t* () const { return data_; } +}; + +namespace detail { + +// Generic getInfoHelper. The final parameter is used to guide overload +// resolution: the actual parameter passed is an int, which makes this +// a worse conversion sequence than a specialization that declares the +// parameter as an int. +template +inline cl_int getInfoHelper(Functor f, cl_uint name, T* param, long) +{ + return f(name, sizeof(T), param, NULL); +} + +// Specialized getInfoHelper for VECTOR_CLASS params +template +inline cl_int getInfoHelper(Func f, cl_uint name, VECTOR_CLASS* param, long) +{ + ::size_t required; + cl_int err = f(name, 0, NULL, &required); + if (err != CL_SUCCESS) { + return err; + } + + T* value = (T*) alloca(required); + err = f(name, required, value, NULL); + if (err != CL_SUCCESS) { + return err; + } + + param->assign(&value[0], &value[required/sizeof(T)]); + return CL_SUCCESS; +} + +/* Specialization for reference-counted types. This depends on the + * existence of Wrapper::cl_type, and none of the other types having the + * cl_type member. Note that simplify specifying the parameter as Wrapper + * does not work, because when using a derived type (e.g. Context) the generic + * template will provide a better match. + */ +template +inline cl_int getInfoHelper(Func f, cl_uint name, VECTOR_CLASS* param, int, typename T::cl_type = 0) +{ + ::size_t required; + cl_int err = f(name, 0, NULL, &required); + if (err != CL_SUCCESS) { + return err; + } + + typename T::cl_type * value = (typename T::cl_type *) alloca(required); + err = f(name, required, value, NULL); + if (err != CL_SUCCESS) { + return err; + } + + ::size_t elements = required / sizeof(typename T::cl_type); + param->assign(&value[0], &value[elements]); + for (::size_t i = 0; i < elements; i++) + { + if (value[i] != NULL) + { + err = (*param)[i].retain(); + if (err != CL_SUCCESS) { + return err; + } + } + } + return CL_SUCCESS; +} + +// Specialized for getInfo +template +inline cl_int getInfoHelper(Func f, cl_uint name, VECTOR_CLASS* param, int) +{ + cl_int err = f(name, param->size() * sizeof(char *), &(*param)[0], NULL); + + if (err != CL_SUCCESS) { + return err; + } + + return CL_SUCCESS; +} + +// Specialized GetInfoHelper for STRING_CLASS params +template +inline cl_int getInfoHelper(Func f, cl_uint name, STRING_CLASS* param, long) +{ + ::size_t required; + cl_int err = f(name, 0, NULL, &required); + if (err != CL_SUCCESS) { + return err; + } + + // std::string has a constant data member + // a char vector does not + VECTOR_CLASS value(required); + err = f(name, required, value.data(), NULL); + if (err != CL_SUCCESS) { + return err; + } + if (param) { + param->assign(value.begin(), value.end()); + } + return CL_SUCCESS; +} + +// Specialized GetInfoHelper for cl::size_t params +template +inline cl_int getInfoHelper(Func f, cl_uint name, size_t* param, long) +{ + ::size_t required; + cl_int err = f(name, 0, NULL, &required); + if (err != CL_SUCCESS) { + return err; + } + + ::size_t* value = (::size_t*) alloca(required); + err = f(name, required, value, NULL); + if (err != CL_SUCCESS) { + return err; + } + + for(int i = 0; i < N; ++i) { + (*param)[i] = value[i]; + } + + return CL_SUCCESS; +} + +template struct ReferenceHandler; + +/* Specialization for reference-counted types. This depends on the + * existence of Wrapper::cl_type, and none of the other types having the + * cl_type member. Note that simplify specifying the parameter as Wrapper + * does not work, because when using a derived type (e.g. Context) the generic + * template will provide a better match. + */ +template +inline cl_int getInfoHelper(Func f, cl_uint name, T* param, int, typename T::cl_type = 0) +{ + typename T::cl_type value; + cl_int err = f(name, sizeof(value), &value, NULL); + if (err != CL_SUCCESS) { + return err; + } + *param = value; + if (value != NULL) + { + err = param->retain(); + if (err != CL_SUCCESS) { + return err; + } + } + return CL_SUCCESS; +} + +#define __PARAM_NAME_INFO_1_0(F) \ + F(cl_platform_info, CL_PLATFORM_PROFILE, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_VERSION, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_NAME, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_VENDOR, STRING_CLASS) \ + F(cl_platform_info, CL_PLATFORM_EXTENSIONS, STRING_CLASS) \ + \ + F(cl_device_info, CL_DEVICE_TYPE, cl_device_type) \ + F(cl_device_info, CL_DEVICE_VENDOR_ID, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_COMPUTE_UNITS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_WORK_GROUP_SIZE, ::size_t) \ + F(cl_device_info, CL_DEVICE_MAX_WORK_ITEM_SIZES, VECTOR_CLASS< ::size_t>) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_CLOCK_FREQUENCY, cl_uint) \ + F(cl_device_info, CL_DEVICE_ADDRESS_BITS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_READ_IMAGE_ARGS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_WRITE_IMAGE_ARGS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MAX_MEM_ALLOC_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_IMAGE2D_MAX_WIDTH, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE2D_MAX_HEIGHT, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_WIDTH, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_HEIGHT, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_DEPTH, ::size_t) \ + F(cl_device_info, CL_DEVICE_IMAGE_SUPPORT, cl_bool) \ + F(cl_device_info, CL_DEVICE_MAX_PARAMETER_SIZE, ::size_t) \ + F(cl_device_info, CL_DEVICE_MAX_SAMPLERS, cl_uint) \ + F(cl_device_info, CL_DEVICE_MEM_BASE_ADDR_ALIGN, cl_uint) \ + F(cl_device_info, CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE, cl_uint) \ + F(cl_device_info, CL_DEVICE_SINGLE_FP_CONFIG, cl_device_fp_config) \ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHE_TYPE, cl_device_mem_cache_type) \ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE, cl_uint)\ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHE_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_GLOBAL_MEM_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_MAX_CONSTANT_ARGS, cl_uint) \ + F(cl_device_info, CL_DEVICE_LOCAL_MEM_TYPE, cl_device_local_mem_type) \ + F(cl_device_info, CL_DEVICE_LOCAL_MEM_SIZE, cl_ulong) \ + F(cl_device_info, CL_DEVICE_ERROR_CORRECTION_SUPPORT, cl_bool) \ + F(cl_device_info, CL_DEVICE_PROFILING_TIMER_RESOLUTION, ::size_t) \ + F(cl_device_info, CL_DEVICE_ENDIAN_LITTLE, cl_bool) \ + F(cl_device_info, CL_DEVICE_AVAILABLE, cl_bool) \ + F(cl_device_info, CL_DEVICE_COMPILER_AVAILABLE, cl_bool) \ + F(cl_device_info, CL_DEVICE_EXECUTION_CAPABILITIES, cl_device_exec_capabilities) \ + F(cl_device_info, CL_DEVICE_QUEUE_PROPERTIES, cl_command_queue_properties) \ + F(cl_device_info, CL_DEVICE_PLATFORM, cl_platform_id) \ + F(cl_device_info, CL_DEVICE_NAME, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_VENDOR, STRING_CLASS) \ + F(cl_device_info, CL_DRIVER_VERSION, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_PROFILE, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_VERSION, STRING_CLASS) \ + F(cl_device_info, CL_DEVICE_EXTENSIONS, STRING_CLASS) \ + \ + F(cl_context_info, CL_CONTEXT_REFERENCE_COUNT, cl_uint) \ + F(cl_context_info, CL_CONTEXT_DEVICES, VECTOR_CLASS) \ + F(cl_context_info, CL_CONTEXT_PROPERTIES, VECTOR_CLASS) \ + \ + F(cl_event_info, CL_EVENT_COMMAND_QUEUE, cl::CommandQueue) \ + F(cl_event_info, CL_EVENT_COMMAND_TYPE, cl_command_type) \ + F(cl_event_info, CL_EVENT_REFERENCE_COUNT, cl_uint) \ + F(cl_event_info, CL_EVENT_COMMAND_EXECUTION_STATUS, cl_int) \ + \ + F(cl_profiling_info, CL_PROFILING_COMMAND_QUEUED, cl_ulong) \ + F(cl_profiling_info, CL_PROFILING_COMMAND_SUBMIT, cl_ulong) \ + F(cl_profiling_info, CL_PROFILING_COMMAND_START, cl_ulong) \ + F(cl_profiling_info, CL_PROFILING_COMMAND_END, cl_ulong) \ + \ + F(cl_mem_info, CL_MEM_TYPE, cl_mem_object_type) \ + F(cl_mem_info, CL_MEM_FLAGS, cl_mem_flags) \ + F(cl_mem_info, CL_MEM_SIZE, ::size_t) \ + F(cl_mem_info, CL_MEM_HOST_PTR, void*) \ + F(cl_mem_info, CL_MEM_MAP_COUNT, cl_uint) \ + F(cl_mem_info, CL_MEM_REFERENCE_COUNT, cl_uint) \ + F(cl_mem_info, CL_MEM_CONTEXT, cl::Context) \ + \ + F(cl_image_info, CL_IMAGE_FORMAT, cl_image_format) \ + F(cl_image_info, CL_IMAGE_ELEMENT_SIZE, ::size_t) \ + F(cl_image_info, CL_IMAGE_ROW_PITCH, ::size_t) \ + F(cl_image_info, CL_IMAGE_SLICE_PITCH, ::size_t) \ + F(cl_image_info, CL_IMAGE_WIDTH, ::size_t) \ + F(cl_image_info, CL_IMAGE_HEIGHT, ::size_t) \ + F(cl_image_info, CL_IMAGE_DEPTH, ::size_t) \ + \ + F(cl_sampler_info, CL_SAMPLER_REFERENCE_COUNT, cl_uint) \ + F(cl_sampler_info, CL_SAMPLER_CONTEXT, cl::Context) \ + F(cl_sampler_info, CL_SAMPLER_NORMALIZED_COORDS, cl_addressing_mode) \ + F(cl_sampler_info, CL_SAMPLER_ADDRESSING_MODE, cl_filter_mode) \ + F(cl_sampler_info, CL_SAMPLER_FILTER_MODE, cl_bool) \ + \ + F(cl_program_info, CL_PROGRAM_REFERENCE_COUNT, cl_uint) \ + F(cl_program_info, CL_PROGRAM_CONTEXT, cl::Context) \ + F(cl_program_info, CL_PROGRAM_NUM_DEVICES, cl_uint) \ + F(cl_program_info, CL_PROGRAM_DEVICES, VECTOR_CLASS) \ + F(cl_program_info, CL_PROGRAM_SOURCE, STRING_CLASS) \ + F(cl_program_info, CL_PROGRAM_BINARY_SIZES, VECTOR_CLASS< ::size_t>) \ + F(cl_program_info, CL_PROGRAM_BINARIES, VECTOR_CLASS) \ + \ + F(cl_program_build_info, CL_PROGRAM_BUILD_STATUS, cl_build_status) \ + F(cl_program_build_info, CL_PROGRAM_BUILD_OPTIONS, STRING_CLASS) \ + F(cl_program_build_info, CL_PROGRAM_BUILD_LOG, STRING_CLASS) \ + \ + F(cl_kernel_info, CL_KERNEL_FUNCTION_NAME, STRING_CLASS) \ + F(cl_kernel_info, CL_KERNEL_NUM_ARGS, cl_uint) \ + F(cl_kernel_info, CL_KERNEL_REFERENCE_COUNT, cl_uint) \ + F(cl_kernel_info, CL_KERNEL_CONTEXT, cl::Context) \ + F(cl_kernel_info, CL_KERNEL_PROGRAM, cl::Program) \ + \ + F(cl_kernel_work_group_info, CL_KERNEL_WORK_GROUP_SIZE, ::size_t) \ + F(cl_kernel_work_group_info, CL_KERNEL_COMPILE_WORK_GROUP_SIZE, cl::size_t<3>) \ + F(cl_kernel_work_group_info, CL_KERNEL_LOCAL_MEM_SIZE, cl_ulong) \ + \ + F(cl_command_queue_info, CL_QUEUE_CONTEXT, cl::Context) \ + F(cl_command_queue_info, CL_QUEUE_DEVICE, cl::Device) \ + F(cl_command_queue_info, CL_QUEUE_REFERENCE_COUNT, cl_uint) \ + F(cl_command_queue_info, CL_QUEUE_PROPERTIES, cl_command_queue_properties) + +#if defined(CL_VERSION_1_1) +#define __PARAM_NAME_INFO_1_1(F) \ + F(cl_context_info, CL_CONTEXT_NUM_DEVICES, cl_uint)\ + F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_INT, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE, cl_uint) \ + F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF, cl_uint) \ + F(cl_device_info, CL_DEVICE_DOUBLE_FP_CONFIG, cl_device_fp_config) \ + F(cl_device_info, CL_DEVICE_HALF_FP_CONFIG, cl_device_fp_config) \ + F(cl_device_info, CL_DEVICE_HOST_UNIFIED_MEMORY, cl_bool) \ + F(cl_device_info, CL_DEVICE_OPENCL_C_VERSION, STRING_CLASS) \ + \ + F(cl_mem_info, CL_MEM_ASSOCIATED_MEMOBJECT, cl::Memory) \ + F(cl_mem_info, CL_MEM_OFFSET, ::size_t) \ + \ + F(cl_kernel_work_group_info, CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, ::size_t) \ + F(cl_kernel_work_group_info, CL_KERNEL_PRIVATE_MEM_SIZE, cl_ulong) \ + \ + F(cl_event_info, CL_EVENT_CONTEXT, cl::Context) +#endif // CL_VERSION_1_1 + + +#if defined(CL_VERSION_1_2) +#define __PARAM_NAME_INFO_1_2(F) \ + F(cl_image_info, CL_IMAGE_BUFFER, cl::Buffer) \ + \ + F(cl_program_info, CL_PROGRAM_NUM_KERNELS, ::size_t) \ + F(cl_program_info, CL_PROGRAM_KERNEL_NAMES, STRING_CLASS) \ + \ + F(cl_program_build_info, CL_PROGRAM_BINARY_TYPE, cl_program_binary_type) \ + \ + F(cl_kernel_info, CL_KERNEL_ATTRIBUTES, STRING_CLASS) \ + \ + F(cl_kernel_arg_info, CL_KERNEL_ARG_ADDRESS_QUALIFIER, cl_kernel_arg_address_qualifier) \ + F(cl_kernel_arg_info, CL_KERNEL_ARG_ACCESS_QUALIFIER, cl_kernel_arg_access_qualifier) \ + F(cl_kernel_arg_info, CL_KERNEL_ARG_TYPE_NAME, STRING_CLASS) \ + F(cl_kernel_arg_info, CL_KERNEL_ARG_NAME, STRING_CLASS) \ + \ + F(cl_device_info, CL_DEVICE_PARENT_DEVICE, cl_device_id) \ + F(cl_device_info, CL_DEVICE_PARTITION_PROPERTIES, VECTOR_CLASS) \ + F(cl_device_info, CL_DEVICE_PARTITION_TYPE, VECTOR_CLASS) \ + F(cl_device_info, CL_DEVICE_REFERENCE_COUNT, cl_uint) \ + F(cl_device_info, CL_DEVICE_PREFERRED_INTEROP_USER_SYNC, ::size_t) \ + F(cl_device_info, CL_DEVICE_PARTITION_AFFINITY_DOMAIN, cl_device_affinity_domain) \ + F(cl_device_info, CL_DEVICE_BUILT_IN_KERNELS, STRING_CLASS) +#endif // #if defined(CL_VERSION_1_2) + +#if defined(USE_CL_DEVICE_FISSION) +#define __PARAM_NAME_DEVICE_FISSION(F) \ + F(cl_device_info, CL_DEVICE_PARENT_DEVICE_EXT, cl_device_id) \ + F(cl_device_info, CL_DEVICE_PARTITION_TYPES_EXT, VECTOR_CLASS) \ + F(cl_device_info, CL_DEVICE_AFFINITY_DOMAINS_EXT, VECTOR_CLASS) \ + F(cl_device_info, CL_DEVICE_REFERENCE_COUNT_EXT , cl_uint) \ + F(cl_device_info, CL_DEVICE_PARTITION_STYLE_EXT, VECTOR_CLASS) +#endif // USE_CL_DEVICE_FISSION + +template +struct param_traits {}; + +#define __CL_DECLARE_PARAM_TRAITS(token, param_name, T) \ +struct token; \ +template<> \ +struct param_traits \ +{ \ + enum { value = param_name }; \ + typedef T param_type; \ +}; + +__PARAM_NAME_INFO_1_0(__CL_DECLARE_PARAM_TRAITS) +#if defined(CL_VERSION_1_1) +__PARAM_NAME_INFO_1_1(__CL_DECLARE_PARAM_TRAITS) +#endif // CL_VERSION_1_1 +#if defined(CL_VERSION_1_2) +__PARAM_NAME_INFO_1_2(__CL_DECLARE_PARAM_TRAITS) +#endif // CL_VERSION_1_1 + +#if defined(USE_CL_DEVICE_FISSION) +__PARAM_NAME_DEVICE_FISSION(__CL_DECLARE_PARAM_TRAITS); +#endif // USE_CL_DEVICE_FISSION + +#ifdef CL_PLATFORM_ICD_SUFFIX_KHR +__CL_DECLARE_PARAM_TRAITS(cl_platform_info, CL_PLATFORM_ICD_SUFFIX_KHR, STRING_CLASS) +#endif + +#ifdef CL_DEVICE_PROFILING_TIMER_OFFSET_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_PROFILING_TIMER_OFFSET_AMD, cl_ulong) +#endif + +#ifdef CL_DEVICE_GLOBAL_FREE_MEMORY_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_FREE_MEMORY_AMD, VECTOR_CLASS< ::size_t>) +#endif +#ifdef CL_DEVICE_SIMD_PER_COMPUTE_UNIT_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_SIMD_PER_COMPUTE_UNIT_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_SIMD_WIDTH_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_SIMD_WIDTH_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_SIMD_INSTRUCTION_WIDTH_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_SIMD_INSTRUCTION_WIDTH_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_WAVEFRONT_WIDTH_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_WAVEFRONT_WIDTH_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_GLOBAL_MEM_CHANNELS_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNELS_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_GLOBAL_MEM_CHANNEL_BANKS_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNEL_BANKS_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_GLOBAL_MEM_CHANNEL_BANK_WIDTH_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNEL_BANK_WIDTH_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_LOCAL_MEM_SIZE_PER_COMPUTE_UNIT_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_LOCAL_MEM_SIZE_PER_COMPUTE_UNIT_AMD, cl_uint) +#endif +#ifdef CL_DEVICE_LOCAL_MEM_BANKS_AMD +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_LOCAL_MEM_BANKS_AMD, cl_uint) +#endif + +#ifdef CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, cl_uint) +#endif +#ifdef CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV, cl_uint) +#endif +#ifdef CL_DEVICE_REGISTERS_PER_BLOCK_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_REGISTERS_PER_BLOCK_NV, cl_uint) +#endif +#ifdef CL_DEVICE_WARP_SIZE_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_WARP_SIZE_NV, cl_uint) +#endif +#ifdef CL_DEVICE_GPU_OVERLAP_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_GPU_OVERLAP_NV, cl_bool) +#endif +#ifdef CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV, cl_bool) +#endif +#ifdef CL_DEVICE_INTEGRATED_MEMORY_NV +__CL_DECLARE_PARAM_TRAITS(cl_device_info, CL_DEVICE_INTEGRATED_MEMORY_NV, cl_bool) +#endif + +// Convenience functions + +template +inline cl_int +getInfo(Func f, cl_uint name, T* param) +{ + return getInfoHelper(f, name, param, 0); +} + +template +struct GetInfoFunctor0 +{ + Func f_; const Arg0& arg0_; + cl_int operator ()( + cl_uint param, ::size_t size, void* value, ::size_t* size_ret) + { return f_(arg0_, param, size, value, size_ret); } +}; + +template +struct GetInfoFunctor1 +{ + Func f_; const Arg0& arg0_; const Arg1& arg1_; + cl_int operator ()( + cl_uint param, ::size_t size, void* value, ::size_t* size_ret) + { return f_(arg0_, arg1_, param, size, value, size_ret); } +}; + +template +inline cl_int +getInfo(Func f, const Arg0& arg0, cl_uint name, T* param) +{ + GetInfoFunctor0 f0 = { f, arg0 }; + return getInfoHelper(f0, name, param, 0); +} + +template +inline cl_int +getInfo(Func f, const Arg0& arg0, const Arg1& arg1, cl_uint name, T* param) +{ + GetInfoFunctor1 f0 = { f, arg0, arg1 }; + return getInfoHelper(f0, name, param, 0); +} + +template +struct ReferenceHandler +{ }; + +#if defined(CL_VERSION_1_2) +/** + * OpenCL 1.2 devices do have retain/release. + */ +template <> +struct ReferenceHandler +{ + /** + * Retain the device. + * \param device A valid device created using createSubDevices + * \return + * CL_SUCCESS if the function executed successfully. + * CL_INVALID_DEVICE if device was not a valid subdevice + * CL_OUT_OF_RESOURCES + * CL_OUT_OF_HOST_MEMORY + */ + static cl_int retain(cl_device_id device) + { return ::clRetainDevice(device); } + /** + * Retain the device. + * \param device A valid device created using createSubDevices + * \return + * CL_SUCCESS if the function executed successfully. + * CL_INVALID_DEVICE if device was not a valid subdevice + * CL_OUT_OF_RESOURCES + * CL_OUT_OF_HOST_MEMORY + */ + static cl_int release(cl_device_id device) + { return ::clReleaseDevice(device); } +}; +#else // #if defined(CL_VERSION_1_2) +/** + * OpenCL 1.1 devices do not have retain/release. + */ +template <> +struct ReferenceHandler +{ + // cl_device_id does not have retain(). + static cl_int retain(cl_device_id) + { return CL_SUCCESS; } + // cl_device_id does not have release(). + static cl_int release(cl_device_id) + { return CL_SUCCESS; } +}; +#endif // #if defined(CL_VERSION_1_2) + +template <> +struct ReferenceHandler +{ + // cl_platform_id does not have retain(). + static cl_int retain(cl_platform_id) + { return CL_SUCCESS; } + // cl_platform_id does not have release(). + static cl_int release(cl_platform_id) + { return CL_SUCCESS; } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_context context) + { return ::clRetainContext(context); } + static cl_int release(cl_context context) + { return ::clReleaseContext(context); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_command_queue queue) + { return ::clRetainCommandQueue(queue); } + static cl_int release(cl_command_queue queue) + { return ::clReleaseCommandQueue(queue); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_mem memory) + { return ::clRetainMemObject(memory); } + static cl_int release(cl_mem memory) + { return ::clReleaseMemObject(memory); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_sampler sampler) + { return ::clRetainSampler(sampler); } + static cl_int release(cl_sampler sampler) + { return ::clReleaseSampler(sampler); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_program program) + { return ::clRetainProgram(program); } + static cl_int release(cl_program program) + { return ::clReleaseProgram(program); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_kernel kernel) + { return ::clRetainKernel(kernel); } + static cl_int release(cl_kernel kernel) + { return ::clReleaseKernel(kernel); } +}; + +template <> +struct ReferenceHandler +{ + static cl_int retain(cl_event event) + { return ::clRetainEvent(event); } + static cl_int release(cl_event event) + { return ::clReleaseEvent(event); } +}; + + +// Extracts version number with major in the upper 16 bits, minor in the lower 16 +static cl_uint getVersion(const char *versionInfo) +{ + int highVersion = 0; + int lowVersion = 0; + int index = 7; + while(versionInfo[index] != '.' ) { + highVersion *= 10; + highVersion += versionInfo[index]-'0'; + ++index; + } + ++index; + while(versionInfo[index] != ' ' && versionInfo[index] != '\0') { + lowVersion *= 10; + lowVersion += versionInfo[index]-'0'; + ++index; + } + return (highVersion << 16) | lowVersion; +} + +static cl_uint getPlatformVersion(cl_platform_id platform) +{ + ::size_t size = 0; + clGetPlatformInfo(platform, CL_PLATFORM_VERSION, 0, NULL, &size); + char *versionInfo = (char *) alloca(size); + clGetPlatformInfo(platform, CL_PLATFORM_VERSION, size, &versionInfo[0], &size); + return getVersion(versionInfo); +} + +static cl_uint getDevicePlatformVersion(cl_device_id device) +{ + cl_platform_id platform; + clGetDeviceInfo(device, CL_DEVICE_PLATFORM, sizeof(platform), &platform, NULL); + return getPlatformVersion(platform); +} + +#if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) +static cl_uint getContextPlatformVersion(cl_context context) +{ + // The platform cannot be queried directly, so we first have to grab a + // device and obtain its context + ::size_t size = 0; + clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL, &size); + if (size == 0) + return 0; + cl_device_id *devices = (cl_device_id *) alloca(size); + clGetContextInfo(context, CL_CONTEXT_DEVICES, size, devices, NULL); + return getDevicePlatformVersion(devices[0]); +} +#endif // #if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + +template +class Wrapper +{ +public: + typedef T cl_type; + +protected: + cl_type object_; + +public: + Wrapper() : object_(NULL) { } + + Wrapper(const cl_type &obj) : object_(obj) { } + + ~Wrapper() + { + if (object_ != NULL) { release(); } + } + + Wrapper(const Wrapper& rhs) + { + object_ = rhs.object_; + if (object_ != NULL) { detail::errHandler(retain(), __RETAIN_ERR); } + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + Wrapper(Wrapper&& rhs) CL_HPP_NOEXCEPT + { + object_ = rhs.object_; + rhs.object_ = NULL; + } +#endif + + Wrapper& operator = (const Wrapper& rhs) + { + if (this != &rhs) { + if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } + object_ = rhs.object_; + if (object_ != NULL) { detail::errHandler(retain(), __RETAIN_ERR); } + } + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + Wrapper& operator = (Wrapper&& rhs) + { + if (this != &rhs) { + if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } + object_ = rhs.object_; + rhs.object_ = NULL; + } + return *this; + } +#endif + + Wrapper& operator = (const cl_type &rhs) + { + if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } + object_ = rhs; + return *this; + } + + cl_type operator ()() const { return object_; } + + cl_type& operator ()() { return object_; } + +protected: + template + friend inline cl_int getInfoHelper(Func, cl_uint, U*, int, typename U::cl_type); + + cl_int retain() const + { + return ReferenceHandler::retain(object_); + } + + cl_int release() const + { + return ReferenceHandler::release(object_); + } +}; + +template <> +class Wrapper +{ +public: + typedef cl_device_id cl_type; + +protected: + cl_type object_; + bool referenceCountable_; + + static bool isReferenceCountable(cl_device_id device) + { + bool retVal = false; + if (device != NULL) { + int version = getDevicePlatformVersion(device); + if(version > ((1 << 16) + 1)) { + retVal = true; + } + } + return retVal; + } + +public: + Wrapper() : object_(NULL), referenceCountable_(false) + { + } + + Wrapper(const cl_type &obj) : object_(obj), referenceCountable_(false) + { + referenceCountable_ = isReferenceCountable(obj); + } + + ~Wrapper() + { + if (object_ != NULL) { release(); } + } + + Wrapper(const Wrapper& rhs) + { + object_ = rhs.object_; + referenceCountable_ = isReferenceCountable(object_); + if (object_ != NULL) { detail::errHandler(retain(), __RETAIN_ERR); } + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + Wrapper(Wrapper&& rhs) CL_HPP_NOEXCEPT + { + object_ = rhs.object_; + referenceCountable_ = rhs.referenceCountable_; + rhs.object_ = NULL; + rhs.referenceCountable_ = false; + } +#endif + + Wrapper& operator = (const Wrapper& rhs) + { + if (this != &rhs) { + if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } + object_ = rhs.object_; + referenceCountable_ = rhs.referenceCountable_; + if (object_ != NULL) { detail::errHandler(retain(), __RETAIN_ERR); } + } + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + Wrapper& operator = (Wrapper&& rhs) + { + if (this != &rhs) { + if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } + object_ = rhs.object_; + referenceCountable_ = rhs.referenceCountable_; + rhs.object_ = NULL; + rhs.referenceCountable_ = false; + } + return *this; + } +#endif + + Wrapper& operator = (const cl_type &rhs) + { + if (object_ != NULL) { detail::errHandler(release(), __RELEASE_ERR); } + object_ = rhs; + referenceCountable_ = isReferenceCountable(object_); + return *this; + } + + cl_type operator ()() const { return object_; } + + cl_type& operator ()() { return object_; } + +protected: + template + friend inline cl_int getInfoHelper(Func, cl_uint, U*, int, typename U::cl_type); + + template + friend inline cl_int getInfoHelper(Func, cl_uint, VECTOR_CLASS*, int, typename U::cl_type); + + cl_int retain() const + { + if( referenceCountable_ ) { + return ReferenceHandler::retain(object_); + } + else { + return CL_SUCCESS; + } + } + + cl_int release() const + { + if( referenceCountable_ ) { + return ReferenceHandler::release(object_); + } + else { + return CL_SUCCESS; + } + } +}; + +} // namespace detail +//! \endcond + +/*! \stuct ImageFormat + * \brief Adds constructors and member functions for cl_image_format. + * + * \see cl_image_format + */ +struct ImageFormat : public cl_image_format +{ + //! \brief Default constructor - performs no initialization. + ImageFormat(){} + + //! \brief Initializing constructor. + ImageFormat(cl_channel_order order, cl_channel_type type) + { + image_channel_order = order; + image_channel_data_type = type; + } + + //! \brief Assignment operator. + ImageFormat& operator = (const ImageFormat& rhs) + { + if (this != &rhs) { + this->image_channel_data_type = rhs.image_channel_data_type; + this->image_channel_order = rhs.image_channel_order; + } + return *this; + } +}; + +/*! \brief Class interface for cl_device_id. + * + * \note Copies of these objects are inexpensive, since they don't 'own' + * any underlying resources or data structures. + * + * \see cl_device_id + */ +class Device : public detail::Wrapper +{ +public: + //! \brief Default constructor - initializes to NULL. + Device() : detail::Wrapper() { } + + /*! \brief Constructor from cl_device_id. + * + * This simply copies the device ID value, which is an inexpensive operation. + */ + __CL_EXPLICIT_CONSTRUCTORS Device(const cl_device_id &device) : detail::Wrapper(device) { } + + /*! \brief Returns the first device on the default context. + * + * \see Context::getDefault() + */ + static Device getDefault(cl_int * err = NULL); + + /*! \brief Assignment operator from cl_device_id. + * + * This simply copies the device ID value, which is an inexpensive operation. + */ + Device& operator = (const cl_device_id& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Device(const Device& dev) : detail::Wrapper(dev) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Device& operator = (const Device &dev) + { + detail::Wrapper::operator=(dev); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Device(Device&& dev) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(dev)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Device& operator = (Device &&dev) + { + detail::Wrapper::operator=(std::move(dev)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + //! \brief Wrapper for clGetDeviceInfo(). + template + cl_int getInfo(cl_device_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetDeviceInfo, object_, name, param), + __GET_DEVICE_INFO_ERR); + } + + //! \brief Wrapper for clGetDeviceInfo() that returns by value. + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_device_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + /** + * CL 1.2 version + */ +#if defined(CL_VERSION_1_2) + //! \brief Wrapper for clCreateSubDevicesEXT(). + cl_int createSubDevices( + const cl_device_partition_property * properties, + VECTOR_CLASS* devices) + { + cl_uint n = 0; + cl_int err = clCreateSubDevices(object_, properties, 0, NULL, &n); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __CREATE_SUB_DEVICES); + } + + cl_device_id* ids = (cl_device_id*) alloca(n * sizeof(cl_device_id)); + err = clCreateSubDevices(object_, properties, n, ids, NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __CREATE_SUB_DEVICES); + } + + devices->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } +#endif // #if defined(CL_VERSION_1_2) + +/** + * CL 1.1 version that uses device fission. + */ +#if defined(CL_VERSION_1_1) +#if defined(USE_CL_DEVICE_FISSION) + cl_int createSubDevices( + const cl_device_partition_property_ext * properties, + VECTOR_CLASS* devices) + { + typedef CL_API_ENTRY cl_int + ( CL_API_CALL * PFN_clCreateSubDevicesEXT)( + cl_device_id /*in_device*/, + 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; + + static PFN_clCreateSubDevicesEXT pfn_clCreateSubDevicesEXT = NULL; + __INIT_CL_EXT_FCN_PTR(clCreateSubDevicesEXT); + + cl_uint n = 0; + cl_int err = pfn_clCreateSubDevicesEXT(object_, properties, 0, NULL, &n); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __CREATE_SUB_DEVICES); + } + + cl_device_id* ids = (cl_device_id*) alloca(n * sizeof(cl_device_id)); + err = pfn_clCreateSubDevicesEXT(object_, properties, n, ids, NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __CREATE_SUB_DEVICES); + } + + devices->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } +#endif // #if defined(USE_CL_DEVICE_FISSION) +#endif // #if defined(CL_VERSION_1_1) +}; + +/*! \brief Class interface for cl_platform_id. + * + * \note Copies of these objects are inexpensive, since they don't 'own' + * any underlying resources or data structures. + * + * \see cl_platform_id + */ +class Platform : public detail::Wrapper +{ +public: + //! \brief Default constructor - initializes to NULL. + Platform() : detail::Wrapper() { } + + /*! \brief Constructor from cl_platform_id. + * + * This simply copies the platform ID value, which is an inexpensive operation. + */ + __CL_EXPLICIT_CONSTRUCTORS Platform(const cl_platform_id &platform) : detail::Wrapper(platform) { } + + /*! \brief Assignment operator from cl_platform_id. + * + * This simply copies the platform ID value, which is an inexpensive operation. + */ + Platform& operator = (const cl_platform_id& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + //! \brief Wrapper for clGetPlatformInfo(). + cl_int getInfo(cl_platform_info name, STRING_CLASS* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetPlatformInfo, object_, name, param), + __GET_PLATFORM_INFO_ERR); + } + + //! \brief Wrapper for clGetPlatformInfo() that returns by value. + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_platform_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + /*! \brief Gets a list of devices for this platform. + * + * Wraps clGetDeviceIDs(). + */ + cl_int getDevices( + cl_device_type type, + VECTOR_CLASS* devices) const + { + cl_uint n = 0; + if( devices == NULL ) { + return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_DEVICE_IDS_ERR); + } + cl_int err = ::clGetDeviceIDs(object_, type, 0, NULL, &n); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + cl_device_id* ids = (cl_device_id*) alloca(n * sizeof(cl_device_id)); + err = ::clGetDeviceIDs(object_, type, n, ids, NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + devices->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } + +#if defined(USE_DX_INTEROP) + /*! \brief Get the list of available D3D10 devices. + * + * \param d3d_device_source. + * + * \param d3d_object. + * + * \param d3d_device_set. + * + * \param devices returns a vector of OpenCL D3D10 devices found. The cl::Device + * values returned in devices can be used to identify a specific OpenCL + * device. If \a devices argument is NULL, this argument is ignored. + * + * \return One of the following values: + * - CL_SUCCESS if the function is executed successfully. + * + * The application can query specific capabilities of the OpenCL device(s) + * returned by cl::getDevices. This can be used by the application to + * determine which device(s) to use. + * + * \note In the case that exceptions are enabled and a return value + * other than CL_SUCCESS is generated, then cl::Error exception is + * generated. + */ + cl_int getDevices( + cl_d3d10_device_source_khr d3d_device_source, + void * d3d_object, + cl_d3d10_device_set_khr d3d_device_set, + VECTOR_CLASS* devices) const + { + typedef CL_API_ENTRY cl_int (CL_API_CALL *PFN_clGetDeviceIDsFromD3D10KHR)( + cl_platform_id platform, + cl_d3d10_device_source_khr d3d_device_source, + void * d3d_object, + cl_d3d10_device_set_khr d3d_device_set, + cl_uint num_entries, + cl_device_id * devices, + cl_uint* num_devices); + + if( devices == NULL ) { + return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_DEVICE_IDS_ERR); + } + + static PFN_clGetDeviceIDsFromD3D10KHR pfn_clGetDeviceIDsFromD3D10KHR = NULL; + __INIT_CL_EXT_FCN_PTR_PLATFORM(object_, clGetDeviceIDsFromD3D10KHR); + + cl_uint n = 0; + cl_int err = pfn_clGetDeviceIDsFromD3D10KHR( + object_, + d3d_device_source, + d3d_object, + d3d_device_set, + 0, + NULL, + &n); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + cl_device_id* ids = (cl_device_id*) alloca(n * sizeof(cl_device_id)); + err = pfn_clGetDeviceIDsFromD3D10KHR( + object_, + d3d_device_source, + d3d_object, + d3d_device_set, + n, + ids, + NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_DEVICE_IDS_ERR); + } + + devices->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } +#endif + + /*! \brief Gets a list of available platforms. + * + * Wraps clGetPlatformIDs(). + */ + static cl_int get( + VECTOR_CLASS* platforms) + { + cl_uint n = 0; + + if( platforms == NULL ) { + return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_PLATFORM_IDS_ERR); + } + + cl_int err = ::clGetPlatformIDs(0, NULL, &n); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + } + + cl_platform_id* ids = (cl_platform_id*) alloca( + n * sizeof(cl_platform_id)); + err = ::clGetPlatformIDs(n, ids, NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + } + + platforms->assign(&ids[0], &ids[n]); + return CL_SUCCESS; + } + + /*! \brief Gets the first available platform. + * + * Wraps clGetPlatformIDs(), returning the first result. + */ + static cl_int get( + Platform * platform) + { + cl_uint n = 0; + + if( platform == NULL ) { + return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_PLATFORM_IDS_ERR); + } + + cl_int err = ::clGetPlatformIDs(0, NULL, &n); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + } + + cl_platform_id* ids = (cl_platform_id*) alloca( + n * sizeof(cl_platform_id)); + err = ::clGetPlatformIDs(n, ids, NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + } + + *platform = ids[0]; + return CL_SUCCESS; + } + + /*! \brief Gets the first available platform, returning it by value. + * + * Wraps clGetPlatformIDs(), returning the first result. + */ + static Platform get( + cl_int * errResult = NULL) + { + Platform platform; + cl_uint n = 0; + cl_int err = ::clGetPlatformIDs(0, NULL, &n); + if (err != CL_SUCCESS) { + detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + if (errResult != NULL) { + *errResult = err; + } + return Platform(); + } + + cl_platform_id* ids = (cl_platform_id*) alloca( + n * sizeof(cl_platform_id)); + err = ::clGetPlatformIDs(n, ids, NULL); + + if (err != CL_SUCCESS) { + detail::errHandler(err, __GET_PLATFORM_IDS_ERR); + if (errResult != NULL) { + *errResult = err; + } + return Platform(); + } + + + return Platform(ids[0]); + } + + static Platform getDefault( + cl_int *errResult = NULL ) + { + return get(errResult); + } + + +#if defined(CL_VERSION_1_2) + //! \brief Wrapper for clUnloadCompiler(). + cl_int + unloadCompiler() + { + return ::clUnloadPlatformCompiler(object_); + } +#endif // #if defined(CL_VERSION_1_2) +}; // class Platform + +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) +/** + * 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_int +UnloadCompiler() +{ + return ::clUnloadCompiler(); +} +#endif // #if defined(CL_VERSION_1_1) + +/*! \brief Class interface for cl_context. + * + * \note Copies of these objects are shallow, meaning that the copy will refer + * to the same underlying cl_context as the original. For details, see + * clRetainContext() and clReleaseContext(). + * + * \see cl_context + */ +class Context + : public detail::Wrapper +{ +private: + +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED + static std::atomic default_initialized_; +#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED + static volatile int default_initialized_; +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED + static Context default_; + static volatile cl_int default_error_; +public: + /*! \brief Constructs a context including a list of specified devices. + * + * Wraps clCreateContext(). + */ + Context( + const VECTOR_CLASS& devices, + cl_context_properties* properties = NULL, + void (CL_CALLBACK * notifyFptr)( + const char *, + const void *, + ::size_t, + void *) = NULL, + void* data = NULL, + cl_int* err = NULL) + { + cl_int error; + + ::size_t numDevices = devices.size(); + cl_device_id* deviceIDs = (cl_device_id*) alloca(numDevices * sizeof(cl_device_id)); + for( ::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex ) { + deviceIDs[deviceIndex] = (devices[deviceIndex])(); + } + + object_ = ::clCreateContext( + properties, (cl_uint) numDevices, + deviceIDs, + notifyFptr, data, &error); + + detail::errHandler(error, __CREATE_CONTEXT_ERR); + if (err != NULL) { + *err = error; + } + } + + Context( + const Device& device, + cl_context_properties* properties = NULL, + void (CL_CALLBACK * notifyFptr)( + const char *, + const void *, + ::size_t, + void *) = NULL, + void* data = NULL, + cl_int* err = NULL) + { + cl_int error; + + cl_device_id deviceID = device(); + + object_ = ::clCreateContext( + properties, 1, + &deviceID, + notifyFptr, data, &error); + + detail::errHandler(error, __CREATE_CONTEXT_ERR); + if (err != NULL) { + *err = error; + } + } + + /*! \brief Constructs a context including all or a subset of devices of a specified type. + * + * Wraps clCreateContextFromType(). + */ + Context( + cl_device_type type, + cl_context_properties* properties = NULL, + void (CL_CALLBACK * notifyFptr)( + const char *, + const void *, + ::size_t, + void *) = NULL, + void* data = NULL, + cl_int* err = NULL) + { + cl_int error; + +#if !defined(__APPLE__) && !defined(__MACOS) + cl_context_properties prop[4] = {CL_CONTEXT_PLATFORM, 0, 0, 0 }; + + if (properties == NULL) { + // Get a valid platform ID as we cannot send in a blank one + VECTOR_CLASS platforms; + error = Platform::get(&platforms); + if (error != CL_SUCCESS) { + detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR); + if (err != NULL) { + *err = error; + } + return; + } + + // Check the platforms we found for a device of our specified type + cl_context_properties platform_id = 0; + for (unsigned int i = 0; i < platforms.size(); i++) { + + VECTOR_CLASS devices; + +#if defined(__CL_ENABLE_EXCEPTIONS) + try { +#endif + + error = platforms[i].getDevices(type, &devices); + +#if defined(__CL_ENABLE_EXCEPTIONS) + } catch (Error) {} + // Catch if exceptions are enabled as we don't want to exit if first platform has no devices of type + // We do error checking next anyway, and can throw there if needed +#endif + + // Only squash CL_SUCCESS and CL_DEVICE_NOT_FOUND + if (error != CL_SUCCESS && error != CL_DEVICE_NOT_FOUND) { + detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR); + if (err != NULL) { + *err = error; + } + } + + if (devices.size() > 0) { + platform_id = (cl_context_properties)platforms[i](); + break; + } + } + + if (platform_id == 0) { + detail::errHandler(CL_DEVICE_NOT_FOUND, __CREATE_CONTEXT_FROM_TYPE_ERR); + if (err != NULL) { + *err = CL_DEVICE_NOT_FOUND; + } + return; + } + + prop[1] = platform_id; + properties = &prop[0]; + } +#endif + object_ = ::clCreateContextFromType( + properties, type, notifyFptr, data, &error); + + detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR); + if (err != NULL) { + *err = error; + } + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Context(const Context& ctx) : detail::Wrapper(ctx) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Context& operator = (const Context &ctx) + { + detail::Wrapper::operator=(ctx); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Context(Context&& ctx) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(ctx)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Context& operator = (Context &&ctx) + { + detail::Wrapper::operator=(std::move(ctx)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + /*! \brief Returns a singleton context including all devices of CL_DEVICE_TYPE_DEFAULT. + * + * \note All calls to this function return the same cl_context as the first. + */ + static Context getDefault(cl_int * err = NULL) + { + int state = detail::compare_exchange( + &default_initialized_, + __DEFAULT_BEING_INITIALIZED, __DEFAULT_NOT_INITIALIZED); + + if (state & __DEFAULT_INITIALIZED) { + if (err != NULL) { + *err = default_error_; + } + return default_; + } + + if (state & __DEFAULT_BEING_INITIALIZED) { + // Assume writes will propagate eventually... + while(default_initialized_ != __DEFAULT_INITIALIZED) { + detail::fence(); + } + + if (err != NULL) { + *err = default_error_; + } + return default_; + } + + cl_int error; + default_ = Context( + CL_DEVICE_TYPE_DEFAULT, + NULL, + NULL, + NULL, + &error); + + detail::fence(); + + default_error_ = error; + // Assume writes will propagate eventually... + default_initialized_ = __DEFAULT_INITIALIZED; + + detail::fence(); + + if (err != NULL) { + *err = default_error_; + } + return default_; + + } + + //! \brief Default constructor - initializes to NULL. + Context() : detail::Wrapper() { } + + /*! \brief Constructor from cl_context - takes ownership. + * + * This effectively transfers ownership of a refcount on the cl_context + * into the new Context object. + */ + __CL_EXPLICIT_CONSTRUCTORS Context(const cl_context& context) : detail::Wrapper(context) { } + + /*! \brief Assignment operator from cl_context - takes ownership. + * + * This effectively transfers ownership of a refcount on the rhs and calls + * clReleaseContext() on the value previously held by this instance. + */ + Context& operator = (const cl_context& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + //! \brief Wrapper for clGetContextInfo(). + template + cl_int getInfo(cl_context_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetContextInfo, object_, name, param), + __GET_CONTEXT_INFO_ERR); + } + + //! \brief Wrapper for clGetContextInfo() that returns by value. + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_context_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + /*! \brief Gets a list of supported image formats. + * + * Wraps clGetSupportedImageFormats(). + */ + cl_int getSupportedImageFormats( + cl_mem_flags flags, + cl_mem_object_type type, + VECTOR_CLASS* formats) const + { + cl_uint numEntries; + cl_int err = ::clGetSupportedImageFormats( + object_, + flags, + type, + 0, + NULL, + &numEntries); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_SUPPORTED_IMAGE_FORMATS_ERR); + } + + ImageFormat* value = (ImageFormat*) + alloca(numEntries * sizeof(ImageFormat)); + err = ::clGetSupportedImageFormats( + object_, + flags, + type, + numEntries, + (cl_image_format*) value, + NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __GET_SUPPORTED_IMAGE_FORMATS_ERR); + } + + formats->assign(&value[0], &value[numEntries]); + return CL_SUCCESS; + } +}; + +inline Device Device::getDefault(cl_int * err) +{ + cl_int error; + Device device; + + Context context = Context::getDefault(&error); + detail::errHandler(error, __CREATE_CONTEXT_ERR); + + if (error != CL_SUCCESS) { + if (err != NULL) { + *err = error; + } + } + else { + device = context.getInfo()[0]; + if (err != NULL) { + *err = CL_SUCCESS; + } + } + + return device; +} + + +#ifdef _WIN32 +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED +__declspec(selectany) std::atomic Context::default_initialized_; +#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__declspec(selectany) volatile int Context::default_initialized_ = __DEFAULT_NOT_INITIALIZED; +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__declspec(selectany) Context Context::default_; +__declspec(selectany) volatile cl_int Context::default_error_ = CL_SUCCESS; +#else // !_WIN32 +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED +__attribute__((weak)) std::atomic Context::default_initialized_; +#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__attribute__((weak)) volatile int Context::default_initialized_ = __DEFAULT_NOT_INITIALIZED; +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__attribute__((weak)) Context Context::default_; +__attribute__((weak)) volatile cl_int Context::default_error_ = CL_SUCCESS; +#endif // !_WIN32 + +/*! \brief Class interface for cl_event. + * + * \note Copies of these objects are shallow, meaning that the copy will refer + * to the same underlying cl_event as the original. For details, see + * clRetainEvent() and clReleaseEvent(). + * + * \see cl_event + */ +class Event : public detail::Wrapper +{ +public: + //! \brief Default constructor - initializes to NULL. + Event() : detail::Wrapper() { } + + /*! \brief Constructor from cl_event - takes ownership. + * + * This effectively transfers ownership of a refcount on the cl_event + * into the new Event object. + */ + __CL_EXPLICIT_CONSTRUCTORS Event(const cl_event& event) : detail::Wrapper(event) { } + + /*! \brief Assignment operator from cl_event - takes ownership. + * + * This effectively transfers ownership of a refcount on the rhs and calls + * clReleaseEvent() on the value previously held by this instance. + */ + Event& operator = (const cl_event& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + //! \brief Wrapper for clGetEventInfo(). + template + cl_int getInfo(cl_event_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetEventInfo, object_, name, param), + __GET_EVENT_INFO_ERR); + } + + //! \brief Wrapper for clGetEventInfo() that returns by value. + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_event_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + //! \brief Wrapper for clGetEventProfilingInfo(). + template + cl_int getProfilingInfo(cl_profiling_info name, T* param) const + { + return detail::errHandler(detail::getInfo( + &::clGetEventProfilingInfo, object_, name, param), + __GET_EVENT_PROFILE_INFO_ERR); + } + + //! \brief Wrapper for clGetEventProfilingInfo() that returns by value. + template typename + detail::param_traits::param_type + getProfilingInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_profiling_info, name>::param_type param; + cl_int result = getProfilingInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + /*! \brief Blocks the calling thread until this event completes. + * + * Wraps clWaitForEvents(). + */ + cl_int wait() const + { + return detail::errHandler( + ::clWaitForEvents(1, &object_), + __WAIT_FOR_EVENTS_ERR); + } + +#if defined(CL_VERSION_1_1) + /*! \brief Registers a user callback function for a specific command execution status. + * + * Wraps clSetEventCallback(). + */ + cl_int setCallback( + cl_int type, + void (CL_CALLBACK * pfn_notify)(cl_event, cl_int, void *), + void * user_data = NULL) + { + return detail::errHandler( + ::clSetEventCallback( + object_, + type, + pfn_notify, + user_data), + __SET_EVENT_CALLBACK_ERR); + } +#endif + + /*! \brief Blocks the calling thread until every event specified is complete. + * + * Wraps clWaitForEvents(). + */ + static cl_int + waitForEvents(const VECTOR_CLASS& events) + { + return detail::errHandler( + ::clWaitForEvents( + (cl_uint) events.size(), (events.size() > 0) ? (cl_event*)&events.front() : NULL), + __WAIT_FOR_EVENTS_ERR); + } +}; + +#if defined(CL_VERSION_1_1) +/*! \brief Class interface for user events (a subset of cl_event's). + * + * See Event for details about copy semantics, etc. + */ +class UserEvent : public Event +{ +public: + /*! \brief Constructs a user event on a given context. + * + * Wraps clCreateUserEvent(). + */ + UserEvent( + const Context& context, + cl_int * err = NULL) + { + cl_int error; + object_ = ::clCreateUserEvent( + context(), + &error); + + detail::errHandler(error, __CREATE_USER_EVENT_ERR); + if (err != NULL) { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + UserEvent() : Event() { } + + /*! \brief Sets the execution status of a user event object. + * + * Wraps clSetUserEventStatus(). + */ + cl_int setStatus(cl_int status) + { + return detail::errHandler( + ::clSetUserEventStatus(object_,status), + __SET_USER_EVENT_STATUS_ERR); + } +}; +#endif + +/*! \brief Blocks the calling thread until every event specified is complete. + * + * Wraps clWaitForEvents(). + */ +inline static cl_int +WaitForEvents(const VECTOR_CLASS& events) +{ + return detail::errHandler( + ::clWaitForEvents( + (cl_uint) events.size(), (events.size() > 0) ? (cl_event*)&events.front() : NULL), + __WAIT_FOR_EVENTS_ERR); +} + +/*! \brief Class interface for cl_mem. + * + * \note Copies of these objects are shallow, meaning that the copy will refer + * to the same underlying cl_mem as the original. For details, see + * clRetainMemObject() and clReleaseMemObject(). + * + * \see cl_mem + */ +class Memory : public detail::Wrapper +{ +public: + //! \brief Default constructor - initializes to NULL. + Memory() : detail::Wrapper() { } + + /*! \brief Constructor from cl_mem - takes ownership. + * + * This effectively transfers ownership of a refcount on the cl_mem + * into the new Memory object. + */ + __CL_EXPLICIT_CONSTRUCTORS Memory(const cl_mem& memory) : detail::Wrapper(memory) { } + + /*! \brief Assignment operator from cl_mem - takes ownership. + * + * This effectively transfers ownership of a refcount on the rhs and calls + * clReleaseMemObject() on the value previously held by this instance. + */ + Memory& operator = (const cl_mem& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Memory(const Memory& mem) : detail::Wrapper(mem) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Memory& operator = (const Memory &mem) + { + detail::Wrapper::operator=(mem); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Memory(Memory&& mem) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(mem)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Memory& operator = (Memory &&mem) + { + detail::Wrapper::operator=(std::move(mem)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + //! \brief Wrapper for clGetMemObjectInfo(). + template + cl_int getInfo(cl_mem_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetMemObjectInfo, object_, name, param), + __GET_MEM_OBJECT_INFO_ERR); + } + + //! \brief Wrapper for clGetMemObjectInfo() that returns by value. + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_mem_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + +#if defined(CL_VERSION_1_1) + /*! \brief Registers a callback function to be called when the memory object + * is no longer needed. + * + * Wraps clSetMemObjectDestructorCallback(). + * + * Repeated calls to this function, for a given cl_mem value, will append + * to the list of functions called (in reverse order) when memory object's + * resources are freed and the memory object is deleted. + * + * \note + * The registered callbacks are associated with the underlying cl_mem + * value - not the Memory class instance. + */ + cl_int setDestructorCallback( + void (CL_CALLBACK * pfn_notify)(cl_mem, void *), + void * user_data = NULL) + { + return detail::errHandler( + ::clSetMemObjectDestructorCallback( + object_, + pfn_notify, + user_data), + __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR); + } +#endif + +}; + +// Pre-declare copy functions +class Buffer; +template< typename IteratorType > +cl_int copy( IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer ); +template< typename IteratorType > +cl_int copy( const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator ); +template< typename IteratorType > +cl_int copy( const CommandQueue &queue, IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer ); +template< typename IteratorType > +cl_int copy( const CommandQueue &queue, const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator ); + + +/*! \brief Class interface for Buffer Memory Objects. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Buffer : public Memory +{ +public: + + /*! \brief Constructs a Buffer in a specified context. + * + * Wraps clCreateBuffer(). + * + * \param host_ptr Storage to be used if the CL_MEM_USE_HOST_PTR flag was + * specified. Note alignment & exclusivity requirements. + */ + Buffer( + const Context& context, + cl_mem_flags flags, + ::size_t size, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateBuffer(context(), flags, size, host_ptr, &error); + + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + + /*! \brief Constructs a Buffer in the default context. + * + * Wraps clCreateBuffer(). + * + * \param host_ptr Storage to be used if the CL_MEM_USE_HOST_PTR flag was + * specified. Note alignment & exclusivity requirements. + * + * \see Context::getDefault() + */ + Buffer( + cl_mem_flags flags, + ::size_t size, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + + Context context = Context::getDefault(err); + + object_ = ::clCreateBuffer(context(), flags, size, host_ptr, &error); + + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + + /*! + * \brief Construct a Buffer from a host container via iterators. + * IteratorType must be random access. + * If useHostPtr is specified iterators must represent contiguous data. + */ + template< typename IteratorType > + Buffer( + IteratorType startIterator, + IteratorType endIterator, + bool readOnly, + bool useHostPtr = false, + cl_int* err = NULL) + { + typedef typename std::iterator_traits::value_type DataType; + cl_int error; + + cl_mem_flags flags = 0; + if( readOnly ) { + flags |= CL_MEM_READ_ONLY; + } + else { + flags |= CL_MEM_READ_WRITE; + } + if( useHostPtr ) { + flags |= CL_MEM_USE_HOST_PTR; + } + + ::size_t size = sizeof(DataType)*(endIterator - startIterator); + + Context context = Context::getDefault(err); + + if( useHostPtr ) { + object_ = ::clCreateBuffer(context(), flags, size, static_cast(&*startIterator), &error); + } else { + object_ = ::clCreateBuffer(context(), flags, size, 0, &error); + } + + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + + if( !useHostPtr ) { + error = cl::copy(startIterator, endIterator, *this); + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + } + + /*! + * \brief Construct a Buffer from a host container via iterators using a specified context. + * IteratorType must be random access. + * If useHostPtr is specified iterators must represent contiguous data. + */ + template< typename IteratorType > + Buffer(const Context &context, IteratorType startIterator, IteratorType endIterator, + bool readOnly, bool useHostPtr = false, cl_int* err = NULL); + + /*! + * \brief Construct a Buffer from a host container via iterators using a specified queue. + * If useHostPtr is specified iterators must represent contiguous data. + */ + template< typename IteratorType > + Buffer(const CommandQueue &queue, IteratorType startIterator, IteratorType endIterator, + bool readOnly, bool useHostPtr = false, cl_int* err = NULL); + + //! \brief Default constructor - initializes to NULL. + Buffer() : Memory() { } + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Buffer(const cl_mem& buffer) : Memory(buffer) { } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Buffer& operator = (const cl_mem& rhs) + { + Memory::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Buffer(const Buffer& buf) : Memory(buf) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Buffer& operator = (const Buffer &buf) + { + Memory::operator=(buf); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Buffer(Buffer&& buf) CL_HPP_NOEXCEPT : Memory(std::move(buf)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Buffer& operator = (Buffer &&buf) + { + Memory::operator=(std::move(buf)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + +#if defined(CL_VERSION_1_1) + /*! \brief Creates a new buffer object from this. + * + * Wraps clCreateSubBuffer(). + */ + Buffer createSubBuffer( + cl_mem_flags flags, + cl_buffer_create_type buffer_create_type, + const void * buffer_create_info, + cl_int * err = NULL) + { + Buffer result; + cl_int error; + result.object_ = ::clCreateSubBuffer( + object_, + flags, + buffer_create_type, + buffer_create_info, + &error); + + detail::errHandler(error, __CREATE_SUBBUFFER_ERR); + if (err != NULL) { + *err = error; + } + + return result; + } +#endif +}; + +#if defined (USE_DX_INTEROP) +/*! \brief Class interface for creating OpenCL buffers from ID3D10Buffer's. + * + * This is provided to facilitate interoperability with Direct3D. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class BufferD3D10 : public Buffer +{ +public: + typedef CL_API_ENTRY cl_mem (CL_API_CALL *PFN_clCreateFromD3D10BufferKHR)( + cl_context context, cl_mem_flags flags, ID3D10Buffer* buffer, + cl_int* errcode_ret); + + /*! \brief Constructs a BufferD3D10, in a specified context, from a + * given ID3D10Buffer. + * + * Wraps clCreateFromD3D10BufferKHR(). + */ + BufferD3D10( + const Context& context, + cl_mem_flags flags, + ID3D10Buffer* bufobj, + cl_int * err = NULL) + { + static PFN_clCreateFromD3D10BufferKHR pfn_clCreateFromD3D10BufferKHR = NULL; + +#if defined(CL_VERSION_1_2) + vector props = context.getInfo(); + cl_platform platform = -1; + for( int i = 0; i < props.size(); ++i ) { + if( props[i] == CL_CONTEXT_PLATFORM ) { + platform = props[i+1]; + } + } + __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, clCreateFromD3D10BufferKHR); +#endif +#if defined(CL_VERSION_1_1) + __INIT_CL_EXT_FCN_PTR(clCreateFromD3D10BufferKHR); +#endif + + cl_int error; + object_ = pfn_clCreateFromD3D10BufferKHR( + context(), + flags, + bufobj, + &error); + + detail::errHandler(error, __CREATE_GL_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + BufferD3D10() : Buffer() { } + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS BufferD3D10(const cl_mem& buffer) : Buffer(buffer) { } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + BufferD3D10& operator = (const cl_mem& rhs) + { + Buffer::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + BufferD3D10(const BufferD3D10& buf) : Buffer(buf) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + BufferD3D10& operator = (const BufferD3D10 &buf) + { + Buffer::operator=(buf); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + BufferD3D10(BufferD3D10&& buf) CL_HPP_NOEXCEPT : Buffer(std::move(buf)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + BufferD3D10& operator = (BufferD3D10 &&buf) + { + Buffer::operator=(std::move(buf)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; +#endif + +/*! \brief Class interface for GL Buffer Memory Objects. + * + * This is provided to facilitate interoperability with OpenGL. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class BufferGL : public Buffer +{ +public: + /*! \brief Constructs a BufferGL in a specified context, from a given + * GL buffer. + * + * Wraps clCreateFromGLBuffer(). + */ + BufferGL( + const Context& context, + cl_mem_flags flags, + cl_GLuint bufobj, + cl_int * err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLBuffer( + context(), + flags, + bufobj, + &error); + + detail::errHandler(error, __CREATE_GL_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + BufferGL() : Buffer() { } + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS BufferGL(const cl_mem& buffer) : Buffer(buffer) { } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + BufferGL& operator = (const cl_mem& rhs) + { + Buffer::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + BufferGL(const BufferGL& buf) : Buffer(buf) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + BufferGL& operator = (const BufferGL &buf) + { + Buffer::operator=(buf); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + BufferGL(BufferGL&& buf) CL_HPP_NOEXCEPT : Buffer(std::move(buf)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + BufferGL& operator = (BufferGL &&buf) + { + Buffer::operator=(std::move(buf)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + //! \brief Wrapper for clGetGLObjectInfo(). + cl_int getObjectInfo( + cl_gl_object_type *type, + cl_GLuint * gl_object_name) + { + return detail::errHandler( + ::clGetGLObjectInfo(object_,type,gl_object_name), + __GET_GL_OBJECT_INFO_ERR); + } +}; + +/*! \brief C++ base class for Image Memory objects. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Image : public Memory +{ +protected: + //! \brief Default constructor - initializes to NULL. + Image() : Memory() { } + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image(const cl_mem& image) : Memory(image) { } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image& operator = (const cl_mem& rhs) + { + Memory::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image(const Image& img) : Memory(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image& operator = (const Image &img) + { + Memory::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image(Image&& img) CL_HPP_NOEXCEPT : Memory(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image& operator = (Image &&img) + { + Memory::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + +public: + //! \brief Wrapper for clGetImageInfo(). + template + cl_int getImageInfo(cl_image_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetImageInfo, object_, name, param), + __GET_IMAGE_INFO_ERR); + } + + //! \brief Wrapper for clGetImageInfo() that returns by value. + template typename + detail::param_traits::param_type + getImageInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_image_info, name>::param_type param; + cl_int result = getImageInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } +}; + +#if defined(CL_VERSION_1_2) +/*! \brief Class interface for 1D Image Memory objects. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Image1D : public Image +{ +public: + /*! \brief Constructs a 1D Image in a specified context. + * + * Wraps clCreateImage(). + */ + Image1D( + const Context& context, + cl_mem_flags flags, + ImageFormat format, + ::size_t width, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + cl_image_desc desc = + { + CL_MEM_OBJECT_IMAGE1D, + width, + 0, 0, 0, 0, 0, 0, 0, 0 + }; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + host_ptr, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + Image1D() { } + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image1D(const cl_mem& image1D) : Image(image1D) { } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image1D& operator = (const cl_mem& rhs) + { + Image::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image1D(const Image1D& img) : Image(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image1D& operator = (const Image1D &img) + { + Image::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image1D(Image1D&& img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image1D& operator = (Image1D &&img) + { + Image::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; + +/*! \class Image1DBuffer + * \brief Image interface for 1D buffer images. + */ +class Image1DBuffer : public Image +{ +public: + Image1DBuffer( + const Context& context, + cl_mem_flags flags, + ImageFormat format, + ::size_t width, + const Buffer &buffer, + 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() + }; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + NULL, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) { + *err = error; + } + } + + Image1DBuffer() { } + + __CL_EXPLICIT_CONSTRUCTORS Image1DBuffer(const cl_mem& image1D) : Image(image1D) { } + + Image1DBuffer& operator = (const cl_mem& rhs) + { + Image::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image1DBuffer(const Image1DBuffer& img) : Image(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image1DBuffer& operator = (const Image1DBuffer &img) + { + Image::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image1DBuffer(Image1DBuffer&& img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image1DBuffer& operator = (Image1DBuffer &&img) + { + Image::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; + +/*! \class Image1DArray + * \brief Image interface for arrays of 1D images. + */ +class Image1DArray : public Image +{ +public: + Image1DArray( + const Context& context, + cl_mem_flags flags, + ImageFormat format, + ::size_t arraySize, + ::size_t width, + ::size_t rowPitch, + void* host_ptr = NULL, + 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 + }; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + host_ptr, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) { + *err = error; + } + } + + Image1DArray() { } + + __CL_EXPLICIT_CONSTRUCTORS Image1DArray(const cl_mem& imageArray) : Image(imageArray) { } + + Image1DArray& operator = (const cl_mem& rhs) + { + Image::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image1DArray(const Image1DArray& img) : Image(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image1DArray& operator = (const Image1DArray &img) + { + Image::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image1DArray(Image1DArray&& img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image1DArray& operator = (Image1DArray &&img) + { + Image::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; +#endif // #if defined(CL_VERSION_1_2) + + +/*! \brief Class interface for 2D Image Memory objects. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Image2D : public Image +{ +public: + /*! \brief Constructs a 1D Image in a specified context. + * + * Wraps clCreateImage(). + */ + Image2D( + const Context& context, + cl_mem_flags flags, + ImageFormat format, + ::size_t width, + ::size_t height, + ::size_t row_pitch = 0, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + bool useCreateImage; + +#if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + // Run-time decision based on the actual platform + { + cl_uint version = detail::getContextPlatformVersion(context()); + useCreateImage = (version >= 0x10002); // OpenCL 1.2 or above + } +#elif defined(CL_VERSION_1_2) + useCreateImage = true; +#else + useCreateImage = false; +#endif + +#if defined(CL_VERSION_1_2) + if (useCreateImage) + { + cl_image_desc desc = + { + CL_MEM_OBJECT_IMAGE2D, + width, + height, + 0, 0, // depth, array size (unused) + row_pitch, + 0, 0, 0, 0 + }; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + host_ptr, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) { + *err = error; + } + } +#endif // #if defined(CL_VERSION_1_2) +#if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + if (!useCreateImage) + { + object_ = ::clCreateImage2D( + context(), flags,&format, width, height, row_pitch, host_ptr, &error); + + detail::errHandler(error, __CREATE_IMAGE2D_ERR); + if (err != NULL) { + *err = error; + } + } +#endif // #if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + } + + //! \brief Default constructor - initializes to NULL. + Image2D() { } + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image2D(const cl_mem& image2D) : Image(image2D) { } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image2D& operator = (const cl_mem& rhs) + { + Image::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image2D(const Image2D& img) : Image(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image2D& operator = (const Image2D &img) + { + Image::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image2D(Image2D&& img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image2D& operator = (Image2D &&img) + { + Image::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; + + +#if !defined(CL_VERSION_1_2) +/*! \brief Class interface for GL 2D Image Memory objects. + * + * This is provided to facilitate interoperability with OpenGL. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + * \note Deprecated for OpenCL 1.2. Please use ImageGL instead. + */ +class CL_EXT_PREFIX__VERSION_1_1_DEPRECATED Image2DGL CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED : public Image2D +{ +public: + /*! \brief Constructs an Image2DGL in a specified context, from a given + * GL Texture. + * + * Wraps clCreateFromGLTexture2D(). + */ + Image2DGL( + const Context& context, + cl_mem_flags flags, + cl_GLenum target, + cl_GLint miplevel, + cl_GLuint texobj, + cl_int * err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLTexture2D( + context(), + flags, + target, + miplevel, + texobj, + &error); + + detail::errHandler(error, __CREATE_GL_TEXTURE_2D_ERR); + if (err != NULL) { + *err = error; + } + + } + + //! \brief Default constructor - initializes to NULL. + Image2DGL() : Image2D() { } + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image2DGL(const cl_mem& image) : Image2D(image) { } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image2DGL& operator = (const cl_mem& rhs) + { + Image2D::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image2DGL(const Image2DGL& img) : Image2D(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image2DGL& operator = (const Image2DGL &img) + { + Image2D::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image2DGL(Image2DGL&& img) CL_HPP_NOEXCEPT : Image2D(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image2DGL& operator = (Image2DGL &&img) + { + Image2D::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; +#endif // #if !defined(CL_VERSION_1_2) + +#if defined(CL_VERSION_1_2) +/*! \class Image2DArray + * \brief Image interface for arrays of 2D images. + */ +class Image2DArray : public Image +{ +public: + Image2DArray( + const Context& context, + cl_mem_flags flags, + ImageFormat format, + ::size_t arraySize, + ::size_t width, + ::size_t height, + ::size_t rowPitch, + ::size_t slicePitch, + void* host_ptr = NULL, + 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 + }; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + host_ptr, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) { + *err = error; + } + } + + Image2DArray() { } + + __CL_EXPLICIT_CONSTRUCTORS Image2DArray(const cl_mem& imageArray) : Image(imageArray) { } + + Image2DArray& operator = (const cl_mem& rhs) + { + Image::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image2DArray(const Image2DArray& img) : Image(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image2DArray& operator = (const Image2DArray &img) + { + Image::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image2DArray(Image2DArray&& img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image2DArray& operator = (Image2DArray &&img) + { + Image::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; +#endif // #if defined(CL_VERSION_1_2) + +/*! \brief Class interface for 3D Image Memory objects. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Image3D : public Image +{ +public: + /*! \brief Constructs a 3D Image in a specified context. + * + * Wraps clCreateImage(). + */ + Image3D( + const Context& context, + cl_mem_flags flags, + ImageFormat format, + ::size_t width, + ::size_t height, + ::size_t depth, + ::size_t row_pitch = 0, + ::size_t slice_pitch = 0, + void* host_ptr = NULL, + cl_int* err = NULL) + { + cl_int error; + bool useCreateImage; + +#if defined(CL_VERSION_1_2) && defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + // Run-time decision based on the actual platform + { + cl_uint version = detail::getContextPlatformVersion(context()); + useCreateImage = (version >= 0x10002); // OpenCL 1.2 or above + } +#elif defined(CL_VERSION_1_2) + useCreateImage = true; +#else + useCreateImage = false; +#endif + +#if defined(CL_VERSION_1_2) + if (useCreateImage) + { + cl_image_desc desc = + { + CL_MEM_OBJECT_IMAGE3D, + width, + height, + depth, + 0, // array size (unused) + row_pitch, + slice_pitch, + 0, 0, 0 + }; + object_ = ::clCreateImage( + context(), + flags, + &format, + &desc, + host_ptr, + &error); + + detail::errHandler(error, __CREATE_IMAGE_ERR); + if (err != NULL) { + *err = error; + } + } +#endif // #if defined(CL_VERSION_1_2) +#if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + if (!useCreateImage) + { + object_ = ::clCreateImage3D( + context(), flags, &format, width, height, depth, row_pitch, + slice_pitch, host_ptr, &error); + + detail::errHandler(error, __CREATE_IMAGE3D_ERR); + if (err != NULL) { + *err = error; + } + } +#endif // #if !defined(CL_VERSION_1_2) || defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) + } + + //! \brief Default constructor - initializes to NULL. + Image3D() : Image() { } + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image3D(const cl_mem& image3D) : Image(image3D) { } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image3D& operator = (const cl_mem& rhs) + { + Image::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image3D(const Image3D& img) : Image(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image3D& operator = (const Image3D &img) + { + Image::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image3D(Image3D&& img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image3D& operator = (Image3D &&img) + { + Image::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; + +#if !defined(CL_VERSION_1_2) +/*! \brief Class interface for GL 3D Image Memory objects. + * + * This is provided to facilitate interoperability with OpenGL. + * + * See Memory for details about copy semantics, etc. + * + * \see Memory + */ +class Image3DGL : public Image3D +{ +public: + /*! \brief Constructs an Image3DGL in a specified context, from a given + * GL Texture. + * + * Wraps clCreateFromGLTexture3D(). + */ + Image3DGL( + const Context& context, + cl_mem_flags flags, + cl_GLenum target, + cl_GLint miplevel, + cl_GLuint texobj, + cl_int * err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLTexture3D( + context(), + flags, + target, + miplevel, + texobj, + &error); + + detail::errHandler(error, __CREATE_GL_TEXTURE_3D_ERR); + if (err != NULL) { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. + Image3DGL() : Image3D() { } + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ + __CL_EXPLICIT_CONSTRUCTORS Image3DGL(const cl_mem& image) : Image3D(image) { } + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + Image3DGL& operator = (const cl_mem& rhs) + { + Image3D::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image3DGL(const Image3DGL& img) : Image3D(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Image3DGL& operator = (const Image3DGL &img) + { + Image3D::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Image3DGL(Image3DGL&& img) CL_HPP_NOEXCEPT : Image3D(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Image3DGL& operator = (Image3DGL &&img) + { + Image3D::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; +#endif // #if !defined(CL_VERSION_1_2) + +#if defined(CL_VERSION_1_2) +/*! \class ImageGL + * \brief general image interface for GL interop. + * We abstract the 2D and 3D GL images into a single instance here + * that wraps all GL sourced images on the grounds that setup information + * was performed by OpenCL anyway. + */ +class ImageGL : public Image +{ +public: + ImageGL( + const Context& context, + cl_mem_flags flags, + cl_GLenum target, + cl_GLint miplevel, + cl_GLuint texobj, + cl_int * err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLTexture( + context(), + flags, + target, + miplevel, + texobj, + &error); + + detail::errHandler(error, __CREATE_GL_TEXTURE_ERR); + if (err != NULL) { + *err = error; + } + } + + ImageGL() : Image() { } + + __CL_EXPLICIT_CONSTRUCTORS ImageGL(const cl_mem& image) : Image(image) { } + + ImageGL& operator = (const cl_mem& rhs) + { + Image::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + ImageGL(const ImageGL& img) : Image(img) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + ImageGL& operator = (const ImageGL &img) + { + Image::operator=(img); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + ImageGL(ImageGL&& img) CL_HPP_NOEXCEPT : Image(std::move(img)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + ImageGL& operator = (ImageGL &&img) + { + Image::operator=(std::move(img)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) +}; +#endif // #if defined(CL_VERSION_1_2) + +/*! \brief Class interface for GL Render Buffer Memory Objects. +* +* This is provided to facilitate interoperability with OpenGL. +* +* See Memory for details about copy semantics, etc. +* +* \see Memory +*/ +class BufferRenderGL : +#if defined(CL_VERSION_1_2) + public ImageGL +#else // #if defined(CL_VERSION_1_2) + public Image2DGL +#endif //#if defined(CL_VERSION_1_2) +{ +public: + /*! \brief Constructs a BufferRenderGL in a specified context, from a given + * GL Renderbuffer. + * + * Wraps clCreateFromGLRenderbuffer(). + */ + BufferRenderGL( + const Context& context, + cl_mem_flags flags, + cl_GLuint bufobj, + cl_int * err = NULL) + { + cl_int error; + object_ = ::clCreateFromGLRenderbuffer( + context(), + flags, + bufobj, + &error); + + detail::errHandler(error, __CREATE_GL_RENDER_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } + + //! \brief Default constructor - initializes to NULL. +#if defined(CL_VERSION_1_2) + BufferRenderGL() : ImageGL() {}; +#else // #if defined(CL_VERSION_1_2) + BufferRenderGL() : Image2DGL() {}; +#endif //#if defined(CL_VERSION_1_2) + + /*! \brief Constructor from cl_mem - takes ownership. + * + * See Memory for further details. + */ +#if defined(CL_VERSION_1_2) + __CL_EXPLICIT_CONSTRUCTORS BufferRenderGL(const cl_mem& buffer) : ImageGL(buffer) { } +#else // #if defined(CL_VERSION_1_2) + __CL_EXPLICIT_CONSTRUCTORS BufferRenderGL(const cl_mem& buffer) : Image2DGL(buffer) { } +#endif //#if defined(CL_VERSION_1_2) + + + /*! \brief Assignment from cl_mem - performs shallow copy. + * + * See Memory for further details. + */ + BufferRenderGL& operator = (const cl_mem& rhs) + { +#if defined(CL_VERSION_1_2) + ImageGL::operator=(rhs); +#else // #if defined(CL_VERSION_1_2) + Image2DGL::operator=(rhs); +#endif //#if defined(CL_VERSION_1_2) + + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ +#if defined(CL_VERSION_1_2) + BufferRenderGL(const BufferRenderGL& buf) : ImageGL(buf) {} +#else // #if defined(CL_VERSION_1_2) + BufferRenderGL(const BufferRenderGL& buf) : Image2DGL(buf) {} +#endif //#if defined(CL_VERSION_1_2) + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + BufferRenderGL& operator = (const BufferRenderGL &rhs) + { +#if defined(CL_VERSION_1_2) + ImageGL::operator=(rhs); +#else // #if defined(CL_VERSION_1_2) + Image2DGL::operator=(rhs); +#endif //#if defined(CL_VERSION_1_2) + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ +#if defined(CL_VERSION_1_2) + BufferRenderGL(BufferRenderGL&& buf) CL_HPP_NOEXCEPT : ImageGL(std::move(buf)) {} +#else // #if defined(CL_VERSION_1_2) + BufferRenderGL(BufferRenderGL&& buf) CL_HPP_NOEXCEPT : Image2DGL(std::move(buf)) {} +#endif //#if defined(CL_VERSION_1_2) + + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + BufferRenderGL& operator = (BufferRenderGL &&buf) + { +#if defined(CL_VERSION_1_2) + ImageGL::operator=(std::move(buf)); +#else // #if defined(CL_VERSION_1_2) + Image2DGL::operator=(std::move(buf)); +#endif //#if defined(CL_VERSION_1_2) + + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + //! \brief Wrapper for clGetGLObjectInfo(). + cl_int getObjectInfo( + cl_gl_object_type *type, + cl_GLuint * gl_object_name) + { + return detail::errHandler( + ::clGetGLObjectInfo(object_, type, gl_object_name), + __GET_GL_OBJECT_INFO_ERR); + } +}; + +/*! \brief Class interface for cl_sampler. + * + * \note Copies of these objects are shallow, meaning that the copy will refer + * to the same underlying cl_sampler as the original. For details, see + * clRetainSampler() and clReleaseSampler(). + * + * \see cl_sampler + */ +class Sampler : public detail::Wrapper +{ +public: + //! \brief Default constructor - initializes to NULL. + Sampler() { } + + /*! \brief Constructs a Sampler in a specified context. + * + * Wraps clCreateSampler(). + */ + Sampler( + const Context& context, + cl_bool normalized_coords, + cl_addressing_mode addressing_mode, + cl_filter_mode filter_mode, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateSampler( + context(), + normalized_coords, + addressing_mode, + filter_mode, + &error); + + detail::errHandler(error, __CREATE_SAMPLER_ERR); + if (err != NULL) { + *err = error; + } + } + + /*! \brief Constructor from cl_sampler - takes ownership. + * + * This effectively transfers ownership of a refcount on the cl_sampler + * into the new Sampler object. + */ + __CL_EXPLICIT_CONSTRUCTORS Sampler(const cl_sampler& sampler) : detail::Wrapper(sampler) { } + + /*! \brief Assignment operator from cl_sampler - takes ownership. + * + * This effectively transfers ownership of a refcount on the rhs and calls + * clReleaseSampler() on the value previously held by this instance. + */ + Sampler& operator = (const cl_sampler& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Sampler(const Sampler& sam) : detail::Wrapper(sam) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Sampler& operator = (const Sampler &sam) + { + detail::Wrapper::operator=(sam); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Sampler(Sampler&& sam) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(sam)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Sampler& operator = (Sampler &&sam) + { + detail::Wrapper::operator=(std::move(sam)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + //! \brief Wrapper for clGetSamplerInfo(). + template + cl_int getInfo(cl_sampler_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetSamplerInfo, object_, name, param), + __GET_SAMPLER_INFO_ERR); + } + + //! \brief Wrapper for clGetSamplerInfo() that returns by value. + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_sampler_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } +}; + +class Program; +class CommandQueue; +class Kernel; + +//! \brief Class interface for specifying NDRange values. +class NDRange +{ +private: + size_t<3> sizes_; + cl_uint dimensions_; + +public: + //! \brief Default constructor - resulting range has zero dimensions. + NDRange() + : dimensions_(0) + { } + + //! \brief Constructs one-dimensional range. + NDRange(::size_t size0) + : dimensions_(1) + { + sizes_[0] = size0; + } + + //! \brief Constructs two-dimensional range. + NDRange(::size_t size0, ::size_t size1) + : dimensions_(2) + { + sizes_[0] = size0; + sizes_[1] = size1; + } + + //! \brief Constructs three-dimensional range. + NDRange(::size_t size0, ::size_t size1, ::size_t size2) + : dimensions_(3) + { + sizes_[0] = size0; + sizes_[1] = size1; + sizes_[2] = size2; + } + + /*! \brief Conversion operator to const ::size_t *. + * + * \returns a pointer to the size of the first dimension. + */ + operator const ::size_t*() const { + return (const ::size_t*) sizes_; + } + + //! \brief Queries the number of dimensions in the range. + ::size_t dimensions() const { return dimensions_; } +}; + +//! \brief A zero-dimensional range. +static const NDRange NullRange; + +//! \brief Local address wrapper for use with Kernel::setArg +struct LocalSpaceArg +{ + ::size_t size_; +}; + +namespace detail { + +template +struct KernelArgumentHandler +{ + static ::size_t size(const T&) { return sizeof(T); } + static const T* ptr(const T& value) { return &value; } +}; + +template <> +struct KernelArgumentHandler +{ + static ::size_t size(const LocalSpaceArg& value) { return value.size_; } + static const void* ptr(const LocalSpaceArg&) { return NULL; } +}; + +} +//! \endcond + +/*! __local + * \brief Helper function for generating LocalSpaceArg objects. + * Deprecated. Replaced with Local. + */ +inline CL_EXT_PREFIX__VERSION_1_1_DEPRECATED LocalSpaceArg +__local(::size_t size) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; +inline LocalSpaceArg +__local(::size_t size) +{ + LocalSpaceArg ret = { size }; + return ret; +} + +/*! Local + * \brief Helper function for generating LocalSpaceArg objects. + */ +inline LocalSpaceArg +Local(::size_t size) +{ + LocalSpaceArg ret = { size }; + return ret; +} + +//class KernelFunctor; + +/*! \brief Class interface for cl_kernel. + * + * \note Copies of these objects are shallow, meaning that the copy will refer + * to the same underlying cl_kernel as the original. For details, see + * clRetainKernel() and clReleaseKernel(). + * + * \see cl_kernel + */ +class Kernel : public detail::Wrapper +{ +public: + inline Kernel(const Program& program, const char* name, cl_int* err = NULL); + + //! \brief Default constructor - initializes to NULL. + Kernel() { } + + /*! \brief Constructor from cl_kernel - takes ownership. + * + * This effectively transfers ownership of a refcount on the cl_kernel + * into the new Kernel object. + */ + __CL_EXPLICIT_CONSTRUCTORS Kernel(const cl_kernel& kernel) : detail::Wrapper(kernel) { } + + /*! \brief Assignment operator from cl_kernel - takes ownership. + * + * This effectively transfers ownership of a refcount on the rhs and calls + * clReleaseKernel() on the value previously held by this instance. + */ + Kernel& operator = (const cl_kernel& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Kernel(const Kernel& kernel) : detail::Wrapper(kernel) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Kernel& operator = (const Kernel &kernel) + { + detail::Wrapper::operator=(kernel); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Kernel(Kernel&& kernel) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(kernel)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Kernel& operator = (Kernel &&kernel) + { + detail::Wrapper::operator=(std::move(kernel)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + template + cl_int getInfo(cl_kernel_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetKernelInfo, object_, name, param), + __GET_KERNEL_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_kernel_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + +#if defined(CL_VERSION_1_2) + template + cl_int getArgInfo(cl_uint argIndex, cl_kernel_arg_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetKernelArgInfo, object_, argIndex, name, param), + __GET_KERNEL_ARG_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getArgInfo(cl_uint argIndex, cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_kernel_arg_info, name>::param_type param; + cl_int result = getArgInfo(argIndex, name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } +#endif // #if defined(CL_VERSION_1_2) + + template + cl_int getWorkGroupInfo( + const Device& device, cl_kernel_work_group_info name, T* param) const + { + return detail::errHandler( + detail::getInfo( + &::clGetKernelWorkGroupInfo, object_, device(), name, param), + __GET_KERNEL_WORK_GROUP_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getWorkGroupInfo(const Device& device, cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_kernel_work_group_info, name>::param_type param; + cl_int result = getWorkGroupInfo(device, name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + template + cl_int setArg(cl_uint index, const T &value) + { + return detail::errHandler( + ::clSetKernelArg( + object_, + index, + detail::KernelArgumentHandler::size(value), + detail::KernelArgumentHandler::ptr(value)), + __SET_KERNEL_ARGS_ERR); + } + + cl_int setArg(cl_uint index, ::size_t size, const void* argPtr) + { + return detail::errHandler( + ::clSetKernelArg(object_, index, size, argPtr), + __SET_KERNEL_ARGS_ERR); + } +}; + +/*! \class Program + * \brief Program interface that implements cl_program. + */ +class Program : public detail::Wrapper +{ +public: + typedef VECTOR_CLASS > Binaries; + typedef VECTOR_CLASS > Sources; + + Program( + const STRING_CLASS& source, + bool build = false, + cl_int* err = NULL) + { + cl_int error; + + const char * strings = source.c_str(); + const ::size_t length = source.size(); + + Context context = Context::getDefault(err); + + object_ = ::clCreateProgramWithSource( + context(), (cl_uint)1, &strings, &length, &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); + + if (error == CL_SUCCESS && build) { + + error = ::clBuildProgram( + object_, + 0, + NULL, + "", + NULL, + NULL); + + detail::errHandler(error, __BUILD_PROGRAM_ERR); + } + + if (err != NULL) { + *err = error; + } + } + + Program( + const Context& context, + const STRING_CLASS& source, + bool build = false, + cl_int* err = NULL) + { + cl_int error; + + const char * strings = source.c_str(); + const ::size_t length = source.size(); + + object_ = ::clCreateProgramWithSource( + context(), (cl_uint)1, &strings, &length, &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); + + if (error == CL_SUCCESS && build) { + + error = ::clBuildProgram( + object_, + 0, + NULL, + "", + NULL, + NULL); + + detail::errHandler(error, __BUILD_PROGRAM_ERR); + } + + if (err != NULL) { + *err = error; + } + } + + Program( + const Context& context, + const Sources& sources, + cl_int* err = NULL) + { + cl_int error; + + const ::size_t n = (::size_t)sources.size(); + ::size_t* lengths = (::size_t*) alloca(n * sizeof(::size_t)); + const char** strings = (const char**) alloca(n * sizeof(const char*)); + + for (::size_t i = 0; i < n; ++i) { + strings[i] = sources[(int)i].first; + lengths[i] = sources[(int)i].second; + } + + object_ = ::clCreateProgramWithSource( + context(), (cl_uint)n, strings, lengths, &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR); + if (err != NULL) { + *err = error; + } + } + + /** + * Construct a program object from a list of devices and a per-device list of binaries. + * \param context A valid OpenCL context in which to construct the program. + * \param devices A vector of OpenCL device objects for which the program will be created. + * \param binaries A vector of pairs of a pointer to a binary object and its length. + * \param binaryStatus An optional vector that on completion will be resized to + * match the size of binaries and filled with values to specify if each binary + * was successfully loaded. + * Set to CL_SUCCESS if the binary was successfully loaded. + * Set to CL_INVALID_VALUE if the length is 0 or the binary pointer is NULL. + * Set to CL_INVALID_BINARY if the binary provided is not valid for the matching device. + * \param err if non-NULL will be set to CL_SUCCESS on successful operation or one of the following errors: + * CL_INVALID_CONTEXT if context is not a valid context. + * CL_INVALID_VALUE if the length of devices is zero; or if the length of binaries does not match the length of devices; + * or if any entry in binaries is NULL or has length 0. + * CL_INVALID_DEVICE if OpenCL devices listed in devices are not in the list of devices associated with context. + * CL_INVALID_BINARY if an invalid program binary was encountered for any device. binaryStatus will return specific status for each device. + * CL_OUT_OF_HOST_MEMORY if there is a failure to allocate resources required by the OpenCL implementation on the host. + */ + Program( + const Context& context, + const VECTOR_CLASS& devices, + const Binaries& binaries, + VECTOR_CLASS* binaryStatus = NULL, + cl_int* err = NULL) + { + cl_int error; + + const ::size_t numDevices = devices.size(); + + // Catch size mismatch early and return + if(binaries.size() != numDevices) { + error = CL_INVALID_VALUE; + detail::errHandler(error, __CREATE_PROGRAM_WITH_BINARY_ERR); + if (err != NULL) { + *err = error; + } + return; + } + + ::size_t* lengths = (::size_t*) alloca(numDevices * sizeof(::size_t)); + const unsigned char** images = (const unsigned char**) alloca(numDevices * sizeof(const unsigned char**)); + + for (::size_t i = 0; i < numDevices; ++i) { + images[i] = (const unsigned char*)binaries[i].first; + lengths[i] = binaries[(int)i].second; + } + + cl_device_id* deviceIDs = (cl_device_id*) alloca(numDevices * sizeof(cl_device_id)); + for( ::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex ) { + deviceIDs[deviceIndex] = (devices[deviceIndex])(); + } + + if(binaryStatus) { + binaryStatus->resize(numDevices); + } + + object_ = ::clCreateProgramWithBinary( + context(), (cl_uint) devices.size(), + deviceIDs, + lengths, images, (binaryStatus != NULL && numDevices > 0) + ? &binaryStatus->front() + : NULL, &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_BINARY_ERR); + if (err != NULL) { + *err = error; + } + } + + +#if defined(CL_VERSION_1_2) + /** + * Create program using builtin kernels. + * \param kernelNames Semi-colon separated list of builtin kernel names + */ + Program( + const Context& context, + const VECTOR_CLASS& devices, + const STRING_CLASS& kernelNames, + cl_int* err = NULL) + { + cl_int error; + + + ::size_t numDevices = devices.size(); + cl_device_id* deviceIDs = (cl_device_id*) alloca(numDevices * sizeof(cl_device_id)); + for( ::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex ) { + deviceIDs[deviceIndex] = (devices[deviceIndex])(); + } + + object_ = ::clCreateProgramWithBuiltInKernels( + context(), + (cl_uint) devices.size(), + deviceIDs, + kernelNames.c_str(), + &error); + + detail::errHandler(error, __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR); + if (err != NULL) { + *err = error; + } + } +#endif // #if defined(CL_VERSION_1_2) + + Program() { } + + __CL_EXPLICIT_CONSTRUCTORS Program(const cl_program& program) : detail::Wrapper(program) { } + + Program& operator = (const cl_program& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + Program(const Program& program) : detail::Wrapper(program) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + Program& operator = (const Program &program) + { + detail::Wrapper::operator=(program); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + Program(Program&& program) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(program)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + Program& operator = (Program &&program) + { + detail::Wrapper::operator=(std::move(program)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + cl_int build( + const VECTOR_CLASS& devices, + const char* options = NULL, + void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, + void* data = NULL) const + { + ::size_t numDevices = devices.size(); + cl_device_id* deviceIDs = (cl_device_id*) alloca(numDevices * sizeof(cl_device_id)); + for( ::size_t deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex ) { + deviceIDs[deviceIndex] = (devices[deviceIndex])(); + } + + return detail::errHandler( + ::clBuildProgram( + object_, + (cl_uint) + devices.size(), + deviceIDs, + options, + notifyFptr, + data), + __BUILD_PROGRAM_ERR); + } + + cl_int build( + const char* options = NULL, + void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, + void* data = NULL) const + { + return detail::errHandler( + ::clBuildProgram( + object_, + 0, + NULL, + options, + notifyFptr, + data), + __BUILD_PROGRAM_ERR); + } + +#if defined(CL_VERSION_1_2) + cl_int compile( + const char* options = NULL, + void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, + void* data = NULL) const + { + return detail::errHandler( + ::clCompileProgram( + object_, + 0, + NULL, + options, + 0, + NULL, + NULL, + notifyFptr, + data), + __COMPILE_PROGRAM_ERR); + } +#endif + + template + cl_int getInfo(cl_program_info name, T* param) const + { + return detail::errHandler( + detail::getInfo(&::clGetProgramInfo, object_, name, param), + __GET_PROGRAM_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_program_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + template + cl_int getBuildInfo( + const Device& device, cl_program_build_info name, T* param) const + { + return detail::errHandler( + detail::getInfo( + &::clGetProgramBuildInfo, object_, device(), name, param), + __GET_PROGRAM_BUILD_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getBuildInfo(const Device& device, cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_program_build_info, name>::param_type param; + cl_int result = getBuildInfo(device, name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + cl_int createKernels(VECTOR_CLASS* kernels) + { + cl_uint numKernels; + cl_int err = ::clCreateKernelsInProgram(object_, 0, NULL, &numKernels); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __CREATE_KERNELS_IN_PROGRAM_ERR); + } + + Kernel* value = (Kernel*) alloca(numKernels * sizeof(Kernel)); + err = ::clCreateKernelsInProgram( + object_, numKernels, (cl_kernel*) value, NULL); + if (err != CL_SUCCESS) { + return detail::errHandler(err, __CREATE_KERNELS_IN_PROGRAM_ERR); + } + + kernels->assign(&value[0], &value[numKernels]); + return CL_SUCCESS; + } +}; + +#if defined(CL_VERSION_1_2) +inline Program linkProgram( + Program input1, + Program input2, + const char* options = NULL, + void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, + void* data = NULL, + cl_int* err = NULL) +{ + cl_int error_local = CL_SUCCESS; + + cl_program programs[2] = { input1(), input2() }; + + Context ctx = input1.getInfo(&error_local); + if(error_local!=CL_SUCCESS) { + detail::errHandler(error_local, __LINK_PROGRAM_ERR); + } + + cl_program prog = ::clLinkProgram( + ctx(), + 0, + NULL, + options, + 2, + programs, + notifyFptr, + data, + &error_local); + + detail::errHandler(error_local,__COMPILE_PROGRAM_ERR); + if (err != NULL) { + *err = error_local; + } + + return Program(prog); +} + +inline Program linkProgram( + VECTOR_CLASS inputPrograms, + const char* options = NULL, + void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL, + void* data = NULL, + cl_int* err = NULL) +{ + cl_int error_local = CL_SUCCESS; + + cl_program * programs = (cl_program*) alloca(inputPrograms.size() * sizeof(cl_program)); + + if (programs != NULL) { + for (unsigned int i = 0; i < inputPrograms.size(); i++) { + programs[i] = inputPrograms[i](); + } + } + + Context ctx; + if(inputPrograms.size() > 0) { + ctx = inputPrograms[0].getInfo(&error_local); + if(error_local!=CL_SUCCESS) { + detail::errHandler(error_local, __LINK_PROGRAM_ERR); + } + } + cl_program prog = ::clLinkProgram( + ctx(), + 0, + NULL, + options, + (cl_uint)inputPrograms.size(), + programs, + notifyFptr, + data, + &error_local); + + detail::errHandler(error_local,__COMPILE_PROGRAM_ERR); + if (err != NULL) { + *err = error_local; + } + + return Program(prog); +} +#endif + +template<> +inline VECTOR_CLASS cl::Program::getInfo(cl_int* err) const +{ + VECTOR_CLASS< ::size_t> sizes = getInfo(); + VECTOR_CLASS binaries; + for (VECTOR_CLASS< ::size_t>::iterator s = sizes.begin(); s != sizes.end(); ++s) + { + char *ptr = NULL; + if (*s != 0) + ptr = new char[*s]; + binaries.push_back(ptr); + } + + cl_int result = getInfo(CL_PROGRAM_BINARIES, &binaries); + if (err != NULL) { + *err = result; + } + return binaries; +} + +inline Kernel::Kernel(const Program& program, const char* name, cl_int* err) +{ + cl_int error; + + object_ = ::clCreateKernel(program(), name, &error); + detail::errHandler(error, __CREATE_KERNEL_ERR); + + if (err != NULL) { + *err = error; + } + +} + +/*! \class CommandQueue + * \brief CommandQueue interface for cl_command_queue. + */ +class CommandQueue : public detail::Wrapper +{ +private: +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED + static std::atomic default_initialized_; +#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED + static volatile int default_initialized_; +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED + static CommandQueue default_; + static volatile cl_int default_error_; +public: + CommandQueue( + cl_command_queue_properties properties, + cl_int* err = NULL) + { + cl_int error; + + Context context = Context::getDefault(&error); + detail::errHandler(error, __CREATE_CONTEXT_ERR); + + if (error != CL_SUCCESS) { + if (err != NULL) { + *err = error; + } + } + else { + Device device = context.getInfo()[0]; + + object_ = ::clCreateCommandQueue( + context(), device(), properties, &error); + + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + if (err != NULL) { + *err = error; + } + } + } + /*! + * \brief Constructs a CommandQueue for an implementation defined device in the given context + */ + explicit CommandQueue( + const Context& context, + cl_command_queue_properties properties = 0, + cl_int* err = NULL) + { + cl_int error; + VECTOR_CLASS devices; + error = context.getInfo(CL_CONTEXT_DEVICES, &devices); + + detail::errHandler(error, __CREATE_CONTEXT_ERR); + + if (error != CL_SUCCESS) + { + if (err != NULL) { + *err = error; + } + return; + } + + object_ = ::clCreateCommandQueue(context(), devices[0](), properties, &error); + + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + + if (err != NULL) { + *err = error; + } + + } + + CommandQueue( + const Context& context, + const Device& device, + cl_command_queue_properties properties = 0, + cl_int* err = NULL) + { + cl_int error; + object_ = ::clCreateCommandQueue( + context(), device(), properties, &error); + + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + if (err != NULL) { + *err = error; + } + } + + /*! \brief Copy constructor to forward copy to the superclass correctly. + * Required for MSVC. + */ + CommandQueue(const CommandQueue& queue) : detail::Wrapper(queue) {} + + /*! \brief Copy assignment to forward copy to the superclass correctly. + * Required for MSVC. + */ + CommandQueue& operator = (const CommandQueue &queue) + { + detail::Wrapper::operator=(queue); + return *this; + } + +#if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + /*! \brief Move constructor to forward move to the superclass correctly. + * Required for MSVC. + */ + CommandQueue(CommandQueue&& queue) CL_HPP_NOEXCEPT : detail::Wrapper(std::move(queue)) {} + + /*! \brief Move assignment to forward move to the superclass correctly. + * Required for MSVC. + */ + CommandQueue& operator = (CommandQueue &&queue) + { + detail::Wrapper::operator=(std::move(queue)); + return *this; + } +#endif // #if defined(CL_HPP_RVALUE_REFERENCES_SUPPORTED) + + static CommandQueue getDefault(cl_int * err = NULL) + { + int state = detail::compare_exchange( + &default_initialized_, + __DEFAULT_BEING_INITIALIZED, __DEFAULT_NOT_INITIALIZED); + + if (state & __DEFAULT_INITIALIZED) { + if (err != NULL) { + *err = default_error_; + } + return default_; + } + + if (state & __DEFAULT_BEING_INITIALIZED) { + // Assume writes will propagate eventually... + while(default_initialized_ != __DEFAULT_INITIALIZED) { + detail::fence(); + } + + if (err != NULL) { + *err = default_error_; + } + return default_; + } + + cl_int error; + + Context context = Context::getDefault(&error); + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + + if (error != CL_SUCCESS) { + if (err != NULL) { + *err = error; + } + } + else { + Device device = context.getInfo()[0]; + + default_ = CommandQueue(context, device, 0, &error); + + detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR); + if (err != NULL) { + *err = error; + } + } + + detail::fence(); + + default_error_ = error; + // Assume writes will propagate eventually... + default_initialized_ = __DEFAULT_INITIALIZED; + + detail::fence(); + + if (err != NULL) { + *err = default_error_; + } + return default_; + + } + + CommandQueue() { } + + __CL_EXPLICIT_CONSTRUCTORS CommandQueue(const cl_command_queue& commandQueue) : detail::Wrapper(commandQueue) { } + + CommandQueue& operator = (const cl_command_queue& rhs) + { + detail::Wrapper::operator=(rhs); + return *this; + } + + template + cl_int getInfo(cl_command_queue_info name, T* param) const + { + return detail::errHandler( + detail::getInfo( + &::clGetCommandQueueInfo, object_, name, param), + __GET_COMMAND_QUEUE_INFO_ERR); + } + + template typename + detail::param_traits::param_type + getInfo(cl_int* err = NULL) const + { + typename detail::param_traits< + detail::cl_command_queue_info, name>::param_type param; + cl_int result = getInfo(name, ¶m); + if (err != NULL) { + *err = result; + } + return param; + } + + cl_int enqueueReadBuffer( + const Buffer& buffer, + cl_bool blocking, + ::size_t offset, + ::size_t size, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueReadBuffer( + object_, buffer(), blocking, offset, size, + ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_READ_BUFFER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueWriteBuffer( + const Buffer& buffer, + cl_bool blocking, + ::size_t offset, + ::size_t size, + const void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueWriteBuffer( + object_, buffer(), blocking, offset, size, + ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_WRITE_BUFFER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueCopyBuffer( + const Buffer& src, + const Buffer& dst, + ::size_t src_offset, + ::size_t dst_offset, + ::size_t size, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueCopyBuffer( + object_, src(), dst(), src_offset, dst_offset, size, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQEUE_COPY_BUFFER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueReadBufferRect( + const Buffer& buffer, + cl_bool blocking, + const size_t<3>& buffer_offset, + const size_t<3>& host_offset, + const size_t<3>& region, + ::size_t buffer_row_pitch, + ::size_t buffer_slice_pitch, + ::size_t host_row_pitch, + ::size_t host_slice_pitch, + void *ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueReadBufferRect( + object_, + buffer(), + blocking, + (const ::size_t *)buffer_offset, + (const ::size_t *)host_offset, + (const ::size_t *)region, + buffer_row_pitch, + buffer_slice_pitch, + host_row_pitch, + host_slice_pitch, + ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_READ_BUFFER_RECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueWriteBufferRect( + const Buffer& buffer, + cl_bool blocking, + const size_t<3>& buffer_offset, + const size_t<3>& host_offset, + const size_t<3>& region, + ::size_t buffer_row_pitch, + ::size_t buffer_slice_pitch, + ::size_t host_row_pitch, + ::size_t host_slice_pitch, + void *ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueWriteBufferRect( + object_, + buffer(), + blocking, + (const ::size_t *)buffer_offset, + (const ::size_t *)host_offset, + (const ::size_t *)region, + buffer_row_pitch, + buffer_slice_pitch, + host_row_pitch, + host_slice_pitch, + ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_WRITE_BUFFER_RECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueCopyBufferRect( + const Buffer& src, + const Buffer& dst, + const size_t<3>& src_origin, + const size_t<3>& dst_origin, + const size_t<3>& region, + ::size_t src_row_pitch, + ::size_t src_slice_pitch, + ::size_t dst_row_pitch, + ::size_t dst_slice_pitch, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueCopyBufferRect( + object_, + src(), + dst(), + (const ::size_t *)src_origin, + (const ::size_t *)dst_origin, + (const ::size_t *)region, + src_row_pitch, + src_slice_pitch, + dst_row_pitch, + dst_slice_pitch, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQEUE_COPY_BUFFER_RECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + +#if defined(CL_VERSION_1_2) + /** + * Enqueue a command to fill a buffer object with a pattern + * of a given size. The pattern is specified a as vector. + * \tparam PatternType The datatype of the pattern field. + * The pattern type must be an accepted OpenCL data type. + */ + template + cl_int enqueueFillBuffer( + const Buffer& buffer, + PatternType pattern, + ::size_t offset, + ::size_t size, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueFillBuffer( + object_, + buffer(), + static_cast(&pattern), + sizeof(PatternType), + offset, + size, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_FILL_BUFFER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } +#endif // #if defined(CL_VERSION_1_2) + + cl_int enqueueReadImage( + const Image& image, + cl_bool blocking, + const size_t<3>& origin, + const size_t<3>& region, + ::size_t row_pitch, + ::size_t slice_pitch, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueReadImage( + object_, image(), blocking, (const ::size_t *) origin, + (const ::size_t *) region, row_pitch, slice_pitch, ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_READ_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueWriteImage( + const Image& image, + cl_bool blocking, + const size_t<3>& origin, + const size_t<3>& region, + ::size_t row_pitch, + ::size_t slice_pitch, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueWriteImage( + object_, image(), blocking, (const ::size_t *) origin, + (const ::size_t *) region, row_pitch, slice_pitch, ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_WRITE_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueCopyImage( + const Image& src, + const Image& dst, + const size_t<3>& src_origin, + const size_t<3>& dst_origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueCopyImage( + object_, src(), dst(), (const ::size_t *) src_origin, + (const ::size_t *)dst_origin, (const ::size_t *) region, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_COPY_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + +#if defined(CL_VERSION_1_2) + /** + * Enqueue a command to fill an image object with a specified color. + * \param fillColor is the color to use to fill the image. + * This is a four component RGBA floating-point color value if + * the image channel data type is not an unnormalized signed or + * unsigned data type. + */ + cl_int enqueueFillImage( + const Image& image, + cl_float4 fillColor, + const size_t<3>& origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueFillImage( + object_, + image(), + static_cast(&fillColor), + (const ::size_t *) origin, + (const ::size_t *) region, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_FILL_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + /** + * Enqueue a command to fill an image object with a specified color. + * \param fillColor is the color to use to fill the image. + * This is a four component RGBA signed integer color value if + * the image channel data type is an unnormalized signed integer + * type. + */ + cl_int enqueueFillImage( + const Image& image, + cl_int4 fillColor, + const size_t<3>& origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueFillImage( + object_, + image(), + static_cast(&fillColor), + (const ::size_t *) origin, + (const ::size_t *) region, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_FILL_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + /** + * Enqueue a command to fill an image object with a specified color. + * \param fillColor is the color to use to fill the image. + * This is a four component RGBA unsigned integer color value if + * the image channel data type is an unnormalized unsigned integer + * type. + */ + cl_int enqueueFillImage( + const Image& image, + cl_uint4 fillColor, + const size_t<3>& origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueFillImage( + object_, + image(), + static_cast(&fillColor), + (const ::size_t *) origin, + (const ::size_t *) region, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_FILL_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } +#endif // #if defined(CL_VERSION_1_2) + + cl_int enqueueCopyImageToBuffer( + const Image& src, + const Buffer& dst, + const size_t<3>& src_origin, + const size_t<3>& region, + ::size_t dst_offset, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueCopyImageToBuffer( + object_, src(), dst(), (const ::size_t *) src_origin, + (const ::size_t *) region, dst_offset, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueCopyBufferToImage( + const Buffer& src, + const Image& dst, + ::size_t src_offset, + const size_t<3>& dst_origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueCopyBufferToImage( + object_, src(), dst(), src_offset, + (const ::size_t *) dst_origin, (const ::size_t *) region, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + void* enqueueMapBuffer( + const Buffer& buffer, + cl_bool blocking, + cl_map_flags flags, + ::size_t offset, + ::size_t size, + const VECTOR_CLASS* events = NULL, + Event* event = NULL, + cl_int* err = NULL) const + { + cl_event tmp; + cl_int error; + void * result = ::clEnqueueMapBuffer( + object_, buffer(), blocking, flags, offset, size, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL, + &error); + + detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + if (event != NULL && error == CL_SUCCESS) + *event = tmp; + + return result; + } + + void* enqueueMapImage( + const Image& buffer, + cl_bool blocking, + cl_map_flags flags, + const size_t<3>& origin, + const size_t<3>& region, + ::size_t * row_pitch, + ::size_t * slice_pitch, + const VECTOR_CLASS* events = NULL, + Event* event = NULL, + cl_int* err = NULL) const + { + cl_event tmp; + cl_int error; + void * result = ::clEnqueueMapImage( + object_, buffer(), blocking, flags, + (const ::size_t *) origin, (const ::size_t *) region, + row_pitch, slice_pitch, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL, + &error); + + detail::errHandler(error, __ENQUEUE_MAP_IMAGE_ERR); + if (err != NULL) { + *err = error; + } + if (event != NULL && error == CL_SUCCESS) + *event = tmp; + return result; + } + + cl_int enqueueUnmapMemObject( + const Memory& memory, + void* mapped_ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueUnmapMemObject( + object_, memory(), mapped_ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_UNMAP_MEM_OBJECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + +#if defined(CL_VERSION_1_2) + /** + * Enqueues a marker command which waits for either a list of events to complete, + * or all previously enqueued commands to complete. + * + * Enqueues a marker command which waits for either a list of events to complete, + * or if the list is empty it waits for all commands previously enqueued in command_queue + * to complete before it completes. This command returns an event which can be waited on, + * i.e. this event can be waited on to insure that all events either in the event_wait_list + * or all previously enqueued commands, queued before this command to command_queue, + * have completed. + */ + cl_int enqueueMarkerWithWaitList( + const VECTOR_CLASS *events = 0, + Event *event = 0) + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueMarkerWithWaitList( + object_, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_MARKER_WAIT_LIST_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + /** + * A synchronization point that enqueues a barrier operation. + * + * Enqueues a barrier command which waits for either a list of events to complete, + * or if the list is empty it waits for all commands previously enqueued in command_queue + * to complete before it completes. This command blocks command execution, that is, any + * following commands enqueued after it do not execute until it completes. This command + * returns an event which can be waited on, i.e. this event can be waited on to insure that + * all events either in the event_wait_list or all previously enqueued commands, queued + * before this command to command_queue, have completed. + */ + cl_int enqueueBarrierWithWaitList( + const VECTOR_CLASS *events = 0, + Event *event = 0) + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueBarrierWithWaitList( + object_, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_BARRIER_WAIT_LIST_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + /** + * Enqueues a command to indicate with which device a set of memory objects + * should be associated. + */ + cl_int enqueueMigrateMemObjects( + const VECTOR_CLASS &memObjects, + cl_mem_migration_flags flags, + const VECTOR_CLASS* events = NULL, + Event* event = NULL + ) + { + cl_event tmp; + + cl_mem* localMemObjects = static_cast(alloca(memObjects.size() * sizeof(cl_mem))); + for( int i = 0; i < (int)memObjects.size(); ++i ) { + localMemObjects[i] = memObjects[i](); + } + + + cl_int err = detail::errHandler( + ::clEnqueueMigrateMemObjects( + object_, + (cl_uint)memObjects.size(), + static_cast(localMemObjects), + flags, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_UNMAP_MEM_OBJECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } +#endif // #if defined(CL_VERSION_1_2) + + cl_int enqueueNDRangeKernel( + const Kernel& kernel, + const NDRange& offset, + const NDRange& global, + const NDRange& local = NullRange, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueNDRangeKernel( + object_, kernel(), (cl_uint) global.dimensions(), + offset.dimensions() != 0 ? (const ::size_t*) offset : NULL, + (const ::size_t*) global, + local.dimensions() != 0 ? (const ::size_t*) local : NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_NDRANGE_KERNEL_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueTask( + const Kernel& kernel, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueTask( + object_, kernel(), + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_TASK_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueNativeKernel( + void (CL_CALLBACK *userFptr)(void *), + std::pair args, + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* mem_locs = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_mem * mems = (mem_objects != NULL && mem_objects->size() > 0) + ? (cl_mem*) alloca(mem_objects->size() * sizeof(cl_mem)) + : NULL; + + if (mems != NULL) { + for (unsigned int i = 0; i < mem_objects->size(); i++) { + mems[i] = ((*mem_objects)[i])(); + } + } + + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueNativeKernel( + object_, userFptr, args.first, args.second, + (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, + mems, + (mem_locs != NULL && mem_locs->size() > 0) ? (const void **) &mem_locs->front() : NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_NATIVE_KERNEL); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) + CL_EXT_PREFIX__VERSION_1_1_DEPRECATED + cl_int enqueueMarker(Event* event = NULL) const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueMarker( + object_, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_MARKER_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + CL_EXT_PREFIX__VERSION_1_1_DEPRECATED + cl_int enqueueWaitForEvents(const VECTOR_CLASS& events) const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED + { + return detail::errHandler( + ::clEnqueueWaitForEvents( + object_, + (cl_uint) events.size(), + events.size() > 0 ? (const cl_event*) &events.front() : NULL), + __ENQUEUE_WAIT_FOR_EVENTS_ERR); + } +#endif // #if defined(CL_VERSION_1_1) + + cl_int enqueueAcquireGLObjects( + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueAcquireGLObjects( + object_, + (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, + (mem_objects != NULL && mem_objects->size() > 0) ? (const cl_mem *) &mem_objects->front(): NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_ACQUIRE_GL_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueReleaseGLObjects( + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueReleaseGLObjects( + object_, + (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, + (mem_objects != NULL && mem_objects->size() > 0) ? (const cl_mem *) &mem_objects->front(): NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_RELEASE_GL_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + +#if defined (USE_DX_INTEROP) +typedef CL_API_ENTRY cl_int (CL_API_CALL *PFN_clEnqueueAcquireD3D10ObjectsKHR)( + cl_command_queue command_queue, cl_uint num_objects, + const cl_mem* mem_objects, cl_uint num_events_in_wait_list, + const cl_event* event_wait_list, cl_event* event); +typedef CL_API_ENTRY cl_int (CL_API_CALL *PFN_clEnqueueReleaseD3D10ObjectsKHR)( + cl_command_queue command_queue, cl_uint num_objects, + const cl_mem* mem_objects, cl_uint num_events_in_wait_list, + const cl_event* event_wait_list, cl_event* event); + + cl_int enqueueAcquireD3D10Objects( + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + static PFN_clEnqueueAcquireD3D10ObjectsKHR pfn_clEnqueueAcquireD3D10ObjectsKHR = NULL; +#if defined(CL_VERSION_1_2) + cl_context context = getInfo(); + cl::Device device(getInfo()); + cl_platform_id platform = device.getInfo(); + __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, clEnqueueAcquireD3D10ObjectsKHR); +#endif +#if defined(CL_VERSION_1_1) + __INIT_CL_EXT_FCN_PTR(clEnqueueAcquireD3D10ObjectsKHR); +#endif + + cl_event tmp; + cl_int err = detail::errHandler( + pfn_clEnqueueAcquireD3D10ObjectsKHR( + object_, + (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, + (mem_objects != NULL && mem_objects->size() > 0) ? (const cl_mem *) &mem_objects->front(): NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_ACQUIRE_GL_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } + + cl_int enqueueReleaseD3D10Objects( + const VECTOR_CLASS* mem_objects = NULL, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) const + { + static PFN_clEnqueueReleaseD3D10ObjectsKHR pfn_clEnqueueReleaseD3D10ObjectsKHR = NULL; +#if defined(CL_VERSION_1_2) + cl_context context = getInfo(); + cl::Device device(getInfo()); + cl_platform_id platform = device.getInfo(); + __INIT_CL_EXT_FCN_PTR_PLATFORM(platform, clEnqueueReleaseD3D10ObjectsKHR); +#endif // #if defined(CL_VERSION_1_2) +#if defined(CL_VERSION_1_1) + __INIT_CL_EXT_FCN_PTR(clEnqueueReleaseD3D10ObjectsKHR); +#endif // #if defined(CL_VERSION_1_1) + + cl_event tmp; + cl_int err = detail::errHandler( + pfn_clEnqueueReleaseD3D10ObjectsKHR( + object_, + (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0, + (mem_objects != NULL && mem_objects->size() > 0) ? (const cl_mem *) &mem_objects->front(): NULL, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_RELEASE_GL_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; + } +#endif + +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS) || (defined(CL_VERSION_1_1) && !defined(CL_VERSION_1_2)) + CL_EXT_PREFIX__VERSION_1_1_DEPRECATED + cl_int enqueueBarrier() const CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED + { + return detail::errHandler( + ::clEnqueueBarrier(object_), + __ENQUEUE_BARRIER_ERR); + } +#endif // #if defined(CL_VERSION_1_1) + + cl_int flush() const + { + return detail::errHandler(::clFlush(object_), __FLUSH_ERR); + } + + cl_int finish() const + { + return detail::errHandler(::clFinish(object_), __FINISH_ERR); + } +}; + +#ifdef _WIN32 +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED +__declspec(selectany) std::atomic CommandQueue::default_initialized_; +#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__declspec(selectany) volatile int CommandQueue::default_initialized_ = __DEFAULT_NOT_INITIALIZED; +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__declspec(selectany) CommandQueue CommandQueue::default_; +__declspec(selectany) volatile cl_int CommandQueue::default_error_ = CL_SUCCESS; +#else // !_WIN32 +#ifdef CL_HPP_CPP11_ATOMICS_SUPPORTED +__attribute__((weak)) std::atomic CommandQueue::default_initialized_; +#else // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__attribute__((weak)) volatile int CommandQueue::default_initialized_ = __DEFAULT_NOT_INITIALIZED; +#endif // !CL_HPP_CPP11_ATOMICS_SUPPORTED +__attribute__((weak)) CommandQueue CommandQueue::default_; +__attribute__((weak)) volatile cl_int CommandQueue::default_error_ = CL_SUCCESS; +#endif // !_WIN32 + +template< typename IteratorType > +Buffer::Buffer( + const Context &context, + IteratorType startIterator, + IteratorType endIterator, + bool readOnly, + bool useHostPtr, + cl_int* err) +{ + typedef typename std::iterator_traits::value_type DataType; + cl_int error; + + cl_mem_flags flags = 0; + if( readOnly ) { + flags |= CL_MEM_READ_ONLY; + } + else { + flags |= CL_MEM_READ_WRITE; + } + if( useHostPtr ) { + flags |= CL_MEM_USE_HOST_PTR; + } + + ::size_t size = sizeof(DataType)*(endIterator - startIterator); + + if( useHostPtr ) { + object_ = ::clCreateBuffer(context(), flags, size, static_cast(&*startIterator), &error); + } else { + object_ = ::clCreateBuffer(context(), flags, size, 0, &error); + } + + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + + if( !useHostPtr ) { + CommandQueue queue(context, 0, &error); + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + + error = cl::copy(queue, startIterator, endIterator, *this); + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } +} + +template< typename IteratorType > +Buffer::Buffer( + const CommandQueue &queue, + IteratorType startIterator, + IteratorType endIterator, + bool readOnly, + bool useHostPtr, + cl_int* err) +{ + typedef typename std::iterator_traits::value_type DataType; + cl_int error; + + cl_mem_flags flags = 0; + if (readOnly) { + flags |= CL_MEM_READ_ONLY; + } + else { + flags |= CL_MEM_READ_WRITE; + } + if (useHostPtr) { + flags |= CL_MEM_USE_HOST_PTR; + } + + ::size_t size = sizeof(DataType)*(endIterator - startIterator); + + Context context = queue.getInfo(); + + if (useHostPtr) { + object_ = ::clCreateBuffer(context(), flags, size, static_cast(&*startIterator), &error); + } + else { + object_ = ::clCreateBuffer(context(), flags, size, 0, &error); + } + + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + + if (!useHostPtr) { + error = cl::copy(queue, startIterator, endIterator, *this); + detail::errHandler(error, __CREATE_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + } +} + +inline cl_int enqueueReadBuffer( + const Buffer& buffer, + cl_bool blocking, + ::size_t offset, + ::size_t size, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.enqueueReadBuffer(buffer, blocking, offset, size, ptr, events, event); +} + +inline cl_int enqueueWriteBuffer( + const Buffer& buffer, + cl_bool blocking, + ::size_t offset, + ::size_t size, + const void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.enqueueWriteBuffer(buffer, blocking, offset, size, ptr, events, event); +} + +inline void* enqueueMapBuffer( + const Buffer& buffer, + cl_bool blocking, + cl_map_flags flags, + ::size_t offset, + ::size_t size, + const VECTOR_CLASS* events = NULL, + Event* event = NULL, + cl_int* err = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + + void * result = ::clEnqueueMapBuffer( + queue(), buffer(), blocking, flags, offset, size, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (cl_event*) event, + &error); + + detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); + if (err != NULL) { + *err = error; + } + return result; +} + +inline cl_int enqueueUnmapMemObject( + const Memory& memory, + void* mapped_ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR); + if (error != CL_SUCCESS) { + return error; + } + + cl_event tmp; + cl_int err = detail::errHandler( + ::clEnqueueUnmapMemObject( + queue(), memory(), mapped_ptr, + (events != NULL) ? (cl_uint) events->size() : 0, + (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL, + (event != NULL) ? &tmp : NULL), + __ENQUEUE_UNMAP_MEM_OBJECT_ERR); + + if (event != NULL && err == CL_SUCCESS) + *event = tmp; + + return err; +} + +inline cl_int enqueueCopyBuffer( + const Buffer& src, + const Buffer& dst, + ::size_t src_offset, + ::size_t dst_offset, + ::size_t size, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.enqueueCopyBuffer(src, dst, src_offset, dst_offset, size, events, event); +} + +/** + * Blocking copy operation between iterators and a buffer. + * Host to Device. + * Uses default command queue. + */ +template< typename IteratorType > +inline cl_int copy( IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer ) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + if (error != CL_SUCCESS) + return error; + + return cl::copy(queue, startIterator, endIterator, buffer); +} + +/** + * Blocking copy operation between iterators and a buffer. + * Device to Host. + * Uses default command queue. + */ +template< typename IteratorType > +inline cl_int copy( const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator ) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + if (error != CL_SUCCESS) + return error; + + return cl::copy(queue, buffer, startIterator, endIterator); +} + +/** + * Blocking copy operation between iterators and a buffer. + * Host to Device. + * Uses specified queue. + */ +template< typename IteratorType > +inline cl_int copy( const CommandQueue &queue, IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer ) +{ + typedef typename std::iterator_traits::value_type DataType; + cl_int error; + + ::size_t length = endIterator-startIterator; + ::size_t byteLength = length*sizeof(DataType); + + DataType *pointer = + static_cast(queue.enqueueMapBuffer(buffer, CL_TRUE, CL_MAP_WRITE, 0, byteLength, 0, 0, &error)); + // if exceptions enabled, enqueueMapBuffer will throw + if( error != CL_SUCCESS ) { + return error; + } +#if defined(_MSC_VER) + std::copy( + startIterator, + endIterator, + stdext::checked_array_iterator( + pointer, length)); +#else + std::copy(startIterator, endIterator, pointer); +#endif + Event endEvent; + error = queue.enqueueUnmapMemObject(buffer, pointer, 0, &endEvent); + // if exceptions enabled, enqueueUnmapMemObject will throw + if( error != CL_SUCCESS ) { + return error; + } + endEvent.wait(); + return CL_SUCCESS; +} + +/** + * Blocking copy operation between iterators and a buffer. + * Device to Host. + * Uses specified queue. + */ +template< typename IteratorType > +inline cl_int copy( const CommandQueue &queue, const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator ) +{ + typedef typename std::iterator_traits::value_type DataType; + cl_int error; + + ::size_t length = endIterator-startIterator; + ::size_t byteLength = length*sizeof(DataType); + + DataType *pointer = + static_cast(queue.enqueueMapBuffer(buffer, CL_TRUE, CL_MAP_READ, 0, byteLength, 0, 0, &error)); + // if exceptions enabled, enqueueMapBuffer will throw + if( error != CL_SUCCESS ) { + return error; + } + std::copy(pointer, pointer + length, startIterator); + Event endEvent; + error = queue.enqueueUnmapMemObject(buffer, pointer, 0, &endEvent); + // if exceptions enabled, enqueueUnmapMemObject will throw + if( error != CL_SUCCESS ) { + return error; + } + endEvent.wait(); + return CL_SUCCESS; +} + +#if defined(CL_VERSION_1_1) +inline cl_int enqueueReadBufferRect( + const Buffer& buffer, + cl_bool blocking, + const size_t<3>& buffer_offset, + const size_t<3>& host_offset, + const size_t<3>& region, + ::size_t buffer_row_pitch, + ::size_t buffer_slice_pitch, + ::size_t host_row_pitch, + ::size_t host_slice_pitch, + void *ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.enqueueReadBufferRect( + buffer, + blocking, + buffer_offset, + host_offset, + region, + buffer_row_pitch, + buffer_slice_pitch, + host_row_pitch, + host_slice_pitch, + ptr, + events, + event); +} + +inline cl_int enqueueWriteBufferRect( + const Buffer& buffer, + cl_bool blocking, + const size_t<3>& buffer_offset, + const size_t<3>& host_offset, + const size_t<3>& region, + ::size_t buffer_row_pitch, + ::size_t buffer_slice_pitch, + ::size_t host_row_pitch, + ::size_t host_slice_pitch, + void *ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.enqueueWriteBufferRect( + buffer, + blocking, + buffer_offset, + host_offset, + region, + buffer_row_pitch, + buffer_slice_pitch, + host_row_pitch, + host_slice_pitch, + ptr, + events, + event); +} + +inline cl_int enqueueCopyBufferRect( + const Buffer& src, + const Buffer& dst, + const size_t<3>& src_origin, + const size_t<3>& dst_origin, + const size_t<3>& region, + ::size_t src_row_pitch, + ::size_t src_slice_pitch, + ::size_t dst_row_pitch, + ::size_t dst_slice_pitch, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.enqueueCopyBufferRect( + src, + dst, + src_origin, + dst_origin, + region, + src_row_pitch, + src_slice_pitch, + dst_row_pitch, + dst_slice_pitch, + events, + event); +} +#endif + +inline cl_int enqueueReadImage( + const Image& image, + cl_bool blocking, + const size_t<3>& origin, + const size_t<3>& region, + ::size_t row_pitch, + ::size_t slice_pitch, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.enqueueReadImage( + image, + blocking, + origin, + region, + row_pitch, + slice_pitch, + ptr, + events, + event); +} + +inline cl_int enqueueWriteImage( + const Image& image, + cl_bool blocking, + const size_t<3>& origin, + const size_t<3>& region, + ::size_t row_pitch, + ::size_t slice_pitch, + void* ptr, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.enqueueWriteImage( + image, + blocking, + origin, + region, + row_pitch, + slice_pitch, + ptr, + events, + event); +} + +inline cl_int enqueueCopyImage( + const Image& src, + const Image& dst, + const size_t<3>& src_origin, + const size_t<3>& dst_origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.enqueueCopyImage( + src, + dst, + src_origin, + dst_origin, + region, + events, + event); +} + +inline cl_int enqueueCopyImageToBuffer( + const Image& src, + const Buffer& dst, + const size_t<3>& src_origin, + const size_t<3>& region, + ::size_t dst_offset, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.enqueueCopyImageToBuffer( + src, + dst, + src_origin, + region, + dst_offset, + events, + event); +} + +inline cl_int enqueueCopyBufferToImage( + const Buffer& src, + const Image& dst, + ::size_t src_offset, + const size_t<3>& dst_origin, + const size_t<3>& region, + const VECTOR_CLASS* events = NULL, + Event* event = NULL) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.enqueueCopyBufferToImage( + src, + dst, + src_offset, + dst_origin, + region, + events, + event); +} + + +inline cl_int flush(void) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + return queue.flush(); +} + +inline cl_int finish(void) +{ + cl_int error; + CommandQueue queue = CommandQueue::getDefault(&error); + + if (error != CL_SUCCESS) { + return error; + } + + + return queue.finish(); +} + +// Kernel Functor support +// New interface as of September 2011 +// Requires the C++11 std::tr1::function (note do not support TR1) +// Visual Studio 2010 and GCC 4.2 + +struct EnqueueArgs +{ + CommandQueue queue_; + const NDRange offset_; + const NDRange global_; + const NDRange local_; + VECTOR_CLASS events_; + + EnqueueArgs(NDRange global) : + queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(NullRange) + { + + } + + EnqueueArgs(NDRange global, NDRange local) : + queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(local) + { + + } + + EnqueueArgs(NDRange offset, NDRange global, NDRange local) : + queue_(CommandQueue::getDefault()), + offset_(offset), + global_(global), + local_(local) + { + + } + + EnqueueArgs(Event e, NDRange global) : + queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(NullRange) + { + events_.push_back(e); + } + + EnqueueArgs(Event e, NDRange global, NDRange local) : + queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(local) + { + events_.push_back(e); + } + + EnqueueArgs(Event e, NDRange offset, NDRange global, NDRange local) : + queue_(CommandQueue::getDefault()), + offset_(offset), + global_(global), + local_(local) + { + events_.push_back(e); + } + + EnqueueArgs(const VECTOR_CLASS &events, NDRange global) : + queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(NullRange), + events_(events) + { + + } + + EnqueueArgs(const VECTOR_CLASS &events, NDRange global, NDRange local) : + queue_(CommandQueue::getDefault()), + offset_(NullRange), + global_(global), + local_(local), + events_(events) + { + + } + + EnqueueArgs(const VECTOR_CLASS &events, NDRange offset, NDRange global, NDRange local) : + queue_(CommandQueue::getDefault()), + offset_(offset), + global_(global), + local_(local), + events_(events) + { + + } + + EnqueueArgs(CommandQueue &queue, NDRange global) : + queue_(queue), + offset_(NullRange), + global_(global), + local_(NullRange) + { + + } + + EnqueueArgs(CommandQueue &queue, NDRange global, NDRange local) : + queue_(queue), + offset_(NullRange), + global_(global), + local_(local) + { + + } + + EnqueueArgs(CommandQueue &queue, NDRange offset, NDRange global, NDRange local) : + queue_(queue), + offset_(offset), + global_(global), + local_(local) + { + + } + + EnqueueArgs(CommandQueue &queue, Event e, NDRange global) : + queue_(queue), + offset_(NullRange), + global_(global), + local_(NullRange) + { + events_.push_back(e); + } + + EnqueueArgs(CommandQueue &queue, Event e, NDRange global, NDRange local) : + queue_(queue), + offset_(NullRange), + global_(global), + local_(local) + { + events_.push_back(e); + } + + EnqueueArgs(CommandQueue &queue, Event e, NDRange offset, NDRange global, NDRange local) : + queue_(queue), + offset_(offset), + global_(global), + local_(local) + { + events_.push_back(e); + } + + EnqueueArgs(CommandQueue &queue, const VECTOR_CLASS &events, NDRange global) : + queue_(queue), + offset_(NullRange), + global_(global), + local_(NullRange), + events_(events) + { + + } + + EnqueueArgs(CommandQueue &queue, const VECTOR_CLASS &events, NDRange global, NDRange local) : + queue_(queue), + offset_(NullRange), + global_(global), + local_(local), + events_(events) + { + + } + + EnqueueArgs(CommandQueue &queue, const VECTOR_CLASS &events, NDRange offset, NDRange global, NDRange local) : + queue_(queue), + offset_(offset), + global_(global), + local_(local), + events_(events) + { + + } +}; + +namespace detail { + +class NullType {}; + +template +struct SetArg +{ + static void set (Kernel kernel, T0 arg) + { + kernel.setArg(index, arg); + } +}; + +template +struct SetArg +{ + static void set (Kernel, NullType) + { + } +}; + +template < + typename T0, typename T1, typename T2, typename T3, + typename T4, typename T5, typename T6, typename T7, + typename T8, typename T9, typename T10, typename T11, + typename T12, typename T13, typename T14, typename T15, + typename T16, typename T17, typename T18, typename T19, + typename T20, typename T21, typename T22, typename T23, + typename T24, typename T25, typename T26, typename T27, + typename T28, typename T29, typename T30, typename T31 +> +class KernelFunctorGlobal +{ +private: + Kernel kernel_; + +public: + KernelFunctorGlobal( + Kernel kernel) : + kernel_(kernel) + {} + + KernelFunctorGlobal( + const Program& program, + const STRING_CLASS name, + cl_int * err = NULL) : + kernel_(program, name.c_str(), err) + {} + + Event operator() ( + const EnqueueArgs& args, + T0 t0, + T1 t1 = NullType(), + T2 t2 = NullType(), + T3 t3 = NullType(), + T4 t4 = NullType(), + T5 t5 = NullType(), + T6 t6 = NullType(), + T7 t7 = NullType(), + T8 t8 = NullType(), + T9 t9 = NullType(), + T10 t10 = NullType(), + T11 t11 = NullType(), + T12 t12 = NullType(), + T13 t13 = NullType(), + T14 t14 = NullType(), + T15 t15 = NullType(), + T16 t16 = NullType(), + T17 t17 = NullType(), + T18 t18 = NullType(), + T19 t19 = NullType(), + T20 t20 = NullType(), + T21 t21 = NullType(), + T22 t22 = NullType(), + T23 t23 = NullType(), + T24 t24 = NullType(), + T25 t25 = NullType(), + T26 t26 = NullType(), + T27 t27 = NullType(), + T28 t28 = NullType(), + T29 t29 = NullType(), + T30 t30 = NullType(), + T31 t31 = NullType() + ) + { + Event event; + SetArg<0, T0>::set(kernel_, t0); + SetArg<1, T1>::set(kernel_, t1); + SetArg<2, T2>::set(kernel_, t2); + SetArg<3, T3>::set(kernel_, t3); + SetArg<4, T4>::set(kernel_, t4); + SetArg<5, T5>::set(kernel_, t5); + SetArg<6, T6>::set(kernel_, t6); + SetArg<7, T7>::set(kernel_, t7); + SetArg<8, T8>::set(kernel_, t8); + SetArg<9, T9>::set(kernel_, t9); + SetArg<10, T10>::set(kernel_, t10); + SetArg<11, T11>::set(kernel_, t11); + SetArg<12, T12>::set(kernel_, t12); + SetArg<13, T13>::set(kernel_, t13); + SetArg<14, T14>::set(kernel_, t14); + SetArg<15, T15>::set(kernel_, t15); + SetArg<16, T16>::set(kernel_, t16); + SetArg<17, T17>::set(kernel_, t17); + SetArg<18, T18>::set(kernel_, t18); + SetArg<19, T19>::set(kernel_, t19); + SetArg<20, T20>::set(kernel_, t20); + SetArg<21, T21>::set(kernel_, t21); + SetArg<22, T22>::set(kernel_, t22); + SetArg<23, T23>::set(kernel_, t23); + SetArg<24, T24>::set(kernel_, t24); + SetArg<25, T25>::set(kernel_, t25); + SetArg<26, T26>::set(kernel_, t26); + SetArg<27, T27>::set(kernel_, t27); + SetArg<28, T28>::set(kernel_, t28); + SetArg<29, T29>::set(kernel_, t29); + SetArg<30, T30>::set(kernel_, t30); + SetArg<31, T31>::set(kernel_, t31); + + args.queue_.enqueueNDRangeKernel( + kernel_, + args.offset_, + args.global_, + args.local_, + &args.events_, + &event); + + return event; + } + +}; + +//------------------------------------------------------------------------------------------------------ + + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26, + typename T27, + typename T28, + typename T29, + typename T30, + typename T31> +struct functionImplementation_ +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + T30, + T31> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 32)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + T30, + T31); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26, + T27 arg27, + T28 arg28, + T29 arg29, + T30 arg30, + T31 arg31) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26, + arg27, + arg28, + arg29, + arg30, + arg31); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26, + typename T27, + typename T28, + typename T29, + typename T30> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + T30, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + T30, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 31)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + T30); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26, + T27 arg27, + T28 arg28, + T29 arg29, + T30 arg30) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26, + arg27, + arg28, + arg29, + arg30); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26, + typename T27, + typename T28, + typename T29> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 30)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + T29); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26, + T27 arg27, + T28 arg28, + T29 arg29) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26, + arg27, + arg28, + arg29); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26, + typename T27, + typename T28> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 29)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + T28); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26, + T27 arg27, + T28 arg28) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26, + arg27, + arg28); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26, + typename T27> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 28)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + T27); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26, + T27 arg27) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26, + arg27); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25, + typename T26> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 27)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + T26); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25, + T26 arg26) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25, + arg26); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24, + typename T25> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 26)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + T25); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24, + T25 arg25) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24, + arg25); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23, + typename T24> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 25)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + T24); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23, + T24 arg24) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23, + arg24); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22, + typename T23> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 24)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + T23); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22, + T23 arg23) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22, + arg23); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21, + typename T22> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 23)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + T22); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21, + T22 arg22) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21, + arg22); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20, + typename T21> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 22)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + T21); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20, + T21 arg21) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20, + arg21); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19, + typename T20> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 21)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + T20); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19, + T20 arg20) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19, + arg20); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18, + typename T19> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 20)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + T19); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18, + T19 arg19) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18, + arg19); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17, + typename T18> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 19)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + T18); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17, + T18 arg18) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17, + arg18); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16, + typename T17> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 18)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + T17); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16, + T17 arg17) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16, + arg17); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15, + typename T16> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 17)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + T16); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15, + T16 arg16) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15, + arg16); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14, + typename T15> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 16)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + T15); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14, + T15 arg15) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14, + arg15); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13, + typename T14> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 15)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + T14); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13, + T14 arg14) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13, + arg14); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12, + typename T13> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 14)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + T13); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12, + T13 arg13) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12, + arg13); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11, + typename T12> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 13)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + T12); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11, + T12 arg12) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11, + arg12); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10, + typename T11> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 12)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + T11); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10, + T11 arg11) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10, + arg11); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9, + typename T10> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 11)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + T10); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9, + T10 arg10) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9, + arg10); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8, + typename T9> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 10)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + T9); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8, + T9 arg9) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8, + arg9); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7, + typename T8> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 9)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + T8); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7, + T8 arg8) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6, + typename T7> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 8)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6, + T7); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6, + T7 arg7) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5, + typename T6> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + T6, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + T6, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 7)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5, + T6); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5, + T6 arg6) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4, + typename T5> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + T5, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + T5, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 6)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4, + T5); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4, + T5 arg5) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4, + arg5); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3, + typename T4> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + T4, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + T4, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 5)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3, + T4); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3, + T4 arg4) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3, + arg4); + } + + +}; + +template< + typename T0, + typename T1, + typename T2, + typename T3> +struct functionImplementation_ +< T0, + T1, + T2, + T3, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + T3, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 4)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2, + T3); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2, + T3 arg3) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2, + arg3); + } + + +}; + +template< + typename T0, + typename T1, + typename T2> +struct functionImplementation_ +< T0, + T1, + T2, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + T2, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 3)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1, + T2); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1, + T2 arg2) + { + return functor_( + enqueueArgs, + arg0, + arg1, + arg2); + } + + +}; + +template< + typename T0, + typename T1> +struct functionImplementation_ +< T0, + T1, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + T1, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 2)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0, + T1); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0, + T1 arg1) + { + return functor_( + enqueueArgs, + arg0, + arg1); + } + + +}; + +template< + typename T0> +struct functionImplementation_ +< T0, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> +{ + typedef detail::KernelFunctorGlobal< + T0, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType, + NullType> FunctorType; + + FunctorType functor_; + + functionImplementation_(const FunctorType &functor) : + functor_(functor) + { + + #if (defined(_WIN32) && defined(_VARIADIC_MAX) && (_VARIADIC_MAX < 1)) + // Fail variadic expansion for dev11 + static_assert(0, "Visual Studio has a hard limit of argument count for a std::function expansion. Please define _VARIADIC_MAX to be 10. If you need more arguments than that VC12 and below cannot support it."); + #endif + + } + + //! \brief Return type of the functor + typedef Event result_type; + + //! \brief Function signature of kernel functor with no event dependency. + typedef Event type_( + const EnqueueArgs&, + T0); + + Event operator()( + const EnqueueArgs& enqueueArgs, + T0 arg0) + { + return functor_( + enqueueArgs, + arg0); + } + + +}; + + + + + +} // namespace detail + +//---------------------------------------------------------------------------------------------- + +template < + typename T0, typename T1 = detail::NullType, typename T2 = detail::NullType, + typename T3 = detail::NullType, typename T4 = detail::NullType, + typename T5 = detail::NullType, typename T6 = detail::NullType, + typename T7 = detail::NullType, typename T8 = detail::NullType, + typename T9 = detail::NullType, typename T10 = detail::NullType, + typename T11 = detail::NullType, typename T12 = detail::NullType, + typename T13 = detail::NullType, typename T14 = detail::NullType, + typename T15 = detail::NullType, typename T16 = detail::NullType, + typename T17 = detail::NullType, typename T18 = detail::NullType, + typename T19 = detail::NullType, typename T20 = detail::NullType, + typename T21 = detail::NullType, typename T22 = detail::NullType, + typename T23 = detail::NullType, typename T24 = detail::NullType, + typename T25 = detail::NullType, typename T26 = detail::NullType, + typename T27 = detail::NullType, typename T28 = detail::NullType, + typename T29 = detail::NullType, typename T30 = detail::NullType, + typename T31 = detail::NullType +> +struct make_kernel : + public detail::functionImplementation_< + T0, T1, T2, T3, + T4, T5, T6, T7, + T8, T9, T10, T11, + T12, T13, T14, T15, + T16, T17, T18, T19, + T20, T21, T22, T23, + T24, T25, T26, T27, + T28, T29, T30, T31 + > +{ +public: + typedef detail::KernelFunctorGlobal< + T0, T1, T2, T3, + T4, T5, T6, T7, + T8, T9, T10, T11, + T12, T13, T14, T15, + T16, T17, T18, T19, + T20, T21, T22, T23, + T24, T25, T26, T27, + T28, T29, T30, T31 + > FunctorType; + + make_kernel( + const Program& program, + const STRING_CLASS name, + cl_int * err = NULL) : + detail::functionImplementation_< + T0, T1, T2, T3, + T4, T5, T6, T7, + T8, T9, T10, T11, + T12, T13, T14, T15, + T16, T17, T18, T19, + T20, T21, T22, T23, + T24, T25, T26, T27, + T28, T29, T30, T31 + >( + FunctorType(program, name, err)) + {} + + make_kernel( + const Kernel kernel) : + detail::functionImplementation_< + T0, T1, T2, T3, + T4, T5, T6, T7, + T8, T9, T10, T11, + T12, T13, T14, T15, + T16, T17, T18, T19, + T20, T21, T22, T23, + T24, T25, T26, T27, + T28, T29, T30, T31 + >( + FunctorType(kernel)) + {} +}; + + +//---------------------------------------------------------------------------------------------------------------------- + +#undef __ERR_STR +#if !defined(__CL_USER_OVERRIDE_ERROR_STRINGS) +#undef __GET_DEVICE_INFO_ERR +#undef __GET_PLATFORM_INFO_ERR +#undef __GET_DEVICE_IDS_ERR +#undef __GET_CONTEXT_INFO_ERR +#undef __GET_EVENT_INFO_ERR +#undef __GET_EVENT_PROFILE_INFO_ERR +#undef __GET_MEM_OBJECT_INFO_ERR +#undef __GET_IMAGE_INFO_ERR +#undef __GET_SAMPLER_INFO_ERR +#undef __GET_KERNEL_INFO_ERR +#undef __GET_KERNEL_ARG_INFO_ERR +#undef __GET_KERNEL_WORK_GROUP_INFO_ERR +#undef __GET_PROGRAM_INFO_ERR +#undef __GET_PROGRAM_BUILD_INFO_ERR +#undef __GET_COMMAND_QUEUE_INFO_ERR + +#undef __CREATE_CONTEXT_ERR +#undef __CREATE_CONTEXT_FROM_TYPE_ERR +#undef __GET_SUPPORTED_IMAGE_FORMATS_ERR + +#undef __CREATE_BUFFER_ERR +#undef __CREATE_SUBBUFFER_ERR +#undef __CREATE_IMAGE2D_ERR +#undef __CREATE_IMAGE3D_ERR +#undef __CREATE_SAMPLER_ERR +#undef __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR + +#undef __CREATE_USER_EVENT_ERR +#undef __SET_USER_EVENT_STATUS_ERR +#undef __SET_EVENT_CALLBACK_ERR +#undef __SET_PRINTF_CALLBACK_ERR + +#undef __WAIT_FOR_EVENTS_ERR + +#undef __CREATE_KERNEL_ERR +#undef __SET_KERNEL_ARGS_ERR +#undef __CREATE_PROGRAM_WITH_SOURCE_ERR +#undef __CREATE_PROGRAM_WITH_BINARY_ERR +#undef __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR +#undef __BUILD_PROGRAM_ERR +#undef __CREATE_KERNELS_IN_PROGRAM_ERR + +#undef __CREATE_COMMAND_QUEUE_ERR +#undef __SET_COMMAND_QUEUE_PROPERTY_ERR +#undef __ENQUEUE_READ_BUFFER_ERR +#undef __ENQUEUE_WRITE_BUFFER_ERR +#undef __ENQUEUE_READ_BUFFER_RECT_ERR +#undef __ENQUEUE_WRITE_BUFFER_RECT_ERR +#undef __ENQEUE_COPY_BUFFER_ERR +#undef __ENQEUE_COPY_BUFFER_RECT_ERR +#undef __ENQUEUE_READ_IMAGE_ERR +#undef __ENQUEUE_WRITE_IMAGE_ERR +#undef __ENQUEUE_COPY_IMAGE_ERR +#undef __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR +#undef __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR +#undef __ENQUEUE_MAP_BUFFER_ERR +#undef __ENQUEUE_MAP_IMAGE_ERR +#undef __ENQUEUE_UNMAP_MEM_OBJECT_ERR +#undef __ENQUEUE_NDRANGE_KERNEL_ERR +#undef __ENQUEUE_TASK_ERR +#undef __ENQUEUE_NATIVE_KERNEL + +#undef __CL_EXPLICIT_CONSTRUCTORS + +#undef __UNLOAD_COMPILER_ERR +#endif //__CL_USER_OVERRIDE_ERROR_STRINGS + +#undef __CL_FUNCTION_TYPE + +// Extensions +/** + * Deprecated APIs for 1.2 + */ +#if defined(CL_VERSION_1_1) +#undef __INIT_CL_EXT_FCN_PTR +#endif // #if defined(CL_VERSION_1_1) +#undef __CREATE_SUB_DEVICES + +#if defined(USE_CL_DEVICE_FISSION) +#undef __PARAM_NAME_DEVICE_FISSION +#endif // USE_CL_DEVICE_FISSION + +#undef __DEFAULT_NOT_INITIALIZED +#undef __DEFAULT_BEING_INITIALIZED +#undef __DEFAULT_INITIALIZED + +#undef CL_HPP_RVALUE_REFERENCES_SUPPORTED +#undef CL_HPP_NOEXCEPT + +} // namespace cl + +#endif // CL_HPP_ diff --git a/includes/CL/cl_ext.h b/includes/CL/cl_ext.h new file mode 100644 index 0000000..56153f4 --- /dev/null +++ b/includes/CL/cl_ext.h @@ -0,0 +1,334 @@ +/******************************************************************************* + * Copyright (c) 2008-2013 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Materials. + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + ******************************************************************************/ + +/* $Revision: 11928 $ on $Date: 2010-07-13 09:04:56 -0700 (Tue, 13 Jul 2010) $ */ + +/* cl_ext.h contains OpenCL extensions which don't have external */ +/* (OpenGL, D3D) dependencies. */ + +#ifndef __CL_EXT_H +#define __CL_EXT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __APPLE__ + #include + #include +#else + #include +#endif + +/* cl_khr_fp16 extension - no extension #define since it has no functions */ +#define CL_DEVICE_HALF_FP_CONFIG 0x1033 + +/* Memory object destruction + * + * Apple extension for use to manage externally allocated buffers used with cl_mem objects with CL_MEM_USE_HOST_PTR + * + * Registers a user callback function that will be called when the memory object is deleted and its resources + * freed. Each call to clSetMemObjectCallbackFn registers the specified user callback function on a callback + * stack associated with memobj. The registered user callback functions are called in the reverse order in + * which they were registered. The user callback functions are called and then the memory object is deleted + * and its resources freed. This provides a mechanism for the application (and libraries) using memobj to be + * notified when the memory referenced by host_ptr, specified when the memory object is created and used as + * the storage bits for the memory object, can be reused or freed. + * + * The application may not call CL api's with the cl_mem object passed to the pfn_notify. + * + * Please check for the "cl_APPLE_SetMemObjectDestructor" extension using clGetDeviceInfo(CL_DEVICE_EXTENSIONS) + * before using. + */ +#define cl_APPLE_SetMemObjectDestructor 1 +cl_int CL_API_ENTRY clSetMemObjectDestructorAPPLE( cl_mem /* memobj */, + void (* /*pfn_notify*/)( cl_mem /* memobj */, void* /*user_data*/), + void * /*user_data */ ) CL_EXT_SUFFIX__VERSION_1_0; + + +/* Context Logging Functions + * + * The next three convenience functions are intended to be used as the pfn_notify parameter to clCreateContext(). + * Please check for the "cl_APPLE_ContextLoggingFunctions" extension using clGetDeviceInfo(CL_DEVICE_EXTENSIONS) + * before using. + * + * clLogMessagesToSystemLog fowards on all log messages to the Apple System Logger + */ +#define cl_APPLE_ContextLoggingFunctions 1 +extern void CL_API_ENTRY clLogMessagesToSystemLogAPPLE( const char * /* errstr */, + const void * /* private_info */, + size_t /* cb */, + void * /* user_data */ ) CL_EXT_SUFFIX__VERSION_1_0; + +/* clLogMessagesToStdout sends all log messages to the file descriptor stdout */ +extern void CL_API_ENTRY clLogMessagesToStdoutAPPLE( const char * /* errstr */, + const void * /* private_info */, + size_t /* cb */, + void * /* user_data */ ) CL_EXT_SUFFIX__VERSION_1_0; + +/* clLogMessagesToStderr sends all log messages to the file descriptor stderr */ +extern void CL_API_ENTRY clLogMessagesToStderrAPPLE( const char * /* errstr */, + const void * /* private_info */, + size_t /* cb */, + void * /* user_data */ ) CL_EXT_SUFFIX__VERSION_1_0; + + +/************************ +* cl_khr_icd extension * +************************/ +#define cl_khr_icd 1 + +/* cl_platform_info */ +#define CL_PLATFORM_ICD_SUFFIX_KHR 0x0920 + +/* Additional Error Codes */ +#define CL_PLATFORM_NOT_FOUND_KHR -1001 + +extern CL_API_ENTRY cl_int CL_API_CALL +clIcdGetPlatformIDsKHR(cl_uint /* num_entries */, + cl_platform_id * /* platforms */, + cl_uint * /* num_platforms */); + +typedef CL_API_ENTRY cl_int (CL_API_CALL *clIcdGetPlatformIDsKHR_fn)( + cl_uint /* num_entries */, + cl_platform_id * /* platforms */, + cl_uint * /* num_platforms */); + + +/* Extension: cl_khr_image2D_buffer + * + * This extension allows a 2D image to be created from a cl_mem buffer without a copy. + * The type associated with a 2D image created from a buffer in an OpenCL program is image2d_t. + * Both the sampler and sampler-less read_image built-in functions are supported for 2D images + * and 2D images created from a buffer. Similarly, the write_image built-ins are also supported + * for 2D images created from a buffer. + * + * When the 2D image from buffer is created, the client must specify the width, + * height, image format (i.e. channel order and channel data type) and optionally the row pitch + * + * The pitch specified must be a multiple of CL_DEVICE_IMAGE_PITCH_ALIGNMENT pixels. + * The base address of the buffer must be aligned to CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT pixels. + */ + +/************************************* + * cl_khr_initalize_memory extension * + *************************************/ + +#define CL_CONTEXT_MEMORY_INITIALIZE_KHR 0x200E + + +/************************************** + * cl_khr_terminate_context extension * + **************************************/ + +#define CL_DEVICE_TERMINATE_CAPABILITY_KHR 0x200F +#define CL_CONTEXT_TERMINATE_KHR 0x2010 + +#define cl_khr_terminate_context 1 +extern CL_API_ENTRY cl_int CL_API_CALL clTerminateContextKHR(cl_context /* context */) CL_EXT_SUFFIX__VERSION_1_2; + +typedef CL_API_ENTRY cl_int (CL_API_CALL *clTerminateContextKHR_fn)(cl_context /* context */) CL_EXT_SUFFIX__VERSION_1_2; + + +/* + * Extension: cl_khr_spir + * + * This extension adds support to create an OpenCL program object from a + * Standard Portable Intermediate Representation (SPIR) instance + */ + +#define CL_DEVICE_SPIR_VERSIONS 0x40E0 +#define CL_PROGRAM_BINARY_TYPE_INTERMEDIATE 0x40E1 + + +/****************************************** +* cl_nv_device_attribute_query extension * +******************************************/ +/* cl_nv_device_attribute_query extension - no extension #define since it has no functions */ +#define CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV 0x4000 +#define CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV 0x4001 +#define CL_DEVICE_REGISTERS_PER_BLOCK_NV 0x4002 +#define CL_DEVICE_WARP_SIZE_NV 0x4003 +#define CL_DEVICE_GPU_OVERLAP_NV 0x4004 +#define CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV 0x4005 +#define CL_DEVICE_INTEGRATED_MEMORY_NV 0x4006 +#define CL_DEVICE_ATTRIBUTE_ASYNC_ENGINE_COUNT_NV 0x4007 +#define CL_DEVICE_PCI_BUS_ID_NV 0x4008 +#define CL_DEVICE_PCI_SLOT_ID_NV 0x4009 + +/****************************************** +* cl_nv_create_buffer extension * +******************************************/ +typedef cl_bitfield cl_mem_flags_NV; + +CL_API_ENTRY cl_mem CL_API_CALL +clCreateBufferNV(cl_context context, + cl_mem_flags flags, + cl_mem_flags_NV flags_NV, + size_t size, + void *host_ptr, + cl_int *errcode_ret); +#define CL_MEM_LOCATION_HOST_NV (1 << 0) +#define CL_MEM_PINNED_NV (1 << 1) + +/********************************* +* cl_amd_device_attribute_query * +*********************************/ +#define CL_DEVICE_PROFILING_TIMER_OFFSET_AMD 0x4036 + +/********************************* +* cl_arm_printf extension +*********************************/ +#define CL_PRINTF_CALLBACK_ARM 0x40B0 +#define CL_PRINTF_BUFFERSIZE_ARM 0x40B1 + +#ifdef CL_VERSION_1_1 + /*********************************** + * cl_ext_device_fission extension * + ***********************************/ + #define cl_ext_device_fission 1 + + extern CL_API_ENTRY cl_int CL_API_CALL + clReleaseDeviceEXT( cl_device_id /*device*/ ) CL_EXT_SUFFIX__VERSION_1_1; + + typedef CL_API_ENTRY cl_int + (CL_API_CALL *clReleaseDeviceEXT_fn)( cl_device_id /*device*/ ) CL_EXT_SUFFIX__VERSION_1_1; + + extern CL_API_ENTRY cl_int CL_API_CALL + clRetainDeviceEXT( cl_device_id /*device*/ ) CL_EXT_SUFFIX__VERSION_1_1; + + typedef CL_API_ENTRY cl_int + (CL_API_CALL *clRetainDeviceEXT_fn)( cl_device_id /*device*/ ) CL_EXT_SUFFIX__VERSION_1_1; + + typedef cl_ulong cl_device_partition_property_ext; + extern CL_API_ENTRY cl_int CL_API_CALL + clCreateSubDevicesEXT( cl_device_id /*in_device*/, + 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; + + typedef CL_API_ENTRY cl_int + ( CL_API_CALL * clCreateSubDevicesEXT_fn)( cl_device_id /*in_device*/, + 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_device_partition_property_ext */ + #define CL_DEVICE_PARTITION_EQUALLY_EXT 0x4050 + #define CL_DEVICE_PARTITION_BY_COUNTS_EXT 0x4051 + #define CL_DEVICE_PARTITION_BY_NAMES_EXT 0x4052 + #define CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN_EXT 0x4053 + + /* clDeviceGetInfo selectors */ + #define CL_DEVICE_PARENT_DEVICE_EXT 0x4054 + #define CL_DEVICE_PARTITION_TYPES_EXT 0x4055 + #define CL_DEVICE_AFFINITY_DOMAINS_EXT 0x4056 + #define CL_DEVICE_REFERENCE_COUNT_EXT 0x4057 + #define CL_DEVICE_PARTITION_STYLE_EXT 0x4058 + + /* error codes */ + #define CL_DEVICE_PARTITION_FAILED_EXT -1057 + #define CL_INVALID_PARTITION_COUNT_EXT -1058 + #define CL_INVALID_PARTITION_NAME_EXT -1059 + + /* CL_AFFINITY_DOMAINs */ + #define CL_AFFINITY_DOMAIN_L1_CACHE_EXT 0x1 + #define CL_AFFINITY_DOMAIN_L2_CACHE_EXT 0x2 + #define CL_AFFINITY_DOMAIN_L3_CACHE_EXT 0x3 + #define CL_AFFINITY_DOMAIN_L4_CACHE_EXT 0x4 + #define CL_AFFINITY_DOMAIN_NUMA_EXT 0x10 + #define CL_AFFINITY_DOMAIN_NEXT_FISSIONABLE_EXT 0x100 + + /* cl_device_partition_property_ext list terminators */ + #define CL_PROPERTIES_LIST_END_EXT ((cl_device_partition_property_ext) 0) + #define CL_PARTITION_BY_COUNTS_LIST_END_EXT ((cl_device_partition_property_ext) 0) + #define CL_PARTITION_BY_NAMES_LIST_END_EXT ((cl_device_partition_property_ext) 0 - 1) + +/********************************* +* cl_qcom_ext_host_ptr extension +*********************************/ + +#define CL_MEM_EXT_HOST_PTR_QCOM (1 << 29) + +#define CL_DEVICE_EXT_MEM_PADDING_IN_BYTES_QCOM 0x40A0 +#define CL_DEVICE_PAGE_SIZE_QCOM 0x40A1 +#define CL_IMAGE_ROW_ALIGNMENT_QCOM 0x40A2 +#define CL_IMAGE_SLICE_ALIGNMENT_QCOM 0x40A3 +#define CL_MEM_HOST_UNCACHED_QCOM 0x40A4 +#define CL_MEM_HOST_WRITEBACK_QCOM 0x40A5 +#define CL_MEM_HOST_WRITETHROUGH_QCOM 0x40A6 +#define CL_MEM_HOST_WRITE_COMBINING_QCOM 0x40A7 + +typedef cl_uint cl_image_pitch_info_qcom; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetDeviceImageInfoQCOM(cl_device_id device, + size_t image_width, + size_t image_height, + const cl_image_format *image_format, + cl_image_pitch_info_qcom param_name, + size_t param_value_size, + void *param_value, + size_t *param_value_size_ret); + +typedef struct _cl_mem_ext_host_ptr +{ + /* Type of external memory allocation. */ + /* Legal values will be defined in layered extensions. */ + cl_uint allocation_type; + + /* Host cache policy for this external memory allocation. */ + cl_uint host_cache_policy; + +} cl_mem_ext_host_ptr; + +/********************************* +* cl_qcom_ion_host_ptr extension +*********************************/ + +#define CL_MEM_ION_HOST_PTR_QCOM 0x40A8 + +typedef struct _cl_mem_ion_host_ptr +{ + /* Type of external memory allocation. */ + /* Must be CL_MEM_ION_HOST_PTR_QCOM for ION allocations. */ + cl_mem_ext_host_ptr ext_host_ptr; + + /* ION file descriptor */ + int ion_filedesc; + + /* Host pointer to the ION allocated memory */ + void* ion_hostptr; + +} cl_mem_ion_host_ptr; + +#endif /* CL_VERSION_1_1 */ + +#ifdef __cplusplus +} +#endif + + +#endif /* __CL_EXT_H */ diff --git a/includes/CL/cl_gl.h b/includes/CL/cl_gl.h new file mode 100644 index 0000000..63b102a --- /dev/null +++ b/includes/CL/cl_gl.h @@ -0,0 +1,162 @@ +/********************************************************************************** + * Copyright (c) 2008 - 2012 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Materials. + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + **********************************************************************************/ + +#ifndef __OPENCL_CL_GL_H +#define __OPENCL_CL_GL_H + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef cl_uint cl_gl_object_type; +typedef cl_uint cl_gl_texture_info; +typedef cl_uint cl_gl_platform_info; +typedef struct __GLsync *cl_GLsync; + +/* cl_gl_object_type = 0x2000 - 0x200F enum values are currently taken */ +#define CL_GL_OBJECT_BUFFER 0x2000 +#define CL_GL_OBJECT_TEXTURE2D 0x2001 +#define CL_GL_OBJECT_TEXTURE3D 0x2002 +#define CL_GL_OBJECT_RENDERBUFFER 0x2003 +#define CL_GL_OBJECT_TEXTURE2D_ARRAY 0x200E +#define CL_GL_OBJECT_TEXTURE1D 0x200F +#define CL_GL_OBJECT_TEXTURE1D_ARRAY 0x2010 +#define CL_GL_OBJECT_TEXTURE_BUFFER 0x2011 + +/* cl_gl_texture_info */ +#define CL_GL_TEXTURE_TARGET 0x2004 +#define CL_GL_MIPMAP_LEVEL 0x2005 +#define CL_GL_NUM_SAMPLES 0x2012 + + +extern CL_API_ENTRY cl_mem CL_API_CALL +clCreateFromGLBuffer(cl_context /* context */, + cl_mem_flags /* flags */, + cl_GLuint /* bufobj */, + int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_mem CL_API_CALL +clCreateFromGLTexture(cl_context /* context */, + cl_mem_flags /* flags */, + cl_GLenum /* target */, + cl_GLint /* miplevel */, + cl_GLuint /* texture */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_2; + +extern CL_API_ENTRY cl_mem CL_API_CALL +clCreateFromGLRenderbuffer(cl_context /* context */, + cl_mem_flags /* flags */, + cl_GLuint /* renderbuffer */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetGLObjectInfo(cl_mem /* memobj */, + cl_gl_object_type * /* gl_object_type */, + cl_GLuint * /* gl_object_name */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetGLTextureInfo(cl_mem /* memobj */, + cl_gl_texture_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueAcquireGLObjects(cl_command_queue /* command_queue */, + cl_uint /* num_objects */, + const cl_mem * /* mem_objects */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +extern CL_API_ENTRY cl_int CL_API_CALL +clEnqueueReleaseGLObjects(cl_command_queue /* command_queue */, + cl_uint /* num_objects */, + const cl_mem * /* mem_objects */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + + +/* Deprecated OpenCL 1.1 APIs */ +extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_mem CL_API_CALL +clCreateFromGLTexture2D(cl_context /* context */, + cl_mem_flags /* flags */, + cl_GLenum /* target */, + cl_GLint /* miplevel */, + cl_GLuint /* texture */, + cl_int * /* errcode_ret */) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; + +extern CL_API_ENTRY CL_EXT_PREFIX__VERSION_1_1_DEPRECATED cl_mem CL_API_CALL +clCreateFromGLTexture3D(cl_context /* context */, + cl_mem_flags /* flags */, + cl_GLenum /* target */, + cl_GLint /* miplevel */, + cl_GLuint /* texture */, + cl_int * /* errcode_ret */) CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED; + +/* cl_khr_gl_sharing extension */ + +#define cl_khr_gl_sharing 1 + +typedef cl_uint cl_gl_context_info; + +/* Additional Error Codes */ +#define CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR -1000 + +/* cl_gl_context_info */ +#define CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KHR 0x2006 +#define CL_DEVICES_FOR_GL_CONTEXT_KHR 0x2007 + +/* Additional cl_context_properties */ +#define CL_GL_CONTEXT_KHR 0x2008 +#define CL_EGL_DISPLAY_KHR 0x2009 +#define CL_GLX_DISPLAY_KHR 0x200A +#define CL_WGL_HDC_KHR 0x200B +#define CL_CGL_SHAREGROUP_KHR 0x200C + +extern CL_API_ENTRY cl_int CL_API_CALL +clGetGLContextInfoKHR(const cl_context_properties * /* properties */, + cl_gl_context_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL *clGetGLContextInfoKHR_fn)( + const cl_context_properties * properties, + cl_gl_context_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret); + +#ifdef __cplusplus +} +#endif + +#endif /* __OPENCL_CL_GL_H */ diff --git a/includes/CL/cl_gl_ext.h b/includes/CL/cl_gl_ext.h new file mode 100644 index 0000000..0b2fc93 --- /dev/null +++ b/includes/CL/cl_gl_ext.h @@ -0,0 +1,69 @@ +/********************************************************************************** + * Copyright (c) 2008-2012 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Materials. + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + **********************************************************************************/ + +/* $Revision: 11708 $ on $Date: 2010-06-13 23:36:24 -0700 (Sun, 13 Jun 2010) $ */ + +/* cl_gl_ext.h contains vendor (non-KHR) OpenCL extensions which have */ +/* OpenGL dependencies. */ + +#ifndef __OPENCL_CL_GL_EXT_H +#define __OPENCL_CL_GL_EXT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __APPLE__ + #include +#else + #include +#endif + +/* + * For each extension, follow this template + * cl_VEN_extname extension */ +/* #define cl_VEN_extname 1 + * ... define new types, if any + * ... define new tokens, if any + * ... define new APIs, if any + * + * If you need GLtypes here, mirror them with a cl_GLtype, rather than including a GL header + * This allows us to avoid having to decide whether to include GL headers or GLES here. + */ + +/* + * cl_khr_gl_event extension + * See section 9.9 in the OpenCL 1.1 spec for more information + */ +#define CL_COMMAND_GL_FENCE_SYNC_OBJECT_KHR 0x200D + +extern CL_API_ENTRY cl_event CL_API_CALL +clCreateEventFromGLsyncKHR(cl_context /* context */, + cl_GLsync /* cl_GLsync */, + cl_int * /* errcode_ret */) CL_EXT_SUFFIX__VERSION_1_1; + +#ifdef __cplusplus +} +#endif + +#endif /* __OPENCL_CL_GL_EXT_H */ diff --git a/includes/CL/cl_platform.h b/includes/CL/cl_platform.h new file mode 100644 index 0000000..a583a54 --- /dev/null +++ b/includes/CL/cl_platform.h @@ -0,0 +1,1278 @@ +/********************************************************************************** + * Copyright (c) 2008-2012 The Khronos Group Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and/or associated documentation files (the + * "Materials"), to deal in the Materials without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Materials, and to + * permit persons to whom the Materials are furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Materials. + * + * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + **********************************************************************************/ + +/* $Revision: 11803 $ on $Date: 2010-06-25 10:02:12 -0700 (Fri, 25 Jun 2010) $ */ + +#ifndef __CL_PLATFORM_H +#define __CL_PLATFORM_H + +#ifdef __APPLE__ + /* Contains #defines for AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER below */ + #include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_WIN32) + #define CL_API_ENTRY + #define CL_API_CALL __stdcall + #define CL_CALLBACK __stdcall +#else + #define CL_API_ENTRY + #define CL_API_CALL + #define CL_CALLBACK +#endif + +#ifdef __APPLE__ + #define CL_EXTENSION_WEAK_LINK __attribute__((weak_import)) + #define CL_API_SUFFIX__VERSION_1_0 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + #define CL_EXT_SUFFIX__VERSION_1_0 CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + #define CL_API_SUFFIX__VERSION_1_1 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER + #define GCL_API_SUFFIX__VERSION_1_1 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER + #define CL_EXT_SUFFIX__VERSION_1_1 CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER + #define CL_EXT_SUFFIX__VERSION_1_0_DEPRECATED CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_7 + + #ifdef AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER + #define CL_API_SUFFIX__VERSION_1_2 AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER + #define GCL_API_SUFFIX__VERSION_1_2 AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER + #define CL_EXT_SUFFIX__VERSION_1_2 CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER + #define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED + #define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_8 + #else + #warning This path should never happen outside of internal operating system development. AvailabilityMacros do not function correctly here! + #define CL_API_SUFFIX__VERSION_1_2 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER + #define GCL_API_SUFFIX__VERSION_1_2 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER + #define CL_EXT_SUFFIX__VERSION_1_2 CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER + #define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER + #endif +#else + #define CL_EXTENSION_WEAK_LINK + #define CL_API_SUFFIX__VERSION_1_0 + #define CL_EXT_SUFFIX__VERSION_1_0 + #define CL_API_SUFFIX__VERSION_1_1 + #define CL_EXT_SUFFIX__VERSION_1_1 + #define CL_API_SUFFIX__VERSION_1_2 + #define CL_EXT_SUFFIX__VERSION_1_2 + + #ifdef __GNUC__ + #ifdef CL_USE_DEPRECATED_OPENCL_1_0_APIS + #define CL_EXT_SUFFIX__VERSION_1_0_DEPRECATED + #define CL_EXT_PREFIX__VERSION_1_0_DEPRECATED + #else + #define CL_EXT_SUFFIX__VERSION_1_0_DEPRECATED __attribute__((deprecated)) + #define CL_EXT_PREFIX__VERSION_1_0_DEPRECATED + #endif + + #ifdef CL_USE_DEPRECATED_OPENCL_1_1_APIS + #define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED + #define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED + #else + #define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED __attribute__((deprecated)) + #define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED + #endif + #elif _WIN32 + #ifdef CL_USE_DEPRECATED_OPENCL_1_0_APIS + #define CL_EXT_SUFFIX__VERSION_1_0_DEPRECATED + #define CL_EXT_PREFIX__VERSION_1_0_DEPRECATED + #else + #define CL_EXT_SUFFIX__VERSION_1_0_DEPRECATED + #define CL_EXT_PREFIX__VERSION_1_0_DEPRECATED __declspec(deprecated) + #endif + + #ifdef CL_USE_DEPRECATED_OPENCL_1_1_APIS + #define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED + #define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED + #else + #define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED + #define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED __declspec(deprecated) + #endif + #else + #define CL_EXT_SUFFIX__VERSION_1_0_DEPRECATED + #define CL_EXT_PREFIX__VERSION_1_0_DEPRECATED + + #define CL_EXT_SUFFIX__VERSION_1_1_DEPRECATED + #define CL_EXT_PREFIX__VERSION_1_1_DEPRECATED + #endif +#endif + +#if (defined (_WIN32) && defined(_MSC_VER)) + +/* scalar types */ +typedef signed __int8 cl_char; +typedef unsigned __int8 cl_uchar; +typedef signed __int16 cl_short; +typedef unsigned __int16 cl_ushort; +typedef signed __int32 cl_int; +typedef unsigned __int32 cl_uint; +typedef signed __int64 cl_long; +typedef unsigned __int64 cl_ulong; + +typedef unsigned __int16 cl_half; +typedef float cl_float; +typedef double cl_double; + +/* Macro names and corresponding values defined by OpenCL */ +#define CL_CHAR_BIT 8 +#define CL_SCHAR_MAX 127 +#define CL_SCHAR_MIN (-127-1) +#define CL_CHAR_MAX CL_SCHAR_MAX +#define CL_CHAR_MIN CL_SCHAR_MIN +#define CL_UCHAR_MAX 255 +#define CL_SHRT_MAX 32767 +#define CL_SHRT_MIN (-32767-1) +#define CL_USHRT_MAX 65535 +#define CL_INT_MAX 2147483647 +#define CL_INT_MIN (-2147483647-1) +#define CL_UINT_MAX 0xffffffffU +#define CL_LONG_MAX ((cl_long) 0x7FFFFFFFFFFFFFFFLL) +#define CL_LONG_MIN ((cl_long) -0x7FFFFFFFFFFFFFFFLL - 1LL) +#define CL_ULONG_MAX ((cl_ulong) 0xFFFFFFFFFFFFFFFFULL) + +#define CL_FLT_DIG 6 +#define CL_FLT_MANT_DIG 24 +#define CL_FLT_MAX_10_EXP +38 +#define CL_FLT_MAX_EXP +128 +#define CL_FLT_MIN_10_EXP -37 +#define CL_FLT_MIN_EXP -125 +#define CL_FLT_RADIX 2 +#define CL_FLT_MAX 340282346638528859811704183484516925440.0f +#define CL_FLT_MIN 1.175494350822287507969e-38f +#define CL_FLT_EPSILON 0x1.0p-23f + +#define CL_DBL_DIG 15 +#define CL_DBL_MANT_DIG 53 +#define CL_DBL_MAX_10_EXP +308 +#define CL_DBL_MAX_EXP +1024 +#define CL_DBL_MIN_10_EXP -307 +#define CL_DBL_MIN_EXP -1021 +#define CL_DBL_RADIX 2 +#define CL_DBL_MAX 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0 +#define CL_DBL_MIN 2.225073858507201383090e-308 +#define CL_DBL_EPSILON 2.220446049250313080847e-16 + +#define CL_M_E 2.718281828459045090796 +#define CL_M_LOG2E 1.442695040888963387005 +#define CL_M_LOG10E 0.434294481903251816668 +#define CL_M_LN2 0.693147180559945286227 +#define CL_M_LN10 2.302585092994045901094 +#define CL_M_PI 3.141592653589793115998 +#define CL_M_PI_2 1.570796326794896557999 +#define CL_M_PI_4 0.785398163397448278999 +#define CL_M_1_PI 0.318309886183790691216 +#define CL_M_2_PI 0.636619772367581382433 +#define CL_M_2_SQRTPI 1.128379167095512558561 +#define CL_M_SQRT2 1.414213562373095145475 +#define CL_M_SQRT1_2 0.707106781186547572737 + +#define CL_M_E_F 2.71828174591064f +#define CL_M_LOG2E_F 1.44269502162933f +#define CL_M_LOG10E_F 0.43429449200630f +#define CL_M_LN2_F 0.69314718246460f +#define CL_M_LN10_F 2.30258512496948f +#define CL_M_PI_F 3.14159274101257f +#define CL_M_PI_2_F 1.57079637050629f +#define CL_M_PI_4_F 0.78539818525314f +#define CL_M_1_PI_F 0.31830987334251f +#define CL_M_2_PI_F 0.63661974668503f +#define CL_M_2_SQRTPI_F 1.12837922573090f +#define CL_M_SQRT2_F 1.41421353816986f +#define CL_M_SQRT1_2_F 0.70710676908493f + +#define CL_NAN (CL_INFINITY - CL_INFINITY) +#define CL_HUGE_VALF ((cl_float) 1e50) +#define CL_HUGE_VAL ((cl_double) 1e500) +#define CL_MAXFLOAT CL_FLT_MAX +#define CL_INFINITY CL_HUGE_VALF + +#else + +#include + +/* scalar types */ +typedef int8_t cl_char; +typedef uint8_t cl_uchar; +typedef int16_t cl_short __attribute__((aligned(2))); +typedef uint16_t cl_ushort __attribute__((aligned(2))); +typedef int32_t cl_int __attribute__((aligned(4))); +typedef uint32_t cl_uint __attribute__((aligned(4))); +typedef int64_t cl_long __attribute__((aligned(8))); +typedef uint64_t cl_ulong __attribute__((aligned(8))); + +typedef uint16_t cl_half __attribute__((aligned(2))); +typedef float cl_float __attribute__((aligned(4))); +typedef double cl_double __attribute__((aligned(8))); + +/* Macro names and corresponding values defined by OpenCL */ +#define CL_CHAR_BIT 8 +#define CL_SCHAR_MAX 127 +#define CL_SCHAR_MIN (-127-1) +#define CL_CHAR_MAX CL_SCHAR_MAX +#define CL_CHAR_MIN CL_SCHAR_MIN +#define CL_UCHAR_MAX 255 +#define CL_SHRT_MAX 32767 +#define CL_SHRT_MIN (-32767-1) +#define CL_USHRT_MAX 65535 +#define CL_INT_MAX 2147483647 +#define CL_INT_MIN (-2147483647-1) +#define CL_UINT_MAX 0xffffffffU +#define CL_LONG_MAX ((cl_long) 0x7FFFFFFFFFFFFFFFLL) +#define CL_LONG_MIN ((cl_long) -0x7FFFFFFFFFFFFFFFLL - 1LL) +#define CL_ULONG_MAX ((cl_ulong) 0xFFFFFFFFFFFFFFFFULL) + +#define CL_FLT_DIG 6 +#define CL_FLT_MANT_DIG 24 +#define CL_FLT_MAX_10_EXP +38 +#define CL_FLT_MAX_EXP +128 +#define CL_FLT_MIN_10_EXP -37 +#define CL_FLT_MIN_EXP -125 +#define CL_FLT_RADIX 2 +#define CL_FLT_MAX 0x1.fffffep127f +#define CL_FLT_MIN 0x1.0p-126f +#define CL_FLT_EPSILON 0x1.0p-23f + +#define CL_DBL_DIG 15 +#define CL_DBL_MANT_DIG 53 +#define CL_DBL_MAX_10_EXP +308 +#define CL_DBL_MAX_EXP +1024 +#define CL_DBL_MIN_10_EXP -307 +#define CL_DBL_MIN_EXP -1021 +#define CL_DBL_RADIX 2 +#define CL_DBL_MAX 0x1.fffffffffffffp1023 +#define CL_DBL_MIN 0x1.0p-1022 +#define CL_DBL_EPSILON 0x1.0p-52 + +#define CL_M_E 2.718281828459045090796 +#define CL_M_LOG2E 1.442695040888963387005 +#define CL_M_LOG10E 0.434294481903251816668 +#define CL_M_LN2 0.693147180559945286227 +#define CL_M_LN10 2.302585092994045901094 +#define CL_M_PI 3.141592653589793115998 +#define CL_M_PI_2 1.570796326794896557999 +#define CL_M_PI_4 0.785398163397448278999 +#define CL_M_1_PI 0.318309886183790691216 +#define CL_M_2_PI 0.636619772367581382433 +#define CL_M_2_SQRTPI 1.128379167095512558561 +#define CL_M_SQRT2 1.414213562373095145475 +#define CL_M_SQRT1_2 0.707106781186547572737 + +#define CL_M_E_F 2.71828174591064f +#define CL_M_LOG2E_F 1.44269502162933f +#define CL_M_LOG10E_F 0.43429449200630f +#define CL_M_LN2_F 0.69314718246460f +#define CL_M_LN10_F 2.30258512496948f +#define CL_M_PI_F 3.14159274101257f +#define CL_M_PI_2_F 1.57079637050629f +#define CL_M_PI_4_F 0.78539818525314f +#define CL_M_1_PI_F 0.31830987334251f +#define CL_M_2_PI_F 0.63661974668503f +#define CL_M_2_SQRTPI_F 1.12837922573090f +#define CL_M_SQRT2_F 1.41421353816986f +#define CL_M_SQRT1_2_F 0.70710676908493f + +#if defined( __GNUC__ ) + #define CL_HUGE_VALF __builtin_huge_valf() + #define CL_HUGE_VAL __builtin_huge_val() + #define CL_NAN __builtin_nanf( "" ) +#else + #define CL_HUGE_VALF ((cl_float) 1e50) + #define CL_HUGE_VAL ((cl_double) 1e500) + float nanf( const char * ); + #define CL_NAN nanf( "" ) +#endif +#define CL_MAXFLOAT CL_FLT_MAX +#define CL_INFINITY CL_HUGE_VALF + +#endif + +#include + +/* Mirror types to GL types. Mirror types allow us to avoid deciding which 87s to load based on whether we are using GL or GLES here. */ +typedef unsigned int cl_GLuint; +typedef int cl_GLint; +typedef unsigned int cl_GLenum; + +/* + * Vector types + * + * Note: OpenCL requires that all types be naturally aligned. + * This means that vector types must be naturally aligned. + * For example, a vector of four floats must be aligned to + * a 16 byte boundary (calculated as 4 * the natural 4-byte + * alignment of the float). The alignment qualifiers here + * will only function properly if your compiler supports them + * and if you don't actively work to defeat them. For example, + * in order for a cl_float4 to be 16 byte aligned in a struct, + * the start of the struct must itself be 16-byte aligned. + * + * Maintaining proper alignment is the user's responsibility. + */ + +/* Define basic vector types */ +#if defined( __VEC__ ) + #include /* may be omitted depending on compiler. AltiVec spec provides no way to detect whether the header is required. */ + typedef vector unsigned char __cl_uchar16; + typedef vector signed char __cl_char16; + typedef vector unsigned short __cl_ushort8; + typedef vector signed short __cl_short8; + typedef vector unsigned int __cl_uint4; + typedef vector signed int __cl_int4; + typedef vector float __cl_float4; + #define __CL_UCHAR16__ 1 + #define __CL_CHAR16__ 1 + #define __CL_USHORT8__ 1 + #define __CL_SHORT8__ 1 + #define __CL_UINT4__ 1 + #define __CL_INT4__ 1 + #define __CL_FLOAT4__ 1 +#endif + +#if defined( __SSE__ ) + #if defined( __MINGW64__ ) + #include + #else + #include + #endif + #if defined( __GNUC__ ) + typedef float __cl_float4 __attribute__((vector_size(16))); + #else + typedef __m128 __cl_float4; + #endif + #define __CL_FLOAT4__ 1 +#endif + +#if defined( __SSE2__ ) + #if defined( __MINGW64__ ) + #include + #else + #include + #endif + #if defined( __GNUC__ ) + typedef cl_uchar __cl_uchar16 __attribute__((vector_size(16))); + typedef cl_char __cl_char16 __attribute__((vector_size(16))); + typedef cl_ushort __cl_ushort8 __attribute__((vector_size(16))); + typedef cl_short __cl_short8 __attribute__((vector_size(16))); + typedef cl_uint __cl_uint4 __attribute__((vector_size(16))); + typedef cl_int __cl_int4 __attribute__((vector_size(16))); + typedef cl_ulong __cl_ulong2 __attribute__((vector_size(16))); + typedef cl_long __cl_long2 __attribute__((vector_size(16))); + typedef cl_double __cl_double2 __attribute__((vector_size(16))); + #else + typedef __m128i __cl_uchar16; + typedef __m128i __cl_char16; + typedef __m128i __cl_ushort8; + typedef __m128i __cl_short8; + typedef __m128i __cl_uint4; + typedef __m128i __cl_int4; + typedef __m128i __cl_ulong2; + typedef __m128i __cl_long2; + typedef __m128d __cl_double2; + #endif + #define __CL_UCHAR16__ 1 + #define __CL_CHAR16__ 1 + #define __CL_USHORT8__ 1 + #define __CL_SHORT8__ 1 + #define __CL_INT4__ 1 + #define __CL_UINT4__ 1 + #define __CL_ULONG2__ 1 + #define __CL_LONG2__ 1 + #define __CL_DOUBLE2__ 1 +#endif + +#if defined( __MMX__ ) + #include + #if defined( __GNUC__ ) + typedef cl_uchar __cl_uchar8 __attribute__((vector_size(8))); + typedef cl_char __cl_char8 __attribute__((vector_size(8))); + typedef cl_ushort __cl_ushort4 __attribute__((vector_size(8))); + typedef cl_short __cl_short4 __attribute__((vector_size(8))); + typedef cl_uint __cl_uint2 __attribute__((vector_size(8))); + typedef cl_int __cl_int2 __attribute__((vector_size(8))); + typedef cl_ulong __cl_ulong1 __attribute__((vector_size(8))); + typedef cl_long __cl_long1 __attribute__((vector_size(8))); + typedef cl_float __cl_float2 __attribute__((vector_size(8))); + #else + typedef __m64 __cl_uchar8; + typedef __m64 __cl_char8; + typedef __m64 __cl_ushort4; + typedef __m64 __cl_short4; + typedef __m64 __cl_uint2; + typedef __m64 __cl_int2; + typedef __m64 __cl_ulong1; + typedef __m64 __cl_long1; + typedef __m64 __cl_float2; + #endif + #define __CL_UCHAR8__ 1 + #define __CL_CHAR8__ 1 + #define __CL_USHORT4__ 1 + #define __CL_SHORT4__ 1 + #define __CL_INT2__ 1 + #define __CL_UINT2__ 1 + #define __CL_ULONG1__ 1 + #define __CL_LONG1__ 1 + #define __CL_FLOAT2__ 1 +#endif + +#if defined( __AVX__ ) + #if defined( __MINGW64__ ) + #include + #else + #include + #endif + #if defined( __GNUC__ ) + typedef cl_float __cl_float8 __attribute__((vector_size(32))); + typedef cl_double __cl_double4 __attribute__((vector_size(32))); + #else + typedef __m256 __cl_float8; + typedef __m256d __cl_double4; + #endif + #define __CL_FLOAT8__ 1 + #define __CL_DOUBLE4__ 1 +#endif + +/* Define capabilities for anonymous struct members. */ +#if defined( __GNUC__) && ! defined( __STRICT_ANSI__ ) +#define __CL_HAS_ANON_STRUCT__ 1 +#define __CL_ANON_STRUCT__ __extension__ +#elif defined( _WIN32) && (_MSC_VER >= 1500) + /* Microsoft Developer Studio 2008 supports anonymous structs, but + * complains by default. */ +#define __CL_HAS_ANON_STRUCT__ 1 +#define __CL_ANON_STRUCT__ + /* Disable warning C4201: nonstandard extension used : nameless + * struct/union */ +#pragma warning( push ) +#pragma warning( disable : 4201 ) +#else +#define __CL_HAS_ANON_STRUCT__ 0 +#define __CL_ANON_STRUCT__ +#endif + +/* Define alignment keys */ +#if defined( __GNUC__ ) + #define CL_ALIGNED(_x) __attribute__ ((aligned(_x))) +#elif defined( _WIN32) && (_MSC_VER) + /* Alignment keys neutered on windows because MSVC can't swallow function arguments with alignment requirements */ + /* http://msdn.microsoft.com/en-us/library/373ak2y1%28VS.71%29.aspx */ + /* #include */ + /* #define CL_ALIGNED(_x) _CRT_ALIGN(_x) */ + #define CL_ALIGNED(_x) +#else + #warning Need to implement some method to align data here + #define CL_ALIGNED(_x) +#endif + +/* Indicate whether .xyzw, .s0123 and .hi.lo are supported */ +#if __CL_HAS_ANON_STRUCT__ + /* .xyzw and .s0123...{f|F} are supported */ + #define CL_HAS_NAMED_VECTOR_FIELDS 1 + /* .hi and .lo are supported */ + #define CL_HAS_HI_LO_VECTOR_FIELDS 1 +#endif + +/* Define cl_vector types */ + +/* ---- cl_charn ---- */ +typedef union +{ + cl_char CL_ALIGNED(2) s[2]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_char x, y; }; + __CL_ANON_STRUCT__ struct{ cl_char s0, s1; }; + __CL_ANON_STRUCT__ struct{ cl_char lo, hi; }; +#endif +#if defined( __CL_CHAR2__) + __cl_char2 v2; +#endif +}cl_char2; + +typedef union +{ + cl_char CL_ALIGNED(4) s[4]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_char x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_char s0, s1, s2, s3; }; + __CL_ANON_STRUCT__ struct{ cl_char2 lo, hi; }; +#endif +#if defined( __CL_CHAR2__) + __cl_char2 v2[2]; +#endif +#if defined( __CL_CHAR4__) + __cl_char4 v4; +#endif +}cl_char4; + +/* cl_char3 is identical in size, alignment and behavior to cl_char4. See section 6.1.5. */ +typedef cl_char4 cl_char3; + +typedef union +{ + cl_char CL_ALIGNED(8) s[8]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_char x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_char s0, s1, s2, s3, s4, s5, s6, s7; }; + __CL_ANON_STRUCT__ struct{ cl_char4 lo, hi; }; +#endif +#if defined( __CL_CHAR2__) + __cl_char2 v2[4]; +#endif +#if defined( __CL_CHAR4__) + __cl_char4 v4[2]; +#endif +#if defined( __CL_CHAR8__ ) + __cl_char8 v8; +#endif +}cl_char8; + +typedef union +{ + cl_char CL_ALIGNED(16) s[16]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_char x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __CL_ANON_STRUCT__ struct{ cl_char s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __CL_ANON_STRUCT__ struct{ cl_char8 lo, hi; }; +#endif +#if defined( __CL_CHAR2__) + __cl_char2 v2[8]; +#endif +#if defined( __CL_CHAR4__) + __cl_char4 v4[4]; +#endif +#if defined( __CL_CHAR8__ ) + __cl_char8 v8[2]; +#endif +#if defined( __CL_CHAR16__ ) + __cl_char16 v16; +#endif +}cl_char16; + + +/* ---- cl_ucharn ---- */ +typedef union +{ + cl_uchar CL_ALIGNED(2) s[2]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_uchar x, y; }; + __CL_ANON_STRUCT__ struct{ cl_uchar s0, s1; }; + __CL_ANON_STRUCT__ struct{ cl_uchar lo, hi; }; +#endif +#if defined( __cl_uchar2__) + __cl_uchar2 v2; +#endif +}cl_uchar2; + +typedef union +{ + cl_uchar CL_ALIGNED(4) s[4]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_uchar x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_uchar s0, s1, s2, s3; }; + __CL_ANON_STRUCT__ struct{ cl_uchar2 lo, hi; }; +#endif +#if defined( __CL_UCHAR2__) + __cl_uchar2 v2[2]; +#endif +#if defined( __CL_UCHAR4__) + __cl_uchar4 v4; +#endif +}cl_uchar4; + +/* cl_uchar3 is identical in size, alignment and behavior to cl_uchar4. See section 6.1.5. */ +typedef cl_uchar4 cl_uchar3; + +typedef union +{ + cl_uchar CL_ALIGNED(8) s[8]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_uchar x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_uchar s0, s1, s2, s3, s4, s5, s6, s7; }; + __CL_ANON_STRUCT__ struct{ cl_uchar4 lo, hi; }; +#endif +#if defined( __CL_UCHAR2__) + __cl_uchar2 v2[4]; +#endif +#if defined( __CL_UCHAR4__) + __cl_uchar4 v4[2]; +#endif +#if defined( __CL_UCHAR8__ ) + __cl_uchar8 v8; +#endif +}cl_uchar8; + +typedef union +{ + cl_uchar CL_ALIGNED(16) s[16]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_uchar x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __CL_ANON_STRUCT__ struct{ cl_uchar s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __CL_ANON_STRUCT__ struct{ cl_uchar8 lo, hi; }; +#endif +#if defined( __CL_UCHAR2__) + __cl_uchar2 v2[8]; +#endif +#if defined( __CL_UCHAR4__) + __cl_uchar4 v4[4]; +#endif +#if defined( __CL_UCHAR8__ ) + __cl_uchar8 v8[2]; +#endif +#if defined( __CL_UCHAR16__ ) + __cl_uchar16 v16; +#endif +}cl_uchar16; + + +/* ---- cl_shortn ---- */ +typedef union +{ + cl_short CL_ALIGNED(4) s[2]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_short x, y; }; + __CL_ANON_STRUCT__ struct{ cl_short s0, s1; }; + __CL_ANON_STRUCT__ struct{ cl_short lo, hi; }; +#endif +#if defined( __CL_SHORT2__) + __cl_short2 v2; +#endif +}cl_short2; + +typedef union +{ + cl_short CL_ALIGNED(8) s[4]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_short x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_short s0, s1, s2, s3; }; + __CL_ANON_STRUCT__ struct{ cl_short2 lo, hi; }; +#endif +#if defined( __CL_SHORT2__) + __cl_short2 v2[2]; +#endif +#if defined( __CL_SHORT4__) + __cl_short4 v4; +#endif +}cl_short4; + +/* cl_short3 is identical in size, alignment and behavior to cl_short4. See section 6.1.5. */ +typedef cl_short4 cl_short3; + +typedef union +{ + cl_short CL_ALIGNED(16) s[8]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_short x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_short s0, s1, s2, s3, s4, s5, s6, s7; }; + __CL_ANON_STRUCT__ struct{ cl_short4 lo, hi; }; +#endif +#if defined( __CL_SHORT2__) + __cl_short2 v2[4]; +#endif +#if defined( __CL_SHORT4__) + __cl_short4 v4[2]; +#endif +#if defined( __CL_SHORT8__ ) + __cl_short8 v8; +#endif +}cl_short8; + +typedef union +{ + cl_short CL_ALIGNED(32) s[16]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_short x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __CL_ANON_STRUCT__ struct{ cl_short s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __CL_ANON_STRUCT__ struct{ cl_short8 lo, hi; }; +#endif +#if defined( __CL_SHORT2__) + __cl_short2 v2[8]; +#endif +#if defined( __CL_SHORT4__) + __cl_short4 v4[4]; +#endif +#if defined( __CL_SHORT8__ ) + __cl_short8 v8[2]; +#endif +#if defined( __CL_SHORT16__ ) + __cl_short16 v16; +#endif +}cl_short16; + + +/* ---- cl_ushortn ---- */ +typedef union +{ + cl_ushort CL_ALIGNED(4) s[2]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_ushort x, y; }; + __CL_ANON_STRUCT__ struct{ cl_ushort s0, s1; }; + __CL_ANON_STRUCT__ struct{ cl_ushort lo, hi; }; +#endif +#if defined( __CL_USHORT2__) + __cl_ushort2 v2; +#endif +}cl_ushort2; + +typedef union +{ + cl_ushort CL_ALIGNED(8) s[4]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_ushort x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_ushort s0, s1, s2, s3; }; + __CL_ANON_STRUCT__ struct{ cl_ushort2 lo, hi; }; +#endif +#if defined( __CL_USHORT2__) + __cl_ushort2 v2[2]; +#endif +#if defined( __CL_USHORT4__) + __cl_ushort4 v4; +#endif +}cl_ushort4; + +/* cl_ushort3 is identical in size, alignment and behavior to cl_ushort4. See section 6.1.5. */ +typedef cl_ushort4 cl_ushort3; + +typedef union +{ + cl_ushort CL_ALIGNED(16) s[8]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_ushort x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_ushort s0, s1, s2, s3, s4, s5, s6, s7; }; + __CL_ANON_STRUCT__ struct{ cl_ushort4 lo, hi; }; +#endif +#if defined( __CL_USHORT2__) + __cl_ushort2 v2[4]; +#endif +#if defined( __CL_USHORT4__) + __cl_ushort4 v4[2]; +#endif +#if defined( __CL_USHORT8__ ) + __cl_ushort8 v8; +#endif +}cl_ushort8; + +typedef union +{ + cl_ushort CL_ALIGNED(32) s[16]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_ushort x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __CL_ANON_STRUCT__ struct{ cl_ushort s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __CL_ANON_STRUCT__ struct{ cl_ushort8 lo, hi; }; +#endif +#if defined( __CL_USHORT2__) + __cl_ushort2 v2[8]; +#endif +#if defined( __CL_USHORT4__) + __cl_ushort4 v4[4]; +#endif +#if defined( __CL_USHORT8__ ) + __cl_ushort8 v8[2]; +#endif +#if defined( __CL_USHORT16__ ) + __cl_ushort16 v16; +#endif +}cl_ushort16; + +/* ---- cl_intn ---- */ +typedef union +{ + cl_int CL_ALIGNED(8) s[2]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_int x, y; }; + __CL_ANON_STRUCT__ struct{ cl_int s0, s1; }; + __CL_ANON_STRUCT__ struct{ cl_int lo, hi; }; +#endif +#if defined( __CL_INT2__) + __cl_int2 v2; +#endif +}cl_int2; + +typedef union +{ + cl_int CL_ALIGNED(16) s[4]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_int x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_int s0, s1, s2, s3; }; + __CL_ANON_STRUCT__ struct{ cl_int2 lo, hi; }; +#endif +#if defined( __CL_INT2__) + __cl_int2 v2[2]; +#endif +#if defined( __CL_INT4__) + __cl_int4 v4; +#endif +}cl_int4; + +/* cl_int3 is identical in size, alignment and behavior to cl_int4. See section 6.1.5. */ +typedef cl_int4 cl_int3; + +typedef union +{ + cl_int CL_ALIGNED(32) s[8]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_int x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_int s0, s1, s2, s3, s4, s5, s6, s7; }; + __CL_ANON_STRUCT__ struct{ cl_int4 lo, hi; }; +#endif +#if defined( __CL_INT2__) + __cl_int2 v2[4]; +#endif +#if defined( __CL_INT4__) + __cl_int4 v4[2]; +#endif +#if defined( __CL_INT8__ ) + __cl_int8 v8; +#endif +}cl_int8; + +typedef union +{ + cl_int CL_ALIGNED(64) s[16]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_int x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __CL_ANON_STRUCT__ struct{ cl_int s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __CL_ANON_STRUCT__ struct{ cl_int8 lo, hi; }; +#endif +#if defined( __CL_INT2__) + __cl_int2 v2[8]; +#endif +#if defined( __CL_INT4__) + __cl_int4 v4[4]; +#endif +#if defined( __CL_INT8__ ) + __cl_int8 v8[2]; +#endif +#if defined( __CL_INT16__ ) + __cl_int16 v16; +#endif +}cl_int16; + + +/* ---- cl_uintn ---- */ +typedef union +{ + cl_uint CL_ALIGNED(8) s[2]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_uint x, y; }; + __CL_ANON_STRUCT__ struct{ cl_uint s0, s1; }; + __CL_ANON_STRUCT__ struct{ cl_uint lo, hi; }; +#endif +#if defined( __CL_UINT2__) + __cl_uint2 v2; +#endif +}cl_uint2; + +typedef union +{ + cl_uint CL_ALIGNED(16) s[4]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_uint x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_uint s0, s1, s2, s3; }; + __CL_ANON_STRUCT__ struct{ cl_uint2 lo, hi; }; +#endif +#if defined( __CL_UINT2__) + __cl_uint2 v2[2]; +#endif +#if defined( __CL_UINT4__) + __cl_uint4 v4; +#endif +}cl_uint4; + +/* cl_uint3 is identical in size, alignment and behavior to cl_uint4. See section 6.1.5. */ +typedef cl_uint4 cl_uint3; + +typedef union +{ + cl_uint CL_ALIGNED(32) s[8]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_uint x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_uint s0, s1, s2, s3, s4, s5, s6, s7; }; + __CL_ANON_STRUCT__ struct{ cl_uint4 lo, hi; }; +#endif +#if defined( __CL_UINT2__) + __cl_uint2 v2[4]; +#endif +#if defined( __CL_UINT4__) + __cl_uint4 v4[2]; +#endif +#if defined( __CL_UINT8__ ) + __cl_uint8 v8; +#endif +}cl_uint8; + +typedef union +{ + cl_uint CL_ALIGNED(64) s[16]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_uint x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __CL_ANON_STRUCT__ struct{ cl_uint s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __CL_ANON_STRUCT__ struct{ cl_uint8 lo, hi; }; +#endif +#if defined( __CL_UINT2__) + __cl_uint2 v2[8]; +#endif +#if defined( __CL_UINT4__) + __cl_uint4 v4[4]; +#endif +#if defined( __CL_UINT8__ ) + __cl_uint8 v8[2]; +#endif +#if defined( __CL_UINT16__ ) + __cl_uint16 v16; +#endif +}cl_uint16; + +/* ---- cl_longn ---- */ +typedef union +{ + cl_long CL_ALIGNED(16) s[2]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_long x, y; }; + __CL_ANON_STRUCT__ struct{ cl_long s0, s1; }; + __CL_ANON_STRUCT__ struct{ cl_long lo, hi; }; +#endif +#if defined( __CL_LONG2__) + __cl_long2 v2; +#endif +}cl_long2; + +typedef union +{ + cl_long CL_ALIGNED(32) s[4]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_long x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_long s0, s1, s2, s3; }; + __CL_ANON_STRUCT__ struct{ cl_long2 lo, hi; }; +#endif +#if defined( __CL_LONG2__) + __cl_long2 v2[2]; +#endif +#if defined( __CL_LONG4__) + __cl_long4 v4; +#endif +}cl_long4; + +/* cl_long3 is identical in size, alignment and behavior to cl_long4. See section 6.1.5. */ +typedef cl_long4 cl_long3; + +typedef union +{ + cl_long CL_ALIGNED(64) s[8]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_long x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_long s0, s1, s2, s3, s4, s5, s6, s7; }; + __CL_ANON_STRUCT__ struct{ cl_long4 lo, hi; }; +#endif +#if defined( __CL_LONG2__) + __cl_long2 v2[4]; +#endif +#if defined( __CL_LONG4__) + __cl_long4 v4[2]; +#endif +#if defined( __CL_LONG8__ ) + __cl_long8 v8; +#endif +}cl_long8; + +typedef union +{ + cl_long CL_ALIGNED(128) s[16]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_long x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __CL_ANON_STRUCT__ struct{ cl_long s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __CL_ANON_STRUCT__ struct{ cl_long8 lo, hi; }; +#endif +#if defined( __CL_LONG2__) + __cl_long2 v2[8]; +#endif +#if defined( __CL_LONG4__) + __cl_long4 v4[4]; +#endif +#if defined( __CL_LONG8__ ) + __cl_long8 v8[2]; +#endif +#if defined( __CL_LONG16__ ) + __cl_long16 v16; +#endif +}cl_long16; + + +/* ---- cl_ulongn ---- */ +typedef union +{ + cl_ulong CL_ALIGNED(16) s[2]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_ulong x, y; }; + __CL_ANON_STRUCT__ struct{ cl_ulong s0, s1; }; + __CL_ANON_STRUCT__ struct{ cl_ulong lo, hi; }; +#endif +#if defined( __CL_ULONG2__) + __cl_ulong2 v2; +#endif +}cl_ulong2; + +typedef union +{ + cl_ulong CL_ALIGNED(32) s[4]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_ulong x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_ulong s0, s1, s2, s3; }; + __CL_ANON_STRUCT__ struct{ cl_ulong2 lo, hi; }; +#endif +#if defined( __CL_ULONG2__) + __cl_ulong2 v2[2]; +#endif +#if defined( __CL_ULONG4__) + __cl_ulong4 v4; +#endif +}cl_ulong4; + +/* cl_ulong3 is identical in size, alignment and behavior to cl_ulong4. See section 6.1.5. */ +typedef cl_ulong4 cl_ulong3; + +typedef union +{ + cl_ulong CL_ALIGNED(64) s[8]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_ulong x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_ulong s0, s1, s2, s3, s4, s5, s6, s7; }; + __CL_ANON_STRUCT__ struct{ cl_ulong4 lo, hi; }; +#endif +#if defined( __CL_ULONG2__) + __cl_ulong2 v2[4]; +#endif +#if defined( __CL_ULONG4__) + __cl_ulong4 v4[2]; +#endif +#if defined( __CL_ULONG8__ ) + __cl_ulong8 v8; +#endif +}cl_ulong8; + +typedef union +{ + cl_ulong CL_ALIGNED(128) s[16]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_ulong x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __CL_ANON_STRUCT__ struct{ cl_ulong s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __CL_ANON_STRUCT__ struct{ cl_ulong8 lo, hi; }; +#endif +#if defined( __CL_ULONG2__) + __cl_ulong2 v2[8]; +#endif +#if defined( __CL_ULONG4__) + __cl_ulong4 v4[4]; +#endif +#if defined( __CL_ULONG8__ ) + __cl_ulong8 v8[2]; +#endif +#if defined( __CL_ULONG16__ ) + __cl_ulong16 v16; +#endif +}cl_ulong16; + + +/* --- cl_floatn ---- */ + +typedef union +{ + cl_float CL_ALIGNED(8) s[2]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_float x, y; }; + __CL_ANON_STRUCT__ struct{ cl_float s0, s1; }; + __CL_ANON_STRUCT__ struct{ cl_float lo, hi; }; +#endif +#if defined( __CL_FLOAT2__) + __cl_float2 v2; +#endif +}cl_float2; + +typedef union +{ + cl_float CL_ALIGNED(16) s[4]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_float x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_float s0, s1, s2, s3; }; + __CL_ANON_STRUCT__ struct{ cl_float2 lo, hi; }; +#endif +#if defined( __CL_FLOAT2__) + __cl_float2 v2[2]; +#endif +#if defined( __CL_FLOAT4__) + __cl_float4 v4; +#endif +}cl_float4; + +/* cl_float3 is identical in size, alignment and behavior to cl_float4. See section 6.1.5. */ +typedef cl_float4 cl_float3; + +typedef union +{ + cl_float CL_ALIGNED(32) s[8]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_float x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_float s0, s1, s2, s3, s4, s5, s6, s7; }; + __CL_ANON_STRUCT__ struct{ cl_float4 lo, hi; }; +#endif +#if defined( __CL_FLOAT2__) + __cl_float2 v2[4]; +#endif +#if defined( __CL_FLOAT4__) + __cl_float4 v4[2]; +#endif +#if defined( __CL_FLOAT8__ ) + __cl_float8 v8; +#endif +}cl_float8; + +typedef union +{ + cl_float CL_ALIGNED(64) s[16]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_float x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __CL_ANON_STRUCT__ struct{ cl_float s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __CL_ANON_STRUCT__ struct{ cl_float8 lo, hi; }; +#endif +#if defined( __CL_FLOAT2__) + __cl_float2 v2[8]; +#endif +#if defined( __CL_FLOAT4__) + __cl_float4 v4[4]; +#endif +#if defined( __CL_FLOAT8__ ) + __cl_float8 v8[2]; +#endif +#if defined( __CL_FLOAT16__ ) + __cl_float16 v16; +#endif +}cl_float16; + +/* --- cl_doublen ---- */ + +typedef union +{ + cl_double CL_ALIGNED(16) s[2]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_double x, y; }; + __CL_ANON_STRUCT__ struct{ cl_double s0, s1; }; + __CL_ANON_STRUCT__ struct{ cl_double lo, hi; }; +#endif +#if defined( __CL_DOUBLE2__) + __cl_double2 v2; +#endif +}cl_double2; + +typedef union +{ + cl_double CL_ALIGNED(32) s[4]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_double x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_double s0, s1, s2, s3; }; + __CL_ANON_STRUCT__ struct{ cl_double2 lo, hi; }; +#endif +#if defined( __CL_DOUBLE2__) + __cl_double2 v2[2]; +#endif +#if defined( __CL_DOUBLE4__) + __cl_double4 v4; +#endif +}cl_double4; + +/* cl_double3 is identical in size, alignment and behavior to cl_double4. See section 6.1.5. */ +typedef cl_double4 cl_double3; + +typedef union +{ + cl_double CL_ALIGNED(64) s[8]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_double x, y, z, w; }; + __CL_ANON_STRUCT__ struct{ cl_double s0, s1, s2, s3, s4, s5, s6, s7; }; + __CL_ANON_STRUCT__ struct{ cl_double4 lo, hi; }; +#endif +#if defined( __CL_DOUBLE2__) + __cl_double2 v2[4]; +#endif +#if defined( __CL_DOUBLE4__) + __cl_double4 v4[2]; +#endif +#if defined( __CL_DOUBLE8__ ) + __cl_double8 v8; +#endif +}cl_double8; + +typedef union +{ + cl_double CL_ALIGNED(128) s[16]; +#if __CL_HAS_ANON_STRUCT__ + __CL_ANON_STRUCT__ struct{ cl_double x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __CL_ANON_STRUCT__ struct{ cl_double s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __CL_ANON_STRUCT__ struct{ cl_double8 lo, hi; }; +#endif +#if defined( __CL_DOUBLE2__) + __cl_double2 v2[8]; +#endif +#if defined( __CL_DOUBLE4__) + __cl_double4 v4[4]; +#endif +#if defined( __CL_DOUBLE8__ ) + __cl_double8 v8[2]; +#endif +#if defined( __CL_DOUBLE16__ ) + __cl_double16 v16; +#endif +}cl_double16; + +/* Macro to facilitate debugging + * Usage: + * Place CL_PROGRAM_STRING_DEBUG_INFO on the line before the first line of your source. + * The first line ends with: CL_PROGRAM_STRING_DEBUG_INFO \" + * Each line thereafter of OpenCL C source must end with: \n\ + * The last line ends in "; + * + * Example: + * + * const char *my_program = CL_PROGRAM_STRING_DEBUG_INFO "\ + * kernel void foo( int a, float * b ) \n\ + * { \n\ + * // my comment \n\ + * *b[ get_global_id(0)] = a; \n\ + * } \n\ + * "; + * + * This should correctly set up the line, (column) and file information for your source + * string so you can do source level debugging. + */ +#define __CL_STRINGIFY( _x ) # _x +#define _CL_STRINGIFY( _x ) __CL_STRINGIFY( _x ) +#define CL_PROGRAM_STRING_DEBUG_INFO "#line " _CL_STRINGIFY(__LINE__) " \"" __FILE__ "\" \n\n" + +#ifdef __cplusplus +} +#endif + +#undef __CL_HAS_ANON_STRUCT__ +#undef __CL_ANON_STRUCT__ +#if defined( _WIN32) && (_MSC_VER >= 1500) +#pragma warning( pop ) +#endif + +#endif /* __CL_PLATFORM_H */ diff --git a/includes/CL/lib/OpenCL.lib b/includes/CL/lib/OpenCL.lib new file mode 100644 index 0000000000000000000000000000000000000000..7a761ed95f39ce7dd0931b81ba34f21e4f4fc077 GIT binary patch literal 25870 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 Cvjlno literal 0 HcmV?d00001 diff --git a/includes/CL/lib/libOpenCL.so b/includes/CL/lib/libOpenCL.so new file mode 100644 index 0000000000000000000000000000000000000000..c4f09790d095234dd59c0183f78fdf9522258132 GIT binary patch literal 27424 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 S*W0ekJ +#include +#include +#include + +#else + +#include +#include +#include +#include + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __OPENCL_H */ + diff --git a/includes/Computer.hpp b/includes/Computer.hpp index cc993a0..0025dec 100644 --- a/includes/Computer.hpp +++ b/includes/Computer.hpp @@ -13,6 +13,7 @@ class Computer static std::vector positions; // The position of the stars. static std::vector speeds; // The speed of the stars. static std::vector accelerations; // The acceleration of the stars. + static std::vector star_types; // The types of the stars (positive or negative). static cl::Buffer positions_buffer; // The OpenCL buffer of the positions. static cl::Buffer speeds_buffer; // The OpenCL buffer of the speeds. static cl::Buffer accelerations_buffer; // The OpenCL buffer of the accelerations. @@ -20,7 +21,8 @@ class Computer static cl::Buffer smoothing_length_buffer; // The OpenCL buffer of the smoothing length. static cl::Buffer interaction_rate_buffer; // The OpenCL buffer of the interaction rate. static cl::Buffer black_hole_mass_buffer; // The OpenCL buffer of the mass of the black hole. - + static cl::Buffer types_buffer; // The OpenCL buffer of the types of the stars. + /** * @brief Gives a point randomly placed in a sphere of the diameter of the galaxy. * @@ -28,6 +30,11 @@ class Computer */ static dim::Vector3 random_sphere(); + /** + * @brief Initializes the types of the stars randomly. + */ + static void initialize_star_types(int num_stars); + /** * @brief Add a star in the galaxy setup. * diff --git a/includes/Menu.hpp b/includes/Menu.hpp index 2bce166..81afe07 100644 --- a/includes/Menu.hpp +++ b/includes/Menu.hpp @@ -31,8 +31,10 @@ class Menu static float galaxy_diameter; // The diameter of the galaxy. static float galaxy_thickness; // The thickness of the galaxy. static float galaxies_distance; // The distance between the galaxies. - static float stars_speed; // The initial speed of the stars. + static float stars_speed; // The speed of the stars. static float black_hole_mass; // The mass of the black hole. + static float negative_attraction_constant; // Add this line + static float repulsion_constant; // Add this line /** * @brief Handle the events of the menu. diff --git a/shaders/compute/cl_compute_shader.cl b/shaders/compute/cl_compute_shader.cl index 03aa29f..229f6e5 100644 --- a/shaders/compute/cl_compute_shader.cl +++ b/shaders/compute/cl_compute_shader.cl @@ -1,3 +1,7 @@ +// Define constants for attraction and repulsion +#define NEGATIVE_ATTRACTION_CONSTANT 1.f +#define REPULSION_CONSTANT 1.f + // Convert a 4D vector to a 3D vector. float3 convert_3(float4 vector) { @@ -22,24 +26,37 @@ float distance_2(float3 point_1, float3 point_2) return norm_2(point_2 - point_1); } -// Handle the interactions betweens the stars. +// Handle the interactions between the stars. __kernel void interactions(__global float4* positions, __global float4* accelerations, - __global float* interaction_rate, __global float* smoothing_length, __global float* black_hole_mass) + __global float* interaction_rate, __global float* smoothing_length, __global float* black_hole_mass, __global int* types) { - int index = get_global_id(0); - float3 acc = (float3)(0, 0, 0); - - for (int i = 0; i < *interaction_rate * get_global_size(0); i++) - { - if (i != index) - { - float3 vector = convert_3(positions[i]) - convert_3(positions[index]); - acc += (normalize(vector) / (norm_2(vector) + *smoothing_length)) / *interaction_rate; - } - } - - acc += (*black_hole_mass * normalize(-convert_3(positions[index]))) / (norm_2(convert_3(positions[index])) + *smoothing_length); - accelerations[index] = convert_4(acc); + int index = get_global_id(0); + float3 acc = (float3)(0, 0, 0); + int type = types[index]; + + for (int i = 0; i < *interaction_rate * get_global_size(0); i++) + { + if (i != index) + { + float3 vector = convert_3(positions[i]) - convert_3(positions[index]); + int other_type = types[i]; + float sign; + + if (type == other_type) + { + sign = (type == -1) ? NEGATIVE_ATTRACTION_CONSTANT : 1.0f; // Use NEGATIVE_ATTRACTION_CONSTANT for negative stars + } + else + { + sign = -REPULSION_CONSTANT; // Use REPULSION_CONSTANT for different types repulsing each other + } + + acc += sign * (normalize(vector) / (norm_2(vector) + *smoothing_length)) / *interaction_rate; + } + } + + acc += (*black_hole_mass * normalize(-convert_3(positions[index]))) / (norm_2(convert_3(positions[index])) + *smoothing_length); + accelerations[index] = convert_4(acc); } // Make the integrations to update the position of the stars. diff --git a/sources/Computer.cpp b/sources/Computer.cpp index 41b84f3..9c5467d 100644 --- a/sources/Computer.cpp +++ b/sources/Computer.cpp @@ -1,9 +1,12 @@ #include "Computer.hpp" #include "Simulator.hpp" +#include // For rand() and srand() +#include // For time() std::vector Computer::positions; std::vector Computer::speeds; std::vector Computer::accelerations; +std::vector Computer::star_types; // Add this line cl::Buffer Computer::positions_buffer; cl::Buffer Computer::speeds_buffer; cl::Buffer Computer::accelerations_buffer; @@ -11,7 +14,7 @@ cl::Buffer Computer::step_buffer; cl::Buffer Computer::smoothing_length_buffer; cl::Buffer Computer::interaction_rate_buffer; cl::Buffer Computer::black_hole_mass_buffer; - +cl::Buffer Computer::types_buffer; // Add this line dim::Vector3 Computer::random_sphere() { dim::Vector3 result = dim::Vector3::null; @@ -27,6 +30,17 @@ dim::Vector3 Computer::random_sphere() return result; } +void Computer::initialize_star_types(int num_stars) +{ + star_types.resize(num_stars); + srand(static_cast(time(0))); // Seed the random number generator + + for (int i = 0; i < num_stars; ++i) + { + star_types[i] = (rand() % 2 == 0) ? 1 : -1; // Assign 1 for positive, -1 for negative + } +} + void Computer::create_galaxy(int i) { positions[i].set_norm(static_cast(pow(positions[i].get_norm() / (Simulator::galaxy_diameter / 2.f), 5)) * (Simulator::galaxy_diameter / 2.f)); @@ -61,10 +75,16 @@ void Computer::init() positions.clear(); speeds.clear(); accelerations.clear(); + star_types.clear(); // Add this line + positions.resize(Simulator::nb_stars); speeds.resize(Simulator::nb_stars); accelerations.resize(Simulator::nb_stars, dim::Vector4::null); + star_types.resize(Simulator::nb_stars); // Add this line + + initialize_star_types(Simulator::nb_stars); // Add this line + for (int i = 0; i < Simulator::nb_stars; i++) { @@ -86,6 +106,8 @@ void Computer::init() smoothing_length_buffer = ComputeShader::Buffer(Simulator::smoothing_length, Permissions::Read); interaction_rate_buffer = ComputeShader::Buffer(Simulator::interaction_rate, Permissions::Read); black_hole_mass_buffer = ComputeShader::Buffer(Simulator::black_hole_mass, Permissions::Read); + types_buffer = ComputeShader::Buffer(star_types, Permissions::Read); // Add this line + } void Computer::compute() @@ -94,14 +116,16 @@ void Computer::compute() smoothing_length_buffer = ComputeShader::Buffer(Simulator::smoothing_length, Permissions::Read); interaction_rate_buffer = ComputeShader::Buffer(Simulator::interaction_rate, Permissions::Read); black_hole_mass_buffer = ComputeShader::Buffer(Simulator::black_hole_mass, Permissions::Read); + types_buffer = ComputeShader::Buffer(star_types, Permissions::Read); // Add this line + // The interactions computations. - ComputeShader::launch("interactions", { &positions_buffer, &accelerations_buffer, &interaction_rate_buffer, - &smoothing_length_buffer, &black_hole_mass_buffer }, cl::NDRange(accelerations.size())); - ComputeShader::get_data(accelerations_buffer, accelerations); - - // The integration computation. - ComputeShader::launch("integration", { &positions_buffer, &speeds_buffer, &accelerations_buffer, &step_buffer }, cl::NDRange(speeds.size())); - ComputeShader::get_data(positions_buffer, positions); - ComputeShader::get_data(speeds_buffer, speeds); + ComputeShader::launch("interactions", { &positions_buffer, &accelerations_buffer, &interaction_rate_buffer, + &smoothing_length_buffer, &black_hole_mass_buffer, &types_buffer }, cl::NDRange(accelerations.size())); // Add types_buffer + ComputeShader::get_data(accelerations_buffer, accelerations); + + // The integration computation. + ComputeShader::launch("integration", { &positions_buffer, &speeds_buffer, &accelerations_buffer, &step_buffer }, cl::NDRange(speeds.size())); + ComputeShader::get_data(positions_buffer, positions); + ComputeShader::get_data(speeds_buffer, speeds); } diff --git a/sources/Menu.cpp b/sources/Menu.cpp index 0650ecd..4e58a27 100644 --- a/sources/Menu.cpp +++ b/sources/Menu.cpp @@ -14,6 +14,8 @@ float Menu::galaxy_thickness; float Menu::galaxies_distance; float Menu::stars_speed; float Menu::black_hole_mass; +float Menu::negative_attraction_constant = 1.0f; // Add this line +float Menu::repulsion_constant = 1.0f; // Add this line void Menu::check_events(const sf::Event& sf_event) { @@ -59,6 +61,8 @@ void Menu::set_default_values() smoothing_length = 1.f; galaxies_distance = 75.f; black_hole_mass = 1000.f; + negative_attraction_constant = 1.0f; // Add this line + repulsion_constant = 1.0f; // Add this line switch (simulation_type) { @@ -180,6 +184,13 @@ void Menu::display() set_default_values(); Simulator::reload = true; } + ImGui::NewLine(); + + // Add UI elements for the constants + ImGui::Text("Negative Attraction Constant"); + ImGui::SliderFloat("##Negative_Attraction_Constant", &negative_attraction_constant, -3.0f, 3.0f); // Update range + ImGui::Text("Repulsion Constant"); + ImGui::SliderFloat("##Repulsion_Constant", &repulsion_constant, -3.0f, 3.0f); // Update range ImGui::NewLine(); From e957ca33fa1a3fe065c356f2862625776386694e Mon Sep 17 00:00:00 2001 From: Cittadhammo <82962905+cittadhammo@users.noreply.github.com> Date: Mon, 27 Jan 2025 13:00:47 +0000 Subject: [PATCH 2/8] add two different brithness (but cannot change color in galazy.frag) --- imgui.ini | 2 +- shaders/compute/cl_compute_shader.cl | 21 +++---- shaders/galaxy.frag | 15 ++++- shaders/galaxy.vert | 9 ++- sources/Computer.cpp | 22 ++++---- sources/Renderer.cpp | 82 ++++++++++++++++++---------- 6 files changed, 94 insertions(+), 57 deletions(-) diff --git a/imgui.ini b/imgui.ini index d3f266a..b33fa91 100644 --- a/imgui.ini +++ b/imgui.ini @@ -30,7 +30,7 @@ Collapsed=0 [Window][Simulation settings (F1 to hide)] Pos=51,51 -Size=275,909 +Size=273,734 Collapsed=0 [Docking][Data] diff --git a/shaders/compute/cl_compute_shader.cl b/shaders/compute/cl_compute_shader.cl index 229f6e5..5710404 100644 --- a/shaders/compute/cl_compute_shader.cl +++ b/shaders/compute/cl_compute_shader.cl @@ -1,34 +1,31 @@ -// Define constants for attraction and repulsion -#define NEGATIVE_ATTRACTION_CONSTANT 1.f -#define REPULSION_CONSTANT 1.f - // Convert a 4D vector to a 3D vector. float3 convert_3(float4 vector) { - return (float3)(vector.x, vector.y, vector.z); + return (float3)(vector.x, vector.y, vector.z); } // Convert a 3D vector to a 4D vector. float4 convert_4(float3 vector) { - return (float4)(vector.x, vector.y, vector.z, 0); + return (float4)(vector.x, vector.y, vector.z, 0); } // Give the squared norm of the vector. float norm_2(float3 vector) { - return pow(vector.x, 2) + pow(vector.y, 2) + pow(vector.z, 2); + return pow(vector.x, 2) + pow(vector.y, 2) + pow(vector.z, 2); } // Give the squared distance between to points. float distance_2(float3 point_1, float3 point_2) { - return norm_2(point_2 - point_1); + return norm_2(point_2 - point_1); } // Handle the interactions between the stars. __kernel void interactions(__global float4* positions, __global float4* accelerations, - __global float* interaction_rate, __global float* smoothing_length, __global float* black_hole_mass, __global int* types) + __global float* interaction_rate, __global float* smoothing_length, __global float* black_hole_mass, __global int* types, + __global float* negative_attraction_constant, __global float* repulsion_constant) { int index = get_global_id(0); float3 acc = (float3)(0, 0, 0); @@ -44,11 +41,11 @@ __kernel void interactions(__global float4* positions, __global float4* accelera if (type == other_type) { - sign = (type == -1) ? NEGATIVE_ATTRACTION_CONSTANT : 1.0f; // Use NEGATIVE_ATTRACTION_CONSTANT for negative stars + sign = (type == -1) ? *negative_attraction_constant : 1.0f; // Use negative_attraction_constant for negative stars } else { - sign = -REPULSION_CONSTANT; // Use REPULSION_CONSTANT for different types repulsing each other + sign = -*repulsion_constant; // Use repulsion_constant for different types repulsing each other } acc += sign * (normalize(vector) / (norm_2(vector) + *smoothing_length)) / *interaction_rate; @@ -65,4 +62,4 @@ __kernel void integration(__global float3* positions, __global float3* speeds, _ int index = get_global_id(0); speeds[index] += *step * accelerations[index]; positions[index] += *step * speeds[index]; -} +} \ No newline at end of file diff --git a/shaders/galaxy.frag b/shaders/galaxy.frag index 00ca12f..3f1d42f 100644 --- a/shaders/galaxy.frag +++ b/shaders/galaxy.frag @@ -2,10 +2,21 @@ precision mediump float; in float v_brightness; +flat in int v_starType; // Add this line to receive star type out vec4 frag_color; void main() { - frag_color = vec4(v_brightness / 5., 0., 0., 1.); -} + float brightness = v_brightness / 5.0; + float brightness2 = v_brightness / 1.0; + + if (v_starType > 0) + { + frag_color = vec4(brightness2, 0.0, 0.0, 1.0); // gives blue stars for positive stars + } + else + { + frag_color = vec4(brightness, 0.0, 0.0, 1.0); // gives brigther blue stars for positive stars + } +} \ No newline at end of file diff --git a/shaders/galaxy.vert b/shaders/galaxy.vert index a19ad14..af9e411 100644 --- a/shaders/galaxy.vert +++ b/shaders/galaxy.vert @@ -3,13 +3,16 @@ precision mediump float; in vec4 a_position; in vec4 a_speed; +in int a_starType; // Add this line to receive star type out float v_brightness; +flat out int v_starType; // Add this line to pass star type to fragment shader uniform mat4 u_mvp; void main() { - v_brightness = length(vec3(a_speed)); - gl_Position = u_mvp * vec4(a_position.xyz, 1.); -} + v_brightness = length(vec3(a_speed)); + v_starType = a_starType; // Pass star type to fragment shader + gl_Position = u_mvp * vec4(a_position.xyz, 1.); +} \ No newline at end of file diff --git a/sources/Computer.cpp b/sources/Computer.cpp index 9c5467d..248872f 100644 --- a/sources/Computer.cpp +++ b/sources/Computer.cpp @@ -112,20 +112,22 @@ void Computer::init() void Computer::compute() { - step_buffer = ComputeShader::Buffer(Simulator::step, Permissions::Read); - smoothing_length_buffer = ComputeShader::Buffer(Simulator::smoothing_length, Permissions::Read); - interaction_rate_buffer = ComputeShader::Buffer(Simulator::interaction_rate, Permissions::Read); - black_hole_mass_buffer = ComputeShader::Buffer(Simulator::black_hole_mass, Permissions::Read); - types_buffer = ComputeShader::Buffer(star_types, Permissions::Read); // Add this line - - - // The interactions computations. + step_buffer = ComputeShader::Buffer(Simulator::step, Permissions::Read); + smoothing_length_buffer = ComputeShader::Buffer(Simulator::smoothing_length, Permissions::Read); + interaction_rate_buffer = ComputeShader::Buffer(Simulator::interaction_rate, Permissions::Read); + black_hole_mass_buffer = ComputeShader::Buffer(Simulator::black_hole_mass, Permissions::Read); + types_buffer = ComputeShader::Buffer(Computer::star_types, Permissions::Read); + cl::Buffer negative_attraction_constant_buffer = ComputeShader::Buffer(Menu::negative_attraction_constant, Permissions::Read); + cl::Buffer repulsion_constant_buffer = ComputeShader::Buffer(Menu::repulsion_constant, Permissions::Read); + + // The interactions computations. ComputeShader::launch("interactions", { &positions_buffer, &accelerations_buffer, &interaction_rate_buffer, - &smoothing_length_buffer, &black_hole_mass_buffer, &types_buffer }, cl::NDRange(accelerations.size())); // Add types_buffer + &smoothing_length_buffer, &black_hole_mass_buffer, &types_buffer, &negative_attraction_constant_buffer, &repulsion_constant_buffer }, + cl::NDRange(accelerations.size())); ComputeShader::get_data(accelerations_buffer, accelerations); // The integration computation. ComputeShader::launch("integration", { &positions_buffer, &speeds_buffer, &accelerations_buffer, &step_buffer }, cl::NDRange(speeds.size())); ComputeShader::get_data(positions_buffer, positions); ComputeShader::get_data(speeds_buffer, speeds); -} +} \ No newline at end of file diff --git a/sources/Renderer.cpp b/sources/Renderer.cpp index 7d0a45a..a4eea13 100644 --- a/sources/Renderer.cpp +++ b/sources/Renderer.cpp @@ -12,50 +12,74 @@ dim::FrameBuffer Renderer::blur_fbo_2; void Renderer::init_vbo() { - // delete buffers - glDeleteBuffers(1, &vbo); - glDeleteVertexArrays(1, &vao); + // Delete buffers + glDeleteBuffers(1, &vbo); + glDeleteVertexArrays(1, &vao); - // Create VBO - glGenBuffers(1, &vbo); - glBindBuffer(GL_ARRAY_BUFFER, vbo); + // Create VBO + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); - GLsizeiptr array_size = Computer::positions.size() * sizeof(dim::Vector4); + GLsizeiptr positions_size = Computer::positions.size() * sizeof(dim::Vector4); + GLsizeiptr speeds_size = Computer::speeds.size() * sizeof(dim::Vector4); + GLsizeiptr types_size = Computer::star_types.size() * sizeof(int); - glBufferData(GL_ARRAY_BUFFER, 2 * array_size, NULL, GL_DYNAMIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, array_size, Computer::positions.data()); - glBufferSubData(GL_ARRAY_BUFFER, array_size, array_size, Computer::speeds.data()); + // Allocate buffer data for positions, speeds, and star types + glBufferData(GL_ARRAY_BUFFER, positions_size + speeds_size + types_size, NULL, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); + // Update positions + glBufferSubData(GL_ARRAY_BUFFER, 0, positions_size, Computer::positions.data()); - // Create VAO - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); - glBindBuffer(GL_ARRAY_BUFFER, vbo); + // Update speeds + glBufferSubData(GL_ARRAY_BUFFER, positions_size, speeds_size, Computer::speeds.data()); - GLint positions = glGetAttribLocation(dim::Shader::get("galaxy").get_id(), "a_position"); - glVertexAttribPointer(positions, 4, GL_FLOAT, GL_FALSE, sizeof(dim::Vector4), reinterpret_cast(0)); - glEnableVertexAttribArray(positions); + // Update star types + glBufferSubData(GL_ARRAY_BUFFER, positions_size + speeds_size, types_size, Computer::star_types.data()); - GLint speeds = glGetAttribLocation(dim::Shader::get("galaxy").get_id(), "a_speed"); - glVertexAttribPointer(speeds, 4, GL_FLOAT, GL_FALSE, sizeof(dim::Vector4), reinterpret_cast(array_size)); - glEnableVertexAttribArray(speeds); + glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); + // Create VAO + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + + GLint positions = glGetAttribLocation(dim::Shader::get("galaxy").get_id(), "a_position"); + glVertexAttribPointer(positions, 4, GL_FLOAT, GL_FALSE, sizeof(dim::Vector4), reinterpret_cast(0)); + glEnableVertexAttribArray(positions); + + GLint speeds = glGetAttribLocation(dim::Shader::get("galaxy").get_id(), "a_speed"); + glVertexAttribPointer(speeds, 4, GL_FLOAT, GL_FALSE, sizeof(dim::Vector4), reinterpret_cast(positions_size)); + glEnableVertexAttribArray(speeds); + + GLint star_types = glGetAttribLocation(dim::Shader::get("galaxy").get_id(), "a_starType"); + glVertexAttribPointer(star_types, 1, GL_INT, GL_FALSE, sizeof(int), reinterpret_cast(positions_size + speeds_size)); + glEnableVertexAttribArray(star_types); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); } void Renderer::update_vbo() { - glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); - GLsizeiptr array_size = Computer::positions.size() * sizeof(dim::Vector4); + GLsizeiptr positions_size = Computer::positions.size() * sizeof(dim::Vector4); + GLsizeiptr speeds_size = Computer::speeds.size() * sizeof(dim::Vector4); + GLsizeiptr types_size = Computer::star_types.size() * sizeof(int); - glBufferData(GL_ARRAY_BUFFER, 2 * array_size, NULL, GL_DYNAMIC_DRAW); - glBufferSubData(GL_ARRAY_BUFFER, 0, array_size, Computer::positions.data()); - glBufferSubData(GL_ARRAY_BUFFER, array_size, array_size, Computer::speeds.data()); + // Allocate buffer data for positions, speeds, and star types + glBufferData(GL_ARRAY_BUFFER, positions_size + speeds_size + types_size, NULL, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); + // Update positions + glBufferSubData(GL_ARRAY_BUFFER, 0, positions_size, Computer::positions.data()); + + // Update speeds + glBufferSubData(GL_ARRAY_BUFFER, positions_size, speeds_size, Computer::speeds.data()); + + // Update star types + glBufferSubData(GL_ARRAY_BUFFER, positions_size + speeds_size, types_size, Computer::star_types.data()); + + glBindBuffer(GL_ARRAY_BUFFER, 0); } void Renderer::draw_vbo() From 51df68adb314906f843070a4153af836fa7d1a5d Mon Sep 17 00:00:00 2001 From: Cittadhammo <82962905+cittadhammo@users.noreply.github.com> Date: Mon, 27 Jan 2025 19:06:58 +0000 Subject: [PATCH 3/8] add two type of colour plus separation by diameter --- imgui.ini | 6 +- includes/Computer.hpp | 9 ++- includes/Menu.hpp | 1 + shaders/galaxy.frag | 4 +- shaders/post.frag | 45 +++++------- shaders/post.vert | 6 +- sources/Computer.cpp | 97 ++++++++++++++----------- sources/Menu.cpp | 10 +++ sources/Renderer.cpp | 164 +++++++++++++++++++++--------------------- 9 files changed, 185 insertions(+), 157 deletions(-) diff --git a/imgui.ini b/imgui.ini index b33fa91..bfd5492 100644 --- a/imgui.ini +++ b/imgui.ini @@ -1,6 +1,6 @@ [Window][InvisibleWindow] Pos=0,0 -Size=1440,810 +Size=1850,1016 Collapsed=0 [Window][Menu] @@ -30,9 +30,9 @@ Collapsed=0 [Window][Simulation settings (F1 to hide)] Pos=51,51 -Size=273,734 +Size=267,907 Collapsed=0 [Docking][Data] -DockSpace ID=0xF442860A Window=0xD8117908 Pos=0,0 Size=1440,810 CentralNode=1 Selected=0x18B8C0DE +DockSpace ID=0xF442860A Window=0xD8117908 Pos=0,0 Size=1850,1016 CentralNode=1 Selected=0x18B8C0DE diff --git a/includes/Computer.hpp b/includes/Computer.hpp index 0025dec..ad3b041 100644 --- a/includes/Computer.hpp +++ b/includes/Computer.hpp @@ -33,7 +33,14 @@ class Computer /** * @brief Initializes the types of the stars randomly. */ - static void initialize_star_types(int num_stars); + // static void initialize_star_types(int num_stars); + + /** + * @brief Initializes the types of the stars around a dimaeter type + * + */ + static void initialize_star_types_and_positions(int num_stars, float type_diameter); + /** * @brief Add a star in the galaxy setup. diff --git a/includes/Menu.hpp b/includes/Menu.hpp index 81afe07..258af36 100644 --- a/includes/Menu.hpp +++ b/includes/Menu.hpp @@ -35,6 +35,7 @@ class Menu static float black_hole_mass; // The mass of the black hole. static float negative_attraction_constant; // Add this line static float repulsion_constant; // Add this line + static float type_diameter; // Add this line /** * @brief Handle the events of the menu. diff --git a/shaders/galaxy.frag b/shaders/galaxy.frag index 3f1d42f..ffff91c 100644 --- a/shaders/galaxy.frag +++ b/shaders/galaxy.frag @@ -13,10 +13,10 @@ void main() if (v_starType > 0) { - frag_color = vec4(brightness2, 0.0, 0.0, 1.0); // gives blue stars for positive stars + frag_color = vec4(3., 0.0, 0.0, 1.0); // gives blue stars for positive stars } else { - frag_color = vec4(brightness, 0.0, 0.0, 1.0); // gives brigther blue stars for positive stars + frag_color = vec4(1.0, 1.0, 0.0, 1.0); // gives brigther blue stars for positive stars } } \ No newline at end of file diff --git a/shaders/post.frag b/shaders/post.frag index dbf3c31..05cdae8 100644 --- a/shaders/post.frag +++ b/shaders/post.frag @@ -5,35 +5,28 @@ in vec2 v_texcoord; out vec4 frag_color; -uniform int u_color_type; uniform sampler2D u_galaxy; uniform sampler2D u_blur; void main() { - float stars = texture(u_galaxy, v_texcoord).r; - float glow = texture(u_blur, v_texcoord).r * 0.2; - vec3 color_1; - vec3 color_2; + vec4 galaxy_data = texture(u_galaxy, v_texcoord); + float stars = galaxy_data.r; + float star_type = galaxy_data.g; // Assuming star type is stored in the green channel + float glow = texture(u_blur, v_texcoord).r * 0.2; + vec3 color_1; + vec3 color_2; - if (u_color_type == 0) - { - color_1 = vec3(0.05, 0.05, 0.3); - color_2 = vec3(0.05, 0.3, 0.3); - frag_color = vec4(0.7 * mix(color_1, color_2 , 0.05 * (stars + glow)) * (stars + glow), 1.); - } - - else if (u_color_type == 1) - { - color_1 = vec3(0.3, 0.05, 0.05); - color_2 = vec3(0.3, 0.3, 0.05); - frag_color = vec4(0.7 * mix(color_1, color_2 , 0.1 * (stars + glow)) * (stars + glow), 1.); - } - - else - { - color_1 = vec3(0.05, 0.05, 0.3); - color_2 = vec3(0.3, 0.05, 0.3); - frag_color = vec4(0.7 * mix(color_1, color_2 , 0.1 * (stars + glow)) * (stars + glow), 1.); - } -} + if (star_type > 0.5) // Positive stars + { + color_1 = vec3(0.3, 0.05, 0.05); // Dark red + color_2 = vec3(0.3, 0.3, 0.05); // Yellow + frag_color = vec4(0.7 * mix(color_1, color_2, 0.1 * (stars + glow)) * (stars + glow), 1.); + } + else // Negative stars + { + color_1 = vec3(0.05, 0.05, 0.3); // Dark blue + color_2 = vec3(0.05, 0.3, 0.3); // Cyan + frag_color = vec4(0.7 * mix(color_1, color_2, 0.05 * (stars + glow)) * (stars + glow), 1.); + } +} \ No newline at end of file diff --git a/shaders/post.vert b/shaders/post.vert index 45d1c6c..abd29cc 100644 --- a/shaders/post.vert +++ b/shaders/post.vert @@ -8,6 +8,6 @@ out vec2 v_texcoord; void main() { - v_texcoord = a_texcoord; - gl_Position = vec4(a_position, 1.); -} + v_texcoord = a_texcoord; + gl_Position = vec4(a_position, 1.); +} \ No newline at end of file diff --git a/sources/Computer.cpp b/sources/Computer.cpp index 248872f..aeb6b55 100644 --- a/sources/Computer.cpp +++ b/sources/Computer.cpp @@ -30,16 +30,18 @@ dim::Vector3 Computer::random_sphere() return result; } -void Computer::initialize_star_types(int num_stars) -{ - star_types.resize(num_stars); - srand(static_cast(time(0))); // Seed the random number generator - for (int i = 0; i < num_stars; ++i) - { - star_types[i] = (rand() % 2 == 0) ? 1 : -1; // Assign 1 for positive, -1 for negative - } -} + +// void Computer::initialize_star_types(int num_stars) +// { +// star_types.resize(num_stars); +// srand(static_cast(time(0))); // Seed the random number generator + +// for (int i = 0; i < num_stars; ++i) +// { +// star_types[i] = (rand() % 2 == 0) ? 1 : -1; // Assign 1 for positive, -1 for negative +// } +// } void Computer::create_galaxy(int i) { @@ -70,44 +72,59 @@ void Computer::create_universe(int i) speeds[i].set_norm((speeds[i].get_norm() / (Simulator::galaxy_diameter / 2.f)) * Simulator::stars_speed); } -void Computer::init() +void Computer::initialize_star_types_and_positions(int num_stars, float type_diameter) { - positions.clear(); - speeds.clear(); - accelerations.clear(); - star_types.clear(); // Add this line - + star_types.resize(num_stars); + positions.resize(num_stars); + speeds.resize(num_stars); + accelerations.resize(num_stars, dim::Vector4::null); - positions.resize(Simulator::nb_stars); - speeds.resize(Simulator::nb_stars); - accelerations.resize(Simulator::nb_stars, dim::Vector4::null); - star_types.resize(Simulator::nb_stars); // Add this line + srand(static_cast(time(0))); // Seed the random number generator - initialize_star_types(Simulator::nb_stars); // Add this line + for (int i = 0; i < num_stars; ++i) + { + dim::Vector3 position = random_sphere(); + positions[i] = dim::Vector4(position, 0.0f); + + if (position.get_norm() <= type_diameter / 2.0f) + { + star_types[i] = 1; // Positive star inside the type_diameter + } + else + { + star_types[i] = -1; // Negative star outside the type_diameter + } + } +} +void Computer::init() +{ + positions.clear(); + speeds.clear(); + accelerations.clear(); + star_types.clear(); - for (int i = 0; i < Simulator::nb_stars; i++) - { - positions[i] = dim::Vector4(random_sphere(), 0.f); - - switch (Simulator::simulation_type) - { - case SimulationType::Galaxy: create_galaxy(i); break; - case SimulationType::Collision: create_collision(i); break; - case SimulationType::Universe: create_universe(i); break; - default: break; - } - } + initialize_star_types_and_positions(Simulator::nb_stars, Menu::type_diameter); - positions_buffer = ComputeShader::Buffer(positions, Permissions::All); - speeds_buffer = ComputeShader::Buffer(speeds, Permissions::All); - accelerations_buffer = ComputeShader::Buffer(accelerations, Permissions::All); - step_buffer = ComputeShader::Buffer(Simulator::step, Permissions::Read); - smoothing_length_buffer = ComputeShader::Buffer(Simulator::smoothing_length, Permissions::Read); - interaction_rate_buffer = ComputeShader::Buffer(Simulator::interaction_rate, Permissions::Read); - black_hole_mass_buffer = ComputeShader::Buffer(Simulator::black_hole_mass, Permissions::Read); - types_buffer = ComputeShader::Buffer(star_types, Permissions::Read); // Add this line + for (int i = 0; i < Simulator::nb_stars; i++) + { + switch (Simulator::simulation_type) + { + case SimulationType::Galaxy: create_galaxy(i); break; + case SimulationType::Collision: create_collision(i); break; + case SimulationType::Universe: create_universe(i); break; + default: break; + } + } + positions_buffer = ComputeShader::Buffer(positions, Permissions::All); + speeds_buffer = ComputeShader::Buffer(speeds, Permissions::All); + accelerations_buffer = ComputeShader::Buffer(accelerations, Permissions::All); + step_buffer = ComputeShader::Buffer(Simulator::step, Permissions::Read); + smoothing_length_buffer = ComputeShader::Buffer(Simulator::smoothing_length, Permissions::Read); + interaction_rate_buffer = ComputeShader::Buffer(Simulator::interaction_rate, Permissions::Read); + black_hole_mass_buffer = ComputeShader::Buffer(Simulator::black_hole_mass, Permissions::Read); + types_buffer = ComputeShader::Buffer(star_types, Permissions::Read); } void Computer::compute() diff --git a/sources/Menu.cpp b/sources/Menu.cpp index 4e58a27..db87b9f 100644 --- a/sources/Menu.cpp +++ b/sources/Menu.cpp @@ -16,6 +16,8 @@ float Menu::stars_speed; float Menu::black_hole_mass; float Menu::negative_attraction_constant = 1.0f; // Add this line float Menu::repulsion_constant = 1.0f; // Add this line +float Menu::type_diameter = 50.0f; // Initialize type_diameter + void Menu::check_events(const sf::Event& sf_event) { @@ -63,6 +65,8 @@ void Menu::set_default_values() black_hole_mass = 1000.f; negative_attraction_constant = 1.0f; // Add this line repulsion_constant = 1.0f; // Add this line + type_diameter = 50.0f; // Initialize type_diameter + switch (simulation_type) { @@ -191,9 +195,15 @@ void Menu::display() ImGui::SliderFloat("##Negative_Attraction_Constant", &negative_attraction_constant, -3.0f, 3.0f); // Update range ImGui::Text("Repulsion Constant"); ImGui::SliderFloat("##Repulsion_Constant", &repulsion_constant, -3.0f, 3.0f); // Update range + ImGui::NewLine(); + + ImGui::Text("Type Diameter"); + ImGui::SliderFloat("##Type_Diameter", &type_diameter, 0.0f, galaxy_diameter); // Add slider for type_diameter ImGui::NewLine(); + + title("Real time settings"); ImGui::NewLine(); diff --git a/sources/Renderer.cpp b/sources/Renderer.cpp index a4eea13..abeb91a 100644 --- a/sources/Renderer.cpp +++ b/sources/Renderer.cpp @@ -145,85 +145,85 @@ void Renderer::clear() void Renderer::draw() { - glDisable(GL_POINT_SMOOTH); - glDisable(GL_LINE_SMOOTH); - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE); - dim::Window::set_thickness(1.f); - - // Draw the stars. - galaxy_fbo_1.bind(); - dim::Shader::get("galaxy").bind(); - bind_vbo(); - - dim::Shader::get("galaxy").send_uniform("u_mvp", dim::Window::get_camera().get_matrix()); - draw_vbo(); - - unbind_vbo(); - dim::Shader::get("galaxy").unbind(); - galaxy_fbo_1.unbind(); - - glEnable(GL_POINT_SMOOTH); - glEnable(GL_LINE_SMOOTH); - dim::Window::set_thickness(2.f); - - // Draw the stars to be blured. - galaxy_fbo_2.bind(); - dim::Shader::get("galaxy").bind(); - bind_vbo(); - - dim::Shader::get("galaxy").send_uniform("u_mvp", dim::Window::get_camera().get_matrix()); - draw_vbo(); - - unbind_vbo(); - dim::Shader::get("galaxy").unbind(); - galaxy_fbo_2.unbind(); - - // The first step of the blur. - blur_fbo_1.bind(); - dim::Shader::get("blur").bind(); - galaxy_fbo_2.get_texture().bind(); - blur_vbo.bind(); - - dim::Shader::get("blur").send_uniform("u_texture", galaxy_fbo_2.get_texture()); - dim::Shader::get("blur").send_uniform("u_horizontal", 1); - blur_vbo.draw(); - - blur_vbo.unbind(); - galaxy_fbo_2.get_texture().unbind(); - dim::Shader::get("blur").unbind(); - blur_fbo_1.unbind(); - - // The second step of the blur. - blur_fbo_2.bind(); - dim::Shader::get("blur").bind(); - blur_fbo_1.get_texture().bind(); - blur_vbo.bind(); - - dim::Shader::get("blur").send_uniform("u_texture", blur_fbo_1.get_texture()); - dim::Shader::get("blur").send_uniform("u_horizontal", 0); - blur_vbo.draw(); - - blur_vbo.unbind(); - blur_fbo_1.get_texture().unbind(); - dim::Shader::get("blur").unbind(); - blur_fbo_2.unbind(); - - // Merge all the steps and set the color. - dim::Shader::get("post").bind(); - galaxy_fbo_1.get_texture().bind(); - blur_fbo_2.get_texture().bind(); - post_vbo.bind(); - - dim::Shader::get("post").send_uniform("u_color_type", static_cast(Simulator::simulation_type)); - dim::Shader::get("post").send_uniform("u_galaxy", galaxy_fbo_1.get_texture()); - dim::Shader::get("post").send_uniform("u_blur", blur_fbo_2.get_texture()); - post_vbo.draw(); - - post_vbo.unbind(); - blur_fbo_2.get_texture().unbind(); - galaxy_fbo_1.get_texture().unbind(); - dim::Shader::get("post").unbind(); - - glDisable(GL_BLEND); -} + glDisable(GL_POINT_SMOOTH); + glDisable(GL_LINE_SMOOTH); + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE); + dim::Window::set_thickness(1.f); + + // Draw the stars. + galaxy_fbo_1.bind(); + dim::Shader::get("galaxy").bind(); + bind_vbo(); + + dim::Shader::get("galaxy").send_uniform("u_mvp", dim::Window::get_camera().get_matrix()); + draw_vbo(); + + unbind_vbo(); + dim::Shader::get("galaxy").unbind(); + galaxy_fbo_1.unbind(); + + glEnable(GL_POINT_SMOOTH); + glEnable(GL_LINE_SMOOTH); + dim::Window::set_thickness(2.f); + + // Draw the stars to be blurred. + galaxy_fbo_2.bind(); + dim::Shader::get("galaxy").bind(); + bind_vbo(); + + dim::Shader::get("galaxy").send_uniform("u_mvp", dim::Window::get_camera().get_matrix()); + draw_vbo(); + + unbind_vbo(); + dim::Shader::get("galaxy").unbind(); + galaxy_fbo_2.unbind(); + + // The first step of the blur. + blur_fbo_1.bind(); + dim::Shader::get("blur").bind(); + galaxy_fbo_2.get_texture().bind(); + blur_vbo.bind(); + + dim::Shader::get("blur").send_uniform("u_texture", galaxy_fbo_2.get_texture()); + dim::Shader::get("blur").send_uniform("u_horizontal", 1); + blur_vbo.draw(); + + blur_vbo.unbind(); + galaxy_fbo_2.get_texture().unbind(); + dim::Shader::get("blur").unbind(); + blur_fbo_1.unbind(); + + // The second step of the blur. + blur_fbo_2.bind(); + dim::Shader::get("blur").bind(); + blur_fbo_1.get_texture().bind(); + blur_vbo.bind(); + + dim::Shader::get("blur").send_uniform("u_texture", blur_fbo_1.get_texture()); + dim::Shader::get("blur").send_uniform("u_horizontal", 0); + blur_vbo.draw(); + + blur_vbo.unbind(); + blur_fbo_1.get_texture().unbind(); + dim::Shader::get("blur").unbind(); + blur_fbo_2.unbind(); + + // Merge all the steps and set the color. + dim::Shader::get("post").bind(); + galaxy_fbo_1.get_texture().bind(); + blur_fbo_2.get_texture().bind(); + post_vbo.bind(); + + // Render stars with star type information + dim::Shader::get("post").send_uniform("u_galaxy", galaxy_fbo_1.get_texture()); + dim::Shader::get("post").send_uniform("u_blur", blur_fbo_2.get_texture()); + post_vbo.draw(); + + post_vbo.unbind(); + blur_fbo_2.get_texture().unbind(); + galaxy_fbo_1.get_texture().unbind(); + dim::Shader::get("post").unbind(); + + glDisable(GL_BLEND); +} \ No newline at end of file From 12ca1e3a8b3df1b9c636920872f1760f3dc08fb2 Mon Sep 17 00:00:00 2001 From: Cittadhammo <82962905+cittadhammo@users.noreply.github.com> Date: Wed, 29 Jan 2025 08:16:04 +0000 Subject: [PATCH 4/8] nice readme + NVidia info --- README.md | 7 +++++++ imgui.ini | 4 ++-- shaders/galaxy.frag | 4 ++-- sources/main.cpp | 25 +++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 33ff485..ddc0d0e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +# Building on Linux + ``` ./build/Galaxy_simulation ``` @@ -22,6 +24,11 @@ sudo apt-get install freeglut3-dev ``` from https://askubuntu.com/questions/96087/how-to-install-opengl-glut-libraries +## Two differents simulation modifications + +- Add different stars type at random in proportion +- Add different stars type from a certain diameter (The current modification) + # ๐ŸŒŒ Galaxy simulation diff --git a/imgui.ini b/imgui.ini index bfd5492..2e099fd 100644 --- a/imgui.ini +++ b/imgui.ini @@ -1,6 +1,6 @@ [Window][InvisibleWindow] Pos=0,0 -Size=1850,1016 +Size=1440,917 Collapsed=0 [Window][Menu] @@ -34,5 +34,5 @@ Size=267,907 Collapsed=0 [Docking][Data] -DockSpace ID=0xF442860A Window=0xD8117908 Pos=0,0 Size=1850,1016 CentralNode=1 Selected=0x18B8C0DE +DockSpace ID=0xF442860A Window=0xD8117908 Pos=0,0 Size=1440,917 CentralNode=1 Selected=0x18B8C0DE diff --git a/shaders/galaxy.frag b/shaders/galaxy.frag index ffff91c..b55069b 100644 --- a/shaders/galaxy.frag +++ b/shaders/galaxy.frag @@ -13,10 +13,10 @@ void main() if (v_starType > 0) { - frag_color = vec4(3., 0.0, 0.0, 1.0); // gives blue stars for positive stars + frag_color = vec4(brightness, 0.0, 0.0, 1.0); // gives blue stars for positive stars } else { - frag_color = vec4(1.0, 1.0, 0.0, 1.0); // gives brigther blue stars for positive stars + frag_color = vec4(1., brightness, 0.0, 1.0); // gives brigther blue stars for positive stars } } \ No newline at end of file diff --git a/sources/main.cpp b/sources/main.cpp index 084d0b3..8002f6b 100644 --- a/sources/main.cpp +++ b/sources/main.cpp @@ -1,11 +1,36 @@ #include #include "Simulator.hpp" +#include +#include + + +// Function to print OpenGL context information +void print_opengl_info() +{ + const GLubyte* renderer = glGetString(GL_RENDERER); // Get renderer string + const GLubyte* vendor = glGetString(GL_VENDOR); // Get vendor string + const GLubyte* version = glGetString(GL_VERSION); // Version as a string + const GLubyte* glslVersion = glGetString(GL_SHADING_LANGUAGE_VERSION); // GLSL version string + + GLint major, minor; + glGetIntegerv(GL_MAJOR_VERSION, &major); + glGetIntegerv(GL_MINOR_VERSION, &minor); + + std::cout << "OpenGL Renderer: " << renderer << std::endl; + std::cout << "OpenGL Vendor: " << vendor << std::endl; + std::cout << "OpenGL Version: " << version << std::endl; + std::cout << "GLSL Version: " << glslVersion << std::endl; + std::cout << "OpenGL Version: " << major << "." << minor << std::endl; +} int main() { dim::Window::open("Galaxy simulation", 0.75f, "resources/icons/icon.png"); Simulator::init(); + // Print OpenGL context information + print_opengl_info(); + // The computation thread. std::thread simulation_thread([]() { From 0fdf65df5ee4826712b9c7522e57cf987483737e Mon Sep 17 00:00:00 2001 From: Cittadhammo Bhikkhu Date: Wed, 18 Feb 2026 16:56:24 +0000 Subject: [PATCH 5/8] fix unix run and add detail in readme for arch install --- README.md | 105 +++++++++++++++++++++++++++++++++------------------- unix_run.sh | 18 +++++++-- 2 files changed, 81 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index ddc0d0e..c16d888 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,3 @@ -# Building on Linux - -``` -./build/Galaxy_simulation -``` -to run the built - -``` -bash unix_run.sh -``` -to built - -error 0: install libglew-dev - -error 1 : https://stackoverflow.com/questions/56858213/how-to-create-nvidia-opencl-project/57017982#57017982 - -https://github.com/ProjectPhysX/OpenCL-Wrapper/tree/master/src/OpenCL and put the file in the incldes with good folders - - - -error 2: that was useful -``` -sudo apt-get install freeglut3-dev -``` -from https://askubuntu.com/questions/96087/how-to-install-opengl-glut-libraries - -## Two differents simulation modifications - -- Add different stars type at random in proportion -- Add different stars type from a certain diameter (The current modification) - - # ๐ŸŒŒ Galaxy simulation ![Release](https://img.shields.io/badge/Release-v4.0-blueviolet) @@ -59,9 +27,13 @@ This repository contains the source code of an n-body type simulation using GPU * **[๐Ÿ“‹ Summary](#-summary)** * **[๐ŸŽฅ Video](#-video)** * **[โœจ Features](#-features)** +* **[๐Ÿง Build on Linux](#-build-on-linux)** * **[๐Ÿ› ๏ธ Install](#%EF%B8%8F-install)** - * [๐Ÿฆด Skeleton project install](#-skeleton-project-install) - * [๐Ÿ“ฆ Additionnal dependencies](#-additionnal-dependencies) + * [๐Ÿ“ฆ Dependencies](#-dependencies) + * [โ–ถ๏ธ Build](#%EF%B8%8F-build) + * [๐Ÿš€ Run](#-run) + * [๐Ÿงฉ Troubleshooting](#-troubleshooting) +* **[๐Ÿงช Simulation variants](#-simulation-variants)** * **[๐Ÿ—“๏ธ Releases](#%EF%B8%8F-releases)** * **[๐Ÿงช Tests](#-tests)** * **[๐Ÿ™ Credits](#-credits)** @@ -100,17 +72,74 @@ Here is a video explaining how the algorithm works : [**Simuler 1 000 000 de
+# ๐Ÿง Build on Linux + +```bash +bash unix_run.sh +``` + +This script: + +* initializes/upgrades git submodules (`--init --recursive`) +* configures CMake with `Unix Makefiles` +* uses the OpenCL include/library shipped in this repository +* builds the executable in `./build` + +
+ # ๐Ÿ› ๏ธ Install -## ๐Ÿฆด Skeleton project install +## ๐Ÿ“ฆ Dependencies + +On Debian/Ubuntu: + +```bash +sudo apt-get update +sudo apt-get install -y \ + build-essential \ + cmake \ + libglew-dev \ + freeglut3-dev \ + ocl-icd-opencl-dev +``` + +## โ–ถ๏ธ Build + +If you clone for the first time: + +```bash +git clone --recurse-submodules https://github.com/angeluriot/Galaxy_simulation.git +cd Galaxy_simulation +``` + +Then build: + +```bash +bash unix_run.sh +``` + +## ๐Ÿš€ Run + +```bash +./build/Galaxy_simulation +``` + +## ๐Ÿงฉ Troubleshooting -This repository is based on my [**Graphics skeleton project**](https://github.com/angeluriot/Graphics_skeleton), so go see its [**install**](https://github.com/angeluriot/Graphics_skeleton#install) part first. +* `Could not find SFML`: make sure submodules are present (`git submodule update --init --recursive`). +* `Could NOT find OpenCL`: use `bash unix_run.sh` (it passes the required OpenCL paths). +* `No platforms found!`: OpenCL loader is present but no OpenCL driver ICD is installed. + On Arch Linux: + `sudo pacman -S --needed pocl` (CPU fallback) or install the NVIDIA-matching OpenCL package (for example `opencl-nvidia-580xx` for 580xx drivers). + Verify with `clinfo`: `Number of platforms` must be at least `1`. +* `Failed to open X11 display`: run from a desktop session with a valid `DISPLAY` variable.
-## ๐Ÿ“ฆ Additionnal dependencies +# ๐Ÿงช Simulation variants -Then, you will also need the [**OpenCL**](https://www.khronos.org/opencl/) library. +* Add different star types at random in proportion. +* Add different star types from a diameter threshold (current modification).
diff --git a/unix_run.sh b/unix_run.sh index 17dbb58..1099f05 100644 --- a/unix_run.sh +++ b/unix_run.sh @@ -1,4 +1,14 @@ -cmake -G "Unix Makefiles" -B "./build" . -cd build -make -cd .. +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +BUILD_DIR="${ROOT_DIR}/build" + +# Required third-party code is provided via submodules. +git -C "${ROOT_DIR}" submodule update --init --recursive + +cmake -G "Unix Makefiles" -B "${BUILD_DIR}" "${ROOT_DIR}" \ + -DOpenCL_INCLUDE_DIR="${ROOT_DIR}/includes" \ + -DOpenCL_LIBRARY="${ROOT_DIR}/includes/CL/lib/libOpenCL.so" + +cmake --build "${BUILD_DIR}" -j"$(nproc)" From 93bf77e1b9f141cd094c429ee981605fb418498e Mon Sep 17 00:00:00 2001 From: Cittadhammo Bhikkhu Date: Wed, 18 Feb 2026 17:46:55 +0000 Subject: [PATCH 6/8] major pdate --- CHANGE.md | 77 ++++++++ README.md | 170 +++++++++++++++++ batch_configs/example.batchcfg | 5 + includes/ComputeShader.hpp | 13 ++ includes/Computer.hpp | 9 +- includes/Menu.hpp | 19 +- includes/Simulator.hpp | 13 ++ run_batch.sh | 34 ++++ run_sim.sh | 10 + shaders/galaxy.frag | 7 +- shaders/post.frag | 25 +-- sources/ComputeShader.cpp | 4 +- sources/Computer.cpp | 217 +++++++++++++-------- sources/Menu.cpp | 87 +++++++-- sources/Renderer.cpp | 15 +- sources/Simulator.cpp | 54 ++++++ sources/main.cpp | 333 ++++++++++++++++++++++++++++++++- 17 files changed, 946 insertions(+), 146 deletions(-) create mode 100644 CHANGE.md create mode 100644 batch_configs/example.batchcfg create mode 100755 run_batch.sh create mode 100755 run_sim.sh diff --git a/CHANGE.md b/CHANGE.md new file mode 100644 index 0000000..2d4cf46 --- /dev/null +++ b/CHANGE.md @@ -0,0 +1,77 @@ +# CHANGELOG + +## 2026-02-18 + +### Added + +* Matter distribution selector for Janus initialization: + * `Core + halo` + * `Random mix` + * `Split on X` +* `Positive Ratio` parameter for random matter assignment. +* `Core + halo` extra-density slider: + * `Extra negative density inside core` in `[0, 1]` +* Batch simulation mode in executable: + * `--batch-steps N` + * `--snapshots K` + * `--output-dir DIR` + * `--config FILE` (load one config line) + * `--batch-config FILE` (run one simulation per line) +* Final snapshot export from multiple camera angles in batch mode. +* Run helper scripts: + * `run_sim.sh` + * `run_batch.sh` + * `run_batch.sh --batch-config batch_configs/example.batchcfg` +* In-app batch export UI: + * set config output path + * append current `SIMCFG` line directly from the menu + +### Changed + +* Rendering color convention aligned with Janus interpretation: + * positive/regular mass rendered in blue + * negative mass rendered in red +* Janus post-process shader simplified to preserve star channel data. +* Core+halo star assignment logic updated to match model: + * positive stars initialized in core sphere (`Type Diameter`) + * halo stars initialized as negative (outside core) + * `Extra negative density inside core` controls core negative injection in `[0, 1]` +* Startup logs now print assigned counts (`stars+`, `stars-`, `core`, `halo`). +* Restart logs now print full one-line configs (`SIMCFG key=value ...`) for copy/paste into batch files. + +### Performance + +* OpenCL command queue is initialized once and reused. +* Per-frame scalar parameters are now updated in existing OpenCL buffers. +* Removed unnecessary per-frame acceleration readback from GPU to CPU. +* OpenGL VBO is no longer reallocated every frame. +* Star type data is uploaded once at initialization/restart. +* Integer star type vertex attribute now uses `glVertexAttribIPointer`. + +### Usage + +Interactive run: + +```bash +./build/Galaxy_simulation +bash run_sim.sh +``` + +Batch run: + +```bash +./build/Galaxy_simulation --batch-steps 5000 --snapshots 4 --output-dir outputs/run_001 +bash run_batch.sh 5000 4 outputs/run_001 +bash run_batch.sh --batch-config batch_configs/example.batchcfg +``` + +### Validation checklist + +* Build succeeds: `bash unix_run.sh`. +* Positive stars appear blue, negative stars appear red. +* Batch run generates `snapshot_*.png` in output directory. +* Runtime improves versus previous version for same star count and parameters. + +### Known limitation + +* Batch mode still requires an OpenGL/X11 context (not true headless yet). diff --git a/README.md b/README.md index c16d888..02f596f 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,11 @@ This repository contains the source code of an n-body type simulation using GPU * [๐Ÿ“ฆ Dependencies](#-dependencies) * [โ–ถ๏ธ Build](#%EF%B8%8F-build) * [๐Ÿš€ Run](#-run) + * [โš™๏ธ Janus + Performance Update](#%EF%B8%8F-janus--performance-update) + * [๐Ÿงช Batch Experiment Workflow](#-batch-experiment-workflow) + * [โœ… Validate Optimized Runs](#-validate-optimized-runs) * [๐Ÿงฉ Troubleshooting](#-troubleshooting) +* **[๐Ÿ“ Changes](#-changes)** * **[๐Ÿงช Simulation variants](#-simulation-variants)** * **[๐Ÿ—“๏ธ Releases](#%EF%B8%8F-releases)** * **[๐Ÿงช Tests](#-tests)** @@ -103,6 +107,33 @@ sudo apt-get install -y \ ocl-icd-opencl-dev ``` +On Arch Linux: + +```bash +sudo pacman -S --needed \ + base-devel \ + cmake \ + glew \ + freeglut \ + opencl-headers \ + ocl-icd \ + clinfo +``` + +Install at least one OpenCL implementation: + +CPU fallback: + +```bash +sudo pacman -S --needed pocl +``` + +NVIDIA GPU: + +```bash +sudo pacman -S --needed opencl-nvidia +``` + ## โ–ถ๏ธ Build If you clone for the first time: @@ -124,6 +155,141 @@ bash unix_run.sh ./build/Galaxy_simulation ``` +Shortcut: + +```bash +bash run_sim.sh +``` + +Batch run (compute N steps, then export final snapshots from multiple angles): + +```bash +./build/Galaxy_simulation --batch-steps 2000 --snapshots 4 --output-dir outputs +``` + +Shortcut: + +```bash +bash run_batch.sh 2000 4 outputs +``` + +Batch file (each line = one simulation job): + +```bash +bash run_batch.sh --batch-config batch_configs/example.batchcfg +``` + +## โš™๏ธ Janus + Performance Update + +This branch includes: + +* Janus star typing with explicit matter distributions: + * `Core + halo` (positive center, negative outer region) + * `Random mix` (positive ratio slider) + * `Split on X` (two spatial halves) +* `Core + halo` negative density control: + * `Extra negative density inside core` in `[0, 1]` + * `0`: core fully positive + * `1`: core fully negative + * in `Core + halo` mode: halo stars are always negative +* Janus force multipliers: + * `Negative Attraction Constant` + * `Repulsion Constant` +* Color convention: + * Positive/regular mass: **blue** + * Negative mass: **red** +* Performance optimizations: + * Reuse OpenCL command queue + * Reuse scalar OpenCL buffers and update them in-place + * Remove unnecessary per-frame acceleration readback + * Avoid per-frame OpenGL VBO reallocation + * Upload star type data only at initialization/restart + +## ๐Ÿงช Batch Experiment Workflow + +Use batch mode when you want to simulate many frames and only inspect final results: + +```bash +./build/Galaxy_simulation --batch-steps 10000 --snapshots 6 --output-dir outputs/run_001 +``` + +Run many jobs from one file (line-by-line): + +```bash +./build/Galaxy_simulation --batch-config batch_configs/example.batchcfg +``` + +Batch file format: + +* each non-comment line is one job +* each line is `key=value` tokens +* lines can start with `SIMCFG` +* recommended keys per line: + * simulation: `simulation_type step smoothing_length interaction_rate nb_stars galaxy_diameter galaxy_thickness galaxies_distance stars_speed black_hole_mass negative_attraction_constant repulsion_constant matter_distribution type_diameter positive_ratio core_extra_negative_density` + * batch: `batch_steps snapshots output_dir` + +Recommended workflow: + +1. Start interactive mode (`./build/Galaxy_simulation`) and tune settings until the setup is close to your target physics. +2. Click `Restart` after changing any setting under `Applies after restart`. +3. In the menu, use `Batch config export`: + * set output file path (default: `batch_configs/user.batchcfg`) + * click `Append current SIMCFG to file` +4. Repeat for each setup you want to queue. +5. Run the whole file with: + ```bash + bash run_batch.sh --batch-config batch_configs/user.batchcfg + ``` +6. Compare the exported snapshots across runs. + +Choosing initial parameters: + +* `Core + halo`: + * `Type Diameter` defines the positive core sphere. + * outside that sphere is halo and always negative. + * `Extra negative density inside core` injects negative stars into the core (`0` to `1`). + * start around `type_diameter = 0.4 * galaxy_diameter` and extra density `0.1`, then sweep. +* `Random mix`: + * use `Positive Ratio` (for example `0.2`, `0.5`, `0.8`) to test segregation behavior. +* `Split on X`: + * good for interface-instability tests. +* For reduced-particle experiments: + * decrease `nb_stars` + * compensate dynamics with `Negative Attraction Constant` and `Repulsion Constant` + * keep `step` and `smoothing_length` stable while you tune force multipliers. + +## โœ… Validate Optimized Runs + +Before launching cloud runs, validate local behavior: + +1. Build and run: + ```bash + bash unix_run.sh + ./build/Galaxy_simulation + ``` +2. Confirm expected visuals: + * positive stars are blue + * negative stars are red +3. Confirm initialization counts in terminal logs: + * `[Init] stars+=... stars-=... core=... halo=...` + * this lets you verify the real positive/negative assignment for each restart + * a copy/paste one-line config is printed as: + `SIMCFG key=value ...` +4. Confirm batch export: + ```bash + ./build/Galaxy_simulation --batch-steps 2000 --snapshots 4 --output-dir outputs/check + ``` +5. Compare timing at same parameters before/after optimization. + +Notes: + +* Batch mode still needs an OpenGL/X11 context on Linux. +* For server VMs without display, use a virtual display (for example `xvfb`) or add a future true headless mode. + +## ๐Ÿ“ Changes + +Detailed change log: see [`CHANGE.md`](CHANGE.md). + ## ๐Ÿงฉ Troubleshooting * `Could not find SFML`: make sure submodules are present (`git submodule update --init --recursive`). @@ -140,6 +306,10 @@ bash unix_run.sh * Add different star types at random in proportion. * Add different star types from a diameter threshold (current modification). +* Select matter distribution in-app: + * `Core + halo`: positive core, negative halo + * `Random mix`: random positive/negative based on ratio + * `Split on X`: one half positive, one half negative
diff --git a/batch_configs/example.batchcfg b/batch_configs/example.batchcfg new file mode 100644 index 0000000..668b71e --- /dev/null +++ b/batch_configs/example.batchcfg @@ -0,0 +1,5 @@ +# Each non-comment line is one simulation job. +# You can copy/paste SIMCFG lines printed by the app and edit batch_* keys. + +SIMCFG simulation_type=Galaxy step=0.001000 smoothing_length=1.000000 interaction_rate=0.050000 nb_stars=30000 galaxy_diameter=100.000000 galaxy_thickness=5.000000 galaxies_distance=75.000000 stars_speed=20.000000 black_hole_mass=1000.000000 negative_attraction_constant=1.000000 repulsion_constant=1.000000 matter_distribution=CoreHalo type_diameter=40.000000 positive_ratio=0.500000 core_extra_negative_density=0.000000 batch_steps=3000 snapshots=4 output_dir=outputs/run_core_clean +SIMCFG simulation_type=Galaxy step=0.001000 smoothing_length=1.000000 interaction_rate=0.050000 nb_stars=30000 galaxy_diameter=100.000000 galaxy_thickness=5.000000 galaxies_distance=75.000000 stars_speed=20.000000 black_hole_mass=1000.000000 negative_attraction_constant=1.000000 repulsion_constant=1.000000 matter_distribution=CoreHalo type_diameter=40.000000 positive_ratio=0.500000 core_extra_negative_density=0.200000 batch_steps=3000 snapshots=4 output_dir=outputs/run_core_mixed diff --git a/includes/ComputeShader.hpp b/includes/ComputeShader.hpp index 24e9730..f7390c2 100644 --- a/includes/ComputeShader.hpp +++ b/includes/ComputeShader.hpp @@ -111,6 +111,19 @@ class ComputeShader { queue.enqueueReadBuffer(buffer, CL_TRUE, 0, sizeof(T), &data); } + + /** + * @brief Write the given data into an OpenCL buffer. + * + * @tparam T the type of data + * @param buffer the OpenCL buffer + * @param data the data + */ + template + static void set_data(const cl::Buffer& buffer, const T& data) + { + queue.enqueueWriteBuffer(buffer, CL_TRUE, 0, sizeof(T), &data); + } }; #endif diff --git a/includes/Computer.hpp b/includes/Computer.hpp index ad3b041..df0a448 100644 --- a/includes/Computer.hpp +++ b/includes/Computer.hpp @@ -22,6 +22,8 @@ class Computer static cl::Buffer interaction_rate_buffer; // The OpenCL buffer of the interaction rate. static cl::Buffer black_hole_mass_buffer; // The OpenCL buffer of the mass of the black hole. static cl::Buffer types_buffer; // The OpenCL buffer of the types of the stars. + static cl::Buffer negative_attraction_constant_buffer; // The OpenCL buffer of the negative attraction constant. + static cl::Buffer repulsion_constant_buffer; // The OpenCL buffer of the repulsion constant. /** * @brief Gives a point randomly placed in a sphere of the diameter of the galaxy. @@ -31,12 +33,7 @@ class Computer static dim::Vector3 random_sphere(); /** - * @brief Initializes the types of the stars randomly. - */ - // static void initialize_star_types(int num_stars); - - /** - * @brief Initializes the types of the stars around a dimaeter type + * @brief Initializes star positions and matter types. * */ static void initialize_star_types_and_positions(int num_stars, float type_diameter); diff --git a/includes/Menu.hpp b/includes/Menu.hpp index 258af36..0155453 100644 --- a/includes/Menu.hpp +++ b/includes/Menu.hpp @@ -13,6 +13,16 @@ enum class SimulationType : int Universe = 2 // The big bang. }; +/** + * @brief The initial distribution of positive/negative matter. + */ +enum class MatterDistribution : int +{ + CoreHalo = 0, // Positive core and negative halo (radius threshold). + RandomMix = 1, // Random mix based on positive ratio. + SplitX = 2 // Split space in two halves along the X axis. +}; + /** * @brief The window to edit the settings of the simulation. */ @@ -33,9 +43,12 @@ class Menu static float galaxies_distance; // The distance between the galaxies. static float stars_speed; // The speed of the stars. static float black_hole_mass; // The mass of the black hole. - static float negative_attraction_constant; // Add this line - static float repulsion_constant; // Add this line - static float type_diameter; // Add this line + static float negative_attraction_constant; // Multiplier for negative-negative attraction. + static float repulsion_constant; // Multiplier for opposite-type interaction. + static float type_diameter; // Diameter used by core/halo matter distribution. + static MatterDistribution matter_distribution; // Initial positive/negative matter distribution model. + static float positive_ratio; // Positive matter ratio for random mix. + static float core_extra_negative_density; // Extra negative density injected inside the core. /** * @brief Handle the events of the menu. diff --git a/includes/Simulator.hpp b/includes/Simulator.hpp index 61ef4ba..229f8ac 100644 --- a/includes/Simulator.hpp +++ b/includes/Simulator.hpp @@ -8,6 +8,7 @@ #include #include #include +#include /** * @brief A static class representing the simulation. @@ -40,6 +41,18 @@ class Simulator */ static void restart(); + /** + * @brief Print all simulation parameters in one line. + */ + static void print_configuration(); + + /** + * @brief Build all simulation parameters in one line. + * + * @return the configuration line + */ + static std::string configuration_line(); + /** * @brief Update the simulation settings from the menu. */ diff --git a/run_batch.sh b/run_batch.sh new file mode 100755 index 0000000..09852c2 --- /dev/null +++ b/run_batch.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +if [[ "${1:-}" == "--batch-config" && -n "${2:-}" ]]; then + BATCH_CONFIG="${2}" + shift 2 + STEPS="${1:-2000}" + SNAPSHOTS="${2:-4}" + OUT_DIR="${3:-outputs}" +else + BATCH_CONFIG="" + STEPS="${1:-2000}" + SNAPSHOTS="${2:-4}" + OUT_DIR="${3:-outputs}" +fi + +if [[ ! -x "${ROOT_DIR}/build/Galaxy_simulation" ]]; then + bash "${ROOT_DIR}/unix_run.sh" +fi + +if [[ -n "${BATCH_CONFIG}" ]]; then + exec "${ROOT_DIR}/build/Galaxy_simulation" \ + --batch-config "${BATCH_CONFIG}" \ + --batch-steps "${STEPS}" \ + --snapshots "${SNAPSHOTS}" \ + --output-dir "${OUT_DIR}" +else + exec "${ROOT_DIR}/build/Galaxy_simulation" \ + --batch-steps "${STEPS}" \ + --snapshots "${SNAPSHOTS}" \ + --output-dir "${OUT_DIR}" +fi diff --git a/run_sim.sh b/run_sim.sh new file mode 100755 index 0000000..88cc623 --- /dev/null +++ b/run_sim.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +if [[ ! -x "${ROOT_DIR}/build/Galaxy_simulation" ]]; then + bash "${ROOT_DIR}/unix_run.sh" +fi + +exec "${ROOT_DIR}/build/Galaxy_simulation" "$@" diff --git a/shaders/galaxy.frag b/shaders/galaxy.frag index b55069b..ab6823b 100644 --- a/shaders/galaxy.frag +++ b/shaders/galaxy.frag @@ -9,14 +9,13 @@ out vec4 frag_color; void main() { float brightness = v_brightness / 5.0; - float brightness2 = v_brightness / 1.0; if (v_starType > 0) { - frag_color = vec4(brightness, 0.0, 0.0, 1.0); // gives blue stars for positive stars + frag_color = vec4(0.0, 0.0, brightness, 1.0); // regular mass (positive): blue } else { - frag_color = vec4(1., brightness, 0.0, 1.0); // gives brigther blue stars for positive stars + frag_color = vec4(brightness, 0.0, 0.0, 1.0); // negative mass: red } -} \ No newline at end of file +} diff --git a/shaders/post.frag b/shaders/post.frag index 05cdae8..287b334 100644 --- a/shaders/post.frag +++ b/shaders/post.frag @@ -11,22 +11,9 @@ uniform sampler2D u_blur; void main() { vec4 galaxy_data = texture(u_galaxy, v_texcoord); - float stars = galaxy_data.r; - float star_type = galaxy_data.g; // Assuming star type is stored in the green channel - float glow = texture(u_blur, v_texcoord).r * 0.2; - vec3 color_1; - vec3 color_2; - - if (star_type > 0.5) // Positive stars - { - color_1 = vec3(0.3, 0.05, 0.05); // Dark red - color_2 = vec3(0.3, 0.3, 0.05); // Yellow - frag_color = vec4(0.7 * mix(color_1, color_2, 0.1 * (stars + glow)) * (stars + glow), 1.); - } - else // Negative stars - { - color_1 = vec3(0.05, 0.05, 0.3); // Dark blue - color_2 = vec3(0.05, 0.3, 0.3); // Cyan - frag_color = vec4(0.7 * mix(color_1, color_2, 0.05 * (stars + glow)) * (stars + glow), 1.); - } -} \ No newline at end of file + vec3 stars = galaxy_data.rgb; + vec3 blur = texture(u_blur, v_texcoord).rgb; + // Boost blue-channel bloom so positive stars get a glow comparable to negatives. + vec3 glow = vec3(0.20 * blur.r, 0.20 * blur.g, 0.34 * blur.b); + frag_color = vec4(0.7 * (stars + glow), 1.0); +} diff --git a/sources/ComputeShader.cpp b/sources/ComputeShader.cpp index d63293a..677a6a6 100644 --- a/sources/ComputeShader.cpp +++ b/sources/ComputeShader.cpp @@ -59,6 +59,8 @@ void ComputeShader::init(const std::string& path) //std::vector<::size_t> maxWorkItems; //maxWorkItems = device.getInfo(); //std::cout << maxWorkItems[0] << " " << maxWorkItems[1] << " " << maxWorkItems[2] << std::endl; + + queue = cl::CommandQueue(context, device); } void ComputeShader::launch(const std::string& function, const std::vector& buffers, const cl::NDRange& global, const cl::NDRange& local) @@ -68,7 +70,6 @@ void ComputeShader::launch(const std::string& function, const std::vector // For rand() and srand() -#include // For time() +#include std::vector Computer::positions; std::vector Computer::speeds; std::vector Computer::accelerations; -std::vector Computer::star_types; // Add this line +std::vector Computer::star_types; cl::Buffer Computer::positions_buffer; cl::Buffer Computer::speeds_buffer; cl::Buffer Computer::accelerations_buffer; @@ -14,7 +13,10 @@ cl::Buffer Computer::step_buffer; cl::Buffer Computer::smoothing_length_buffer; cl::Buffer Computer::interaction_rate_buffer; cl::Buffer Computer::black_hole_mass_buffer; -cl::Buffer Computer::types_buffer; // Add this line +cl::Buffer Computer::types_buffer; +cl::Buffer Computer::negative_attraction_constant_buffer; +cl::Buffer Computer::repulsion_constant_buffer; + dim::Vector3 Computer::random_sphere() { dim::Vector3 result = dim::Vector3::null; @@ -30,19 +32,6 @@ dim::Vector3 Computer::random_sphere() return result; } - - -// void Computer::initialize_star_types(int num_stars) -// { -// star_types.resize(num_stars); -// srand(static_cast(time(0))); // Seed the random number generator - -// for (int i = 0; i < num_stars; ++i) -// { -// star_types[i] = (rand() % 2 == 0) ? 1 : -1; // Assign 1 for positive, -1 for negative -// } -// } - void Computer::create_galaxy(int i) { positions[i].set_norm(static_cast(pow(positions[i].get_norm() / (Simulator::galaxy_diameter / 2.f), 5)) * (Simulator::galaxy_diameter / 2.f)); @@ -74,77 +63,139 @@ void Computer::create_universe(int i) void Computer::initialize_star_types_and_positions(int num_stars, float type_diameter) { - star_types.resize(num_stars); - positions.resize(num_stars); - speeds.resize(num_stars); - accelerations.resize(num_stars, dim::Vector4::null); - - srand(static_cast(time(0))); // Seed the random number generator - - for (int i = 0; i < num_stars; ++i) - { - dim::Vector3 position = random_sphere(); - positions[i] = dim::Vector4(position, 0.0f); - - if (position.get_norm() <= type_diameter / 2.0f) - { - star_types[i] = 1; // Positive star inside the type_diameter - } - else - { - star_types[i] = -1; // Negative star outside the type_diameter - } - } + star_types.resize(num_stars); + positions.resize(num_stars); + speeds.resize(num_stars); + accelerations.resize(num_stars, dim::Vector4::null); + + switch (Menu::matter_distribution) + { + case MatterDistribution::CoreHalo: + { + // Interpretation: + // - Positive core diameter defines the positive sphere. + // - Halo stars are always negative. + // - core_extra_negative_density injects extra negatives inside core in [0, 1]. + const float core_radius = std::max(0.0f, type_diameter / 2.0f); + const float extra_core_negative = std::max(0.0f, std::min(Menu::core_extra_negative_density, 1.0f)); + + for (int i = 0; i < num_stars; ++i) + { + const dim::Vector3 position = random_sphere(); + positions[i] = dim::Vector4(position, 0.0f); + const bool in_core = position.get_norm() <= core_radius; + + if (in_core) + star_types[i] = (dim::random_float(0.f, 1.f) <= extra_core_negative) ? -1 : 1; + else + star_types[i] = -1; + } + break; + } + + case MatterDistribution::RandomMix: + for (int i = 0; i < num_stars; ++i) + { + const dim::Vector3 position = random_sphere(); + positions[i] = dim::Vector4(position, 0.0f); + star_types[i] = (dim::random_float(0.f, 1.f) <= Menu::positive_ratio) ? 1 : -1; + } + break; + + case MatterDistribution::SplitX: + for (int i = 0; i < num_stars; ++i) + { + const dim::Vector3 position = random_sphere(); + positions[i] = dim::Vector4(position, 0.0f); + star_types[i] = (positions[i].x <= 0.0f) ? 1 : -1; + } + break; + } } void Computer::init() { - positions.clear(); - speeds.clear(); - accelerations.clear(); - star_types.clear(); - - initialize_star_types_and_positions(Simulator::nb_stars, Menu::type_diameter); - - for (int i = 0; i < Simulator::nb_stars; i++) - { - switch (Simulator::simulation_type) - { - case SimulationType::Galaxy: create_galaxy(i); break; - case SimulationType::Collision: create_collision(i); break; - case SimulationType::Universe: create_universe(i); break; - default: break; - } - } - - positions_buffer = ComputeShader::Buffer(positions, Permissions::All); - speeds_buffer = ComputeShader::Buffer(speeds, Permissions::All); - accelerations_buffer = ComputeShader::Buffer(accelerations, Permissions::All); - step_buffer = ComputeShader::Buffer(Simulator::step, Permissions::Read); - smoothing_length_buffer = ComputeShader::Buffer(Simulator::smoothing_length, Permissions::Read); - interaction_rate_buffer = ComputeShader::Buffer(Simulator::interaction_rate, Permissions::Read); - black_hole_mass_buffer = ComputeShader::Buffer(Simulator::black_hole_mass, Permissions::Read); - types_buffer = ComputeShader::Buffer(star_types, Permissions::Read); + positions.clear(); + speeds.clear(); + accelerations.clear(); + star_types.clear(); + + initialize_star_types_and_positions(Simulator::nb_stars, Menu::type_diameter); + + for (int i = 0; i < Simulator::nb_stars; i++) + { + switch (Simulator::simulation_type) + { + case SimulationType::Galaxy: create_galaxy(i); break; + case SimulationType::Collision: create_collision(i); break; + case SimulationType::Universe: create_universe(i); break; + default: break; + } + } + + // Core/halo typing must be applied after initial placement shaping. + // Otherwise stars moved by create_galaxy/create_collision can cross the core boundary. + if (Menu::matter_distribution == MatterDistribution::CoreHalo) + { + const float core_radius = std::max(0.0f, Menu::type_diameter / 2.0f); + const float extra_core_negative = std::max(0.0f, std::min(Menu::core_extra_negative_density, 1.0f)); + for (int i = 0; i < Simulator::nb_stars; ++i) + { + if (positions[i].get_norm() <= core_radius) + star_types[i] = (dim::random_float(0.f, 1.f) <= extra_core_negative) ? -1 : 1; + else + star_types[i] = -1; + } + } + + int positive_count = 0; + int negative_count = 0; + int core_count = 0; + int halo_count = 0; + const float core_radius = std::max(0.0f, Menu::type_diameter / 2.0f); + for (int i = 0; i < Simulator::nb_stars; ++i) + { + if (star_types[i] > 0) positive_count++; + else negative_count++; + + if (positions[i].get_norm() <= core_radius) core_count++; + else halo_count++; + } + std::cout << "[Init] stars+=" << positive_count + << " stars-=" << negative_count + << " core=" << core_count + << " halo=" << halo_count + << " mode=" << static_cast(Menu::matter_distribution) + << std::endl; + + positions_buffer = ComputeShader::Buffer(positions, Permissions::All); + speeds_buffer = ComputeShader::Buffer(speeds, Permissions::All); + accelerations_buffer = ComputeShader::Buffer(accelerations, Permissions::All); + step_buffer = ComputeShader::Buffer(Simulator::step, Permissions::Read); + smoothing_length_buffer = ComputeShader::Buffer(Simulator::smoothing_length, Permissions::Read); + interaction_rate_buffer = ComputeShader::Buffer(Simulator::interaction_rate, Permissions::Read); + black_hole_mass_buffer = ComputeShader::Buffer(Simulator::black_hole_mass, Permissions::Read); + types_buffer = ComputeShader::Buffer(star_types, Permissions::Read); + negative_attraction_constant_buffer = ComputeShader::Buffer(Menu::negative_attraction_constant, Permissions::Read); + repulsion_constant_buffer = ComputeShader::Buffer(Menu::repulsion_constant, Permissions::Read); } void Computer::compute() { - step_buffer = ComputeShader::Buffer(Simulator::step, Permissions::Read); - smoothing_length_buffer = ComputeShader::Buffer(Simulator::smoothing_length, Permissions::Read); - interaction_rate_buffer = ComputeShader::Buffer(Simulator::interaction_rate, Permissions::Read); - black_hole_mass_buffer = ComputeShader::Buffer(Simulator::black_hole_mass, Permissions::Read); - types_buffer = ComputeShader::Buffer(Computer::star_types, Permissions::Read); - cl::Buffer negative_attraction_constant_buffer = ComputeShader::Buffer(Menu::negative_attraction_constant, Permissions::Read); - cl::Buffer repulsion_constant_buffer = ComputeShader::Buffer(Menu::repulsion_constant, Permissions::Read); - - // The interactions computations. - ComputeShader::launch("interactions", { &positions_buffer, &accelerations_buffer, &interaction_rate_buffer, - &smoothing_length_buffer, &black_hole_mass_buffer, &types_buffer, &negative_attraction_constant_buffer, &repulsion_constant_buffer }, - cl::NDRange(accelerations.size())); - ComputeShader::get_data(accelerations_buffer, accelerations); - - // The integration computation. - ComputeShader::launch("integration", { &positions_buffer, &speeds_buffer, &accelerations_buffer, &step_buffer }, cl::NDRange(speeds.size())); - ComputeShader::get_data(positions_buffer, positions); - ComputeShader::get_data(speeds_buffer, speeds); -} \ No newline at end of file + ComputeShader::set_data(step_buffer, Simulator::step); + ComputeShader::set_data(smoothing_length_buffer, Simulator::smoothing_length); + ComputeShader::set_data(interaction_rate_buffer, Simulator::interaction_rate); + ComputeShader::set_data(black_hole_mass_buffer, Simulator::black_hole_mass); + ComputeShader::set_data(negative_attraction_constant_buffer, Menu::negative_attraction_constant); + ComputeShader::set_data(repulsion_constant_buffer, Menu::repulsion_constant); + + // The interactions computations. + ComputeShader::launch("interactions", { &positions_buffer, &accelerations_buffer, &interaction_rate_buffer, + &smoothing_length_buffer, &black_hole_mass_buffer, &types_buffer, &negative_attraction_constant_buffer, &repulsion_constant_buffer }, + cl::NDRange(accelerations.size())); + + // The integration computation. + ComputeShader::launch("integration", { &positions_buffer, &speeds_buffer, &accelerations_buffer, &step_buffer }, cl::NDRange(speeds.size())); + ComputeShader::get_data(positions_buffer, positions); + ComputeShader::get_data(speeds_buffer, speeds); +} diff --git a/sources/Menu.cpp b/sources/Menu.cpp index db87b9f..d48645a 100644 --- a/sources/Menu.cpp +++ b/sources/Menu.cpp @@ -1,5 +1,8 @@ #include "Menu.hpp" #include "Simulator.hpp" +#include +#include +#include bool Menu::visible = true; bool Menu::active = false; @@ -14,9 +17,12 @@ float Menu::galaxy_thickness; float Menu::galaxies_distance; float Menu::stars_speed; float Menu::black_hole_mass; -float Menu::negative_attraction_constant = 1.0f; // Add this line -float Menu::repulsion_constant = 1.0f; // Add this line -float Menu::type_diameter = 50.0f; // Initialize type_diameter +float Menu::negative_attraction_constant = 1.0f; +float Menu::repulsion_constant = 1.0f; +float Menu::type_diameter = 50.0f; +MatterDistribution Menu::matter_distribution = MatterDistribution::CoreHalo; +float Menu::positive_ratio = 0.5f; +float Menu::core_extra_negative_density = 0.0f; void Menu::check_events(const sf::Event& sf_event) @@ -63,9 +69,12 @@ void Menu::set_default_values() smoothing_length = 1.f; galaxies_distance = 75.f; black_hole_mass = 1000.f; - negative_attraction_constant = 1.0f; // Add this line - repulsion_constant = 1.0f; // Add this line - type_diameter = 50.0f; // Initialize type_diameter + negative_attraction_constant = 1.0f; + repulsion_constant = 1.0f; + type_diameter = 50.0f; + matter_distribution = MatterDistribution::CoreHalo; + positive_ratio = 0.5f; + core_extra_negative_density = 0.0f; switch (simulation_type) @@ -170,6 +179,8 @@ void Menu::universe() void Menu::display() { static std::string pause_button = "Pause"; + static char config_output_path[256] = "batch_configs/user.batchcfg"; + static std::string config_output_status; if (visible) { @@ -190,20 +201,13 @@ void Menu::display() } ImGui::NewLine(); - // Add UI elements for the constants + // Janus force multipliers (real-time). ImGui::Text("Negative Attraction Constant"); - ImGui::SliderFloat("##Negative_Attraction_Constant", &negative_attraction_constant, -3.0f, 3.0f); // Update range + ImGui::SliderFloat("##Negative_Attraction_Constant", &negative_attraction_constant, -3.0f, 3.0f); ImGui::Text("Repulsion Constant"); - ImGui::SliderFloat("##Repulsion_Constant", &repulsion_constant, -3.0f, 3.0f); // Update range + ImGui::SliderFloat("##Repulsion_Constant", &repulsion_constant, -3.0f, 3.0f); ImGui::NewLine(); - ImGui::Text("Type Diameter"); - ImGui::SliderFloat("##Type_Diameter", &type_diameter, 0.0f, galaxy_diameter); // Add slider for type_diameter - - ImGui::NewLine(); - - - title("Real time settings"); ImGui::NewLine(); @@ -227,6 +231,28 @@ void Menu::display() ImGui::NewLine(); + ImGui::Text("Matter distribution"); + ImGui::Combo("##matter_distribution", reinterpret_cast(&matter_distribution), "Core + halo\0Random mix\0Split on X\0"); + ImGui::NewLine(); + + if (matter_distribution == MatterDistribution::CoreHalo) + { + ImGui::Text("Positive core diameter"); + ImGui::SliderFloat("##Type_Diameter", &type_diameter, 0.0f, galaxy_diameter); + ImGui::NewLine(); + + ImGui::Text("Extra negative density inside core"); + ImGui::SliderFloat("##Core_Extra_Negative_Density", &core_extra_negative_density, 0.0f, 1.0f, "%.2f"); + ImGui::TextDisabled("0 = core fully positive, 1 = core fully negative"); + ImGui::NewLine(); + } + else if (matter_distribution == MatterDistribution::RandomMix) + { + ImGui::Text("Positive matter ratio"); + ImGui::SliderFloat("##Positive_Ratio", &positive_ratio, 0.0f, 1.0f, "%.2f"); + ImGui::NewLine(); + } + switch (simulation_type) { case SimulationType::Galaxy: galaxy(); break; @@ -235,6 +261,35 @@ void Menu::display() default: break; } + ImGui::NewLine(); + ImGui::Separator(); + ImGui::Text("Batch config export"); + ImGui::InputText("##config_output_path", config_output_path, sizeof(config_output_path)); + if (ImGui::Button("Append current SIMCFG to file")) + { + try + { + const std::filesystem::path output_path(config_output_path); + if (output_path.has_parent_path()) + std::filesystem::create_directories(output_path.parent_path()); + + std::ofstream out(config_output_path, std::ios::app); + if (out) + { + out << Simulator::configuration_line() << '\n'; + config_output_status = std::string("Appended to ") + config_output_path; + } + else + config_output_status = std::string("Failed to open ") + config_output_path; + } + catch (const std::exception& e) + { + config_output_status = std::string("Export error: ") + e.what(); + } + } + if (!config_output_status.empty()) + ImGui::TextWrapped("%s", config_output_status.c_str()); + ImGui::NewLine(); std::vector buttons = centered_buttons({ "Restart", pause_button }, 25.f, 20.f); diff --git a/sources/Renderer.cpp b/sources/Renderer.cpp index abeb91a..eb77283 100644 --- a/sources/Renderer.cpp +++ b/sources/Renderer.cpp @@ -24,7 +24,7 @@ void Renderer::init_vbo() GLsizeiptr speeds_size = Computer::speeds.size() * sizeof(dim::Vector4); GLsizeiptr types_size = Computer::star_types.size() * sizeof(int); - // Allocate buffer data for positions, speeds, and star types + // Allocate one packed buffer: positions, speeds, star types. glBufferData(GL_ARRAY_BUFFER, positions_size + speeds_size + types_size, NULL, GL_DYNAMIC_DRAW); // Update positions @@ -52,7 +52,7 @@ void Renderer::init_vbo() glEnableVertexAttribArray(speeds); GLint star_types = glGetAttribLocation(dim::Shader::get("galaxy").get_id(), "a_starType"); - glVertexAttribPointer(star_types, 1, GL_INT, GL_FALSE, sizeof(int), reinterpret_cast(positions_size + speeds_size)); + glVertexAttribIPointer(star_types, 1, GL_INT, sizeof(int), reinterpret_cast(positions_size + speeds_size)); glEnableVertexAttribArray(star_types); glBindBuffer(GL_ARRAY_BUFFER, 0); @@ -65,10 +65,6 @@ void Renderer::update_vbo() GLsizeiptr positions_size = Computer::positions.size() * sizeof(dim::Vector4); GLsizeiptr speeds_size = Computer::speeds.size() * sizeof(dim::Vector4); - GLsizeiptr types_size = Computer::star_types.size() * sizeof(int); - - // Allocate buffer data for positions, speeds, and star types - glBufferData(GL_ARRAY_BUFFER, positions_size + speeds_size + types_size, NULL, GL_DYNAMIC_DRAW); // Update positions glBufferSubData(GL_ARRAY_BUFFER, 0, positions_size, Computer::positions.data()); @@ -76,9 +72,6 @@ void Renderer::update_vbo() // Update speeds glBufferSubData(GL_ARRAY_BUFFER, positions_size, speeds_size, Computer::speeds.data()); - // Update star types - glBufferSubData(GL_ARRAY_BUFFER, positions_size + speeds_size, types_size, Computer::star_types.data()); - glBindBuffer(GL_ARRAY_BUFFER, 0); } @@ -109,8 +102,6 @@ void Renderer::init() galaxy_fbo_2.create(dim::Window::get_size(), dim::Texture::Filtering::Linear, dim::Texture::Warpping::MirroredRepeat, dim::Texture::Type::RGB_16f); blur_fbo_1.create(dim::Window::get_size(), dim::Texture::Filtering::Linear, dim::Texture::Warpping::MirroredRepeat, dim::Texture::Type::RGB_16f); blur_fbo_2.create(dim::Window::get_size(), dim::Texture::Filtering::Linear, dim::Texture::Warpping::MirroredRepeat, dim::Texture::Type::RGB_16f); - - update_vbo(); } void Renderer::check_events(const sf::Event& sf_event) @@ -226,4 +217,4 @@ void Renderer::draw() dim::Shader::get("post").unbind(); glDisable(GL_BLEND); -} \ No newline at end of file +} diff --git a/sources/Simulator.cpp b/sources/Simulator.cpp index 1a42b25..7508b7c 100644 --- a/sources/Simulator.cpp +++ b/sources/Simulator.cpp @@ -1,4 +1,7 @@ #include "Simulator.hpp" +#include +#include +#include std::atomic Simulator::computation_done; std::atomic Simulator::reload; @@ -48,12 +51,63 @@ void Simulator::restart() Computer::init(); Renderer::init(); + print_configuration(); computation_done = false; waiting = false; reload = false; } +void Simulator::print_configuration() +{ + std::cout << configuration_line() << std::endl; +} + +std::string Simulator::configuration_line() +{ + const char* simulation_type_name = "Galaxy"; + switch (Menu::simulation_type) + { + case SimulationType::Galaxy: simulation_type_name = "Galaxy"; break; + case SimulationType::Collision: simulation_type_name = "Collision"; break; + case SimulationType::Universe: simulation_type_name = "Universe"; break; + } + + const char* matter_distribution_name = "CoreHalo"; + switch (Menu::matter_distribution) + { + case MatterDistribution::CoreHalo: matter_distribution_name = "CoreHalo"; break; + case MatterDistribution::RandomMix: matter_distribution_name = "RandomMix"; break; + case MatterDistribution::SplitX: matter_distribution_name = "SplitX"; break; + } + + std::ostringstream out; + out << std::fixed << std::setprecision(6); + out + << "SIMCFG " + << "simulation_type=" << simulation_type_name << " " + << "step=" << Menu::step << " " + << "smoothing_length=" << Menu::smoothing_length << " " + << "interaction_rate=" << Menu::interaction_rate << " " + << "nb_stars=" << Menu::nb_stars << " " + << "galaxy_diameter=" << Menu::galaxy_diameter << " " + << "galaxy_thickness=" << Menu::galaxy_thickness << " " + << "galaxies_distance=" << Menu::galaxies_distance << " " + << "stars_speed=" << Menu::stars_speed << " " + << "black_hole_mass=" << Menu::black_hole_mass << " " + << "negative_attraction_constant=" << Menu::negative_attraction_constant << " " + << "repulsion_constant=" << Menu::repulsion_constant << " " + << "matter_distribution=" << matter_distribution_name << " " + << "type_diameter=" << Menu::type_diameter << " " + << "positive_ratio=" << Menu::positive_ratio << " " + << "core_extra_negative_density=" << Menu::core_extra_negative_density << " " + << "batch_steps=2000 " + << "snapshots=4 " + << "output_dir=outputs"; + + return out.str(); +} + void Simulator::menu_update() { step = Menu::step; diff --git a/sources/main.cpp b/sources/main.cpp index 8002f6b..02f676a 100644 --- a/sources/main.cpp +++ b/sources/main.cpp @@ -2,6 +2,16 @@ #include "Simulator.hpp" #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // Function to print OpenGL context information @@ -23,14 +33,335 @@ void print_opengl_info() std::cout << "OpenGL Version: " << major << "." << minor << std::endl; } -int main() +struct BatchOptions { + bool enabled = false; + int steps = 0; + int snapshots = 3; + std::string output_dir = "outputs"; + std::string config_path; + std::string batch_config_path; +}; + +static int parse_int(const char* value, int fallback) +{ + if (value == nullptr) + return fallback; + try + { + return std::stoi(value); + } + catch (const std::exception&) + { + return fallback; + } +} + +static BatchOptions parse_args(int argc, char** argv) +{ + BatchOptions options; + + for (int i = 1; i < argc; ++i) + { + std::string arg = argv[i]; + if (arg == "--batch-steps" && i + 1 < argc) + { + options.steps = std::max(0, parse_int(argv[++i], 0)); + options.enabled = (options.steps > 0); + } + else if (arg == "--snapshots" && i + 1 < argc) + options.snapshots = std::max(1, parse_int(argv[++i], 3)); + else if (arg == "--output-dir" && i + 1 < argc) + options.output_dir = argv[++i]; + else if (arg == "--config" && i + 1 < argc) + options.config_path = argv[++i]; + else if (arg == "--batch-config" && i + 1 < argc) + options.batch_config_path = argv[++i]; + } + + return options; +} + +static bool to_float(const std::string& text, float& value) +{ + try { value = std::stof(text); return true; } catch (...) { return false; } +} + +static bool to_int(const std::string& text, int& value) +{ + try { value = std::stoi(text); return true; } catch (...) { return false; } +} + +static bool parse_simulation_type(const std::string& text, SimulationType& value) +{ + if (text == "Galaxy" || text == "0") { value = SimulationType::Galaxy; return true; } + if (text == "Collision" || text == "1") { value = SimulationType::Collision; return true; } + if (text == "Universe" || text == "2") { value = SimulationType::Universe; return true; } + return false; +} + +static bool parse_matter_distribution(const std::string& text, MatterDistribution& value) +{ + if (text == "CoreHalo" || text == "Core+halo" || text == "0") { value = MatterDistribution::CoreHalo; return true; } + if (text == "RandomMix" || text == "1") { value = MatterDistribution::RandomMix; return true; } + if (text == "SplitX" || text == "2") { value = MatterDistribution::SplitX; return true; } + return false; +} + +using ConfigKV = std::unordered_map; + +static ConfigKV parse_config_line(const std::string& raw) +{ + std::string line = raw; + const size_t comment_pos = line.find('#'); + if (comment_pos != std::string::npos) + line = line.substr(0, comment_pos); + + std::istringstream in(line); + std::string token; + ConfigKV values; + + while (in >> token) + { + if (token == "SIMCFG" || token == "BATCHCFG") + continue; + + const size_t eq = token.find('='); + if (eq == std::string::npos || eq == 0 || eq + 1 >= token.size()) + continue; + + values[token.substr(0, eq)] = token.substr(eq + 1); + } + + return values; +} + +static std::vector load_config_jobs(const std::string& path) +{ + std::ifstream file(path); + std::vector jobs; + + if (!file.is_open()) + return jobs; + + std::string line; + while (std::getline(file, line)) + { + ConfigKV kv = parse_config_line(line); + if (!kv.empty()) + jobs.push_back(std::move(kv)); + } + + return jobs; +} + +static bool apply_config_kv(const ConfigKV& kv, BatchOptions& batch, bool* output_dir_overridden = nullptr) +{ + if (output_dir_overridden != nullptr) + *output_dir_overridden = false; + + auto get = [&](const char* key) -> const std::string* + { + const auto it = kv.find(key); + return (it == kv.end()) ? nullptr : &it->second; + }; + + if (const std::string* v = get("simulation_type")) + { + SimulationType type = Menu::simulation_type; + if (parse_simulation_type(*v, type)) + Menu::simulation_type = type; + } + if (const std::string* v = get("matter_distribution")) + { + MatterDistribution distribution = Menu::matter_distribution; + if (parse_matter_distribution(*v, distribution)) + Menu::matter_distribution = distribution; + } + + auto set_float = [&](const char* key, float& target) + { + if (const std::string* v = get(key)) + { + float parsed = target; + if (to_float(*v, parsed)) + target = parsed; + } + }; + auto set_int = [&](const char* key, int& target) + { + if (const std::string* v = get(key)) + { + int parsed = target; + if (to_int(*v, parsed)) + target = parsed; + } + }; + + set_float("step", Menu::step); + set_float("smoothing_length", Menu::smoothing_length); + set_float("interaction_rate", Menu::interaction_rate); + set_int("nb_stars", Menu::nb_stars); + set_float("galaxy_diameter", Menu::galaxy_diameter); + set_float("galaxy_thickness", Menu::galaxy_thickness); + set_float("galaxies_distance", Menu::galaxies_distance); + set_float("stars_speed", Menu::stars_speed); + set_float("black_hole_mass", Menu::black_hole_mass); + set_float("negative_attraction_constant", Menu::negative_attraction_constant); + set_float("repulsion_constant", Menu::repulsion_constant); + set_float("type_diameter", Menu::type_diameter); + set_float("positive_ratio", Menu::positive_ratio); + set_float("core_extra_negative_density", Menu::core_extra_negative_density); + + if (const std::string* v = get("batch_steps")) + { + int parsed = batch.steps; + if (to_int(*v, parsed)) + { + batch.steps = std::max(0, parsed); + batch.enabled = (batch.steps > 0); + } + } + if (const std::string* v = get("snapshots")) + { + int parsed = batch.snapshots; + if (to_int(*v, parsed)) + batch.snapshots = std::max(1, parsed); + } + if (const std::string* v = get("output_dir")) + { + batch.output_dir = *v; + if (output_dir_overridden != nullptr) + *output_dir_overridden = true; + } + + return true; +} + +static bool save_window_snapshot(const std::string& path) +{ + sf::RenderWindow& window = dim::Window::get_window(); + const sf::Vector2u size = window.getSize(); + sf::Texture texture; + + if (!texture.create(size.x, size.y)) + return false; + + texture.update(window); + const sf::Image image = texture.copyToImage(); + return image.saveToFile(path); +} + +static void set_snapshot_camera_angle(float theta, float phi = dim::pi / 3.f) +{ + dim::Camera& camera = dim::Window::get_camera(); + const float radius = camera.get_position().get_norm(); + const dim::Vector3 position = dim::Vector3::Spherical(radius, theta, phi); + camera.set_position(position); + camera.set_direction(-position); +} + +static int run_batch_mode(const BatchOptions& options, bool close_window) +{ + std::cout << "Running batch mode for " << options.steps << " steps..." << std::endl; + + Menu::pause = false; + for (int i = 0; i < options.steps && dim::Window::running; ++i) + { + Simulator::menu_update(); + Computer::compute(); + } + + Renderer::update_vbo(); + + std::error_code ec; + std::filesystem::create_directories(options.output_dir, ec); + if (ec) + std::cerr << "Warning: failed to create output directory: " << options.output_dir << std::endl; + + for (int i = 0; i < options.snapshots; ++i) + { + const float theta = (2.f * dim::pi * static_cast(i)) / static_cast(options.snapshots); + set_snapshot_camera_angle(theta); + + dim::Window::clear(dim::Color::black); + dim::Window::update(); + Renderer::clear(); + Simulator::draw(); + dim::Window::display(); + + const std::string path = options.output_dir + "/snapshot_" + std::to_string(i) + ".png"; + if (save_window_snapshot(path)) + std::cout << "Saved " << path << std::endl; + else + std::cerr << "Failed to save " << path << std::endl; + } + + if (close_window) + dim::Window::close(); + return EXIT_SUCCESS; +} + +int main(int argc, char** argv) +{ + const BatchOptions batch_options = parse_args(argc, argv); + BatchOptions mutable_batch_options = batch_options; + dim::Window::open("Galaxy simulation", 0.75f, "resources/icons/icon.png"); Simulator::init(); // Print OpenGL context information print_opengl_info(); + if (!mutable_batch_options.config_path.empty()) + { + const std::vector jobs = load_config_jobs(mutable_batch_options.config_path); + if (jobs.empty()) + std::cerr << "Warning: no valid config line found in " << mutable_batch_options.config_path << std::endl; + else + { + apply_config_kv(jobs.front(), mutable_batch_options); + Simulator::restart(); + } + } + + if (!mutable_batch_options.batch_config_path.empty()) + { + const std::vector jobs = load_config_jobs(mutable_batch_options.batch_config_path); + if (jobs.empty()) + { + std::cerr << "Error: no valid batch jobs found in " << mutable_batch_options.batch_config_path << std::endl; + dim::Window::close(); + return EXIT_FAILURE; + } + + for (size_t i = 0; i < jobs.size(); ++i) + { + BatchOptions job_options = mutable_batch_options; + bool output_dir_overridden = false; + apply_config_kv(jobs[i], job_options, &output_dir_overridden); + + if (!job_options.enabled) + { + std::cerr << "Skipping job " << (i + 1) << ": missing batch_steps" << std::endl; + continue; + } + + if (!output_dir_overridden && jobs.size() > 1) + job_options.output_dir = mutable_batch_options.output_dir + "/run_" + std::to_string(i + 1); + + std::cout << "[Batch] Job " << (i + 1) << "/" << jobs.size() << std::endl; + Simulator::restart(); + run_batch_mode(job_options, false); + } + + dim::Window::close(); + return EXIT_SUCCESS; + } + + if (mutable_batch_options.enabled) + return run_batch_mode(mutable_batch_options, true); + // The computation thread. std::thread simulation_thread([]() { From ee4717bf6a6da0719830ebc53cd8ee28f95937fe Mon Sep 17 00:00:00 2001 From: Cittadhammo Bhikkhu Date: Wed, 18 Feb 2026 18:02:57 +0000 Subject: [PATCH 7/8] major Update 2 --- CHANGE.md | 5 +++++ README.md | 25 +++++++++++++++++++++++- batch_configs/example.batchcfg | 4 ++-- batch_configs/user.batchcfg | 1 + batch_jobs.cfg | 6 ++++++ imgui.ini | 4 ++-- includes/Simulator.hpp | 11 +++++++++++ outputs/snapshot_0.png | Bin 0 -> 45283 bytes outputs/snapshot_1.png | Bin 0 -> 178697 bytes outputs/snapshot_2.png | Bin 0 -> 161268 bytes outputs/snapshot_3.png | Bin 0 -> 168229 bytes run_batch.sh | 7 ++++++- run_sim.sh | 7 ++++++- shaders/blur.frag | 6 +++--- shaders/galaxy.frag | 4 +++- shaders/post.frag | 2 +- simulation.cfg | 4 ++++ sources/Menu.cpp | 7 +++++++ sources/Simulator.cpp | 34 ++++++++++++++++++++++++++++++--- sources/main.cpp | 15 +++++++++++++++ 20 files changed, 127 insertions(+), 15 deletions(-) create mode 100644 batch_configs/user.batchcfg create mode 100644 batch_jobs.cfg create mode 100644 outputs/snapshot_0.png create mode 100644 outputs/snapshot_1.png create mode 100644 outputs/snapshot_2.png create mode 100644 outputs/snapshot_3.png create mode 100644 simulation.cfg diff --git a/CHANGE.md b/CHANGE.md index 2d4cf46..16dfb63 100644 --- a/CHANGE.md +++ b/CHANGE.md @@ -22,9 +22,14 @@ * `run_sim.sh` * `run_batch.sh` * `run_batch.sh --batch-config batch_configs/example.batchcfg` + * `run_batch.sh` automatically uses root `batch_jobs.cfg` when present * In-app batch export UI: * set config output path * append current `SIMCFG` line directly from the menu +* Root-level batch job template file: `batch_jobs.cfg` +* Camera preset in config lines: + * `camera_view=isometric|top` +* Root-level interactive startup config file: `simulation.cfg` ### Changed diff --git a/README.md b/README.md index 02f596f..61af460 100644 --- a/README.md +++ b/README.md @@ -161,6 +161,12 @@ Shortcut: bash run_sim.sh ``` +Default root config for normal (interactive) simulation: + +* `simulation.cfg` +* when you run `bash run_sim.sh` with no extra arguments, this file is loaded automatically +* set `camera_view=top` in `simulation.cfg` for top-down startup + Batch run (compute N steps, then export final snapshots from multiple angles): ```bash @@ -179,6 +185,14 @@ Batch file (each line = one simulation job): bash run_batch.sh --batch-config batch_configs/example.batchcfg ``` +Default root config: + +```bash +bash run_batch.sh +``` + +If `batch_jobs.cfg` exists at repository root, `run_batch.sh` uses it automatically. + ## โš™๏ธ Janus + Performance Update This branch includes: @@ -219,14 +233,23 @@ Run many jobs from one file (line-by-line): ./build/Galaxy_simulation --batch-config batch_configs/example.batchcfg ``` +Root-level default batch file: + +```bash +./build/Galaxy_simulation --batch-config batch_jobs.cfg +``` + Batch file format: * each non-comment line is one job * each line is `key=value` tokens * lines can start with `SIMCFG` * recommended keys per line: - * simulation: `simulation_type step smoothing_length interaction_rate nb_stars galaxy_diameter galaxy_thickness galaxies_distance stars_speed black_hole_mass negative_attraction_constant repulsion_constant matter_distribution type_diameter positive_ratio core_extra_negative_density` + * simulation: `simulation_type step smoothing_length interaction_rate nb_stars galaxy_diameter galaxy_thickness galaxies_distance stars_speed black_hole_mass negative_attraction_constant repulsion_constant matter_distribution type_diameter positive_ratio core_extra_negative_density camera_view` * batch: `batch_steps snapshots output_dir` +* `camera_view` values: + * `isometric` (default) + * `top` (top-down start view) Recommended workflow: diff --git a/batch_configs/example.batchcfg b/batch_configs/example.batchcfg index 668b71e..5633142 100644 --- a/batch_configs/example.batchcfg +++ b/batch_configs/example.batchcfg @@ -1,5 +1,5 @@ # Each non-comment line is one simulation job. # You can copy/paste SIMCFG lines printed by the app and edit batch_* keys. -SIMCFG simulation_type=Galaxy step=0.001000 smoothing_length=1.000000 interaction_rate=0.050000 nb_stars=30000 galaxy_diameter=100.000000 galaxy_thickness=5.000000 galaxies_distance=75.000000 stars_speed=20.000000 black_hole_mass=1000.000000 negative_attraction_constant=1.000000 repulsion_constant=1.000000 matter_distribution=CoreHalo type_diameter=40.000000 positive_ratio=0.500000 core_extra_negative_density=0.000000 batch_steps=3000 snapshots=4 output_dir=outputs/run_core_clean -SIMCFG simulation_type=Galaxy step=0.001000 smoothing_length=1.000000 interaction_rate=0.050000 nb_stars=30000 galaxy_diameter=100.000000 galaxy_thickness=5.000000 galaxies_distance=75.000000 stars_speed=20.000000 black_hole_mass=1000.000000 negative_attraction_constant=1.000000 repulsion_constant=1.000000 matter_distribution=CoreHalo type_diameter=40.000000 positive_ratio=0.500000 core_extra_negative_density=0.200000 batch_steps=3000 snapshots=4 output_dir=outputs/run_core_mixed +SIMCFG simulation_type=Galaxy step=0.001000 smoothing_length=1.000000 interaction_rate=0.050000 nb_stars=30000 galaxy_diameter=100.000000 galaxy_thickness=5.000000 galaxies_distance=75.000000 stars_speed=20.000000 black_hole_mass=1000.000000 negative_attraction_constant=1.000000 repulsion_constant=1.000000 matter_distribution=CoreHalo type_diameter=40.000000 positive_ratio=0.500000 core_extra_negative_density=0.000000 camera_view=isometric batch_steps=3000 snapshots=4 output_dir=outputs/run_core_clean +SIMCFG simulation_type=Galaxy step=0.001000 smoothing_length=1.000000 interaction_rate=0.050000 nb_stars=30000 galaxy_diameter=100.000000 galaxy_thickness=5.000000 galaxies_distance=75.000000 stars_speed=20.000000 black_hole_mass=1000.000000 negative_attraction_constant=1.000000 repulsion_constant=1.000000 matter_distribution=CoreHalo type_diameter=40.000000 positive_ratio=0.500000 core_extra_negative_density=0.200000 camera_view=top batch_steps=3000 snapshots=4 output_dir=outputs/run_core_mixed diff --git a/batch_configs/user.batchcfg b/batch_configs/user.batchcfg new file mode 100644 index 0000000..88d9b5d --- /dev/null +++ b/batch_configs/user.batchcfg @@ -0,0 +1 @@ +SIMCFG simulation_type=Galaxy step=0.001000 smoothing_length=1.000000 interaction_rate=0.050000 nb_stars=20000 galaxy_diameter=100.000000 galaxy_thickness=5.000000 galaxies_distance=75.000000 stars_speed=20.000000 black_hole_mass=1000.000000 negative_attraction_constant=1.000000 repulsion_constant=1.000000 matter_distribution=CoreHalo type_diameter=50.000000 positive_ratio=0.500000 core_extra_negative_density=0.000000 batch_steps=2000 snapshots=4 output_dir=outputs diff --git a/batch_jobs.cfg b/batch_jobs.cfg new file mode 100644 index 0000000..13b6fec --- /dev/null +++ b/batch_jobs.cfg @@ -0,0 +1,6 @@ +# Galaxy simulation batch jobs +# One simulation per line. Copy/paste SIMCFG lines from terminal or menu export. +# Keys: +# simulation_type step smoothing_length interaction_rate nb_stars galaxy_diameter galaxy_thickness galaxies_distance stars_speed black_hole_mass negative_attraction_constant repulsion_constant matter_distribution type_diameter positive_ratio core_extra_negative_density camera_view batch_steps snapshots output_dir + +SIMCFG simulation_type=Galaxy step=0.001000 smoothing_length=1.000000 interaction_rate=0.050000 nb_stars=30000 galaxy_diameter=100.000000 galaxy_thickness=5.000000 galaxies_distance=75.000000 stars_speed=20.000000 black_hole_mass=1000.000000 negative_attraction_constant=1.000000 repulsion_constant=1.000000 matter_distribution=CoreHalo type_diameter=40.000000 positive_ratio=0.500000 core_extra_negative_density=0.000000 camera_view=top batch_steps=3000 snapshots=4 output_dir=outputs/run_001 diff --git a/imgui.ini b/imgui.ini index 2e099fd..bbbdfca 100644 --- a/imgui.ini +++ b/imgui.ini @@ -1,6 +1,6 @@ [Window][InvisibleWindow] Pos=0,0 -Size=1440,917 +Size=1440,810 Collapsed=0 [Window][Menu] @@ -34,5 +34,5 @@ Size=267,907 Collapsed=0 [Docking][Data] -DockSpace ID=0xF442860A Window=0xD8117908 Pos=0,0 Size=1440,917 CentralNode=1 Selected=0x18B8C0DE +DockSpace ID=0xF442860A Window=0xD8117908 Pos=0,0 Size=1440,810 CentralNode=1 Selected=0x18B8C0DE diff --git a/includes/Simulator.hpp b/includes/Simulator.hpp index 229f8ac..5c48fcb 100644 --- a/includes/Simulator.hpp +++ b/includes/Simulator.hpp @@ -16,6 +16,11 @@ class Simulator { public: + enum class CameraView : int + { + Isometric = 0, + Top = 1 + }; static std::atomic computation_done; // True if the computation is done. static std::atomic reload; // True if the simulation have to restart. @@ -30,6 +35,7 @@ class Simulator static float galaxies_distance; // The distance between the galaxies. static float stars_speed; // The initial speed of the stars. static float black_hole_mass; // The mass of the black hole. + static CameraView camera_view; // Camera view preset at startup/config load. /** * @brief Initialize the simulation. @@ -79,6 +85,11 @@ class Simulator * @brief Draw the simulation. */ static void draw(); + + /** + * @brief Apply the selected camera view preset. + */ + static void apply_camera_view(); }; #endif diff --git a/outputs/snapshot_0.png b/outputs/snapshot_0.png new file mode 100644 index 0000000000000000000000000000000000000000..31057161b8bd8b0c41c47f6b897072f6574dcc51 GIT binary patch literal 45283 zcmeIyu?j%}6b9gfu5|0}x|`KxwBm|elCUW$uV7F%o3~IlNgl%NF}#C~XE1+f_=hu| z&i|ce(@~b@X+&h@xR^&I=ZIRnQU7grtM?@0aV?A9a=+d-lS`|USA`q+12sSa2}wvo z5|WUFBqSjTNk~Exl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUFBqSjT zNk~Exl8}TXBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUFBqSjTNk~Exl8}TX zBq0e&NJ0{lkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUFBqSjTNk~Exl8}TXBq0e&NJ0{l zkc1>8Aqh!HLK2dYgd`*(2}wvo5|WUFBqSjTNk~Exl8}TXBq0e&NJ0{lkc1>8Aqh!H uLK2dYgd`*(2}wvo5|WUFBqSjTN%+5nw?RaA5tY~TbBN!R!)bBvZ;oG#pPNGf literal 0 HcmV?d00001 diff --git a/outputs/snapshot_1.png b/outputs/snapshot_1.png new file mode 100644 index 0000000000000000000000000000000000000000..d6594908031738ed4f22ea2154dda0c3bb244148 GIT binary patch literal 178697 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 literal 0 HcmV?d00001 diff --git a/outputs/snapshot_2.png b/outputs/snapshot_2.png new file mode 100644 index 0000000000000000000000000000000000000000..d07f9e7cc7f264d77991784e7332547e967600cd GIT binary patch literal 161268 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­68I+QvqB^vniFI4?lcePq6N##zSMG99C3 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 literal 0 HcmV?d00001 diff --git a/run_batch.sh b/run_batch.sh index 09852c2..84f3448 100755 --- a/run_batch.sh +++ b/run_batch.sh @@ -2,6 +2,7 @@ set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +DEFAULT_BATCH_CONFIG="${ROOT_DIR}/batch_jobs.cfg" if [[ "${1:-}" == "--batch-config" && -n "${2:-}" ]]; then BATCH_CONFIG="${2}" @@ -10,7 +11,11 @@ if [[ "${1:-}" == "--batch-config" && -n "${2:-}" ]]; then SNAPSHOTS="${2:-4}" OUT_DIR="${3:-outputs}" else - BATCH_CONFIG="" + if [[ -f "${DEFAULT_BATCH_CONFIG}" ]]; then + BATCH_CONFIG="${DEFAULT_BATCH_CONFIG}" + else + BATCH_CONFIG="" + fi STEPS="${1:-2000}" SNAPSHOTS="${2:-4}" OUT_DIR="${3:-outputs}" diff --git a/run_sim.sh b/run_sim.sh index 88cc623..3f2f15a 100755 --- a/run_sim.sh +++ b/run_sim.sh @@ -2,9 +2,14 @@ set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +DEFAULT_SIM_CONFIG="${ROOT_DIR}/simulation.cfg" if [[ ! -x "${ROOT_DIR}/build/Galaxy_simulation" ]]; then bash "${ROOT_DIR}/unix_run.sh" fi -exec "${ROOT_DIR}/build/Galaxy_simulation" "$@" +if [[ $# -eq 0 && -f "${DEFAULT_SIM_CONFIG}" ]]; then + exec "${ROOT_DIR}/build/Galaxy_simulation" --config "${DEFAULT_SIM_CONFIG}" +else + exec "${ROOT_DIR}/build/Galaxy_simulation" "$@" +fi diff --git a/shaders/blur.frag b/shaders/blur.frag index d74b483..1cf329d 100644 --- a/shaders/blur.frag +++ b/shaders/blur.frag @@ -17,10 +17,10 @@ const float weight[17] = float[] void main() { - vec2 result = vec2(0.); + vec3 result = vec3(0.); for (int i = 0; i < 17; i++) - result += texture(u_texture, v_blur_texcoord[i]).rg * weight[i]; + result += texture(u_texture, v_blur_texcoord[i]).rgb * weight[i]; - frag_color = vec4(result, 0., 1.); + frag_color = vec4(result, 1.); } diff --git a/shaders/galaxy.frag b/shaders/galaxy.frag index ab6823b..c9fc6e3 100644 --- a/shaders/galaxy.frag +++ b/shaders/galaxy.frag @@ -12,7 +12,9 @@ void main() if (v_starType > 0) { - frag_color = vec4(0.0, 0.0, brightness, 1.0); // regular mass (positive): blue + // Blue stars: bright blue compact core (not white) + softer blue body. + float core = 0.36 * brightness; + frag_color = vec4(0.0, 0.06 * core, 1.10 * brightness + 1.45 * core, 1.0); // regular mass (positive): blue } else { diff --git a/shaders/post.frag b/shaders/post.frag index 287b334..e3f32c5 100644 --- a/shaders/post.frag +++ b/shaders/post.frag @@ -14,6 +14,6 @@ void main() vec3 stars = galaxy_data.rgb; vec3 blur = texture(u_blur, v_texcoord).rgb; // Boost blue-channel bloom so positive stars get a glow comparable to negatives. - vec3 glow = vec3(0.20 * blur.r, 0.20 * blur.g, 0.34 * blur.b); + vec3 glow = vec3(0.20 * blur.r, 0.20 * blur.g, 0.22 * blur.b); frag_color = vec4(0.7 * (stars + glow), 1.0); } diff --git a/simulation.cfg b/simulation.cfg new file mode 100644 index 0000000..f2c5dc4 --- /dev/null +++ b/simulation.cfg @@ -0,0 +1,4 @@ +# Default interactive simulation config loaded by run_sim.sh when no args are passed. +# Set camera_view=top for top-down startup in normal simulation mode. + +SIMCFG simulation_type=Galaxy step=0.001000 smoothing_length=1.000000 interaction_rate=0.050000 nb_stars=20000 galaxy_diameter=100.000000 galaxy_thickness=5.000000 galaxies_distance=75.000000 stars_speed=20.000000 black_hole_mass=1000.000000 negative_attraction_constant=1.000000 repulsion_constant=1.000000 matter_distribution=CoreHalo type_diameter=40.000000 positive_ratio=0.500000 core_extra_negative_density=0.000000 camera_view=top diff --git a/sources/Menu.cpp b/sources/Menu.cpp index d48645a..b24e071 100644 --- a/sources/Menu.cpp +++ b/sources/Menu.cpp @@ -201,6 +201,13 @@ void Menu::display() } ImGui::NewLine(); + Simulator::CameraView previous_camera_view = Simulator::camera_view; + ImGui::Text("Camera view"); + ImGui::Combo("##camera_view", reinterpret_cast(&Simulator::camera_view), "Isometric\0Top"); + if (Simulator::camera_view != previous_camera_view) + Simulator::apply_camera_view(); + ImGui::NewLine(); + // Janus force multipliers (real-time). ImGui::Text("Negative Attraction Constant"); ImGui::SliderFloat("##Negative_Attraction_Constant", &negative_attraction_constant, -3.0f, 3.0f); diff --git a/sources/Simulator.cpp b/sources/Simulator.cpp index 7508b7c..15cfea8 100644 --- a/sources/Simulator.cpp +++ b/sources/Simulator.cpp @@ -2,6 +2,7 @@ #include #include #include +#include std::atomic Simulator::computation_done; std::atomic Simulator::reload; @@ -16,15 +17,14 @@ float Simulator::galaxy_thickness; float Simulator::galaxies_distance; float Simulator::stars_speed; float Simulator::black_hole_mass; +Simulator::CameraView Simulator::camera_view = Simulator::CameraView::Isometric; void Simulator::init() { dim::PerspectiveCamera cam(45.f, 1.f, 10000.f); cam.set_position(dim::Vector3(0.f, 0.f, 130.f)); - dim::Vector3 camera_pos = cam.get_position(); - camera_pos.set_phi(dim::pi / 3.f); - cam.set_position(camera_pos); dim::Window::set_camera(cam); + apply_camera_view(); dim::Window::set_controller(dim::OrbitController(dim::Vector3::null, dim::OrbitController::default_sensitivity, 2.f)); dim::Shader::add("galaxy", "shaders/galaxy.vert", "shaders/galaxy.frag"); @@ -101,6 +101,7 @@ std::string Simulator::configuration_line() << "type_diameter=" << Menu::type_diameter << " " << "positive_ratio=" << Menu::positive_ratio << " " << "core_extra_negative_density=" << Menu::core_extra_negative_density << " " + << "camera_view=" << (camera_view == CameraView::Top ? "top" : "isometric") << " " << "batch_steps=2000 " << "snapshots=4 " << "output_dir=outputs"; @@ -160,3 +161,30 @@ void Simulator::draw() Renderer::clear(); Renderer::draw(); } + +void Simulator::apply_camera_view() +{ + dim::Camera& camera = dim::Window::get_camera(); + const float radius = std::max(1.0f, camera.get_position().get_norm()); + + switch (camera_view) + { + case CameraView::Top: + { + const dim::Vector3 position(0.0f, radius, 0.001f); + camera.set_position(position); + camera.set_direction(-position); + break; + } + + case CameraView::Isometric: + default: + { + dim::Vector3 position(0.f, 0.f, radius); + position.set_phi(dim::pi / 3.f); + camera.set_position(position); + camera.set_direction(-position); + break; + } + } +} diff --git a/sources/main.cpp b/sources/main.cpp index 02f676a..4cc609b 100644 --- a/sources/main.cpp +++ b/sources/main.cpp @@ -108,6 +108,13 @@ static bool parse_matter_distribution(const std::string& text, MatterDistributio return false; } +static bool parse_camera_view(const std::string& text, Simulator::CameraView& value) +{ + if (text == "isometric" || text == "iso" || text == "0") { value = Simulator::CameraView::Isometric; return true; } + if (text == "top" || text == "1") { value = Simulator::CameraView::Top; return true; } + return false; +} + using ConfigKV = std::unordered_map; static ConfigKV parse_config_line(const std::string& raw) @@ -178,6 +185,12 @@ static bool apply_config_kv(const ConfigKV& kv, BatchOptions& batch, bool* outpu if (parse_matter_distribution(*v, distribution)) Menu::matter_distribution = distribution; } + if (const std::string* v = get("camera_view")) + { + Simulator::CameraView view = Simulator::camera_view; + if (parse_camera_view(*v, view)) + Simulator::camera_view = view; + } auto set_float = [&](const char* key, float& target) { @@ -322,6 +335,7 @@ int main(int argc, char** argv) { apply_config_kv(jobs.front(), mutable_batch_options); Simulator::restart(); + Simulator::apply_camera_view(); } } @@ -352,6 +366,7 @@ int main(int argc, char** argv) std::cout << "[Batch] Job " << (i + 1) << "/" << jobs.size() << std::endl; Simulator::restart(); + Simulator::apply_camera_view(); run_batch_mode(job_options, false); } From 055a6cfa538b6577ee6aa81d4c200ec3afc8816d Mon Sep 17 00:00:00 2001 From: Cittadhammo Bhikkhu Date: Wed, 18 Feb 2026 18:35:38 +0000 Subject: [PATCH 8/8] add cloud support --- README.md | 12 ++++++ cloud/README.md | 78 ++++++++++++++++++++++++++++++++++++ cloud/process_batch_queue.sh | 32 +++++++++++++++ cloud/run_headless_batch.sh | 14 +++++++ cloud/setup_ubuntu_vm.sh | 32 +++++++++++++++ cloud/start_live_vnc.sh | 75 ++++++++++++++++++++++++++++++++++ 6 files changed, 243 insertions(+) create mode 100644 cloud/README.md create mode 100755 cloud/process_batch_queue.sh create mode 100755 cloud/run_headless_batch.sh create mode 100755 cloud/setup_ubuntu_vm.sh create mode 100755 cloud/start_live_vnc.sh diff --git a/README.md b/README.md index 61af460..6f9a028 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ This repository contains the source code of an n-body type simulation using GPU * [โš™๏ธ Janus + Performance Update](#%EF%B8%8F-janus--performance-update) * [๐Ÿงช Batch Experiment Workflow](#-batch-experiment-workflow) * [โœ… Validate Optimized Runs](#-validate-optimized-runs) + * [โ˜๏ธ Cloud VM](#%EF%B8%8F-cloud-vm) * [๐Ÿงฉ Troubleshooting](#-troubleshooting) * **[๐Ÿ“ Changes](#-changes)** * **[๐Ÿงช Simulation variants](#-simulation-variants)** @@ -309,6 +310,17 @@ Notes: * Batch mode still needs an OpenGL/X11 context on Linux. * For server VMs without display, use a virtual display (for example `xvfb`) or add a future true headless mode. +## โ˜๏ธ Cloud VM + +For remote runs when your local machine is limited: + +* setup VM dependencies + build: `bash cloud/setup_ubuntu_vm.sh` +* run interactive mode over VNC: `VNC_PASSWORD='change_me' bash cloud/start_live_vnc.sh` +* run headless batch: `bash cloud/run_headless_batch.sh --batch-config batch_configs/example.batchcfg` +* run queued batch files: `bash cloud/process_batch_queue.sh` + +Full guide: [`cloud/README.md`](cloud/README.md) + ## ๐Ÿ“ Changes Detailed change log: see [`CHANGE.md`](CHANGE.md). diff --git a/cloud/README.md b/cloud/README.md new file mode 100644 index 0000000..4946902 --- /dev/null +++ b/cloud/README.md @@ -0,0 +1,78 @@ +# Cloud VM workflow (live + batch) + +This folder provides a practical way to run Galaxy_simulation on a Linux VM with limited local hardware. + +## What this gives you + +- Live mode on a VM using a virtual display and VNC. +- Batch mode on a VM using headless rendering via `xvfb`. +- A simple queue processor for many batch config files. + +## 1) Provision a VM + +Use Ubuntu 22.04/24.04 and at least 4 vCPUs if possible. + +On the VM: + +```bash +git clone --recurse-submodules +cd Galaxy_simulation +bash cloud/setup_ubuntu_vm.sh +``` + +## 2) Run interactive ("live") mode remotely + +Start the app with a virtual X server and VNC: + +```bash +cd Galaxy_simulation +VNC_PASSWORD='strong_password_here' bash cloud/start_live_vnc.sh +``` + +Default settings: + +- virtual display `:1` +- VNC port `5901` +- bound to localhost (`VNC_BIND_LOCALHOST=1`) for safer access + +Recommended SSH tunnel from your laptop: + +```bash +ssh -N -L 5901:127.0.0.1:5901 ubuntu@ +``` + +Then connect your VNC client to `127.0.0.1:5901`. + +## 3) Run one batch job headlessly + +```bash +cd Galaxy_simulation +bash cloud/run_headless_batch.sh 10000 6 outputs/run_100k +``` + +Or run from a batch config file: + +```bash +bash cloud/run_headless_batch.sh --batch-config batch_configs/example.batchcfg +``` + +## 4) Process a queue of batch files + +Put one `.cfg` file per queued run in `batch_queue/pending/`, then: + +```bash +bash cloud/process_batch_queue.sh +``` + +Files are moved to: + +- `batch_queue/done/` on success +- `batch_queue/failed/` on failure + +Outputs go to `outputs/queue//`. + +## Notes for 100k+ stars + +- This project still needs OpenGL context even in batch mode; `xvfb` solves this on headless VMs. +- `LIBGL_ALWAYS_SOFTWARE=1` forces Mesa software rendering; it works but is slower than real GPU. +- For highest star counts, batch mode is generally more stable than keeping interactive live mode running for long periods. diff --git a/cloud/process_batch_queue.sh b/cloud/process_batch_queue.sh new file mode 100755 index 0000000..0191602 --- /dev/null +++ b/cloud/process_batch_queue.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +QUEUE_DIR="${1:-${ROOT_DIR}/batch_queue/pending}" +DONE_DIR="${2:-${ROOT_DIR}/batch_queue/done}" +FAILED_DIR="${3:-${ROOT_DIR}/batch_queue/failed}" +OUTPUT_ROOT="${4:-${ROOT_DIR}/outputs/queue}" + +mkdir -p "${QUEUE_DIR}" "${DONE_DIR}" "${FAILED_DIR}" "${OUTPUT_ROOT}" + +shopt -s nullglob +jobs=( "${QUEUE_DIR}"/*.cfg ) +shopt -u nullglob + +if [[ ${#jobs[@]} -eq 0 ]]; then + echo "No queued batch files in ${QUEUE_DIR}" + exit 0 +fi + +for cfg in "${jobs[@]}"; do + name="$(basename "${cfg}" .cfg)" + out_dir="${OUTPUT_ROOT}/${name}" + echo "Processing ${cfg}" + if bash "${ROOT_DIR}/cloud/run_headless_batch.sh" --batch-config "${cfg}" 2000 4 "${out_dir}"; then + mv "${cfg}" "${DONE_DIR}/" + echo "Done: ${name}" + else + mv "${cfg}" "${FAILED_DIR}/" + echo "Failed: ${name}" + fi +done diff --git a/cloud/run_headless_batch.sh b/cloud/run_headless_batch.sh new file mode 100755 index 0000000..ced7598 --- /dev/null +++ b/cloud/run_headless_batch.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +if ! command -v xvfb-run >/dev/null 2>&1; then + echo "Error: xvfb-run not found. Install xvfb first." + exit 1 +fi + +export LIBGL_ALWAYS_SOFTWARE="${LIBGL_ALWAYS_SOFTWARE:-1}" + +exec xvfb-run -a -s "-screen 0 1920x1080x24" \ + bash "${ROOT_DIR}/run_batch.sh" "$@" diff --git a/cloud/setup_ubuntu_vm.sh b/cloud/setup_ubuntu_vm.sh new file mode 100755 index 0000000..cecd281 --- /dev/null +++ b/cloud/setup_ubuntu_vm.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +if ! command -v sudo >/dev/null 2>&1; then + echo "Error: sudo is required." + exit 1 +fi + +echo "[1/3] Installing system dependencies..." +sudo apt-get update +sudo apt-get install -y \ + git \ + build-essential \ + cmake \ + libglew-dev \ + freeglut3-dev \ + ocl-icd-opencl-dev \ + pocl-opencl-icd \ + xvfb \ + x11vnc \ + fluxbox \ + tmux + +echo "[2/3] Building Galaxy_simulation..." +bash "${ROOT_DIR}/unix_run.sh" + +echo "[3/3] Done." +echo "Try:" +echo " bash cloud/run_headless_batch.sh 4000 4 outputs/test_run" +echo " VNC_PASSWORD=change_me bash cloud/start_live_vnc.sh" diff --git a/cloud/start_live_vnc.sh b/cloud/start_live_vnc.sh new file mode 100755 index 0000000..485c950 --- /dev/null +++ b/cloud/start_live_vnc.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +DISPLAY_NUM="${DISPLAY_NUM:-:1}" +SCREEN_GEOMETRY="${SCREEN_GEOMETRY:-1920x1080x24}" +VNC_PORT="${VNC_PORT:-5901}" +VNC_BIND_LOCALHOST="${VNC_BIND_LOCALHOST:-1}" +SIM_ARGS=("$@") + +if ! command -v Xvfb >/dev/null 2>&1; then + echo "Error: Xvfb not found. Install xvfb first." + exit 1 +fi + +if ! command -v x11vnc >/dev/null 2>&1; then + echo "Error: x11vnc not found. Install x11vnc first." + exit 1 +fi + +VNC_AUTH_ARGS=() +if [[ -n "${VNC_PASSWORD:-}" ]]; then + PASS_FILE="$(mktemp)" + x11vnc -storepasswd "${VNC_PASSWORD}" "${PASS_FILE}" >/dev/null + VNC_AUTH_ARGS=(-rfbauth "${PASS_FILE}") +else + VNC_AUTH_ARGS=(-nopw) +fi + +VNC_BIND_ARGS=() +if [[ "${VNC_BIND_LOCALHOST}" == "1" ]]; then + VNC_BIND_ARGS=(-localhost) +fi + +cleanup() { + set +e + [[ -n "${SIM_PID:-}" ]] && kill "${SIM_PID}" >/dev/null 2>&1 + [[ -n "${VNC_PID:-}" ]] && kill "${VNC_PID}" >/dev/null 2>&1 + [[ -n "${WM_PID:-}" ]] && kill "${WM_PID}" >/dev/null 2>&1 + [[ -n "${XVFB_PID:-}" ]] && kill "${XVFB_PID}" >/dev/null 2>&1 + [[ -n "${PASS_FILE:-}" ]] && rm -f "${PASS_FILE}" +} +trap cleanup EXIT INT TERM + +echo "Starting virtual display ${DISPLAY_NUM} (${SCREEN_GEOMETRY})..." +Xvfb "${DISPLAY_NUM}" -screen 0 "${SCREEN_GEOMETRY}" >/tmp/galaxy_xvfb.log 2>&1 & +XVFB_PID=$! + +echo "Starting lightweight window manager..." +DISPLAY="${DISPLAY_NUM}" fluxbox >/tmp/galaxy_fluxbox.log 2>&1 & +WM_PID=$! + +echo "Starting VNC server on port ${VNC_PORT}..." +x11vnc \ + -display "${DISPLAY_NUM}" \ + -rfbport "${VNC_PORT}" \ + -forever \ + -shared \ + "${VNC_BIND_ARGS[@]}" \ + "${VNC_AUTH_ARGS[@]}" \ + >/tmp/galaxy_x11vnc.log 2>&1 & +VNC_PID=$! + +echo "Launching simulation..." +echo "VNC logs: /tmp/galaxy_x11vnc.log" +echo "Display logs: /tmp/galaxy_xvfb.log" +echo "Window-manager logs: /tmp/galaxy_fluxbox.log" + +export DISPLAY="${DISPLAY_NUM}" +export LIBGL_ALWAYS_SOFTWARE="${LIBGL_ALWAYS_SOFTWARE:-1}" +bash "${ROOT_DIR}/run_sim.sh" "${SIM_ARGS[@]}" & +SIM_PID=$! + +wait "${SIM_PID}"