From 6cc5a7310ab6372c7f3b2fb64a93565f3ffe68d0 Mon Sep 17 00:00:00 2001 From: Ben Ashbaugh Date: Mon, 30 Jun 2025 11:49:02 -0700 Subject: [PATCH 1/3] add a global variable pointer sample --- samples/99_globalvar/CMakeLists.txt | 10 ++ samples/99_globalvar/main.cpp | 237 ++++++++++++++++++++++++++++ samples/CMakeLists.txt | 2 + 3 files changed, 249 insertions(+) create mode 100644 samples/99_globalvar/CMakeLists.txt create mode 100644 samples/99_globalvar/main.cpp diff --git a/samples/99_globalvar/CMakeLists.txt b/samples/99_globalvar/CMakeLists.txt new file mode 100644 index 00000000..efb9ddfd --- /dev/null +++ b/samples/99_globalvar/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2025 Ben Ashbaugh +# +# SPDX-License-Identifier: MIT + +add_opencl_sample( + TEST + NUMBER 99 + TARGET globalvar + VERSION 210 + SOURCES main.cpp) diff --git a/samples/99_globalvar/main.cpp b/samples/99_globalvar/main.cpp new file mode 100644 index 00000000..8aef15d0 --- /dev/null +++ b/samples/99_globalvar/main.cpp @@ -0,0 +1,237 @@ +/* +// Copyright (c) 2019-2025 Ben Ashbaugh +// +// SPDX-License-Identifier: MIT +*/ + +#include + +#include + +#include +#include + +#include "util.hpp" + +static std::vector readSPIRVFromFile( + const std::string& filename ) +{ + std::ifstream is(filename, std::ios::binary); + std::vector ret; + if (!is.good()) { + printf("Couldn't open file '%s'!\n", filename.c_str()); + return ret; + } + + size_t filesize = 0; + is.seekg(0, std::ios::end); + filesize = (size_t)is.tellg(); + is.seekg(0, std::ios::beg); + + ret.reserve(filesize); + ret.insert( + ret.begin(), + std::istreambuf_iterator(is), + std::istreambuf_iterator() ); + + return ret; +} + +static cl::Program createProgramWithIL( + const cl::Context& context, + const std::vector& il ) +{ + cl_program program = nullptr; + + // Use the core clCreateProgramWithIL if a device supports OpenCL 2.1 or + // newer and SPIR-V. + bool useCore = false; + + // Use the extension clCreateProgramWithILKHR if a device supports + // cl_khr_il_program. + bool useExtension = false; + + std::vector devices = context.getInfo(); + for (auto device : devices) { +#ifdef CL_VERSION_2_1 + // Note: This could look for "SPIR-V" in CL_DEVICE_IL_VERSION. + if (getDeviceOpenCLVersion(device) >= CL_MAKE_VERSION(2, 1, 0) && + !device.getInfo().empty()) { + useCore = true; + } +#endif + if (checkDeviceForExtension(device, "cl_khr_il_program")) { + useExtension = true; + } + } + +#ifdef CL_VERSION_2_1 + if (useCore) { + program = clCreateProgramWithIL( + context(), + il.data(), + il.size(), + nullptr); + } + else +#endif + if (useExtension) { + cl::Platform platform{ devices[0].getInfo() }; + + auto clCreateProgramWithILKHR_ = (clCreateProgramWithILKHR_fn) + clGetExtensionFunctionAddressForPlatform( + platform(), + "clCreateProgramWithILKHR"); + + if (clCreateProgramWithILKHR_) { + program = clCreateProgramWithILKHR_( + context(), + il.data(), + il.size(), + nullptr); + } + } + + return cl::Program{ program }; +} + +int main( + int argc, + char** argv ) +{ + int platformIndex = 0; + int deviceIndex = 0; + + std::string fileName(sizeof(void*) == 8 ? "sample_kernel64.spv" : "sample_kernel32.spv"); + std::string buildOptions; + + { + popl::OptionParser op("Supported Options"); + op.add>("p", "platform", "Platform Index", platformIndex, &platformIndex); + op.add>("d", "device", "Device Index", deviceIndex, &deviceIndex); + op.add>("", "file", "Kernel File Name", fileName, &fileName); + op.add>("", "options", "Program Build Options", buildOptions, &buildOptions); + bool printUsage = false; + try { + op.parse(argc, argv); + } catch (std::exception& e) { + fprintf(stderr, "Error: %s\n\n", e.what()); + printUsage = true; + } + + if (printUsage || !op.unknown_options().empty() || !op.non_option_args().empty()) { + fprintf(stderr, + "Usage: globalvar [options]\n" + "%s", op.help().c_str()); + return -1; + } + } + + std::vector platforms; + cl::Platform::get(&platforms); + cl::Platform& platform = platforms[platformIndex]; + + printf("Running on platform: %s\n", + platform.getInfo().c_str() ); + + std::vector devices; + platform.getDevices(CL_DEVICE_TYPE_ALL, &devices); + cl::Device& device = devices[deviceIndex]; + + printf("Running on device: %s\n", + device.getInfo().c_str() ); + printf("CL_DEVICE_ADDRESS_BITS is %d for this device.\n", + device.getInfo() ); + + // Check for SPIR-V support. If the device supports OpenCL 2.1 or newer + // we can use the core clCreateProgramWithIL API. Otherwise, if the device + // the cl_khr_il_program extension we can use the clCreateProgramWithILKHR + // extension API. If neither is supported then we cannot run this sample. +#ifdef CL_VERSION_2_1 + // Note: This could look for "SPIR-V" in CL_DEVICE_IL_VERSION. + if (getDeviceOpenCLVersion(device) >= CL_MAKE_VERSION(2, 1, 0) && + !device.getInfo().empty()) { + printf("Device supports OpenCL 2.1 or newer, using clCreateProgramWithIL.\n"); + } else +#endif + if (checkDeviceForExtension(device, "cl_khr_il_program")) { + printf("Device supports cl_khr_il_program, using clCreateProgramWithILKHR.\n"); + } else { + printf("Device does not support SPIR-V, exiting.\n"); + return -1; + } + + cl::Context context{device}; + cl::CommandQueue commandQueue{context, device}; + + printf("Reading SPIR-V from file: %s\n", fileName.c_str()); + std::vector spirv = readSPIRVFromFile(fileName); + + printf("Building program with build options: %s\n", + buildOptions.empty() ? "(none)" : buildOptions.c_str() ); + cl::Program program = createProgramWithIL( context, spirv ); + program.build(buildOptions.c_str()); + for( auto& device : program.getInfo() ) + { + printf("Program build log for device %s:\n", + device.getInfo().c_str() ); + printf("%s\n", + program.getBuildInfo(device).c_str() ); + } + + typedef cl_int CL_API_CALL + clGetDeviceGlobalVariablePointerINTEL_t( + cl_device_id device, + cl_program program, + const char *globalVariableName, + size_t *globalVariableSizeRet, + void **globalVariablePointerRet); + + typedef clGetDeviceGlobalVariablePointerINTEL_t * + clGetDeviceGlobalVariablePointerINTEL_fn; + + typedef cl_int CL_API_CALL + clGetMemAllocInfoINTEL_t( + cl_context context, + const void* ptr, + cl_mem_info_intel param_name, + size_t param_value_size, + void* param_value, + size_t* param_value_size_ret); + + typedef clGetMemAllocInfoINTEL_t * + clGetMemAllocInfoINTEL_fn ; + + auto clGetDeviceGlobalVariablePointerINTEL = (clGetDeviceGlobalVariablePointerINTEL_fn) + clGetExtensionFunctionAddressForPlatform(platform(), "clGetDeviceGlobalVariablePointerINTEL"); + + auto clGetMemAllocInfoINTEL = (clGetMemAllocInfoINTEL_fn) + clGetExtensionFunctionAddressForPlatform(platform(), "clGetMemAllocInfoINTEL"); + + if (clGetDeviceGlobalVariablePointerINTEL == nullptr) { + printf("Couldn't get function pointer for clGetDeviceGlobalVariablePointerINTEL!\n"); + } else if (clGetMemAllocInfoINTEL == nullptr) { + printf("Couldn't get function pointer for clGetMemAllocInfoINTEL!\n"); + } else { + cl_int errorCode = CL_SUCCESS; + size_t gvsize = 0; void* gvptr = nullptr; + errorCode = clGetDeviceGlobalVariablePointerINTEL( + device(), program(), "uid67f037ed289236e5____ZL2dg", &gvsize, &gvptr); + printf("clGetDeviceGlobalVariablePointerINTEL with uid67f037ed289236e5____ZL2dg returned %d: %zu %p\n", errorCode, gvsize, gvptr); + + gvsize = 0; gvptr = nullptr; + errorCode = clGetDeviceGlobalVariablePointerINTEL( + device(), program(), "_ZL2dg", &gvsize, &gvptr); + printf("clGetDeviceGlobalVariablePointerINTEL with _ZL2dg returned %d: %zu %p\n", errorCode, gvsize, gvptr); + + cl_unified_shared_memory_type_intel gvtype = 0; + errorCode = clGetMemAllocInfoINTEL( + context(), gvptr, CL_MEM_ALLOC_TYPE_INTEL, sizeof(gvtype), &gvtype, nullptr); + + printf("clGetMemAllocInfoINTEL returned %d: %04X\n", errorCode, gvtype); + } + + printf("Done.\n"); + + return 0; +} diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 6eb2ebee..903f75b2 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -78,6 +78,8 @@ add_subdirectory( 06_ndrangekernelfromfile ) add_subdirectory( 10_queueexperiments ) add_subdirectory( 16_floatatomics ) +add_subdirectory( 99_globalvar ) + set(BUILD_EXTENSION_SAMPLES TRUE) if(NOT TARGET OpenCLExt) message(STATUS "Skipping Extension Samples - OpenCL Extension Loader is not found.") From e916b1d92a271e886dbab2315593fd82f5f21a4b Mon Sep 17 00:00:00 2001 From: Ben Ashbaugh Date: Thu, 26 Mar 2026 13:19:47 -0700 Subject: [PATCH 2/3] update and add a test SPIR-V file --- samples/99_globalvar/CMakeLists.txt | 5 ++-- samples/99_globalvar/device_global64.spv | Bin 0 -> 364 bytes samples/99_globalvar/device_global64.spvasm | 27 ++++++++++++++++++++ samples/99_globalvar/main.cpp | 12 ++++----- samples/99_globalvar/to_spv.sh | 2 ++ 5 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 samples/99_globalvar/device_global64.spv create mode 100644 samples/99_globalvar/device_global64.spvasm create mode 100644 samples/99_globalvar/to_spv.sh diff --git a/samples/99_globalvar/CMakeLists.txt b/samples/99_globalvar/CMakeLists.txt index efb9ddfd..2c265db6 100644 --- a/samples/99_globalvar/CMakeLists.txt +++ b/samples/99_globalvar/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2025 Ben Ashbaugh +# Copyright (c) 2025-2026 Ben Ashbaugh # # SPDX-License-Identifier: MIT @@ -7,4 +7,5 @@ add_opencl_sample( NUMBER 99 TARGET globalvar VERSION 210 - SOURCES main.cpp) + SOURCES main.cpp + KERNELS device_global64.spv) diff --git a/samples/99_globalvar/device_global64.spv b/samples/99_globalvar/device_global64.spv new file mode 100644 index 0000000000000000000000000000000000000000..a6fa14a73f9467f7863bf0db4d43e1b6fbfcf59f GIT binary patch literal 364 zcmXX=T?+wG6dV@oqexO7$&-&fqLlKWr6fgOZ0XqXwP%~1bLY(YaI#$& zxeNdo75)`xSG2tO+%e&%)MKWM(?>^x1Ht9WL`F@1Y_^ Date: Thu, 26 Mar 2026 14:27:41 -0700 Subject: [PATCH 3/3] clean up and simplify the tester --- samples/99_globalvar/main.cpp | 200 ++++++++++++++++++---------------- 1 file changed, 106 insertions(+), 94 deletions(-) diff --git a/samples/99_globalvar/main.cpp b/samples/99_globalvar/main.cpp index e3cee252..65371c9f 100644 --- a/samples/99_globalvar/main.cpp +++ b/samples/99_globalvar/main.cpp @@ -13,11 +13,11 @@ #include "util.hpp" -static std::vector readSPIRVFromFile( +static std::vector readSPIRVFromFile( const std::string& filename ) { std::ifstream is(filename, std::ios::binary); - std::vector ret; + std::vector ret; if (!is.good()) { printf("Couldn't open file '%s'!\n", filename.c_str()); return ret; @@ -37,67 +37,7 @@ static std::vector readSPIRVFromFile( return ret; } -static cl::Program createProgramWithIL( - const cl::Context& context, - const std::vector& il ) -{ - cl_program program = nullptr; - - // Use the core clCreateProgramWithIL if a device supports OpenCL 2.1 or - // newer and SPIR-V. - bool useCore = false; - - // Use the extension clCreateProgramWithILKHR if a device supports - // cl_khr_il_program. - bool useExtension = false; - - std::vector devices = context.getInfo(); - for (auto device : devices) { -#ifdef CL_VERSION_2_1 - // Note: This could look for "SPIR-V" in CL_DEVICE_IL_VERSION. - if (getDeviceOpenCLVersion(device) >= CL_MAKE_VERSION(2, 1, 0) && - !device.getInfo().empty()) { - useCore = true; - } -#endif - if (checkDeviceForExtension(device, "cl_khr_il_program")) { - useExtension = true; - } - } - -#ifdef CL_VERSION_2_1 - if (useCore) { - program = clCreateProgramWithIL( - context(), - il.data(), - il.size(), - nullptr); - } - else -#endif - if (useExtension) { - cl::Platform platform{ devices[0].getInfo() }; - - auto clCreateProgramWithILKHR_ = (clCreateProgramWithILKHR_fn) - clGetExtensionFunctionAddressForPlatform( - platform(), - "clCreateProgramWithILKHR"); - - if (clCreateProgramWithILKHR_) { - program = clCreateProgramWithILKHR_( - context(), - il.data(), - il.size(), - nullptr); - } - } - - return cl::Program{ program }; -} - -int main( - int argc, - char** argv ) +int main(int argc, char** argv ) { int platformIndex = 0; int deviceIndex = 0; @@ -131,45 +71,25 @@ int main( cl::Platform::get(&platforms); cl::Platform& platform = platforms[platformIndex]; - printf("Running on platform: %s\n", - platform.getInfo().c_str() ); + printf("Running on platform: %s\n", platform.getInfo().c_str() ); std::vector devices; platform.getDevices(CL_DEVICE_TYPE_ALL, &devices); cl::Device& device = devices[deviceIndex]; - printf("Running on device: %s\n", - device.getInfo().c_str() ); - printf("CL_DEVICE_ADDRESS_BITS is %d for this device.\n", - device.getInfo() ); - - // Check for SPIR-V support. If the device supports OpenCL 2.1 or newer - // we can use the core clCreateProgramWithIL API. Otherwise, if the device - // the cl_khr_il_program extension we can use the clCreateProgramWithILKHR - // extension API. If neither is supported then we cannot run this sample. -#ifdef CL_VERSION_2_1 - // Note: This could look for "SPIR-V" in CL_DEVICE_IL_VERSION. - if (getDeviceOpenCLVersion(device) >= CL_MAKE_VERSION(2, 1, 0) && - !device.getInfo().empty()) { - printf("Device supports OpenCL 2.1 or newer, using clCreateProgramWithIL.\n"); - } else -#endif - if (checkDeviceForExtension(device, "cl_khr_il_program")) { - printf("Device supports cl_khr_il_program, using clCreateProgramWithILKHR.\n"); - } else { - printf("Device does not support SPIR-V, exiting.\n"); - return -1; - } + printf("Running on device: %s\n", device.getInfo().c_str() ); + printf("Running on drivers: %s\n", device.getInfo().c_str() ); + printf("CL_DEVICE_ADDRESS_BITS is %d for this device.\n", device.getInfo() ); cl::Context context{device}; cl::CommandQueue commandQueue{context, device}; printf("Reading SPIR-V from file: %s\n", fileName.c_str()); - std::vector spirv = readSPIRVFromFile(fileName); + std::vector spirv = readSPIRVFromFile(fileName); printf("Building program with build options: %s\n", buildOptions.empty() ? "(none)" : buildOptions.c_str() ); - cl::Program program = createProgramWithIL( context, spirv ); + cl::Program program{context, spirv}; program.build(buildOptions.c_str()); for( auto& device : program.getInfo() ) { @@ -208,6 +128,9 @@ int main( auto clGetMemAllocInfoINTEL = (clGetMemAllocInfoINTEL_fn) clGetExtensionFunctionAddressForPlatform(platform(), "clGetMemAllocInfoINTEL"); + constexpr const char* HostAccessName = "HostAccessName"; + constexpr const char* ExportName = "ExportName"; + if (clGetDeviceGlobalVariablePointerINTEL == nullptr) { printf("Couldn't get function pointer for clGetDeviceGlobalVariablePointerINTEL!\n"); } else if (clGetMemAllocInfoINTEL == nullptr) { @@ -216,13 +139,13 @@ int main( cl_int errorCode = CL_SUCCESS; size_t gvsize = 0; void* gvptr = nullptr; errorCode = clGetDeviceGlobalVariablePointerINTEL( - device(), program(), "HostAccessName", &gvsize, &gvptr); - printf("clGetDeviceGlobalVariablePointerINTEL with HostAccessName returned %d: %zu %p\n", errorCode, gvsize, gvptr); + device(), program(), HostAccessName, &gvsize, &gvptr); + printf("clGetDeviceGlobalVariablePointerINTEL with %s returned %d: %p (size %zu)\n", HostAccessName, errorCode, gvptr, gvsize); gvsize = 0; gvptr = nullptr; errorCode = clGetDeviceGlobalVariablePointerINTEL( - device(), program(), "ExportName", &gvsize, &gvptr); - printf("clGetDeviceGlobalVariablePointerINTEL with ExportName returned %d: %zu %p\n", errorCode, gvsize, gvptr); + device(), program(), ExportName, &gvsize, &gvptr); + printf("clGetDeviceGlobalVariablePointerINTEL with %s returned %d: %p (size %zu)\n", ExportName, errorCode, gvptr, gvsize); cl_unified_shared_memory_type_intel gvtype = 0; errorCode = clGetMemAllocInfoINTEL( @@ -231,7 +154,96 @@ int main( printf("clGetMemAllocInfoINTEL returned %d: %04X\n", errorCode, gvtype); } - printf("Done.\n"); + typedef cl_int CL_API_CALL + clEnqueueWriteGlobalVariableINTEL_t( + cl_command_queue command_queue, + cl_program program, + const char* name, + cl_bool blocking_write, + size_t size, + size_t offset, + const void* ptr, + cl_uint num_events_in_wait_list, + const cl_event* event_wait_list, + cl_event* event); + + typedef clEnqueueWriteGlobalVariableINTEL_t * + clEnqueueWriteGlobalVariableINTEL_fn; + + auto clEnqueueWriteGlobalVariableINTEL = (clEnqueueWriteGlobalVariableINTEL_fn) + clGetExtensionFunctionAddressForPlatform(platform(), "clEnqueueWriteGlobalVariableINTEL"); + + if (clEnqueueWriteGlobalVariableINTEL == nullptr) { + printf("Couldn't get function pointer for clEnqueueWriteGlobalVariableINTEL!\n"); + } else { + const int value = 0xDEADBEEF; + cl_int errorCode; + + errorCode = clEnqueueWriteGlobalVariableINTEL( + commandQueue(), + program(), + HostAccessName, + CL_TRUE, + sizeof(value), 0, &value, + 0, nullptr, nullptr); + printf("clEnqueueWriteGlobalVariableINTEL with %s to write %08X returned %d\n", HostAccessName, value, errorCode); + + errorCode = clEnqueueWriteGlobalVariableINTEL( + commandQueue(), + program(), + ExportName, + CL_TRUE, + sizeof(value), 0, &value, + 0, nullptr, nullptr); + printf("clEnqueueWriteGlobalVariableINTEL with %s to write %08X returned %d\n", ExportName, value, errorCode); + } + typedef cl_int CL_API_CALL + clEnqueueReadGlobalVariableINTEL_t( + cl_command_queue command_queue, + cl_program program, + const char* name, + cl_bool blocking_read, + size_t size, + size_t offset, + void* ptr, + cl_uint num_events_in_wait_list, + const cl_event* event_wait_list, + cl_event* event); + + typedef clEnqueueReadGlobalVariableINTEL_t * + clEnqueueReadGlobalVariableINTEL_fn; + + auto clEnqueueReadGlobalVariableINTEL = (clEnqueueReadGlobalVariableINTEL_fn) + clGetExtensionFunctionAddressForPlatform(platform(), "clEnqueueReadGlobalVariableINTEL"); + + if (clEnqueueReadGlobalVariableINTEL == nullptr) { + printf("Couldn't get function pointer for clEnqueueReadGlobalVariableINTEL!\n"); + } else { + int value; + cl_int errorCode; + + value = -1; + errorCode = clEnqueueReadGlobalVariableINTEL( + commandQueue(), + program(), + HostAccessName, + CL_TRUE, + sizeof(value), 0, &value, + 0, nullptr, nullptr); + printf("clEnqueueReadGlobalVariableINTEL with %s returned %d, read %08X\n", HostAccessName, errorCode, value); + + value = -1; + errorCode = clEnqueueReadGlobalVariableINTEL( + commandQueue(), + program(), + ExportName, + CL_TRUE, + sizeof(value), 0, &value, + 0, nullptr, nullptr); + printf("clEnqueueReadGlobalVariableINTEL with %s returned %d, read %08X\n", ExportName, errorCode, value); + } + + printf("Done.\n"); return 0; }