diff --git a/CMakeLists.txt b/CMakeLists.txt index 63c2d857..03a55c31 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,6 +75,9 @@ set (OPENCL_ICD_LOADER_SOURCES loader/icd_dispatch.c loader/icd_dispatch.h loader/icd_dispatch_generated.c + loader/icd_trace.c + loader/icd_trace.h + loader/icd_library.h loader/icd_envvars.h loader/icd_platform.h) include_directories (include) @@ -84,8 +87,10 @@ if (WIN32) loader/windows/adapter.h loader/windows/icd_windows.c loader/windows/icd_windows.h + loader/windows/icd_windows_formats.h loader/windows/icd_windows_dxgk.c loader/windows/icd_windows_dxgk.h + loader/windows/icd_windows_library.c loader/windows/icd_windows_envvars.c loader/windows/icd_windows_hkr.c loader/windows/icd_windows_hkr.h @@ -109,6 +114,7 @@ if (WIN32) else () list (APPEND OPENCL_ICD_LOADER_SOURCES loader/linux/icd_linux.c + loader/linux/icd_linux_library.c loader/linux/icd_linux_envvars.c loader/linux/icd_exports.map) endif () @@ -223,7 +229,9 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME OR OPENCL_ICD_LOADER_BUILD_TESTING) endif() if((CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME OR OPENCL_ICD_LOADER_BUILD_TESTING) AND BUILD_TESTING) add_subdirectory (test) -endif() + +endif () + install( TARGETS OpenCL diff --git a/loader/icd.c b/loader/icd.c index 376d484c..5747c2aa 100644 --- a/loader/icd.c +++ b/loader/icd.c @@ -24,7 +24,6 @@ KHRicdVendor *khrIcdVendors = NULL; static KHRicdVendor *lastVendor = NULL; -int khrEnableTrace = 0; static int khrDisableLibraryUnloading = 0; static int khrForceLegacyTermination = 0; diff --git a/loader/icd.h b/loader/icd.h index 937c358d..dd1ca469 100644 --- a/loader/icd.h +++ b/loader/icd.h @@ -21,6 +21,8 @@ #include "icd_platform.h" #include "icd_dispatch.h" +#include "icd_trace.h" +#include "icd_library.h" #ifndef CL_USE_DEPRECATED_OPENCL_1_0_APIS #define CL_USE_DEPRECATED_OPENCL_1_0_APIS @@ -110,8 +112,6 @@ struct KHRicdVendorRec // the global state extern KHRicdVendor * khrIcdVendors; -extern int khrEnableTrace; - #if defined(CL_ENABLE_LAYERS) /* * KHRLayer @@ -177,18 +177,6 @@ void khrIcdLayersEnumerateEnv(void); // add a layer to the layer chain void khrIcdLayerAdd(const char *libraryName); -// dynamically load a library. returns NULL on failure -// n.b, this call is OS-specific -void *khrIcdOsLibraryLoad(const char *libraryName); - -// get a function pointer from a loaded library. returns NULL on failure. -// n.b, this call is OS-specific -void *khrIcdOsLibraryGetFunctionAddress(void *library, const char *functionName); - -// unload a library. -// n.b, this call is OS-specific -void khrIcdOsLibraryUnload(void *library); - // parse properties and determine the platform to use from them void khrIcdContextPropertiesGetPlatform( const cl_context_properties *properties, @@ -201,32 +189,6 @@ void khrIcdContextPropertiesGetPlatform( #define ICD_ANON_UNION_INIT_MEMBER(a) a #endif -// internal tracing macros -#define KHR_ICD_TRACE(...) \ -do \ -{ \ - if (khrEnableTrace) \ - { \ - fprintf(stderr, "KHR ICD trace at %s:%d: ", __FILE__, __LINE__); \ - fprintf(stderr, __VA_ARGS__); \ - } \ -} while (0) - -#ifdef _WIN32 -#define KHR_ICD_WIDE_TRACE(...) \ -do \ -{ \ - if (khrEnableTrace) \ - { \ - fwprintf(stderr, L"KHR ICD trace at %hs:%d: ", __FILE__, __LINE__); \ - fwprintf(stderr, __VA_ARGS__); \ - } \ -} while (0) - -#else -#define KHR_ICD_WIDE_TRACE(...) -#endif - #define KHR_ICD_ERROR_RETURN_ERROR(_error) \ do { \ return _error; \ diff --git a/loader/icd_library.h b/loader/icd_library.h new file mode 100644 index 00000000..06dbe322 --- /dev/null +++ b/loader/icd_library.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2026 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. + * + * OpenCL is a trademark of Apple Inc. used under license by Khronos. + */ + +#ifndef _ICD_LIBRARY_H_ +#define _ICD_LIBRARY_H_ + +// dynamically load a library. returns NULL on failure +// n.b, this call is OS-specific +void *khrIcdOsLibraryLoad(const char *libraryName); + +// get a function pointer from a loaded library. returns NULL on failure. +// n.b, this call is OS-specific +void *khrIcdOsLibraryGetFunctionAddress(void *library, const char *functionName); + +// unload a library. +// n.b, this call is OS-specific +void khrIcdOsLibraryUnload(void *library); + +#endif diff --git a/loader/icd_trace.c b/loader/icd_trace.c new file mode 100644 index 00000000..3446e6c9 --- /dev/null +++ b/loader/icd_trace.c @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2026 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. + * + * OpenCL is a trademark of Apple Inc. used under license by Khronos. + */ +#include "icd_trace.h" + +int khrEnableTrace = 0; diff --git a/loader/icd_trace.h b/loader/icd_trace.h new file mode 100644 index 00000000..e57f7a92 --- /dev/null +++ b/loader/icd_trace.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2026 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. + * + * OpenCL is a trademark of Apple Inc. used under license by Khronos. + */ + +#ifndef _ICD_TRACE_H_ +#define _ICD_TRACE_H_ + +#include + +extern int khrEnableTrace; + +// internal tracing macros +#define KHR_ICD_TRACE(...) \ +do \ +{ \ + if (khrEnableTrace) \ + { \ + fprintf(stderr, "KHR ICD trace at %s:%d: ", __FILE__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); \ + } \ +} while (0) + +#ifdef _WIN32 +#define KHR_ICD_WIDE_TRACE(...) \ +do \ +{ \ + if (khrEnableTrace) \ + { \ + fwprintf(stderr, L"KHR ICD trace at %hs:%d: ", __FILE__, __LINE__); \ + fwprintf(stderr, __VA_ARGS__); \ + } \ +} while (0) + +#else +#define KHR_ICD_WIDE_TRACE(...) +#endif + +#endif diff --git a/loader/linux/icd_linux.c b/loader/linux/icd_linux.c index 7e0c133c..80fe1dfd 100644 --- a/loader/linux/icd_linux.c +++ b/loader/linux/icd_linux.c @@ -19,7 +19,6 @@ #include "icd.h" #include "icd_envvars.h" -#include #include #include #include @@ -237,35 +236,6 @@ void khrIcdOsVendorsEnumerateOnce(void) pthread_once(&initialized, khrIcdOsVendorsEnumerate); } -/* - * - * Dynamic library loading functions - * - */ - -// dynamically load a library. returns NULL on failure -void *khrIcdOsLibraryLoad(const char *libraryName) -{ - void* ret = dlopen (libraryName, RTLD_NOW); - if (NULL == ret) - { - KHR_ICD_TRACE("Failed to load driver because %s.\n", dlerror()); - } - return ret; -} - -// get a function pointer from a loaded library. returns NULL on failure. -void *khrIcdOsLibraryGetFunctionAddress(void *library, const char *functionName) -{ - return dlsym(library, functionName); -} - -// unload a library -void khrIcdOsLibraryUnload(void *library) -{ - dlclose(library); -} - #ifndef CL_LAYER_INFO static void __attribute__((destructor)) khrIcdDestructor(void) { diff --git a/loader/linux/icd_linux_library.c b/loader/linux/icd_linux_library.c new file mode 100644 index 00000000..42405adb --- /dev/null +++ b/loader/linux/icd_linux_library.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2026 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. + * + * OpenCL is a trademark of Apple Inc. used under license by Khronos. + */ + +#include "icd_trace.h" +#include "icd_library.h" +#include +#include + +/* + * + * Dynamic library loading functions + * + */ + +// dynamically load a library. returns NULL on failure +void *khrIcdOsLibraryLoad(const char *libraryName) +{ + void* ret = dlopen(libraryName, RTLD_NOW); + if (NULL == ret) + { + KHR_ICD_TRACE("Failed to load driver because %s.\n", dlerror()); + } + return ret; +} + +// get a function pointer from a loaded library. returns NULL on failure. +void *khrIcdOsLibraryGetFunctionAddress(void *library, const char *functionName) +{ + return dlsym(library, functionName); +} + +// unload a library +void khrIcdOsLibraryUnload(void *library) +{ + dlclose(library); +} diff --git a/loader/windows/icd_windows.c b/loader/windows/icd_windows.c index 29de4d75..fdc33350 100644 --- a/loader/windows/icd_windows.c +++ b/loader/windows/icd_windows.c @@ -411,43 +411,6 @@ void khrIcdOsVendorsEnumerateOnce() InitOnceExecuteOnce(&initialized, khrIcdOsVendorsEnumerate, NULL, NULL); } -/* - * - * Dynamic library loading functions - * - */ - -// dynamically load a library. returns NULL on failure -void *khrIcdOsLibraryLoad(const char *libraryName) -{ - HMODULE hTemp = LoadLibraryExA(libraryName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); - if (!hTemp && GetLastError() == ERROR_INVALID_PARAMETER) - { - hTemp = LoadLibraryExA(libraryName, NULL, 0); - } - if (!hTemp) - { - KHR_ICD_TRACE("Failed to load driver. Windows error code is %"PRIuDW".\n", GetLastError()); - } - return (void*)hTemp; -} - -// get a function pointer from a loaded library. returns NULL on failure. -void *khrIcdOsLibraryGetFunctionAddress(void *library, const char *functionName) -{ - if (!library || !functionName) - { - return NULL; - } - return GetProcAddress( (HMODULE)library, functionName); -} - -// unload a library. -void khrIcdOsLibraryUnload(void *library) -{ - FreeLibrary( (HMODULE)library); -} - #ifndef CL_LAYER_INFO BOOL APIENTRY DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved) { (void)hinst; diff --git a/loader/windows/icd_windows.h b/loader/windows/icd_windows.h index 8e9e5f40..0cd26d18 100644 --- a/loader/windows/icd_windows.h +++ b/loader/windows/icd_windows.h @@ -15,21 +15,12 @@ * * OpenCL is a trademark of Apple Inc. used under license by Khronos. */ +#ifndef _ICD_WINDOWS_H_ +#define _ICD_WINDOWS_H_ #include #include - -#ifdef _LP64 -#define PRIDW_PREFIX -#define PRIUL_PREFIX -#else -#define PRIDW_PREFIX "l" -#define PRIUL_PREFIX "l" -#endif -#define PRIuDW PRIDW_PREFIX "u" -#define PRIxDW PRIDW_PREFIX "x" -#define PRIuUL PRIUL_PREFIX "u" -#define PRIxUL PRIUL_PREFIX "x" +#include "icd_windows_formats.h" #ifdef __cplusplus extern "C" { @@ -44,3 +35,5 @@ const char* getOpenCLRegKeyName(void); #ifdef __cplusplus } #endif + +#endif diff --git a/loader/windows/icd_windows_envvars.c b/loader/windows/icd_windows_envvars.c index 279a3b66..b3f8be66 100644 --- a/loader/windows/icd_windows_envvars.c +++ b/loader/windows/icd_windows_envvars.c @@ -16,7 +16,8 @@ * OpenCL is a trademark of Apple Inc. used under license by Khronos. */ -#include +#include "icd_trace.h" +#include "icd_envvars.h" #include #include diff --git a/loader/windows/icd_windows_formats.h b/loader/windows/icd_windows_formats.h new file mode 100644 index 00000000..5330474e --- /dev/null +++ b/loader/windows/icd_windows_formats.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2026 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. + * + * OpenCL is a trademark of Apple Inc. used under license by Khronos. + */ + +#ifndef _ICD_WINDOWS_FORMATS_H_ +#define _ICD_WINDOWS_FORMATS_H_ + +#ifdef _LP64 +#define PRIDW_PREFIX +#define PRIUL_PREFIX +#else +#define PRIDW_PREFIX "l" +#define PRIUL_PREFIX "l" +#endif +#define PRIuDW PRIDW_PREFIX "u" +#define PRIxDW PRIDW_PREFIX "x" +#define PRIuUL PRIUL_PREFIX "u" +#define PRIxUL PRIUL_PREFIX "x" + +#endif diff --git a/loader/windows/icd_windows_library.c b/loader/windows/icd_windows_library.c new file mode 100644 index 00000000..24125345 --- /dev/null +++ b/loader/windows/icd_windows_library.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2026 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. + * + * OpenCL is a trademark of Apple Inc. used under license by Khronos. + */ + +#include "icd_trace.h" +#include "icd_library.h" +#include "icd_windows_formats.h" +#include + +/* + * + * Dynamic library loading functions + * + */ + +// dynamically load a library. returns NULL on failure +void *khrIcdOsLibraryLoad(const char *libraryName) +{ + HMODULE hTemp = LoadLibraryExA(libraryName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (!hTemp && GetLastError() == ERROR_INVALID_PARAMETER) + { + hTemp = LoadLibraryExA(libraryName, NULL, 0); + } + if (!hTemp) + { + KHR_ICD_TRACE("Failed to load driver. Windows error code is %"PRIuDW".\n", GetLastError()); + } + return (void*)hTemp; +} + +// get a function pointer from a loaded library. returns NULL on failure. +void *khrIcdOsLibraryGetFunctionAddress(void *library, const char *functionName) +{ + if (!library || !functionName) + { + return NULL; + } + return GetProcAddress( (HMODULE)library, functionName); +} + +// unload a library. +void khrIcdOsLibraryUnload(void *library) +{ + FreeLibrary( (HMODULE)library); +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 578aa259..80a15239 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -6,6 +6,7 @@ add_subdirectory (loader_test) if (ENABLE_OPENCL_LAYERS) add_subdirectory (layer) endif () +add_subdirectory (plugin_test) set_target_properties (IcdLog OpenCLDriverStub OpenCLDriverStubICD2 icd_loader_test PROPERTIES @@ -30,6 +31,11 @@ if (ENABLE_OPENCL_LAYERINFO) ) endif () +add_test ( + NAME plugin_loader_test + COMMAND cl_plugin_loader_test +) + get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if (GENERATOR_IS_MULTI_CONFIG) set (TEST_WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/$") @@ -54,3 +60,9 @@ if (ENABLE_OPENCL_LAYERINFO) WORKING_DIRECTORY "${TEST_WORKING_DIRECTORY}" ) endif() + +set_tests_properties(plugin_loader_test + PROPERTIES + ENVIRONMENT "PLUGIN=$;OCL_ICD_FILENAMES=$" + WORKING_DIRECTORY "${TEST_WORKING_DIRECTORY}" +) diff --git a/test/plugin_test/CLPlugin-mingw-i686.def b/test/plugin_test/CLPlugin-mingw-i686.def new file mode 100644 index 00000000..b482d7bd --- /dev/null +++ b/test/plugin_test/CLPlugin-mingw-i686.def @@ -0,0 +1,27 @@ +; +; Copyright (c) 2026 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. +; +; OpenCL is a trademark of Apple Inc. used under license by Khronos. + +EXPORTS + +; +; Note: This is a special .def file that should only be needed for i686 +; (32-bit) mingw builds. In this case we need to export the stdcall- +; decorated functions. In all other cases we can use the standard .def +; file that does not have decorated functions. +; + +plugin_init@0 == plugin_init diff --git a/test/plugin_test/CLPlugin.def b/test/plugin_test/CLPlugin.def new file mode 100644 index 00000000..10b524f0 --- /dev/null +++ b/test/plugin_test/CLPlugin.def @@ -0,0 +1,20 @@ +; +; Copyright (c) 2026 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. +; +; OpenCL is a trademark of Apple Inc. used under license by Khronos. + +EXPORTS + +plugin_init diff --git a/test/plugin_test/CMakeLists.txt b/test/plugin_test/CMakeLists.txt new file mode 100644 index 00000000..96fa5644 --- /dev/null +++ b/test/plugin_test/CMakeLists.txt @@ -0,0 +1,53 @@ +set (CL_PLUGIN_SOURCES + cl_plugin.c) + +if (WIN32) + # For mingw-i686 builds only we need a special .def file with stdcall + # exports. In all other cases we can use a standard .def file. + if ((CMAKE_SIZEOF_VOID_P EQUAL 4) AND (MINGW OR MSYS OR CYGWIN)) + list (APPEND CL_PLUGIN_SOURCES CLPlugin-mingw-i686.def) + else () + list (APPEND CL_PLUGIN_SOURCES CLPlugin.def) + endif () +endif () + +add_library (CLPlugin MODULE ${CL_PLUGIN_SOURCES}) +target_compile_definitions(CLPlugin PRIVATE CL_TARGET_OPENCL_VERSION=300) +target_link_libraries (CLPlugin OpenCL OpenCL::Headers) + +set (CL_PLUGIN_LOADER_TEST_SOURCES + cl_plugin_loader_test.c + cl_plugin.h + ../../loader/icd_envvars.h + ../../loader/icd_trace.c + ../../loader/icd_trace.h + ../../loader/icd_library.h +) + +if (WIN32) + list (APPEND CL_PLUGIN_LOADER_TEST_SOURCES + ../../loader/windows/icd_windows_formats.h + ../../loader/windows/icd_windows_envvars.c + ../../loader/windows/icd_windows_library.c) + # Only add the DXSDK include directory if the environment variable is + # defined. Since the DXSDK has merged into the Windows SDK, this is + # only required in rare cases. + if (DEFINED ENV{DXSDK_DIR} AND NOT (MINGW OR MSYS OR CYGWIN)) + include_directories ($ENV{DXSDK_DIR}/Include) + endif () +else () + list (APPEND CL_PLUGIN_LOADER_TEST_SOURCES + ../../loader/linux/icd_linux_envvars.c + ../../loader/linux/icd_linux_library.c) +endif () + +add_executable(cl_plugin_loader_test ${CL_PLUGIN_LOADER_TEST_SOURCES}) + +add_executable(OpenCL::cl_plugin_loader_test ALIAS cl_plugin_loader_test) + +target_link_libraries (cl_plugin_loader_test PUBLIC ${CMAKE_DL_LIBS}) + +target_include_directories (cl_plugin_loader_test + PRIVATE + ${CMAKE_BINARY_DIR} + ../../loader) diff --git a/test/plugin_test/cl_plugin.c b/test/plugin_test/cl_plugin.c new file mode 100644 index 00000000..64edd72d --- /dev/null +++ b/test/plugin_test/cl_plugin.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2026 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. + * + * OpenCL is a trademark of Apple Inc. used under license by Khronos. + */ + +#include +#include +#include +#include "cl_plugin.h" + +#define CL_ERR_CHECK(x) \ + do { \ + cl_int err = x; \ + if (CL_SUCCESS != err) { \ + fprintf(stderr, "%s: failed with error code: %d\n", #x, err); \ + return PLUGIN_ERROR; \ + } \ + } while (0) + +plugin_init_fn PLUGIN_INIT; +extern int PLUGIN_INIT(void) { + cl_uint num_platforms = 0; + cl_platform_id* platforms = NULL; + CL_ERR_CHECK(clGetPlatformIDs(0, NULL, &num_platforms)); + if (!num_platforms) { + fprintf(stderr, "No platform found\n"); + return PLUGIN_ERROR; + } + platforms = (cl_platform_id*) malloc(num_platforms * sizeof(cl_platform_id)); + if (!platforms) { + fprintf(stderr, "malloc failed to allocate %zu bytes\n", + num_platforms * sizeof(cl_platform_id)); + return PLUGIN_ERROR; + } + CL_ERR_CHECK(clGetPlatformIDs(num_platforms, platforms, NULL)); + free(platforms); + return PLUGIN_SUCCESS; +} diff --git a/test/plugin_test/cl_plugin.h b/test/plugin_test/cl_plugin.h new file mode 100644 index 00000000..c70f9666 --- /dev/null +++ b/test/plugin_test/cl_plugin.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2026 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. + * + * OpenCL is a trademark of Apple Inc. used under license by Khronos. + */ +#ifndef _CL_PLUGIN_H_ +#define _CL_PLUGIN_H_ + +#define PLUGIN_INIT plugin_init +#define XSTRING(x) TO_STRING(x) +#define TO_STRING(x) #x +#define PLUGIN_INIT_NAME XSTRING(PLUGIN_INIT) + +#define PLUGIN_SUCCESS 0 +#define PLUGIN_ERROR 1 + +typedef int plugin_init_fn(void); +typedef plugin_init_fn *plugin_init_pfn; + +#endif diff --git a/test/plugin_test/cl_plugin_loader_test.c b/test/plugin_test/cl_plugin_loader_test.c new file mode 100644 index 00000000..78fe029b --- /dev/null +++ b/test/plugin_test/cl_plugin_loader_test.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2026 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. + * + * OpenCL is a trademark of Apple Inc. used under license by Khronos. + */ + +#include "icd_envvars.h" +#include "icd_library.h" +#include "cl_plugin.h" +#include +#include + +/* + * This test program uses loader components for portability (environment, + * library) in order to repeatedly load, initialize, and unload a plugin. The + * interface of the plugin is defined in `cl_plugin.h`. This interface define + * an initialization function and return results. A plugin that is linked to + * the OpenCL ICD Loader, and uses OpenCL functionalities in its initialization + * function, will allow checking that the loader initialization and + * deinitialization are working correctly. + */ + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + char *plugin = khrIcd_getenv("PLUGIN"); + + if (!plugin) { + fprintf(stderr, "PLUGIN is not defined\n"); + return 1; + } + + for (int i = 0; i < 10; i++) { + void *library = khrIcdOsLibraryLoad(plugin); + if (!library) { + fprintf(stderr, "could not load plugin\n"); + return 1; + } + plugin_init_pfn init = (plugin_init_pfn)(size_t) + khrIcdOsLibraryGetFunctionAddress(library, PLUGIN_INIT_NAME); + if (!init) { + fprintf(stderr, "plugin does not contain init function: %s\n", PLUGIN_INIT_NAME); + return 1; + } + int res = init(); + if (PLUGIN_SUCCESS != res) { + fprintf(stderr, "plugin initialization failed\n"); + return 1; + } + khrIcdOsLibraryUnload(library); + } + + khrIcd_free_getenv(plugin); + + return 0; +}