mirror of
https://github.com/KhronosGroup/OpenCL-CTS.git
synced 2026-03-18 22:09:01 +00:00
768 lines
29 KiB
C++
768 lines
29 KiB
C++
//
|
|
// Copyright (c) 2025 The Khronos Group Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
#include "testBase.h"
|
|
#include <algorithm>
|
|
#include <map>
|
|
#include <vector>
|
|
|
|
#define SPV_ENABLE_UTILITY_CODE
|
|
#include <spirv/unified1/spirv.hpp>
|
|
|
|
static bool is_spirv_version_supported(cl_device_id deviceID,
|
|
const std::string& version)
|
|
{
|
|
std::string ilVersions = get_device_il_version_string(deviceID);
|
|
return ilVersions.find(version) != std::string::npos;
|
|
}
|
|
|
|
static int doQueries(cl_device_id device,
|
|
std::vector<const char*>& extendedInstructionSets,
|
|
std::vector<const char*>& extensions,
|
|
std::vector<cl_uint>& capabilities)
|
|
{
|
|
cl_int error = CL_SUCCESS;
|
|
|
|
size_t size = 0;
|
|
error =
|
|
clGetDeviceInfo(device, CL_DEVICE_SPIRV_EXTENDED_INSTRUCTION_SETS_KHR,
|
|
0, nullptr, &size);
|
|
test_error(error,
|
|
"clGetDeviceInfo failed for "
|
|
"CL_DEVICE_SPIRV_EXTENDED_INSTRUCTION_SETS_KHR size\n");
|
|
|
|
extendedInstructionSets.resize(size / sizeof(const char*));
|
|
error =
|
|
clGetDeviceInfo(device, CL_DEVICE_SPIRV_EXTENDED_INSTRUCTION_SETS_KHR,
|
|
size, extendedInstructionSets.data(), nullptr);
|
|
test_error(error,
|
|
"clGetDeviceInfo failed for "
|
|
"CL_DEVICE_SPIRV_EXTENDED_INSTRUCTION_SETS_KHR\n");
|
|
|
|
error = clGetDeviceInfo(device, CL_DEVICE_SPIRV_EXTENSIONS_KHR, 0, nullptr,
|
|
&size);
|
|
test_error(
|
|
error,
|
|
"clGetDeviceInfo failed for CL_DEVICE_SPIRV_EXTENSIONS_KHR size\n");
|
|
|
|
extensions.resize(size / sizeof(const char*));
|
|
error = clGetDeviceInfo(device, CL_DEVICE_SPIRV_EXTENSIONS_KHR, size,
|
|
extensions.data(), nullptr);
|
|
test_error(error,
|
|
"clGetDeviceInfo failed for CL_DEVICE_SPIRV_EXTENSIONS_KHR\n");
|
|
|
|
error = clGetDeviceInfo(device, CL_DEVICE_SPIRV_CAPABILITIES_KHR, 0,
|
|
nullptr, &size);
|
|
test_error(
|
|
error,
|
|
"clGetDeviceInfo failed for CL_DEVICE_SPIRV_CAPABILITIES_KHR size\n");
|
|
|
|
capabilities.resize(size / sizeof(cl_uint));
|
|
error = clGetDeviceInfo(device, CL_DEVICE_SPIRV_CAPABILITIES_KHR, size,
|
|
capabilities.data(), nullptr);
|
|
test_error(error,
|
|
"clGetDeviceInfo failed for CL_DEVICE_SPIRV_CAPABILITIES_KHR\n");
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
static int findRequirements(cl_device_id device,
|
|
std::vector<const char*>& extendedInstructionSets,
|
|
std::vector<const char*>& extensions,
|
|
std::vector<cl_uint>& capabilities)
|
|
{
|
|
cl_int error = CL_SUCCESS;
|
|
|
|
auto version = get_device_cl_version(device);
|
|
auto ilVersions = get_device_il_version_string(device);
|
|
|
|
// If no SPIR-V versions are supported, there are no requirements.
|
|
if (ilVersions.find("SPIR-V") == std::string::npos)
|
|
{
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
cl_bool deviceImageSupport = CL_FALSE;
|
|
cl_bool deviceReadWriteImageSupport = CL_FALSE;
|
|
cl_bool deviceSubGroupsSupport = CL_FALSE;
|
|
cl_bool deviceGenericAddressSpaceSupport = CL_FALSE;
|
|
cl_bool deviceWorkGroupCollectiveFunctionsSupport = CL_FALSE;
|
|
cl_bool devicePipeSupport = CL_FALSE;
|
|
cl_bool deviceDeviceEnqueueSupport = CL_FALSE;
|
|
cl_device_integer_dot_product_capabilities_khr
|
|
deviceIntegerDotProductCapabilities = 0;
|
|
cl_device_fp_atomic_capabilities_ext deviceFp32AtomicCapabilities = 0;
|
|
cl_device_fp_atomic_capabilities_ext deviceFp16AtomicCapabilities = 0;
|
|
cl_device_fp_atomic_capabilities_ext deviceFp64AtomicCapabilities = 0;
|
|
|
|
error = clGetDeviceInfo(device, CL_DEVICE_IMAGE_SUPPORT,
|
|
sizeof(deviceImageSupport), &deviceImageSupport,
|
|
nullptr);
|
|
test_error(error, "clGetDeviceInfo failed for CL_DEVICE_IMAGE_SUPPORT\n");
|
|
|
|
if (version >= Version(2, 0))
|
|
{
|
|
cl_uint deviceMaxReadWriteImageArgs = 0;
|
|
error = clGetDeviceInfo(device, CL_DEVICE_MAX_READ_WRITE_IMAGE_ARGS,
|
|
sizeof(deviceMaxReadWriteImageArgs),
|
|
&deviceMaxReadWriteImageArgs, nullptr);
|
|
test_error(
|
|
error,
|
|
"clGetDeviceInfo failed for CL_DEVICE_MAX_READ_WRITE_IMAGE_ARGS\n");
|
|
|
|
deviceReadWriteImageSupport =
|
|
deviceMaxReadWriteImageArgs != 0 ? CL_TRUE : CL_FALSE;
|
|
}
|
|
|
|
if (version >= Version(2, 1))
|
|
{
|
|
cl_uint deviceMaxNumSubGroups = 0;
|
|
error = clGetDeviceInfo(device, CL_DEVICE_MAX_NUM_SUB_GROUPS,
|
|
sizeof(deviceMaxNumSubGroups),
|
|
&deviceMaxNumSubGroups, nullptr);
|
|
test_error(error,
|
|
"clGetDeviceInfo failed for CL_DEVICE_MAX_NUM_SUB_GROUPS\n");
|
|
|
|
deviceSubGroupsSupport =
|
|
deviceMaxNumSubGroups != 0 ? CL_TRUE : CL_FALSE;
|
|
}
|
|
else if (is_extension_available(device, "cl_khr_subgroups"))
|
|
{
|
|
deviceSubGroupsSupport = CL_TRUE;
|
|
}
|
|
|
|
if (version >= Version(3, 0))
|
|
{
|
|
error = clGetDeviceInfo(device, CL_DEVICE_GENERIC_ADDRESS_SPACE_SUPPORT,
|
|
sizeof(deviceGenericAddressSpaceSupport),
|
|
&deviceGenericAddressSpaceSupport, nullptr);
|
|
test_error(error,
|
|
"clGetDeviceInfo failed for "
|
|
"CL_DEVICE_GENERIC_ADDRESS_SPACE_SUPPORT\n");
|
|
|
|
error = clGetDeviceInfo(
|
|
device, CL_DEVICE_WORK_GROUP_COLLECTIVE_FUNCTIONS_SUPPORT,
|
|
sizeof(deviceWorkGroupCollectiveFunctionsSupport),
|
|
&deviceWorkGroupCollectiveFunctionsSupport, nullptr);
|
|
test_error(error,
|
|
"clGetDeviceInfo failed for "
|
|
"CL_DEVICE_WORK_GROUP_COLLECTIVE_FUNCTIONS_SUPPORT\n");
|
|
|
|
error = clGetDeviceInfo(device, CL_DEVICE_PIPE_SUPPORT,
|
|
sizeof(devicePipeSupport), &devicePipeSupport,
|
|
nullptr);
|
|
test_error(error,
|
|
"clGetDeviceInfo failed for CL_DEVICE_PIPE_SUPPORT\n");
|
|
|
|
cl_device_device_enqueue_capabilities deviceDeviceEnqueueCapabilities =
|
|
0;
|
|
error = clGetDeviceInfo(device, CL_DEVICE_DEVICE_ENQUEUE_CAPABILITIES,
|
|
sizeof(deviceDeviceEnqueueCapabilities),
|
|
&deviceDeviceEnqueueCapabilities, nullptr);
|
|
test_error(error,
|
|
"clGetDeviceInfo failed for "
|
|
"CL_DEVICE_DEVICE_ENQUEUE_CAPABILITIES\n");
|
|
|
|
deviceDeviceEnqueueSupport =
|
|
deviceDeviceEnqueueCapabilities != 0 ? CL_TRUE : CL_FALSE;
|
|
}
|
|
else if (version >= Version(2, 0))
|
|
{
|
|
deviceGenericAddressSpaceSupport = CL_TRUE;
|
|
deviceWorkGroupCollectiveFunctionsSupport = CL_TRUE;
|
|
devicePipeSupport = CL_TRUE;
|
|
deviceDeviceEnqueueSupport = CL_TRUE;
|
|
}
|
|
|
|
if (is_extension_available(device, "cl_khr_integer_dot_product"))
|
|
{
|
|
error = clGetDeviceInfo(device,
|
|
CL_DEVICE_INTEGER_DOT_PRODUCT_CAPABILITIES_KHR,
|
|
sizeof(deviceIntegerDotProductCapabilities),
|
|
&deviceIntegerDotProductCapabilities, nullptr);
|
|
test_error(error,
|
|
"clGetDeviceInfo failed for "
|
|
"CL_DEVICE_INTEGER_DOT_PRODUCT_CAPABILITIES_KHR\n");
|
|
}
|
|
|
|
if (is_extension_available(device, "cl_ext_float_atomics"))
|
|
{
|
|
error =
|
|
clGetDeviceInfo(device, CL_DEVICE_SINGLE_FP_ATOMIC_CAPABILITIES_EXT,
|
|
sizeof(deviceFp32AtomicCapabilities),
|
|
&deviceFp32AtomicCapabilities, nullptr);
|
|
test_error(error,
|
|
"clGetDeviceInfo failed for "
|
|
"CL_DEVICE_SINGLE_FP_ATOMIC_CAPABILITIES_EXT\n");
|
|
|
|
error =
|
|
clGetDeviceInfo(device, CL_DEVICE_HALF_FP_ATOMIC_CAPABILITIES_EXT,
|
|
sizeof(deviceFp16AtomicCapabilities),
|
|
&deviceFp16AtomicCapabilities, nullptr);
|
|
test_error(error,
|
|
"clGetDeviceInfo failed for "
|
|
"CL_DEVICE_HALF_FP_ATOMIC_CAPABILITIES_EXT\n");
|
|
|
|
error =
|
|
clGetDeviceInfo(device, CL_DEVICE_DOUBLE_FP_ATOMIC_CAPABILITIES_EXT,
|
|
sizeof(deviceFp64AtomicCapabilities),
|
|
&deviceFp64AtomicCapabilities, nullptr);
|
|
test_error(error,
|
|
"clGetDeviceInfo failed for "
|
|
"CL_DEVICE_DOUBLE_FP_ATOMIC_CAPABILITIES_EXT\n");
|
|
}
|
|
|
|
// Required.
|
|
extendedInstructionSets.push_back("OpenCL.std");
|
|
|
|
capabilities.push_back(spv::CapabilityAddresses);
|
|
capabilities.push_back(spv::CapabilityFloat16Buffer);
|
|
capabilities.push_back(spv::CapabilityInt16);
|
|
capabilities.push_back(spv::CapabilityInt8);
|
|
capabilities.push_back(spv::CapabilityKernel);
|
|
capabilities.push_back(spv::CapabilityLinkage);
|
|
capabilities.push_back(spv::CapabilityVector16);
|
|
|
|
// Required for FULL_PROFILE devices, or devices supporting
|
|
// cles_khr_int64.
|
|
if (gHasLong)
|
|
{
|
|
capabilities.push_back(spv::CapabilityInt64);
|
|
}
|
|
|
|
// Required for devices supporting images.
|
|
if (deviceImageSupport == CL_TRUE)
|
|
{
|
|
capabilities.push_back(spv::CapabilityImage1D);
|
|
capabilities.push_back(spv::CapabilityImageBasic);
|
|
capabilities.push_back(spv::CapabilityImageBuffer);
|
|
capabilities.push_back(spv::CapabilityLiteralSampler);
|
|
capabilities.push_back(spv::CapabilitySampled1D);
|
|
capabilities.push_back(spv::CapabilitySampledBuffer);
|
|
}
|
|
|
|
// Required for devices supporting SPIR-V 1.6.
|
|
if (ilVersions.find("SPIR-V_1.6") != std::string::npos)
|
|
{
|
|
capabilities.push_back(spv::CapabilityUniformDecoration);
|
|
}
|
|
|
|
// Required for devices supporting read-write images.
|
|
if (deviceReadWriteImageSupport == CL_TRUE)
|
|
{
|
|
capabilities.push_back(spv::CapabilityImageReadWrite);
|
|
}
|
|
|
|
// Required for devices supporting the generic address space.
|
|
if (deviceGenericAddressSpaceSupport == CL_TRUE)
|
|
{
|
|
capabilities.push_back(spv::CapabilityGenericPointer);
|
|
}
|
|
|
|
// Required for devices supporting sub-groups or work-group collective
|
|
// functions.
|
|
if (deviceSubGroupsSupport == CL_TRUE
|
|
|| deviceWorkGroupCollectiveFunctionsSupport == CL_TRUE)
|
|
{
|
|
capabilities.push_back(spv::CapabilityGroups);
|
|
}
|
|
|
|
// Required for devices supporting pipes.
|
|
if (devicePipeSupport == CL_TRUE)
|
|
{
|
|
capabilities.push_back(spv::CapabilityPipes);
|
|
}
|
|
|
|
// Required for devices supporting device-side enqueue.
|
|
if (deviceDeviceEnqueueSupport == CL_TRUE)
|
|
{
|
|
capabilities.push_back(spv::CapabilityDeviceEnqueue);
|
|
}
|
|
|
|
// Required for devices supporting SPIR-V 1.1 and OpenCL 2.2.
|
|
if (ilVersions.find("SPIR-V_1.1") != std::string::npos
|
|
&& version == Version(2, 2))
|
|
{
|
|
capabilities.push_back(spv::CapabilityPipeStorage);
|
|
}
|
|
|
|
// Required for devices supporting SPIR-V 1.1 and either OpenCL 2.2 or
|
|
// OpenCL 3.0 devices supporting sub-groups.
|
|
if (ilVersions.find("SPIR-V_1.1") != std::string::npos
|
|
&& (version == Version(2, 2)
|
|
|| (version >= Version(3, 0) && deviceSubGroupsSupport == CL_TRUE)))
|
|
{
|
|
capabilities.push_back(spv::CapabilitySubgroupDispatch);
|
|
}
|
|
|
|
// Required for devices supporting cl_khr_expect_assume.
|
|
if (is_extension_available(device, "cl_khr_expect_assume"))
|
|
{
|
|
extensions.push_back("SPV_KHR_expect_assume");
|
|
capabilities.push_back(spv::CapabilityExpectAssumeKHR);
|
|
}
|
|
|
|
// Required for devices supporting cl_khr_extended_bit_ops.
|
|
if (is_extension_available(device, "cl_khr_extended_bit_ops"))
|
|
{
|
|
extensions.push_back("SPV_KHR_bit_instructions");
|
|
capabilities.push_back(spv::CapabilityBitInstructions);
|
|
}
|
|
|
|
// Required for devices supporting half-precision floating-point
|
|
// (cl_khr_fp16).
|
|
if (is_extension_available(device, "cl_khr_fp16"))
|
|
{
|
|
capabilities.push_back(spv::CapabilityFloat16);
|
|
}
|
|
|
|
// Required for devices supporting double-precision floating-point
|
|
// (cl_khr_fp64).
|
|
if (is_extension_available(device, "cl_khr_fp64"))
|
|
{
|
|
capabilities.push_back(spv::CapabilityFloat64);
|
|
}
|
|
|
|
// Required for devices supporting 64-bit atomics
|
|
// (cl_khr_int64_base_atomics or cl_khr_int64_extended_atomics).
|
|
if (is_extension_available(device, "cl_khr_int64_base_atomics")
|
|
|| is_extension_available(device, "cl_khr_int64_extended_atomics"))
|
|
{
|
|
capabilities.push_back(spv::CapabilityInt64Atomics);
|
|
}
|
|
|
|
// Required for devices supporting cl_khr_integer_dot_product.
|
|
if (is_extension_available(device, "cl_khr_integer_dot_product"))
|
|
{
|
|
extensions.push_back("SPV_KHR_integer_dot_product");
|
|
capabilities.push_back(spv::CapabilityDotProduct);
|
|
capabilities.push_back(spv::CapabilityDotProductInput4x8BitPacked);
|
|
}
|
|
|
|
// Required for devices supporting cl_khr_integer_dot_product and
|
|
// CL_DEVICE_INTEGER_DOT_PRODUCT_INPUT_4x8BIT_KHR.
|
|
if (is_extension_available(device, "cl_khr_integer_dot_product")
|
|
&& (deviceIntegerDotProductCapabilities
|
|
& CL_DEVICE_INTEGER_DOT_PRODUCT_INPUT_4x8BIT_KHR))
|
|
{
|
|
capabilities.push_back(spv::CapabilityDotProductInput4x8Bit);
|
|
}
|
|
|
|
// Required for devices supporting cl_khr_kernel_clock.
|
|
if (is_extension_available(device, "cl_khr_kernel_clock"))
|
|
{
|
|
extensions.push_back("SPV_KHR_shader_clock");
|
|
capabilities.push_back(spv::CapabilityShaderClockKHR);
|
|
}
|
|
|
|
// Required for devices supporting both cl_khr_mipmap_image and
|
|
// cl_khr_mipmap_image_writes.
|
|
if (is_extension_available(device, "cl_khr_mipmap_image")
|
|
&& is_extension_available(device, "cl_khr_mipmap_image_writes"))
|
|
{
|
|
capabilities.push_back(spv::CapabilityImageMipmap);
|
|
}
|
|
|
|
// Required for devices supporting cl_khr_spirv_extended_debug_info.
|
|
if (is_extension_available(device, "cl_khr_spirv_extended_debug_info"))
|
|
{
|
|
extendedInstructionSets.push_back("OpenCL.DebugInfo.100");
|
|
}
|
|
|
|
// Required for devices supporting cl_khr_spirv_linkonce_odr.
|
|
if (is_extension_available(device, "cl_khr_spirv_linkonce_odr"))
|
|
{
|
|
extensions.push_back("SPV_KHR_linkonce_odr");
|
|
}
|
|
|
|
// Required for devices supporting
|
|
// cl_khr_spirv_no_integer_wrap_decoration.
|
|
if (is_extension_available(device,
|
|
"cl_khr_spirv_no_integer_wrap_decoration"))
|
|
{
|
|
extensions.push_back("SPV_KHR_no_integer_wrap_decoration");
|
|
}
|
|
|
|
// Required for devices supporting cl_khr_subgroup_ballot.
|
|
if (is_extension_available(device, "cl_khr_subgroup_ballot"))
|
|
{
|
|
capabilities.push_back(spv::CapabilityGroupNonUniformBallot);
|
|
}
|
|
|
|
// Required for devices supporting cl_khr_subgroup_clustered_reduce.
|
|
if (is_extension_available(device, "cl_khr_subgroup_clustered_reduce"))
|
|
{
|
|
capabilities.push_back(spv::CapabilityGroupNonUniformClustered);
|
|
}
|
|
|
|
// Required for devices supporting cl_khr_subgroup_named_barrier.
|
|
if (is_extension_available(device, "cl_khr_subgroup_named_barrier"))
|
|
{
|
|
capabilities.push_back(spv::CapabilityNamedBarrier);
|
|
}
|
|
|
|
// Required for devices supporting
|
|
// cl_khr_subgroup_non_uniform_arithmetic.
|
|
if (is_extension_available(device,
|
|
"cl_khr_subgroup_non_uniform_arithmetic"))
|
|
{
|
|
capabilities.push_back(spv::CapabilityGroupNonUniformArithmetic);
|
|
}
|
|
|
|
// Required for devices supporting cl_khr_subgroup_non_uniform_vote.
|
|
if (is_extension_available(device, "cl_khr_subgroup_non_uniform_vote"))
|
|
{
|
|
capabilities.push_back(spv::CapabilityGroupNonUniform);
|
|
capabilities.push_back(spv::CapabilityGroupNonUniformVote);
|
|
}
|
|
|
|
// Required for devices supporting cl_khr_subgroup_rotate.
|
|
if (is_extension_available(device, "cl_khr_subgroup_rotate"))
|
|
{
|
|
extensions.push_back("SPV_KHR_subgroup_rotate");
|
|
capabilities.push_back(spv::CapabilityGroupNonUniformRotateKHR);
|
|
}
|
|
|
|
// Required for devices supporting cl_khr_subgroup_shuffle.
|
|
if (is_extension_available(device, "cl_khr_subgroup_shuffle"))
|
|
{
|
|
capabilities.push_back(spv::CapabilityGroupNonUniformShuffle);
|
|
}
|
|
|
|
// Required for devices supporting cl_khr_subgroup_shuffle_relative.
|
|
if (is_extension_available(device, "cl_khr_subgroup_shuffle_relative"))
|
|
{
|
|
capabilities.push_back(spv::CapabilityGroupNonUniformShuffleRelative);
|
|
}
|
|
|
|
// Required for devices supporting cl_khr_work_group_uniform_arithmetic.
|
|
if (is_extension_available(device, "cl_khr_work_group_uniform_arithmetic"))
|
|
{
|
|
extensions.push_back("SPV_KHR_uniform_group_instructions");
|
|
capabilities.push_back(spv::CapabilityGroupUniformArithmeticKHR);
|
|
}
|
|
|
|
// Required for devices supporting cl_ext_float_atomics and fp32 atomic
|
|
// adds.
|
|
if (is_extension_available(device, "cl_ext_float_atomics")
|
|
&& (deviceFp32AtomicCapabilities
|
|
& (CL_DEVICE_GLOBAL_FP_ATOMIC_ADD_EXT
|
|
| CL_DEVICE_LOCAL_FP_ATOMIC_ADD_EXT)))
|
|
{
|
|
capabilities.push_back(spv::CapabilityAtomicFloat32AddEXT);
|
|
}
|
|
|
|
// Required for devices supporting cl_ext_float_atomics and fp32 atomic
|
|
// min and max.
|
|
if (is_extension_available(device, "cl_ext_float_atomics")
|
|
&& (deviceFp32AtomicCapabilities
|
|
& (CL_DEVICE_GLOBAL_FP_ATOMIC_MIN_MAX_EXT
|
|
| CL_DEVICE_LOCAL_FP_ATOMIC_MIN_MAX_EXT)))
|
|
{
|
|
capabilities.push_back(spv::CapabilityAtomicFloat32MinMaxEXT);
|
|
}
|
|
|
|
// Required for devices supporting cl_ext_float_atomics and fp16 atomic
|
|
// adds.
|
|
if (is_extension_available(device, "cl_ext_float_atomics")
|
|
&& (deviceFp16AtomicCapabilities
|
|
& (CL_DEVICE_GLOBAL_FP_ATOMIC_ADD_EXT
|
|
| CL_DEVICE_LOCAL_FP_ATOMIC_ADD_EXT)))
|
|
{
|
|
extensions.push_back("SPV_EXT_shader_atomic_float16_add");
|
|
capabilities.push_back(spv::CapabilityAtomicFloat16AddEXT);
|
|
}
|
|
|
|
// Required for devices supporting cl_ext_float_atomics and fp16 atomic
|
|
// min and max.
|
|
if (is_extension_available(device, "cl_ext_float_atomics")
|
|
&& (deviceFp16AtomicCapabilities
|
|
& (CL_DEVICE_GLOBAL_FP_ATOMIC_MIN_MAX_EXT
|
|
| CL_DEVICE_LOCAL_FP_ATOMIC_MIN_MAX_EXT)))
|
|
{
|
|
capabilities.push_back(spv::CapabilityAtomicFloat16MinMaxEXT);
|
|
}
|
|
|
|
// Required for devices supporting cl_ext_float_atomics and fp64 atomic
|
|
// adds.
|
|
if (is_extension_available(device, "cl_ext_float_atomics")
|
|
&& (deviceFp64AtomicCapabilities
|
|
& (CL_DEVICE_GLOBAL_FP_ATOMIC_ADD_EXT
|
|
| CL_DEVICE_LOCAL_FP_ATOMIC_ADD_EXT)))
|
|
{
|
|
capabilities.push_back(spv::CapabilityAtomicFloat64AddEXT);
|
|
}
|
|
|
|
// Required for devices supporting cl_ext_float_atomics and fp64 atomic
|
|
// min and max.
|
|
if (is_extension_available(device, "cl_ext_float_atomics")
|
|
&& (deviceFp64AtomicCapabilities
|
|
& (CL_DEVICE_GLOBAL_FP_ATOMIC_MIN_MAX_EXT
|
|
| CL_DEVICE_LOCAL_FP_ATOMIC_MIN_MAX_EXT)))
|
|
{
|
|
capabilities.push_back(spv::CapabilityAtomicFloat64MinMaxEXT);
|
|
}
|
|
|
|
// Required for devices supporting cl_ext_float_atomics and fp16, fp32,
|
|
// or fp64 atomic min or max.
|
|
if (is_extension_available(device, "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))))
|
|
{
|
|
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 (is_extension_available(device, "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))))
|
|
{
|
|
extensions.push_back("SPV_EXT_shader_atomic_float_add");
|
|
}
|
|
|
|
// Required for devices supporting cl_intel_bfloat16_conversions.
|
|
if (is_extension_available(device, "cl_intel_bfloat16_conversions"))
|
|
{
|
|
extensions.push_back("SPV_INTEL_bfloat16_conversion");
|
|
capabilities.push_back(spv::CapabilityBFloat16ConversionINTEL);
|
|
}
|
|
|
|
// Required for devices supporting
|
|
// cl_intel_spirv_device_side_avc_motion_estimation.
|
|
if (is_extension_available(
|
|
device, "cl_intel_spirv_device_side_avc_motion_estimation"))
|
|
{
|
|
extensions.push_back("SPV_INTEL_device_side_avc_motion_estimation");
|
|
capabilities.push_back(
|
|
spv::CapabilitySubgroupAvcMotionEstimationChromaINTEL);
|
|
capabilities.push_back(spv::CapabilitySubgroupAvcMotionEstimationINTEL);
|
|
capabilities.push_back(
|
|
spv::CapabilitySubgroupAvcMotionEstimationIntraINTEL);
|
|
}
|
|
|
|
// Required for devices supporting cl_intel_spirv_media_block_io.
|
|
if (is_extension_available(device, "cl_intel_spirv_media_block_io"))
|
|
{
|
|
extensions.push_back("SPV_INTEL_media_block_io");
|
|
capabilities.push_back(spv::CapabilitySubgroupImageMediaBlockIOINTEL);
|
|
}
|
|
|
|
// Required for devices supporting cl_intel_spirv_subgroups.
|
|
if (is_extension_available(device, "cl_intel_spirv_subgroups"))
|
|
{
|
|
extensions.push_back("SPV_INTEL_subgroups");
|
|
capabilities.push_back(spv::CapabilitySubgroupBufferBlockIOINTEL);
|
|
capabilities.push_back(spv::CapabilitySubgroupImageBlockIOINTEL);
|
|
capabilities.push_back(spv::CapabilitySubgroupShuffleINTEL);
|
|
}
|
|
|
|
// Required for devices supporting cl_intel_split_work_group_barrier.
|
|
if (is_extension_available(device, "cl_intel_split_work_group_barrier"))
|
|
{
|
|
extensions.push_back("SPV_INTEL_split_barrier");
|
|
capabilities.push_back(spv::CapabilitySplitBarrierINTEL);
|
|
}
|
|
|
|
// Required for devices supporting cl_intel_subgroup_buffer_prefetch.
|
|
if (is_extension_available(device, "cl_intel_subgroup_buffer_prefetch"))
|
|
{
|
|
extensions.push_back("SPV_INTEL_subgroup_buffer_prefetch");
|
|
capabilities.push_back(spv::CapabilitySubgroupBufferPrefetchINTEL);
|
|
}
|
|
|
|
return CL_SUCCESS;
|
|
}
|
|
|
|
REGISTER_TEST(spirv_query_requirements)
|
|
{
|
|
if (!is_extension_available(device, "cl_khr_spirv_queries"))
|
|
{
|
|
log_info("cl_khr_spirv_queries is not supported; skipping test.\n");
|
|
return TEST_SKIPPED_ITSELF;
|
|
}
|
|
|
|
cl_int error;
|
|
|
|
std::vector<const char*> queriedExtendedInstructionSets;
|
|
std::vector<const char*> queriedExtensions;
|
|
std::vector<cl_uint> queriedCapabilities;
|
|
|
|
error = doQueries(device, queriedExtendedInstructionSets, queriedExtensions,
|
|
queriedCapabilities);
|
|
test_error_fail(error, "Unable to perform SPIR-V queries");
|
|
|
|
std::vector<const char*> requiredExtendedInstructionSets;
|
|
std::vector<const char*> requiredExtensions;
|
|
std::vector<cl_uint> requiredCapabilities;
|
|
error = findRequirements(device, requiredExtendedInstructionSets,
|
|
requiredExtensions, requiredCapabilities);
|
|
test_error_fail(error, "Unable to find SPIR-V requirements");
|
|
|
|
for (auto check : requiredExtendedInstructionSets)
|
|
{
|
|
auto cmp = [=](const char* queried) {
|
|
return strcmp(check, queried) == 0;
|
|
};
|
|
auto it = std::find_if(queriedExtendedInstructionSets.begin(),
|
|
queriedExtendedInstructionSets.end(), cmp);
|
|
if (it == queriedExtendedInstructionSets.end())
|
|
{
|
|
test_fail("Missing required extended instruction set: %s\n", check);
|
|
}
|
|
}
|
|
|
|
for (auto check : requiredExtensions)
|
|
{
|
|
auto cmp = [=](const char* queried) {
|
|
return strcmp(check, queried) == 0;
|
|
};
|
|
auto it = std::find_if(queriedExtensions.begin(),
|
|
queriedExtensions.end(), cmp);
|
|
if (it == queriedExtensions.end())
|
|
{
|
|
test_fail("Missing required extension: %s\n", check);
|
|
}
|
|
}
|
|
|
|
for (auto check : requiredCapabilities)
|
|
{
|
|
if (std::find(queriedCapabilities.begin(), queriedCapabilities.end(),
|
|
check)
|
|
== queriedCapabilities.end())
|
|
{
|
|
test_fail(
|
|
"Missing required capability: %s\n",
|
|
spv::CapabilityToString(static_cast<spv::Capability>(check)));
|
|
}
|
|
}
|
|
|
|
// Find any extraneous capabilities (informational):
|
|
for (auto check : queriedCapabilities)
|
|
{
|
|
if (std::find(requiredCapabilities.begin(), requiredCapabilities.end(),
|
|
check)
|
|
== requiredCapabilities.end())
|
|
{
|
|
log_info(
|
|
"Found non-required capability: %s\n",
|
|
spv::CapabilityToString(static_cast<spv::Capability>(check)));
|
|
}
|
|
}
|
|
|
|
return TEST_PASS;
|
|
}
|
|
|
|
REGISTER_TEST(spirv_query_dependencies)
|
|
{
|
|
if (!is_extension_available(device, "cl_khr_spirv_queries"))
|
|
{
|
|
log_info("cl_khr_spirv_queries is not supported; skipping test.\n");
|
|
return TEST_SKIPPED_ITSELF;
|
|
}
|
|
|
|
cl_int error;
|
|
|
|
std::vector<const char*> queriedExtendedInstructionSets;
|
|
std::vector<const char*> queriedExtensions;
|
|
std::vector<cl_uint> queriedCapabilities;
|
|
|
|
error = doQueries(device, queriedExtendedInstructionSets, queriedExtensions,
|
|
queriedCapabilities);
|
|
test_error_fail(error, "Unable to perform SPIR-V queries");
|
|
|
|
struct CapabilityDependencies
|
|
{
|
|
std::vector<std::string> extensions;
|
|
std::string version;
|
|
};
|
|
|
|
std::map<spv::Capability, CapabilityDependencies> dependencies;
|
|
|
|
#define SPIRV_CAPABILITY_VERSION_DEPENDENCY(_cap, _ver) \
|
|
dependencies[spv::Capability##_cap].version = _ver;
|
|
#define SPIRV_CAPABILITY_EXTENSION_DEPENDENCY(_cap, _ext) \
|
|
dependencies[spv::Capability##_cap].extensions.push_back(_ext);
|
|
#include "spirv_capability_deps.def"
|
|
|
|
// For each queried SPIR-V capability, ensure that either that any SPIR-V
|
|
// version dependencies or SPIR-V extension dependencies are satisfied.
|
|
|
|
for (auto check : queriedCapabilities)
|
|
{
|
|
// Log and skip any unknown capabilities
|
|
auto it = dependencies.find(static_cast<spv::Capability>(check));
|
|
if (it == dependencies.end())
|
|
{
|
|
log_info(
|
|
"No known dependencies for queried capability %s!\n",
|
|
spv::CapabilityToString(static_cast<spv::Capability>(check)));
|
|
continue;
|
|
}
|
|
|
|
// Check if a SPIR-V version dependency is satisfied
|
|
const auto& version_dep = it->second.version;
|
|
if (!version_dep.empty()
|
|
&& is_spirv_version_supported(device, version_dep))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Check if a SPIR-V extension dependency is satisfied
|
|
bool found = false;
|
|
for (const auto& extension_dep : it->second.extensions)
|
|
{
|
|
if (std::find(queriedExtensions.begin(), queriedExtensions.end(),
|
|
extension_dep)
|
|
!= queriedExtensions.end())
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (found)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// If we get here then the capability has an unsatisfied dependency.
|
|
log_error("Couldn't find a dependency for queried capability %s!\n",
|
|
spv::CapabilityToString(static_cast<spv::Capability>(check)));
|
|
if (!version_dep.empty())
|
|
{
|
|
log_error("Checked for SPIR-V version %s.\n", version_dep.c_str());
|
|
}
|
|
for (const auto& extension_dep : it->second.extensions)
|
|
{
|
|
log_error("Checked for SPIR-V extension %s.n",
|
|
extension_dep.c_str());
|
|
}
|
|
return TEST_FAIL;
|
|
}
|
|
|
|
return TEST_PASS;
|
|
}
|