mirror of
https://github.com/KhronosGroup/OpenCL-CTS.git
synced 2026-03-19 06:09:01 +00:00
tests for cl_khr_spirv_queries (#2409)
See: https://github.com/KhronosGroup/OpenCL-Docs/pull/1385
This commit is contained in:
5
.github/workflows/presubmit.yml
vendored
5
.github/workflows/presubmit.yml
vendored
@@ -61,6 +61,10 @@ jobs:
|
|||||||
cd OpenCL-Headers
|
cd OpenCL-Headers
|
||||||
ln -s CL OpenCL # For OSX builds
|
ln -s CL OpenCL # For OSX builds
|
||||||
cd ..
|
cd ..
|
||||||
|
- name: Fetch SPIR-V Headers
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/KhronosGroup/SPIRV-Headers.git
|
||||||
- name: Install Vulkan SDK
|
- name: Install Vulkan SDK
|
||||||
uses: humbletim/install-vulkan-sdk@main
|
uses: humbletim/install-vulkan-sdk@main
|
||||||
with:
|
with:
|
||||||
@@ -160,6 +164,7 @@ jobs:
|
|||||||
-DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
|
-DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
|
||||||
-DCMAKE_CACHE_OPTIONS="-DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache" \
|
-DCMAKE_CACHE_OPTIONS="-DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache" \
|
||||||
-DCL_INCLUDE_DIR='${{ github.workspace }}'/OpenCL-Headers \
|
-DCL_INCLUDE_DIR='${{ github.workspace }}'/OpenCL-Headers \
|
||||||
|
-DSPIRV_INCLUDE_DIR='${{ github.workspace }}'/SPIRV-Headers \
|
||||||
-DCL_LIB_DIR='${{ github.workspace }}'/OpenCL-ICD-Loader/build \
|
-DCL_LIB_DIR='${{ github.workspace }}'/OpenCL-ICD-Loader/build \
|
||||||
-DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_FILE} \
|
-DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_FILE} \
|
||||||
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=./bin \
|
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=./bin \
|
||||||
|
|||||||
@@ -59,6 +59,12 @@ else(CL_INCLUDE_DIR AND CL_LIB_DIR)
|
|||||||
message(FATAL_ERROR "Either install OpenCL or pass -DCL_INCLUDE_DIR and -DCL_LIB_DIR")
|
message(FATAL_ERROR "Either install OpenCL or pass -DCL_INCLUDE_DIR and -DCL_LIB_DIR")
|
||||||
endif(CL_INCLUDE_DIR AND CL_LIB_DIR)
|
endif(CL_INCLUDE_DIR AND CL_LIB_DIR)
|
||||||
|
|
||||||
|
# SPIRV_INCLUDE_DIR - path to dir with SPIR-V headers
|
||||||
|
if(NOT SPIRV_INCLUDE_DIR)
|
||||||
|
message(STATUS "SPIR-V headers haven't been found!")
|
||||||
|
message(FATAL_ERROR "Pass -DSPIRV_INCLUDE_DIR")
|
||||||
|
endif(NOT SPIRV_INCLUDE_DIR)
|
||||||
|
|
||||||
# CLConform_GL_LIBRARIES_DIR - path to OpenGL libraries
|
# CLConform_GL_LIBRARIES_DIR - path to OpenGL libraries
|
||||||
if(GL_IS_SUPPORTED AND CLConform_GL_LIBRARIES_DIR)
|
if(GL_IS_SUPPORTED AND CLConform_GL_LIBRARIES_DIR)
|
||||||
link_directories(${CLConform_GL_LIBRARIES_DIR})
|
link_directories(${CLConform_GL_LIBRARIES_DIR})
|
||||||
@@ -195,6 +201,7 @@ if(APPLE)
|
|||||||
endif(APPLE)
|
endif(APPLE)
|
||||||
|
|
||||||
include_directories(SYSTEM ${CL_INCLUDE_DIR})
|
include_directories(SYSTEM ${CL_INCLUDE_DIR})
|
||||||
|
include_directories(SYSTEM ${SPIRV_INCLUDE_DIR}/include)
|
||||||
include_directories(${CLConform_SOURCE_DIR}/test_common/harness
|
include_directories(${CLConform_SOURCE_DIR}/test_common/harness
|
||||||
${CLConform_SOURCE_DIR}/test_common/gles
|
${CLConform_SOURCE_DIR}/test_common/gles
|
||||||
${CLConform_SOURCE_DIR}/test_common/gl
|
${CLConform_SOURCE_DIR}/test_common/gl
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ Compiling the CTS requires the following CMake configuration options to be set:
|
|||||||
|
|
||||||
* `CL_INCLUDE_DIR` Points to the unified
|
* `CL_INCLUDE_DIR` Points to the unified
|
||||||
[OpenCL-Headers](https://github.com/KhronosGroup/OpenCL-Headers).
|
[OpenCL-Headers](https://github.com/KhronosGroup/OpenCL-Headers).
|
||||||
|
* `SPIRV_INCLUDE_DIR` Points to the unified
|
||||||
|
[SPIRV-Headers](https://github.com/KhronosGroup/SPIRV-Headers).
|
||||||
* `CL_LIB_DIR` Directory containing the OpenCL library to build against.
|
* `CL_LIB_DIR` Directory containing the OpenCL library to build against.
|
||||||
* `SPIRV_TOOLS_DIR` Directory containing the `spirv-as` and `spirv-val` binaries
|
* `SPIRV_TOOLS_DIR` Directory containing the `spirv-as` and `spirv-val` binaries
|
||||||
to be used in the CTS build process. Alternatively, the location to these binaries
|
to be used in the CTS build process. Alternatively, the location to these binaries
|
||||||
@@ -31,6 +33,7 @@ a build, and compile.
|
|||||||
```sh
|
```sh
|
||||||
git clone https://github.com/KhronosGroup/OpenCL-CTS.git
|
git clone https://github.com/KhronosGroup/OpenCL-CTS.git
|
||||||
git clone https://github.com/KhronosGroup/OpenCL-Headers.git
|
git clone https://github.com/KhronosGroup/OpenCL-Headers.git
|
||||||
|
git clone https://github.com/KhronosGroup/SPIRV-Headers.git
|
||||||
git clone https://github.com/KhronosGroup/OpenCL-ICD-Loader.git
|
git clone https://github.com/KhronosGroup/OpenCL-ICD-Loader.git
|
||||||
git clone https://github.com/KhronosGroup/SPIRV-Tools.git
|
git clone https://github.com/KhronosGroup/SPIRV-Tools.git
|
||||||
git clone https://github.com/KhronosGroup/SPIRV-Headers.git SPIRV-Tools/external/spirv-headers
|
git clone https://github.com/KhronosGroup/SPIRV-Headers.git SPIRV-Tools/external/spirv-headers
|
||||||
@@ -50,6 +53,7 @@ cmake --build SPIRV-Tools/build --config Release
|
|||||||
mkdir OpenCL-CTS/build
|
mkdir OpenCL-CTS/build
|
||||||
cmake -S OpenCL-CTS -B OpenCL-CTS/build \
|
cmake -S OpenCL-CTS -B OpenCL-CTS/build \
|
||||||
-DCL_INCLUDE_DIR=$PWD/OpenCL-Headers \
|
-DCL_INCLUDE_DIR=$PWD/OpenCL-Headers \
|
||||||
|
-DSPIRV_INCLUDE_DIR=$PWD/SPIRV-Headers \
|
||||||
-DCL_LIB_DIR=$PWD/OpenCL-ICD-Loader/build \
|
-DCL_LIB_DIR=$PWD/OpenCL-ICD-Loader/build \
|
||||||
-DSPIRV_TOOLS_DIR=$PWD/SPIRV-Tools/build/tools/ \
|
-DSPIRV_TOOLS_DIR=$PWD/SPIRV-Tools/build/tools/ \
|
||||||
-DOPENCL_LIBRARIES=OpenCL
|
-DOPENCL_LIBRARIES=OpenCL
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
set(MODULE_NAME API)
|
set(MODULE_NAME API)
|
||||||
|
|
||||||
|
find_package(Python3 COMPONENTS Interpreter QUIET)
|
||||||
|
|
||||||
set(${MODULE_NAME}_SOURCES
|
set(${MODULE_NAME}_SOURCES
|
||||||
main.cpp
|
main.cpp
|
||||||
negative_platform.cpp
|
negative_platform.cpp
|
||||||
@@ -40,6 +42,20 @@ set(${MODULE_NAME}_SOURCES
|
|||||||
test_pipe_properties_queries.cpp
|
test_pipe_properties_queries.cpp
|
||||||
test_wg_suggested_local_work_size.cpp
|
test_wg_suggested_local_work_size.cpp
|
||||||
test_device_command_queue.cpp
|
test_device_command_queue.cpp
|
||||||
|
test_spirv_queries.cpp
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/spirv_capability_deps.def
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/spirv_capability_deps.def
|
||||||
|
COMMENT "Generating spirv_capability_deps.def..."
|
||||||
|
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/generate_spirv_capability_deps.py
|
||||||
|
--grammar "${SPIRV_INCLUDE_DIR}/include/spirv/unified1/spirv.core.grammar.json"
|
||||||
|
--output "${CMAKE_CURRENT_BINARY_DIR}/spirv_capability_deps.def"
|
||||||
|
DEPENDS generate_spirv_capability_deps.py "${SPIRV_INCLUDE_DIR}/include/spirv/unified1/spirv.core.grammar.json"
|
||||||
|
USES_TERMINAL
|
||||||
|
VERBATIM)
|
||||||
|
|
||||||
include(../CMakeCommon.txt)
|
include(../CMakeCommon.txt)
|
||||||
|
|
||||||
|
target_include_directories(${${MODULE_NAME}_OUT} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|||||||
102
test_conformance/api/generate_spirv_capability_deps.py
Normal file
102
test_conformance/api/generate_spirv_capability_deps.py
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
#####################################################################
|
||||||
|
# Copyright (c) 2025 The Khronos Group Inc. All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#####################################################################
|
||||||
|
|
||||||
|
"""
|
||||||
|
Generates a file describing the SPIR-V extension dependencies or SPIR-V version
|
||||||
|
dependencies for a SPIR-V capability. This can be used to ensure that if support
|
||||||
|
for a SPIR-V capability is reported, the necessary SPIR-V extensions or SPIR-V
|
||||||
|
version is also supported.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
|
||||||
|
header_text = """\
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
// This file is generated from the SPIR-V JSON grammar file.
|
||||||
|
// Please do not edit it directly!
|
||||||
|
"""
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='Generate SPIR-V extension and version dependencies for SPIR-V capabilities')
|
||||||
|
|
||||||
|
parser.add_argument('--grammar', metavar='<path>',
|
||||||
|
type=str, required=True,
|
||||||
|
help='input JSON grammar file')
|
||||||
|
parser.add_argument('--output', metavar='<path>',
|
||||||
|
type=str, required=False,
|
||||||
|
help='output file path (default: stdout)')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
dependencies = {}
|
||||||
|
capabilities = []
|
||||||
|
with open(args.grammar) as json_file:
|
||||||
|
grammar_json = json.loads(json_file.read())
|
||||||
|
for operand_kind in grammar_json['operand_kinds']:
|
||||||
|
if operand_kind['kind'] == 'Capability':
|
||||||
|
for cap in operand_kind['enumerants']:
|
||||||
|
capname = cap['enumerant']
|
||||||
|
capabilities.append(capname)
|
||||||
|
dependencies[capname] = {}
|
||||||
|
dependencies[capname]['extensions'] = cap['extensions'] if 'extensions' in cap else []
|
||||||
|
dependencies[capname]['version'] = ("SPIR-V_" + cap['version']) if 'version' in cap and cap['version'] != 'None' else ""
|
||||||
|
|
||||||
|
capabilities.sort()
|
||||||
|
|
||||||
|
output = []
|
||||||
|
output.append(header_text)
|
||||||
|
output.append("// clang-format off")
|
||||||
|
if False:
|
||||||
|
for cap in capabilities:
|
||||||
|
deps = dependencies[cap]
|
||||||
|
extensions_str = ', '.join(f'"{ext}"' for ext in deps['extensions'])
|
||||||
|
|
||||||
|
output.append('SPIRV_CAPABILITY_DEPENDENCIES( {}, {{{}}}, "{}" )'.format(
|
||||||
|
cap, extensions_str, deps['version']))
|
||||||
|
else:
|
||||||
|
for cap in capabilities:
|
||||||
|
deps = dependencies[cap]
|
||||||
|
if deps['version'] != "":
|
||||||
|
output.append('SPIRV_CAPABILITY_VERSION_DEPENDENCY( {}, "{}" )'.format(cap, deps['version']))
|
||||||
|
for ext in deps['extensions']:
|
||||||
|
output.append('SPIRV_CAPABILITY_EXTENSION_DEPENDENCY( {}, "{}" )'.format(cap, ext))
|
||||||
|
output.append("// clang-format on")
|
||||||
|
|
||||||
|
if args.output:
|
||||||
|
with open(args.output, 'w') as output_file:
|
||||||
|
output_file.write('\n'.join(output))
|
||||||
|
else:
|
||||||
|
print('\n'.join(output))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
767
test_conformance/api/test_spirv_queries.cpp
Normal file
767
test_conformance/api/test_spirv_queries.cpp
Normal file
@@ -0,0 +1,767 @@
|
|||||||
|
//
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user