diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e9aafd5..5487668 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -66,6 +66,13 @@ jobs: repository: bashbaug/opencl-extension-loader path: external/opencl-extension-loader + - name: Get SPIR-V Headers + if: matrix.ext == 'YES' + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + repository: KhronosGroup/SPIRV-Headers + path: external/SPIRV-Headers + - name: Create Build Directory run: cmake -E make_directory ${{runner.workspace}}/build diff --git a/CMakeLists.txt b/CMakeLists.txt index b055038..3b73eec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,12 @@ else() message(STATUS "OpenCL Extension Loader is not found.") endif() +if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/external/SPIRV-Headers) + add_subdirectory(external/SPIRV-Headers) +else() + message(STATUS "SPIR-V Headers are not found.") +endif() + if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) enable_testing() endif() diff --git a/README.md b/README.md index 5c92553..a5e4ff3 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,10 @@ Many samples that use extensions additionally require the OpenCL Extension Loade git clone https://github.com/bashbaug/opencl-extension-loader external/opencl-extension-loader +Several samples that interact with SPIR-V require the SPIR-V headres: + + git clone https://github.com/KhronosGroup/SPIRV-Headers external/SPIRV-Headers + After satisfying the external dependencies create build files using CMake. For example: mkdir build && cd build diff --git a/include/CL/opencl.hpp b/include/CL/opencl.hpp index 4b267a8..d9ee805 100644 --- a/include/CL/opencl.hpp +++ b/include/CL/opencl.hpp @@ -1800,6 +1800,12 @@ CL_HPP_DECLARE_PARAM_TRAITS_(cl_mutable_command_info_khr, CL_MUTABLE_DISPATCH_LO CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_KERNEL_CLOCK_CAPABILITIES_KHR, cl_device_kernel_clock_capabilities_khr) #endif /* cl_khr_kernel_clock */ +#if defined(cl_khr_spirv_queries) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_SPIRV_EXTENDED_INSTRUCTION_SETS_KHR, cl::vector) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_SPIRV_EXTENSIONS_KHR, cl::vector) +CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_SPIRV_CAPABILITIES_KHR, cl::vector) +#endif /* cl_khr_spirv_queries */ + #if defined(cl_ext_float_atomics) CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_SINGLE_FP_ATOMIC_CAPABILITIES_EXT, cl_device_fp_atomic_capabilities_ext) CL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_DOUBLE_FP_ATOMIC_CAPABILITIES_EXT, cl_device_fp_atomic_capabilities_ext) diff --git a/include/layer_util.hpp b/include/layer_util.hpp index e07d310..8c6847d 100644 --- a/include/layer_util.hpp +++ b/include/layer_util.hpp @@ -77,7 +77,7 @@ static inline cl_int writeStringToMemory( return CL_SUCCESS; } -static cl_uint getOpenCLVersionFromString( +static cl_version getOpenCLVersionFromString( const char* str) { cl_uint major = 0; @@ -105,7 +105,7 @@ static cl_uint getOpenCLVersionFromString( } } - return (major << 16) | minor; + return CL_MAKE_VERSION(major, minor, 0); } static inline bool checkStringForExtension( diff --git a/include/util.hpp b/include/util.hpp index e659fc8..4b7d478 100644 --- a/include/util.hpp +++ b/include/util.hpp @@ -8,7 +8,7 @@ #include #include -static cl_uint getDeviceOpenCLVersion( +static cl_version getDeviceOpenCLVersion( const cl::Device& device) { cl_uint major = 0; @@ -36,7 +36,7 @@ static cl_uint getDeviceOpenCLVersion( } } - return (major << 16) | minor; + return CL_MAKE_VERSION(major, minor, 0); } static bool checkDeviceForExtension( diff --git a/layers/10_cmdbufemu/emulate.cpp b/layers/10_cmdbufemu/emulate.cpp index d962f47..6584eeb 100644 --- a/layers/10_cmdbufemu/emulate.cpp +++ b/layers/10_cmdbufemu/emulate.cpp @@ -2897,7 +2897,7 @@ bool clGetDeviceInfo_override( deviceExtensions.data(), CL_KHR_COMMAND_BUFFER_EXTENSION_NAME ) == false && getOpenCLVersionFromString( - deviceVersion.data() ) >= 0x00020001) + deviceVersion.data() ) >= CL_MAKE_VERSION(2, 1, 0)) { std::string newExtensions; newExtensions += CL_KHR_COMMAND_BUFFER_EXTENSION_NAME; @@ -2981,7 +2981,7 @@ bool clGetDeviceInfo_override( if( found == false && getOpenCLVersionFromString( - deviceVersion.data() ) >= 0x00020001) + deviceVersion.data() ) >= CL_MAKE_VERSION(2, 1, 0)) { { extensions.emplace_back(); @@ -3246,7 +3246,7 @@ bool clGetPlatformInfo_override( platformExtensions.data(), CL_KHR_COMMAND_BUFFER_EXTENSION_NAME ) == false && getOpenCLVersionFromString( - platformVersion.data() ) >= 0x00020001) + platformVersion.data() ) >= CL_MAKE_VERSION(2, 1, 0)) { std::string newExtensions; newExtensions += CL_KHR_COMMAND_BUFFER_EXTENSION_NAME; @@ -3330,7 +3330,7 @@ bool clGetPlatformInfo_override( if( found == false && getOpenCLVersionFromString( - platformVersion.data() ) >= 0x00020001) + platformVersion.data() ) >= CL_MAKE_VERSION(2, 1, 0)) { { extensions.emplace_back(); diff --git a/layers/11_semaemu/CMakeLists.txt b/layers/11_semaemu/CMakeLists.txt index a721c8d..997ffc5 100644 --- a/layers/11_semaemu/CMakeLists.txt +++ b/layers/11_semaemu/CMakeLists.txt @@ -3,7 +3,7 @@ # SPDX-License-Identifier: MIT add_opencl_layer( - NUMBER 10 + NUMBER 11 TARGET SemaEmu VERSION 300 SOURCES main.cpp emulate.cpp emulate.h) diff --git a/layers/12_spirvqueriesemu/CMakeLists.txt b/layers/12_spirvqueriesemu/CMakeLists.txt new file mode 100644 index 0000000..e3c4fe8 --- /dev/null +++ b/layers/12_spirvqueriesemu/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2025 Ben Ashbaugh +# +# SPDX-License-Identifier: MIT + +add_opencl_layer( + NUMBER 12 + TARGET SpirvQueriesEmu + VERSION 300 + SOURCES main.cpp emulate.cpp emulate.h + INCLUDES ${SPIRV-Headers_SOURCE_DIR}/include) diff --git a/layers/12_spirvqueriesemu/emulate.cpp b/layers/12_spirvqueriesemu/emulate.cpp new file mode 100644 index 0000000..d5cabef --- /dev/null +++ b/layers/12_spirvqueriesemu/emulate.cpp @@ -0,0 +1,858 @@ +/* +// Copyright (c) 2025 Ben Ashbaugh +// +// SPDX-License-Identifier: MIT +*/ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "layer_util.hpp" + +#include "emulate.h" + +static constexpr cl_version version_cl_khr_subgroup_queries = + CL_MAKE_VERSION(0, 1, 0); + +struct SDeviceInfo +{ + bool supports_cl_khr_subgroup_queries = true; + + std::vector ExtendedInstructionSets; + std::vector Extensions; + std::vector Capabilities; +}; + +struct SLayerContext +{ + SLayerContext() + { + cl_uint numPlatforms = 0; + g_pNextDispatch->clGetPlatformIDs( + 0, + nullptr, + &numPlatforms); + + std::vector platforms; + platforms.resize(numPlatforms); + g_pNextDispatch->clGetPlatformIDs( + numPlatforms, + platforms.data(), + nullptr); + + for (auto platform : platforms) { + getSPIRVQueriesForPlatform(platform); + } + } + + const SDeviceInfo& getDeviceInfo(cl_device_id device) const + { + // TODO: query the parent device if this is a sub-device? + return m_DeviceInfo.at(device); + } + + const SDeviceInfo& getDeviceInfo(cl_device_id device) + { + return m_DeviceInfo[device]; + } + +private: + std::map m_DeviceInfo; + + void getSPIRVQueriesForPlatform(cl_platform_id platform) + { + cl_uint numDevices = 0; + g_pNextDispatch->clGetDeviceIDs( + platform, + CL_DEVICE_TYPE_ALL, + 0, + nullptr, + &numDevices); + + std::vector devices; + devices.resize(numDevices); + g_pNextDispatch->clGetDeviceIDs( + platform, + CL_DEVICE_TYPE_ALL, + numDevices, + devices.data(), + nullptr); + + for (auto device : devices) { + SDeviceInfo& deviceInfo = m_DeviceInfo[device]; + + size_t size = 0; + + std::string deviceExtensions; + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_EXTENSIONS, + 0, + nullptr, + &size); + if (size) { + deviceExtensions.resize(size); + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_EXTENSIONS, + size, + &deviceExtensions[0], + nullptr); + deviceExtensions.pop_back(); + deviceInfo.supports_cl_khr_subgroup_queries = + checkStringForExtension( + deviceExtensions.c_str(), + CL_KHR_SPIRV_QUERIES_EXTENSION_NAME); + } + + std::string deviceILVersion; + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_IL_VERSION, + 0, + nullptr, + &size); + if (size) { + deviceILVersion.resize(size); + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_IL_VERSION, + size, + &deviceILVersion[0], + nullptr); + deviceILVersion.pop_back(); + } + + if (deviceInfo.supports_cl_khr_subgroup_queries == false && + deviceILVersion.find("SPIR-V") != std::string::npos) { + + cl_version deviceVersion = CL_MAKE_VERSION(0, 0, 0); + std::string deviceVersionString; + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_VERSION, + 0, + nullptr, + &size); + if (size) { + deviceVersionString.resize(size); + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_VERSION, + size, + &deviceVersionString[0], + nullptr); + deviceVersionString.pop_back(); + deviceVersion = getOpenCLVersionFromString( + deviceVersionString.c_str()); + } + + std::string deviceProfile; + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_PROFILE, + 0, + nullptr, + &size); + if (size) { + deviceProfile.resize(size); + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_PROFILE, + size, + &deviceProfile[0], + nullptr); + deviceProfile.pop_back(); + } + + cl_bool deviceImageSupport = CL_FALSE; + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_IMAGE_SUPPORT, + sizeof(deviceImageSupport), + &deviceImageSupport, + nullptr); + + cl_uint deviceMaxReadWriteImageArgs = 0; + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_MAX_READ_WRITE_IMAGE_ARGS, + sizeof(deviceMaxReadWriteImageArgs), + &deviceMaxReadWriteImageArgs, + nullptr); + + cl_uint deviceMaxNumSubGroups = 0; + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_MAX_NUM_SUB_GROUPS, + sizeof(deviceMaxNumSubGroups), + &deviceMaxNumSubGroups, + nullptr); + + cl_bool deviceGenericAddressSpaceSupport = CL_FALSE; + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_GENERIC_ADDRESS_SPACE_SUPPORT, + sizeof(deviceGenericAddressSpaceSupport), + &deviceGenericAddressSpaceSupport, + nullptr); + + cl_bool deviceWorkGroupCollectiveFunctionsSupport = CL_FALSE; + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_WORK_GROUP_COLLECTIVE_FUNCTIONS_SUPPORT, + sizeof(deviceWorkGroupCollectiveFunctionsSupport), + &deviceWorkGroupCollectiveFunctionsSupport, + nullptr); + + cl_bool devicePipeSupport = CL_FALSE; + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_PIPE_SUPPORT, + sizeof(devicePipeSupport), + &devicePipeSupport, + nullptr); + + cl_device_device_enqueue_capabilities deviceDeviceEnqueueCapabilities = 0; + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_DEVICE_ENQUEUE_CAPABILITIES, + sizeof(deviceDeviceEnqueueCapabilities), + &deviceDeviceEnqueueCapabilities, + nullptr); + + cl_device_integer_dot_product_capabilities_khr deviceIntegerDotProductCapabilities = 0; + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_INTEGER_DOT_PRODUCT_CAPABILITIES_KHR, + sizeof(deviceIntegerDotProductCapabilities), + &deviceIntegerDotProductCapabilities, + nullptr); + + cl_device_fp_atomic_capabilities_ext deviceFp32AtomicCapabilities = 0; + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_SINGLE_FP_ATOMIC_CAPABILITIES_EXT, + sizeof(deviceFp32AtomicCapabilities), + &deviceFp32AtomicCapabilities, + nullptr); + + cl_device_fp_atomic_capabilities_ext deviceFp16AtomicCapabilities = 0; + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_HALF_FP_ATOMIC_CAPABILITIES_EXT, + sizeof(deviceFp16AtomicCapabilities), + &deviceFp16AtomicCapabilities, + nullptr); + + cl_device_fp_atomic_capabilities_ext deviceFp64AtomicCapabilities = 0; + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_DOUBLE_FP_ATOMIC_CAPABILITIES_EXT, + sizeof(deviceFp64AtomicCapabilities), + &deviceFp64AtomicCapabilities, + nullptr); + + + // Required. + deviceInfo.ExtendedInstructionSets.push_back("OpenCL.std"); + + deviceInfo.Capabilities.push_back(spv::CapabilityAddresses); + deviceInfo.Capabilities.push_back(spv::CapabilityFloat16Buffer); + deviceInfo.Capabilities.push_back(spv::CapabilityInt16); + deviceInfo.Capabilities.push_back(spv::CapabilityInt8); + deviceInfo.Capabilities.push_back(spv::CapabilityKernel); + deviceInfo.Capabilities.push_back(spv::CapabilityLinkage); + deviceInfo.Capabilities.push_back(spv::CapabilityVector16); + + // Required for FULL_PROFILE devices, or devices supporting cles_khr_int64. + if (deviceProfile == "FULL_PROFILE" || + checkStringForExtension(deviceExtensions.c_str(), "cles_khr_int64")) { + deviceInfo.Capabilities.push_back(spv::CapabilityInt64); + } + + // Required for devices supporting images. + if (deviceImageSupport == CL_TRUE) { + deviceInfo.Capabilities.push_back(spv::CapabilityImage1D); + deviceInfo.Capabilities.push_back(spv::CapabilityImageBasic); + deviceInfo.Capabilities.push_back(spv::CapabilityImageBuffer); + deviceInfo.Capabilities.push_back(spv::CapabilityLiteralSampler); + deviceInfo.Capabilities.push_back(spv::CapabilitySampled1D); + deviceInfo.Capabilities.push_back(spv::CapabilitySampledBuffer); + } + + // Required for devices supporting SPIR-V 1.6. + if (deviceILVersion.find("SPIR-V_1.6") != std::string::npos) { + deviceInfo.Capabilities.push_back(spv::CapabilityUniformDecoration); + } + + // Required for devices supporting images, for OpenCL 2.0, OpenCL 2.1, OpenCL 2.2, or OpenCL 3.0 devices supporting read-write images. + if (deviceImageSupport == CL_TRUE && + (deviceVersion == CL_MAKE_VERSION(2, 0, 0) || + deviceVersion == CL_MAKE_VERSION(2, 1, 0) || + deviceVersion == CL_MAKE_VERSION(2, 2, 0) || + (deviceVersion >= CL_MAKE_VERSION(3, 0, 0) && + deviceMaxReadWriteImageArgs != 0))) { + deviceInfo.Capabilities.push_back(spv::CapabilityImageReadWrite); + } + + // Required for OpenCL 2.0, OpenCL 2.1, OpenCL 2.2, or OpenCL 3.0 devices supporting the generic address space. + if (deviceVersion == CL_MAKE_VERSION(2, 0, 0) || + deviceVersion == CL_MAKE_VERSION(2, 1, 0) || + deviceVersion == CL_MAKE_VERSION(2, 2, 0) || + (deviceVersion >= CL_MAKE_VERSION(3, 0, 0) && + deviceGenericAddressSpaceSupport == CL_TRUE)) { + deviceInfo.Capabilities.push_back(spv::CapabilityGenericPointer); + } + + // Required for OpenCL 2.0, OpenCL 2.1, OpenCL 2.2, or OpenCL 3.0 devices supporting sub-groups or work-group collective functions. + if (deviceVersion == CL_MAKE_VERSION(2, 0, 0) || + deviceVersion == CL_MAKE_VERSION(2, 1, 0) || + deviceVersion == CL_MAKE_VERSION(2, 2, 0) || + (deviceVersion >= CL_MAKE_VERSION(3, 0, 0) && + (deviceMaxNumSubGroups != 0 || deviceWorkGroupCollectiveFunctionsSupport == CL_TRUE))) { + deviceInfo.Capabilities.push_back(spv::CapabilityGroups); + } + + // Required for OpenCL 2.0, OpenCL 2.1, OpenCL 2.2, or OpenCL 3.0 devices supporting the generic address space. + if (deviceVersion == CL_MAKE_VERSION(2, 0, 0) || + deviceVersion == CL_MAKE_VERSION(2, 1, 0) || + deviceVersion == CL_MAKE_VERSION(2, 2, 0) || + (deviceVersion >= CL_MAKE_VERSION(3, 0, 0) && + devicePipeSupport == CL_TRUE)) { + deviceInfo.Capabilities.push_back(spv::CapabilityPipes); + } + + // Required for OpenCL 2.0, OpenCL 2.1, OpenCL 2.2, or OpenCL 3.0 devices supporting device-side enqueue. + if (deviceVersion == CL_MAKE_VERSION(2, 0, 0) || + deviceVersion == CL_MAKE_VERSION(2, 1, 0) || + deviceVersion == CL_MAKE_VERSION(2, 2, 0) || + (deviceVersion >= CL_MAKE_VERSION(3, 0, 0) && + deviceDeviceEnqueueCapabilities != 0)) { + deviceInfo.Capabilities.push_back(spv::CapabilityDeviceEnqueue); + } + + // Required for OpenCL 2.2 devices. + if (deviceVersion == CL_MAKE_VERSION(2, 2, 0)) { + deviceInfo.Capabilities.push_back(spv::CapabilityPipeStorage); + } + + // Required for OpenCL 2.2, or OpenCL 3.0 devices supporting sub-groups. + if (deviceVersion == CL_MAKE_VERSION(2, 2, 0) || + (deviceVersion >= CL_MAKE_VERSION(3, 0, 0) && deviceMaxNumSubGroups != 0)) { + deviceInfo.Capabilities.push_back(spv::CapabilitySubgroupDispatch); + } + + // Required for devices supporting cl_khr_expect_assume. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_khr_expect_assume")) { + deviceInfo.Extensions.push_back("SPV_KHR_expect_assume"); + deviceInfo.Capabilities.push_back(spv::CapabilityExpectAssumeKHR); + } + + // Required for devices supporting cl_khr_extended_bit_ops. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_khr_extended_bit_ops")) { + deviceInfo.Extensions.push_back("SPV_KHR_bit_instructions"); + deviceInfo.Capabilities.push_back(spv::CapabilityBitInstructions); + } + + // Required for devices supporting half-precision floating-point (cl_khr_fp16). + if (checkStringForExtension(deviceExtensions.c_str(), "cl_khr_fp16")) { + deviceInfo.Capabilities.push_back(spv::CapabilityFloat16); + } + + // Required for devices supporting double-precision floating-point (cl_khr_fp64). + if (checkStringForExtension(deviceExtensions.c_str(), "cl_khr_fp64")) { + deviceInfo.Capabilities.push_back(spv::CapabilityFloat64); + } + + // Required for devices supporting 64-bit atomics (cl_khr_int64_base_atomics or cl_khr_int64_extended_atomics). + if (checkStringForExtension(deviceExtensions.c_str(), "cl_khr_int64_base_atomics") || + checkStringForExtension(deviceExtensions.c_str(), "cl_khr_int64_extended_atomics")) { + deviceInfo.Capabilities.push_back(spv::CapabilityInt64Atomics); + } + + // Required for devices supporting cl_khr_integer_dot_product. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_khr_integer_dot_product")) { + deviceInfo.Extensions.push_back("SPV_KHR_integer_dot_product"); + deviceInfo.Capabilities.push_back(spv::CapabilityDotProduct); + deviceInfo.Capabilities.push_back(spv::CapabilityDotProductInput4x8BitPacked); + } + + // Required for devices supporting cl_khr_integer_dot_product and CL_DEVICE_INTEGER_DOT_PRODUCT_INPUT_4x8BIT_KHR. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_khr_integer_dot_product") && + (deviceIntegerDotProductCapabilities & CL_DEVICE_INTEGER_DOT_PRODUCT_INPUT_4x8BIT_KHR)) { + deviceInfo.Capabilities.push_back(spv::CapabilityDotProductInput4x8Bit); + } + + // Required for devices supporting cl_khr_kernel_clock. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_khr_kernel_clock")) { + deviceInfo.Extensions.push_back("SPV_KHR_shader_clock"); + deviceInfo.Capabilities.push_back(spv::CapabilityShaderClockKHR); + } + + // Required for devices supporting both cl_khr_mipmap_image and cl_khr_mipmap_image_writes. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_khr_mipmap_image") && + checkStringForExtension(deviceExtensions.c_str(), "cl_khr_mipmap_image_writes")) { + deviceInfo.Capabilities.push_back(spv::CapabilityImageMipmap); + } + + // Required for devices supporting cl_khr_spirv_linkonce_odr. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_khr_spirv_linkonce_odr")) { + deviceInfo.Extensions.push_back("SPV_KHR_linkonce_odr"); + } + + // Required for devices supporting cl_khr_spirv_no_integer_wrap_decoration. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_khr_spirv_no_integer_wrap_decoration")) { + deviceInfo.Extensions.push_back("SPV_KHR_no_integer_wrap_decoration"); + } + + // Required for devices supporting cl_khr_subgroup_ballot. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_khr_subgroup_ballot")) { + deviceInfo.Capabilities.push_back(spv::CapabilityGroupNonUniformBallot); + } + + // Required for devices supporting cl_khr_subgroup_clustered_reduce. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_khr_subgroup_clustered_reduce")) { + deviceInfo.Capabilities.push_back(spv::CapabilityGroupNonUniformClustered); + } + + // Required for devices supporting cl_khr_subgroup_named_barrier. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_khr_subgroup_named_barrier")) { + deviceInfo.Capabilities.push_back(spv::CapabilityNamedBarrier); + } + + // Required for devices supporting cl_khr_subgroup_non_uniform_arithmetic. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_khr_subgroup_non_uniform_arithmetic")) { + deviceInfo.Capabilities.push_back(spv::CapabilityGroupNonUniformArithmetic); + } + + // Required for devices supporting cl_khr_subgroup_non_uniform_vote. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_khr_subgroup_non_uniform_vote")) { + deviceInfo.Capabilities.push_back(spv::CapabilityGroupNonUniform); + deviceInfo.Capabilities.push_back(spv::CapabilityGroupNonUniformVote); + } + + // Required for devices supporting cl_khr_subgroup_rotate. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_khr_subgroup_rotate")) { + deviceInfo.Extensions.push_back("SPV_KHR_subgroup_rotate"); + deviceInfo.Capabilities.push_back(spv::CapabilityGroupNonUniformRotateKHR); + } + + // Required for devices supporting cl_khr_subgroup_shuffle. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_khr_subgroup_shuffle")) { + deviceInfo.Capabilities.push_back(spv::CapabilityGroupNonUniformShuffle); + } + + // Required for devices supporting cl_khr_subgroup_shuffle_relative. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_khr_subgroup_shuffle_relative")) { + deviceInfo.Capabilities.push_back(spv::CapabilityGroupNonUniformShuffleRelative); + } + + // Required for devices supporting cl_khr_work_group_uniform_arithmetic. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_khr_work_group_uniform_arithmetic")) { + deviceInfo.Extensions.push_back("SPV_KHR_uniform_group_instructions"); + deviceInfo.Capabilities.push_back(spv::CapabilityGroupUniformArithmeticKHR); + } + + // Required for devices supporting cl_ext_float_atomics and fp32 atomic adds. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_ext_float_atomics") && + (deviceFp32AtomicCapabilities & (CL_DEVICE_GLOBAL_FP_ATOMIC_ADD_EXT | CL_DEVICE_LOCAL_FP_ATOMIC_ADD_EXT))) { + deviceInfo.Capabilities.push_back(spv::CapabilityAtomicFloat32AddEXT); + } + + // Required for devices supporting cl_ext_float_atomics and fp32 atomic min and max. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_ext_float_atomics") && + (deviceFp32AtomicCapabilities & (CL_DEVICE_GLOBAL_FP_ATOMIC_MIN_MAX_EXT | CL_DEVICE_LOCAL_FP_ATOMIC_MIN_MAX_EXT))) { + deviceInfo.Capabilities.push_back(spv::CapabilityAtomicFloat32MinMaxEXT); + } + + // Required for devices supporting cl_ext_float_atomics and fp16 atomic adds. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_ext_float_atomics") && + (deviceFp16AtomicCapabilities & (CL_DEVICE_GLOBAL_FP_ATOMIC_ADD_EXT | CL_DEVICE_LOCAL_FP_ATOMIC_ADD_EXT))) { + deviceInfo.Extensions.push_back("SPV_EXT_shader_atomic_float16_add"); + deviceInfo.Capabilities.push_back(spv::CapabilityAtomicFloat16AddEXT); + } + + // Required for devices supporting cl_ext_float_atomics and fp16 atomic min and max. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_ext_float_atomics") && + (deviceFp16AtomicCapabilities & (CL_DEVICE_GLOBAL_FP_ATOMIC_MIN_MAX_EXT | CL_DEVICE_LOCAL_FP_ATOMIC_MIN_MAX_EXT))) { + deviceInfo.Capabilities.push_back(spv::CapabilityAtomicFloat16MinMaxEXT); + } + + // Required for devices supporting cl_ext_float_atomics and fp64 atomic adds. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_ext_float_atomics") && + (deviceFp64AtomicCapabilities & (CL_DEVICE_GLOBAL_FP_ATOMIC_ADD_EXT | CL_DEVICE_LOCAL_FP_ATOMIC_ADD_EXT))) { + deviceInfo.Capabilities.push_back(spv::CapabilityAtomicFloat64MinMaxEXT); + } + + // Required for devices supporting cl_ext_float_atomics and fp64 atomic min and max. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_ext_float_atomics") && + (deviceFp64AtomicCapabilities & (CL_DEVICE_GLOBAL_FP_ATOMIC_MIN_MAX_EXT | CL_DEVICE_LOCAL_FP_ATOMIC_MIN_MAX_EXT))) { + deviceInfo.Capabilities.push_back(spv::CapabilityAtomicFloat64MinMaxEXT); + } + + // Required for devices supporting cl_ext_float_atomics and fp16, fp32, or fp64 atomic min or max. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_ext_float_atomics") && + ((deviceFp32AtomicCapabilities & (CL_DEVICE_GLOBAL_FP_ATOMIC_MIN_MAX_EXT | CL_DEVICE_LOCAL_FP_ATOMIC_MIN_MAX_EXT)) || + (deviceFp16AtomicCapabilities & (CL_DEVICE_GLOBAL_FP_ATOMIC_MIN_MAX_EXT | CL_DEVICE_LOCAL_FP_ATOMIC_MIN_MAX_EXT)) || + (deviceFp64AtomicCapabilities & (CL_DEVICE_GLOBAL_FP_ATOMIC_MIN_MAX_EXT | CL_DEVICE_LOCAL_FP_ATOMIC_MIN_MAX_EXT)))) { + deviceInfo.Extensions.push_back("SPV_EXT_shader_atomic_float_min_max"); + } + + // Required for devices supporting cl_ext_float_atomics and fp32 or fp64 atomic adds. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_ext_float_atomics") && + ((deviceFp32AtomicCapabilities & (CL_DEVICE_GLOBAL_FP_ATOMIC_ADD_EXT | CL_DEVICE_LOCAL_FP_ATOMIC_ADD_EXT)) || + (deviceFp64AtomicCapabilities & (CL_DEVICE_GLOBAL_FP_ATOMIC_ADD_EXT | CL_DEVICE_LOCAL_FP_ATOMIC_ADD_EXT)))) { + deviceInfo.Extensions.push_back("SPV_EXT_shader_atomic_float_add"); + } + + // Required for devices supporting cl_intel_bfloat16_conversions. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_intel_bfloat16_conversions")) { + deviceInfo.Extensions.push_back("SPV_INTEL_bfloat16_conversion"); + deviceInfo.Capabilities.push_back(spv::CapabilityBFloat16ConversionINTEL); + } + + // Required for devices supporting cl_intel_spirv_device_side_avc_motion_estimation. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_intel_spirv_device_side_avc_motion_estimation")) { + deviceInfo.Extensions.push_back("SPV_INTEL_device_side_avc_motion_estimation"); + deviceInfo.Capabilities.push_back(spv::CapabilitySubgroupAvcMotionEstimationChromaINTEL); + deviceInfo.Capabilities.push_back(spv::CapabilitySubgroupAvcMotionEstimationINTEL); + deviceInfo.Capabilities.push_back(spv::CapabilitySubgroupAvcMotionEstimationIntraINTEL); + } + + // Required for devices supporting cl_intel_spirv_media_block_io. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_intel_spirv_media_block_io")) { + deviceInfo.Extensions.push_back("SPV_INTEL_media_block_io"); + deviceInfo.Capabilities.push_back(spv::CapabilitySubgroupImageMediaBlockIOINTEL); + } + + // Required for devices supporting cl_intel_spirv_subgroups. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_intel_spirv_subgroups")) { + deviceInfo.Extensions.push_back("SPV_INTEL_subgroups"); + deviceInfo.Capabilities.push_back(spv::CapabilitySubgroupBufferBlockIOINTEL); + deviceInfo.Capabilities.push_back(spv::CapabilitySubgroupImageBlockIOINTEL); + deviceInfo.Capabilities.push_back(spv::CapabilitySubgroupShuffleINTEL); + } + + // Required for devices supporting cl_intel_split_work_group_barrier. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_intel_split_work_group_barrier")) { + deviceInfo.Extensions.push_back("SPV_INTEL_split_barrier"); + deviceInfo.Capabilities.push_back(spv::CapabilitySplitBarrierINTEL); + } + + // Required for devices supporting cl_intel_subgroup_buffer_prefetch. + if (checkStringForExtension(deviceExtensions.c_str(), "cl_intel_subgroup_buffer_prefetch")) { + deviceInfo.Extensions.push_back("SPV_INTEL_subgroup_buffer_prefetch"); + deviceInfo.Capabilities.push_back(spv::CapabilitySubgroupBufferPrefetchINTEL); + } + } + } + } +}; + +SLayerContext& getLayerContext(void) +{ + static SLayerContext c; + return c; +} + +bool clGetDeviceInfo_override( + cl_device_id device, + cl_device_info param_name, + size_t param_value_size, + void* param_value, + size_t* param_value_size_ret, + cl_int* errcode_ret) +{ + const auto& deviceInfo = getLayerContext().getDeviceInfo(device); + if (deviceInfo.supports_cl_khr_subgroup_queries) { + return false; + } + + switch(param_name) { + case CL_DEVICE_EXTENSIONS: + { + size_t size = 0; + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_EXTENSIONS, + 0, + nullptr, + &size ); + + std::vector deviceExtensions(size); + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_EXTENSIONS, + size, + deviceExtensions.data(), + nullptr ); + + if( checkStringForExtension( + deviceExtensions.data(), + CL_KHR_SPIRV_QUERIES_EXTENSION_NAME ) == false ) + { + std::string newExtensions; + newExtensions += CL_KHR_SPIRV_QUERIES_EXTENSION_NAME; + + std::string oldExtensions(deviceExtensions.data()); + + // If the old extension string ends with a space ensure the + // new extension string does too. + if( oldExtensions.back() == ' ' ) + { + newExtensions += ' '; + } + else + { + oldExtensions += ' '; + } + + oldExtensions += newExtensions; + + auto ptr = (char*)param_value; + cl_int errorCode = writeStringToMemory( + param_value_size, + oldExtensions.c_str(), + param_value_size_ret, + ptr ); + + if( errcode_ret ) + { + errcode_ret[0] = errorCode; + } + return true; + } + } + break; + case CL_DEVICE_EXTENSIONS_WITH_VERSION: + { + size_t size = 0; + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_EXTENSIONS_WITH_VERSION, + 0, + nullptr, + &size ); + + size_t numExtensions = size / sizeof(cl_name_version); + std::vector extensions(numExtensions); + g_pNextDispatch->clGetDeviceInfo( + device, + CL_DEVICE_EXTENSIONS_WITH_VERSION, + size, + extensions.data(), + nullptr ); + + bool found = false; + for( const auto& extension : extensions ) + { + if( strcmp(extension.name, CL_KHR_SPIRV_QUERIES_EXTENSION_NAME) == 0 ) + { + found = true; + break; + } + } + + if( found == false ) + { + extensions.emplace_back(); + cl_name_version& extension = extensions.back(); + + memset(extension.name, 0, CL_NAME_VERSION_MAX_NAME_SIZE); + strcpy(extension.name, CL_KHR_SPIRV_QUERIES_EXTENSION_NAME); + + extension.version = version_cl_khr_subgroup_queries; + + auto ptr = (cl_name_version*)param_value; + cl_int errorCode = writeVectorToMemory( + param_value_size, + extensions, + param_value_size_ret, + ptr ); + + if( errcode_ret ) + { + errcode_ret[0] = errorCode; + } + return true; + } + } + break; + case CL_DEVICE_SPIRV_EXTENDED_INSTRUCTION_SETS_KHR: + { + auto ptr = (const char**)param_value; + cl_int errorCode = writeVectorToMemory( + param_value_size, + deviceInfo.ExtendedInstructionSets, + param_value_size_ret, + ptr); + if (errcode_ret) { + errcode_ret[0] = errorCode; + } + return true; + } + case CL_DEVICE_SPIRV_EXTENSIONS_KHR: + { + auto ptr = (const char**)param_value; + cl_int errorCode = writeVectorToMemory( + param_value_size, + deviceInfo.Extensions, + param_value_size_ret, + ptr); + if (errcode_ret) { + errcode_ret[0] = errorCode; + } + return true; + } + case CL_DEVICE_SPIRV_CAPABILITIES_KHR: + { + auto ptr = (cl_uint*)param_value; + cl_int errorCode = writeVectorToMemory( + param_value_size, + deviceInfo.Capabilities, + param_value_size_ret, + ptr); + if (errcode_ret) { + errcode_ret[0] = errorCode; + } + return true; + } + default: break; + } + + return false; +} + +bool clGetPlatformInfo_override( + cl_platform_id platform, + cl_platform_info param_name, + size_t param_value_size, + void* param_value, + size_t* param_value_size_ret, + cl_int* errcode_ret) +{ + switch(param_name) { + case CL_PLATFORM_EXTENSIONS: + { + size_t size = 0; + g_pNextDispatch->clGetPlatformInfo( + platform, + CL_PLATFORM_EXTENSIONS, + 0, + nullptr, + &size ); + + std::vector platformExtensions(size); + g_pNextDispatch->clGetPlatformInfo( + platform, + CL_PLATFORM_EXTENSIONS, + size, + platformExtensions.data(), + nullptr ); + + if( checkStringForExtension( + platformExtensions.data(), + CL_KHR_SPIRV_QUERIES_EXTENSION_NAME ) == false ) + { + std::string newExtensions; + newExtensions += CL_KHR_SPIRV_QUERIES_EXTENSION_NAME; + + std::string oldExtensions(platformExtensions.data()); + + // If the old extension string ends with a space ensure the + // new extension string does too. + if( oldExtensions.back() == ' ' ) + { + newExtensions += ' '; + } + else + { + oldExtensions += ' '; + } + + oldExtensions += newExtensions; + + auto ptr = (char*)param_value; + cl_int errorCode = writeStringToMemory( + param_value_size, + oldExtensions.c_str(), + param_value_size_ret, + ptr ); + + if( errcode_ret ) + { + errcode_ret[0] = errorCode; + } + return true; + } + } + break; + case CL_PLATFORM_EXTENSIONS_WITH_VERSION: + { + size_t size = 0; + g_pNextDispatch->clGetPlatformInfo( + platform, + CL_PLATFORM_EXTENSIONS_WITH_VERSION, + 0, + nullptr, + &size ); + + size_t numExtensions = size / sizeof(cl_name_version); + std::vector extensions(numExtensions); + g_pNextDispatch->clGetPlatformInfo( + platform, + CL_PLATFORM_EXTENSIONS_WITH_VERSION, + size, + extensions.data(), + nullptr ); + + bool found = false; + for( const auto& extension : extensions ) + { + if( strcmp(extension.name, CL_KHR_SPIRV_QUERIES_EXTENSION_NAME) == 0 ) + { + found = true; + break; + } + } + + if( found == false ) + { + extensions.emplace_back(); + cl_name_version& extension = extensions.back(); + + memset(extension.name, 0, CL_NAME_VERSION_MAX_NAME_SIZE); + strcpy(extension.name, CL_KHR_SPIRV_QUERIES_EXTENSION_NAME); + + extension.version = version_cl_khr_subgroup_queries; + + auto ptr = (cl_name_version*)param_value; + cl_int errorCode = writeVectorToMemory( + param_value_size, + extensions, + param_value_size_ret, + ptr ); + + if( errcode_ret ) + { + errcode_ret[0] = errorCode; + } + return true; + } + } + break; + default: break; + } + return false; +} diff --git a/layers/12_spirvqueriesemu/emulate.h b/layers/12_spirvqueriesemu/emulate.h new file mode 100644 index 0000000..2e80b1c --- /dev/null +++ b/layers/12_spirvqueriesemu/emulate.h @@ -0,0 +1,37 @@ +/* +// Copyright (c) 2025 Ben Ashbaugh +// +// SPDX-License-Identifier: MIT +*/ + +#include +#include + +extern const struct _cl_icd_dispatch* g_pNextDispatch; + +#ifndef cl_khr_spirv_queries +#define cl_khr_spirv_queries 1 +#define CL_KHR_SPIRV_QUERIES_EXTENSION_NAME "cl_khr_spirv_queries" +#define CL_DEVICE_SPIRV_EXTENDED_INSTRUCTION_SETS_KHR 0x12B9 +#define CL_DEVICE_SPIRV_EXTENSIONS_KHR 0x12BA +#define CL_DEVICE_SPIRV_CAPABILITIES_KHR 0x12BB +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Override Functions + +bool clGetDeviceInfo_override( + cl_device_id device, + cl_device_info param_name, + size_t param_value_size, + void* param_value, + size_t* param_value_size_ret, + cl_int* errcode_ret); + +bool clGetPlatformInfo_override( + cl_platform_id platform, + cl_platform_info param_name, + size_t param_value_size, + void* param_value, + size_t* param_value_size_ret, + cl_int* errcode_ret); diff --git a/layers/12_spirvqueriesemu/main.cpp b/layers/12_spirvqueriesemu/main.cpp new file mode 100644 index 0000000..fcbbd74 --- /dev/null +++ b/layers/12_spirvqueriesemu/main.cpp @@ -0,0 +1,158 @@ +/* +// Copyright (c) 2025 Ben Ashbaugh +// +// SPDX-License-Identifier: MIT +*/ + +#if defined _WIN32 || defined __CYGWIN__ +#ifdef __GNUC__ +#define CL_API_ENTRY __attribute__((dllexport)) +#else +#define CL_API_ENTRY __declspec(dllexport) +#endif +#else +#if __GNUC__ >= 4 +#define CL_API_ENTRY __attribute__((visibility("default"))) +#else +#define CL_API_ENTRY +#endif +#endif + +#include + +#include +#include + +#include "layer_util.hpp" + +#include "emulate.h" + +const struct _cl_icd_dispatch* g_pNextDispatch = NULL; + +static cl_int CL_API_CALL +clGetDeviceInfo_layer( + cl_device_id device, + cl_device_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret) +{ + cl_int errorCode = CL_SUCCESS; + + if (clGetDeviceInfo_override( + device, + param_name, + param_value_size, + param_value, + param_value_size_ret, + &errorCode) == false) { + return g_pNextDispatch->clGetDeviceInfo( + device, + param_name, + param_value_size, + param_value, + param_value_size_ret); + } + + return errorCode; +} + +static cl_int CL_API_CALL +clGetPlatformInfo_layer( + cl_platform_id platform, + cl_platform_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret) +{ + cl_int errorCode = CL_SUCCESS; + + if (clGetPlatformInfo_override( + platform, + param_name, + param_value_size, + param_value, + param_value_size_ret, + &errorCode) == false) { + return g_pNextDispatch->clGetPlatformInfo( + platform, + param_name, + param_value_size, + param_value, + param_value_size_ret); + } + + return errorCode; +} + +static struct _cl_icd_dispatch dispatch; +static void _init_dispatch() +{ + dispatch.clGetDeviceInfo = clGetDeviceInfo_layer; + dispatch.clGetPlatformInfo = clGetPlatformInfo_layer; +} + +CL_API_ENTRY cl_int CL_API_CALL clGetLayerInfo( + cl_layer_info param_name, + size_t param_value_size, + void* param_value, + size_t* param_value_size_ret) +{ + switch (param_name) { + case CL_LAYER_API_VERSION: + { + auto ptr = (cl_layer_api_version*)param_value; + auto value = cl_layer_api_version{CL_LAYER_API_VERSION_100}; + return writeParamToMemory( + param_value_size, + value, + param_value_size_ret, + ptr); + } + break; +#if defined(CL_LAYER_NAME) + case CL_LAYER_NAME: + { + auto ptr = (char*)param_value; + return writeStringToMemory( + param_value_size, + "Emulation Layer for " CL_KHR_SPIRV_QUERIES_EXTENSION_NAME, + param_value_size_ret, + ptr); + } + break; +#endif + default: + return CL_INVALID_VALUE; + } + return CL_SUCCESS; +} + +CL_API_ENTRY cl_int CL_API_CALL clInitLayer( + cl_uint num_entries, + const struct _cl_icd_dispatch* target_dispatch, + cl_uint* num_entries_out, + const struct _cl_icd_dispatch** layer_dispatch_ret) +{ + const size_t dispatchTableSize = + sizeof(dispatch) / sizeof(dispatch.clGetPlatformIDs); + + if (target_dispatch == nullptr || + num_entries_out == nullptr || + layer_dispatch_ret == nullptr) { + return CL_INVALID_VALUE; + } + + if (num_entries < dispatchTableSize) { + return CL_INVALID_VALUE; + } + + _init_dispatch(); + + g_pNextDispatch = target_dispatch; + + *layer_dispatch_ret = &dispatch; + *num_entries_out = dispatchTableSize; + + return CL_SUCCESS; +} diff --git a/layers/CMakeLists.txt b/layers/CMakeLists.txt index 724c4d2..4375b52 100644 --- a/layers/CMakeLists.txt +++ b/layers/CMakeLists.txt @@ -54,3 +54,7 @@ add_subdirectory( 00_example ) add_subdirectory( 10_cmdbufemu ) add_subdirectory( 11_semaemu ) + +if(TARGET SPIRV-Headers) + add_subdirectory( 12_spirvqueriesemu ) +endif() diff --git a/samples/00_spirvqueries/CMakeLists.txt b/samples/00_spirvqueries/CMakeLists.txt new file mode 100644 index 0000000..1d2cfd9 --- /dev/null +++ b/samples/00_spirvqueries/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (c) 2025 Ben Ashbaugh +# +# SPDX-License-Identifier: MIT + +add_opencl_sample( + TEST + NUMBER 00 + TARGET spirvqueries + VERSION 120 + SOURCES main.cpp + INCLUDES ${SPIRV-Headers_SOURCE_DIR}/include) diff --git a/samples/00_spirvqueries/main.cpp b/samples/00_spirvqueries/main.cpp new file mode 100644 index 0000000..3f4219d --- /dev/null +++ b/samples/00_spirvqueries/main.cpp @@ -0,0 +1,101 @@ +/* +// Copyright (c) 2025 Ben Ashbaugh +// +// SPDX-License-Identifier: MIT +*/ + +#include +#include +#include +#include + +#include + +#ifndef cl_khr_spirv_queries +#define cl_khr_spirv_queries 1 +#define CL_KHR_SPIRV_QUERIES_EXTENSION_NAME "cl_khr_spirv_queries" +#define CL_DEVICE_SPIRV_EXTENDED_INSTRUCTION_SETS_KHR 0x12B9 +#define CL_DEVICE_SPIRV_EXTENSIONS_KHR 0x12BA +#define CL_DEVICE_SPIRV_CAPABILITIES_KHR 0x12BB +#endif + +#define SPV_ENABLE_UTILITY_CODE +#include + +#include + +#include "util.hpp" + +int main( + int argc, + char** argv ) +{ + { + popl::OptionParser op("Supported Options"); + + 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: spirvqueries [options]\n" + "%s", op.help().c_str()); + return -1; + } + } + + std::vector platforms; + cl::Platform::get(&platforms); + + for (size_t p = 0; p < platforms.size(); p++) { + const cl::Platform& platform = platforms[p]; + + printf("Platform[%zu]:\n", p); + printf("\tName: %s\n", platform.getInfo().c_str() ); + printf("\tVendor: %s\n", platform.getInfo().c_str() ); + printf("\tDriver Version: %s\n", platform.getInfo().c_str() ); + + std::vector devices; + platform.getDevices(CL_DEVICE_TYPE_ALL, &devices); + for (size_t d = 0; d < devices.size(); d++) { + const cl::Device& device = devices[d]; + + printf("\tDevice[%zu]:\n", d); + printf("\tName: %s\n", device.getInfo().c_str() ); + printf("\tVendor: %s\n", device.getInfo().c_str() ); + printf("\tDevice Version: %s\n", device.getInfo().c_str() ); + printf("\tDriver Version: %s\n", device.getInfo().c_str() ); + + auto spirvExtendedInstructionSets = + device.getInfo(); + printf("\t\tSupported SPIR-V ExtendedInstructionSets:\n"); + for (auto s : spirvExtendedInstructionSets) { + printf("\t\t\t%s\n", s); + } + + auto spirvExtensions = + device.getInfo(); + printf("\t\tSupported SPIR-V Extensions:\n"); + for (auto s : spirvExtensions) { + printf("\t\t\t%s\n", s); + } + + auto spirvCapabilities = + device.getInfo(); + printf("\t\tSupported SPIR-V Capabilities:\n"); + for (auto c : spirvCapabilities) { + printf("\t\t\t%s\n", spv::CapabilityToString(static_cast(c))); + } + } + printf("\n"); + } + + printf( "Done.\n" ); + + return 0; +} diff --git a/samples/05_spirvkernelfromfile/main.cpp b/samples/05_spirvkernelfromfile/main.cpp index 6e1aa6d..45dcfc7 100644 --- a/samples/05_spirvkernelfromfile/main.cpp +++ b/samples/05_spirvkernelfromfile/main.cpp @@ -55,7 +55,7 @@ static cl::Program createProgramWithIL( for (auto device : devices) { #ifdef CL_VERSION_2_1 // Note: This could look for "SPIR-V" in CL_DEVICE_IL_VERSION. - if (getDeviceOpenCLVersion(device) >= 0x00020001 && + if (getDeviceOpenCLVersion(device) >= CL_MAKE_VERSION(2, 1, 0) && !device.getInfo().empty()) { useCore = true; } @@ -151,7 +151,7 @@ int main( // 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(devices[deviceIndex]) >= 0x00020001 && + if (getDeviceOpenCLVersion(devices[deviceIndex]) >= CL_MAKE_VERSION(2, 1, 0) && !devices[deviceIndex].getInfo().empty()) { printf("Device supports OpenCL 2.1 or newer, using clCreateProgramWithIL.\n"); } else diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index faad042..6eb2ebe 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -92,3 +92,7 @@ if(BUILD_EXTENSION_SAMPLES) add_subdirectory( 14_ooqcommandbuffers ) add_subdirectory( 15_mutablecommandbufferasserts ) endif() + +if(TARGET SPIRV-Headers) + add_subdirectory( 00_spirvqueries ) +endif()