From a99950812c85be42728ad9c4b6021598213c4803 Mon Sep 17 00:00:00 2001 From: Vitalii Koshura Date: Wed, 23 Aug 2023 23:59:15 +0200 Subject: [PATCH] [Android] Fix GPU detection Starting from Android 8, the GPU detection is broken due to the fact that dlopen() now return NULL. This was done to fix issues with library names resolution. New API was introduced, but it's not available from the NDK. Instead, we have to load the library manually and call the function directly. Unfortunately, on Android this behavior was changed even more, and now we need to look for other functions. By fixing this behavior, we have now successful Mali GPU detection. But unfortunately, this doesn't work for Qualcomm Adreno GPUs. Looks like implementation of Qualcomm has some problems with clGetDeviceIDs. It returns CL_DEVICE_NOT_FOUND for CL_DEVICE_TYPE_GPU and CL_DEVICE_TYPE_ACCELERATOR combined. But it returns CL_SUCCESS when asking separately for CL_DEVICE_TYPE_GPU or CL_DEVICE_TYPE_ACCELERATOR. So we will ask for CL_DEVICE_TYPE_GPU and CL_DEVICE_TYPE_ACCELERATOR separately. This fixes #3613 and #4204. Signed-off-by: Vitalii Koshura --- client/gpu_opencl.cpp | 109 +++++++++++++++++++++++++++++++++++++++++- lib/cl_boinc.h | 1 + lib/opencl_boinc.h | 2 +- 3 files changed, 109 insertions(+), 3 deletions(-) diff --git a/client/gpu_opencl.cpp b/client/gpu_opencl.cpp index 5f0c48a5b1..bf4f16adf2 100644 --- a/client/gpu_opencl.cpp +++ b/client/gpu_opencl.cpp @@ -176,6 +176,72 @@ int compareOSVersionTo(int toMajor, int toMinor) { } #endif +#ifdef ANDROID +#include +void* (*p_android_dlopen_ext)(const char*, int, const android_dlextinfo*); +struct android_namespace_t* (*p_android_create_namespace)(const char*, const char*, const char*, uint64_t, const char*, struct android_namespace_t*); +struct android_namespace_t* (*p_android_get_exported_namespace)(const char*); + +struct android_namespace_t* get_android_namespace(vector& warnings) { + p_android_get_exported_namespace = (struct android_namespace_t*(*)(const char*)) dlsym(RTLD_DEFAULT, "android_get_exported_namespace"); + if (!p_android_get_exported_namespace) { + gpu_warning(warnings, "No android_get_exported_namespace()"); + } + if (!p_android_get_exported_namespace) { + p_android_get_exported_namespace = (struct android_namespace_t*(*)(const char*)) dlsym(RTLD_DEFAULT, "__loader_android_get_exported_namespace"); + if (!p_android_get_exported_namespace) { + gpu_warning(warnings, "No __loader_android_get_exported_namespace()"); + } + } + if (p_android_get_exported_namespace) { + return (*p_android_get_exported_namespace)("vndk"); + } + + p_android_create_namespace = (struct android_namespace_t*(*)(const char*, const char*, const char*, uint64_t, const char*, struct android_namespace_t*)) dlsym(RTLD_DEFAULT, "android_create_namespace"); + if (!p_android_create_namespace) { + gpu_warning(warnings, "No android_create_namespace()"); + return NULL; + } + string lib_path; + if (sizeof(void*) == 8) { + lib_path = "/system/lib64/"; + } + else { + lib_path = "/system/lib/"; + } +#define ANDROID_NAMESPACE_TYPE_ISOLATED 1 +#define ANDROID_NAMESPACE_TYPE_SHARED 2 + return (*p_android_create_namespace)("trustme", lib_path.c_str(), lib_path.c_str(), ANDROID_NAMESPACE_TYPE_SHARED | ANDROID_NAMESPACE_TYPE_ISOLATED, "/system/:/data/:/vendor/", NULL); +} + +void* android_dlopen(const char* filename, vector& warnings) { + char buf[256]; + gpu_warning(warnings, "Trying dlopen()"); + void* handle = dlopen(filename, RTLD_NOW); + if (handle) { + return handle; + } + + p_android_dlopen_ext = (void*(*)(const char*, int, const android_dlextinfo*)) dlsym(RTLD_DEFAULT, "android_dlopen_ext"); + if (!p_android_dlopen_ext) { + gpu_warning(warnings, "No android_dlopen_ext()"); + return NULL; + } + + struct android_namespace_t* ns = get_android_namespace(warnings); + if (!ns) { + gpu_warning(warnings, "No namespace"); + return NULL; + } + + const android_dlextinfo dlextinfo = { + .flags = ANDROID_DLEXT_USE_NAMESPACE, + .library_namespace = ns, + }; + gpu_warning(warnings, "Trying android_dlopen_ext()"); + return (*p_android_dlopen_ext)(filename, RTLD_NOW, &dlextinfo); +} +#endif // OpenCL interfaces are documented here: // http://www.khronos.org/registry/cl/sdk/1.0/docs/man/xhtml/ and @@ -219,6 +285,8 @@ void COPROCS::get_opencl( #else #ifdef __APPLE__ opencl_lib = dlopen("/System/Library/Frameworks/OpenCL.framework/Versions/Current/OpenCL", RTLD_NOW); +#elif defined ANDROID + opencl_lib = android_dlopen("libOpenCL.so", warnings); #else opencl_lib = dlopen("libOpenCL.so", RTLD_NOW); if (!opencl_lib) { @@ -338,14 +406,49 @@ void COPROCS::get_opencl( //////////// GPUs and Accelerators ////////////// +// Looks like implementation of Qualcomm has some problems with clGetDeviceIDs +// It returns CL_DEVICE_NOT_FOUND for CL_DEVICE_TYPE_GPU and CL_DEVICE_TYPE_ACCELERATOR combined +// But it returns CL_SUCCESS when asking separately for CL_DEVICE_TYPE_GPU or CL_DEVICE_TYPE_ACCELERATOR +// So we will ask for CL_DEVICE_TYPE_GPU and CL_DEVICE_TYPE_ACCELERATOR separately +#ifdef ANDROID + cl_device_id android_gpu[MAX_COPROC_INSTANCES]; + cl_uint num_android_gpu = 0; + ciErrNum = (*p_clGetDeviceIDs)( + platforms[platform_index], + (CL_DEVICE_TYPE_GPU), + MAX_COPROC_INSTANCES, android_gpu, &num_android_gpu + ); + if (ciErrNum == CL_SUCCESS && num_android_gpu > 0) { + for (int i=0; i 0) { + for (int i=0; i