diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 923d83c..515524f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -16,3 +16,4 @@ if(NOT WIN32) # testlayer doesn't work on Windows add_subdirectory(testlayer) endif() +add_subdirectory(loadlayer) diff --git a/tests/loadlayer/CMakeLists.txt b/tests/loadlayer/CMakeLists.txt new file mode 100644 index 0000000..0a068a0 --- /dev/null +++ b/tests/loadlayer/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright 2020-2022 The spirv2clc authors. +# +# 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. + +if (APPLE) +set(CMAKE_SHARED_LINKER_FLAGS "-undefined dynamic_lookup") +endif() + +add_library(layerloadicd SHARED icd.cpp) +target_compile_features(layerloadicd PRIVATE cxx_std_17) +target_include_directories(layerloadicd PRIVATE ${OPENCL_HEADERS_DIR}) +target_link_libraries(layerloadicd ${CMAKE_DL_LIBS}) +target_compile_definitions(layerloadicd PRIVATE CL_TARGET_OPENCL_VERSION=300) diff --git a/tests/loadlayer/icd.cpp b/tests/loadlayer/icd.cpp new file mode 100644 index 0000000..07f88da --- /dev/null +++ b/tests/loadlayer/icd.cpp @@ -0,0 +1,121 @@ +#include "icd.hpp" + +#include +#include + +CL_API_ENTRY cl_int CL_API_CALL +clGetPlatformInfo_wrap( + cl_platform_id platform, + cl_platform_info param_name, + size_t param_value_size, + void *param_value, + size_t *param_value_size_ret) +{ + return platform->clGetPlatformInfo( + param_name, + param_value_size, + param_value, + param_value_size_ret + ); +} + +_cl_platform_id::_cl_platform_id(cl_version ver) + : numeric_version{ver} + , version{ std::string{"OpenCL "} + std::to_string(CL_VERSION_MAJOR(ver)) + "." + std::to_string(CL_VERSION_MINOR(ver)) + " Mock" } + , vendor{ "spirv2clc" } + , profile{ "FULL_PROFILE" } + , name{ "SPIRV2CLC Layer Test ICD" } + , extensions{ "cl_khr_icd" } + , suffix{ "spv2clc" } +{ + init_dispatch(); +} + +void _cl_platform_id::init_dispatch() +{ + dispatch.clGetPlatformInfo = clGetPlatformInfo_wrap; +} + +cl_int _cl_platform_id::clGetPlatformInfo( + cl_platform_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret) +{ + if (param_value_size == 0 && param_value != NULL) + return CL_INVALID_VALUE; + + std::string_view result; + switch(param_name) { + case CL_PLATFORM_PROFILE: + result = profile; + break; + case CL_PLATFORM_VERSION: + result = version; + break; + case CL_PLATFORM_NAME: + result = name; + break; + case CL_PLATFORM_VENDOR: + result = vendor; + break; + case CL_PLATFORM_EXTENSIONS: + result = extensions; + break; + case CL_PLATFORM_ICD_SUFFIX_KHR: + result = suffix; + break; + default: + return CL_INVALID_VALUE; + } + + if (param_value_size_ret) + *param_value_size_ret = result.length()+1; + + if (param_value_size && param_value_size < result.length()+1) + return CL_INVALID_VALUE; + + if (param_value) + { + std::copy(result.begin(), result.end(), static_cast(param_value)); + static_cast(param_value)[result.length()] = '\0'; + } + + return CL_SUCCESS; +} + +CL_API_ENTRY cl_int CL_API_CALL +clIcdGetPlatformIDsKHR(cl_uint num_entries, + cl_platform_id* platforms, + cl_uint* num_platforms) +{ + static constexpr std::initializer_list versions{ + CL_MAKE_VERSION(1, 2, 0), + CL_MAKE_VERSION(2, 1, 0), + CL_MAKE_VERSION(3, 0, 0) + }; + + if (spirv2clc::platforms.empty()) + for(cl_version version : versions) + spirv2clc::platforms.emplace_back(version); + + if (num_platforms) + *num_platforms = static_cast(spirv2clc::platforms.size()); + + if ((platforms && num_entries > spirv2clc::platforms.size()) || + (platforms && num_entries <= 0) || + (!platforms && num_entries >= 1)) + { + return CL_INVALID_VALUE; + } + + if (platforms && num_entries == spirv2clc::platforms.size()) + std::transform( + spirv2clc::platforms.begin(), + spirv2clc::platforms.end(), + platforms, + [](_cl_platform_id& plat){ return &plat; } + ); + + return CL_SUCCESS; +} diff --git a/tests/loadlayer/icd.hpp b/tests/loadlayer/icd.hpp new file mode 100644 index 0000000..f4e0761 --- /dev/null +++ b/tests/loadlayer/icd.hpp @@ -0,0 +1,44 @@ +#pragma once + +#if defined(_WIN32) +#define NOMINMAX +#endif + +#include // cl_icd_dispatch + +#include // std::unique_ptr +#include +#include // std::string + +struct _cl_platform_id { + cl_icd_dispatch dispatch; + + cl_version numeric_version; + std::string profile; + std::string version; + std::string name; + std::string vendor; + std::string extensions; + std::string suffix; + + _cl_platform_id() = default; + _cl_platform_id(cl_version ver); + _cl_platform_id(const _cl_platform_id&) = delete; + _cl_platform_id(_cl_platform_id&&) = default; + ~_cl_platform_id() = default; + _cl_platform_id &operator=(const _cl_platform_id&) = delete; + _cl_platform_id &operator=(_cl_platform_id &&) = default; + + void init_dispatch(void); + + cl_int clGetPlatformInfo( + cl_platform_info param_name, + size_t param_value_size, + void * param_value, + size_t * param_value_size_ret); +}; + +namespace spirv2clc +{ + inline std::vector<_cl_platform_id> platforms; +}