参考
https://gitcode.com/openharmony-sig/third_party_opencl-icd-loader
https://gitcode.com/openharmony/third_party_opencl-headers
需要将https://gitcode.com/openharmony/third_party_opencl-headers项目里opencl-headers-CL目录下的头文件放到native层中
#include "napi/native_api.h"
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <cstdint>
#include <sys/stat.h>
#include <unistd.h>
#include <hilog/log.h>
#include <errno.h>
#include <dlfcn.h>
#include <CL/cl.h>
#include <dlfcn.h>
#include <node_api.h>
static napi_value Hello(napi_env env, napi_callback_info info)
{
napi_value result = nullptr;
std::string message;
// 用于返回字符串结果
auto finish = [&](const std::string& text) -> napi_value {
napi_create_string_utf8(env, text.c_str(), NAPI_AUTO_LENGTH, &result);
return result;
};
// 尝试加载 OpenCL 动态库
void* handle = nullptr;
std::string loadedLibraryName;
const char* candidateLibraries[] = {
"/vendor/lib64/libOpenCL.so",
"/vendor/lib64/chipsetsdk/libGLES_mali.so",
"/system/lib64/libGLES_mali.so",
"libGLES_mali.so",
"/vendor/lib64/chipsetsdk/libhvgr_v200.so",
"/vendor/lib64/passthrough/libhvgr_v200.so",
"libhvgr_v200.so",
"/vendor/lib64/chipsetsdk/libEGL_impl.so",
"/vendor/lib64/passthrough/libEGL_impl.so",
"libEGL_impl.so"
};
for (const char* libraryName : candidateLibraries) {
dlerror();
handle = dlopen(libraryName, RTLD_NOW | RTLD_LOCAL);
const char* error = dlerror();
if (handle != nullptr) {
loadedLibraryName = libraryName;
message += "OpenCL动态库加载成功: ";
message += libraryName;
message += "\n";
break;
} else {
message += "OpenCL动态库加载失败: ";
message += libraryName;
message += " , error = ";
message += (error == nullptr ? "unknown" : error);
message += "\n";
}
}
if (handle == nullptr) {
message += "\n结论: native层无法加载OpenCL动态库,当前设备/系统对应用未暴露可用的OpenCL运行库。";
return finish(message);
}
// 解析关键 OpenCL API
auto loadSymbol = [&](const char* symbolName) -> void* {
dlerror();
void* symbol = dlsym(handle, symbolName);
const char* error = dlerror();
if (symbol == nullptr || error != nullptr) {
message += "解析符号失败: ";
message += symbolName;
message += " , error = ";
message += (error == nullptr ? "unknown" : error);
message += "\n";
return nullptr;
}
return symbol;
};
auto clGetPlatformIDsPtr =
reinterpret_cast<cl_int (*)(cl_uint, cl_platform_id*, cl_uint*)>(loadSymbol("clGetPlatformIDs"));
auto clGetPlatformInfoPtr =
reinterpret_cast<cl_int (*)(cl_platform_id, cl_platform_info, size_t, void*, size_t*)>(
loadSymbol("clGetPlatformInfo"));
auto clGetDeviceIDsPtr =
reinterpret_cast<cl_int (*)(cl_platform_id, cl_device_type, cl_uint, cl_device_id*, cl_uint*)>(
loadSymbol("clGetDeviceIDs"));
auto clGetDeviceInfoPtr =
reinterpret_cast<cl_int (*)(cl_device_id, cl_device_info, size_t, void*, size_t*)>(
loadSymbol("clGetDeviceInfo"));
if (clGetPlatformIDsPtr == nullptr ||
clGetPlatformInfoPtr == nullptr ||
clGetDeviceIDsPtr == nullptr ||
clGetDeviceInfoPtr == nullptr) {
message += "\n结论: OpenCL动态库已加载,但关键API符号不完整,无法继续验证。";
dlclose(handle);
return finish(message);
}
// 读取字符串信息的辅助方法
auto getPlatformString = [&](cl_platform_id platform, cl_platform_info param) -> std::string {
size_t size = 0;
cl_int err = clGetPlatformInfoPtr(platform, param, 0, nullptr, &size);
if (err != CL_SUCCESS || size == 0) {
return "";
}
std::vector<char> buffer(size, 0);
err = clGetPlatformInfoPtr(platform, param, size, buffer.data(), nullptr);
if (err != CL_SUCCESS) {
return "";
}
return std::string(buffer.data());
};
auto getDeviceString = [&](cl_device_id device, cl_device_info param) -> std::string {
size_t size = 0;
cl_int err = clGetDeviceInfoPtr(device, param, 0, nullptr, &size);
if (err != CL_SUCCESS || size == 0) {
return "";
}
std::vector<char> buffer(size, 0);
err = clGetDeviceInfoPtr(device, param, size, buffer.data(), nullptr);
if (err != CL_SUCCESS) {
return "";
}
return std::string(buffer.data());
};
// 第一步:验证 OpenCL API 是否真的能调用
cl_uint platformCount = 0;
cl_int err = clGetPlatformIDsPtr(0, nullptr, &platformCount);
message += "clGetPlatformIDs(查询platform数量) 返回值: ";
message += std::to_string(err);
message += "\n";
if (err != CL_SUCCESS) {
message += "结论: OpenCL动态库已加载,但clGetPlatformIDs调用失败,native层无法正常使用OpenCL。";
dlclose(handle);
return finish(message);
}
message += "platform数量: ";
message += std::to_string(platformCount);
message += "\n";
if (platformCount == 0) {
message += "结论: OpenCL API可以调用,但没有枚举到任何platform,通常表示没有实际可用的OpenCL驱动。";
dlclose(handle);
return finish(message);
}
// 获取第一个 platform
std::vector<cl_platform_id> platforms(platformCount);
err = clGetPlatformIDsPtr(platformCount, platforms.data(), nullptr);
message += "clGetPlatformIDs(获取platform列表) 返回值: ";
message += std::to_string(err);
message += "\n";
if (err != CL_SUCCESS || platforms.empty()) {
message += "结论: platform数量可获取,但platform列表获取失败。";
dlclose(handle);
return finish(message);
}
cl_platform_id platform = platforms[0];
std::string platformName = getPlatformString(platform, CL_PLATFORM_NAME);
std::string platformVendor = getPlatformString(platform, CL_PLATFORM_VENDOR);
std::string platformVersion = getPlatformString(platform, CL_PLATFORM_VERSION);
message += "platform名称: ";
message += (platformName.empty() ? "unknown" : platformName);
message += "\n";
message += "platform厂商: ";
message += (platformVendor.empty() ? "unknown" : platformVendor);
message += "\n";
message += "platform版本: ";
message += (platformVersion.empty() ? "unknown" : platformVersion);
message += "\n";
// 第二步:优先检查 GPU 设备
cl_uint gpuDeviceCount = 0;
err = clGetDeviceIDsPtr(platform, CL_DEVICE_TYPE_GPU, 0, nullptr, &gpuDeviceCount);
message += "clGetDeviceIDs(查询GPU设备数量) 返回值: ";
message += std::to_string(err);
message += "\n";
message += "GPU设备数量: ";
message += std::to_string(gpuDeviceCount);
message += "\n";
if (err == CL_SUCCESS && gpuDeviceCount > 0) {
std::vector<cl_device_id> gpuDevices(gpuDeviceCount);
err = clGetDeviceIDsPtr(platform, CL_DEVICE_TYPE_GPU, gpuDeviceCount, gpuDevices.data(), nullptr);
message += "clGetDeviceIDs(获取GPU设备列表) 返回值: ";
message += std::to_string(err);
message += "\n";
if (err == CL_SUCCESS && !gpuDevices.empty()) {
cl_device_id device = gpuDevices[0];
std::string deviceName = getDeviceString(device, CL_DEVICE_NAME);
std::string deviceVendor = getDeviceString(device, CL_DEVICE_VENDOR);
std::string driverVersion = getDeviceString(device, CL_DRIVER_VERSION);
std::string deviceVersion = getDeviceString(device, CL_DEVICE_VERSION);
message += "GPU设备名称: ";
message += (deviceName.empty() ? "unknown" : deviceName);
message += "\n";
message += "GPU设备厂商: ";
message += (deviceVendor.empty() ? "unknown" : deviceVendor);
message += "\n";
message += "驱动版本: ";
message += (driverVersion.empty() ? "unknown" : driverVersion);
message += "\n";
message += "设备版本: ";
message += (deviceVersion.empty() ? "unknown" : deviceVersion);
message += "\n";
message += "\n结论: native层可以成功调用OpenCL,并且检测到了GPU设备。";
dlclose(handle);
return finish(message);
}
}
// 第三步:如果没有 GPU,再检查是否存在任意 OpenCL 设备
cl_uint allDeviceCount = 0;
err = clGetDeviceIDsPtr(platform, CL_DEVICE_TYPE_ALL, 0, nullptr, &allDeviceCount);
message += "clGetDeviceIDs(查询全部设备数量) 返回值: ";
message += std::to_string(err);
message += "\n";
message += "全部设备数量: ";
message += std::to_string(allDeviceCount);
message += "\n";
if (err == CL_SUCCESS && allDeviceCount > 0) {
std::vector<cl_device_id> allDevices(allDeviceCount);
err = clGetDeviceIDsPtr(platform, CL_DEVICE_TYPE_ALL, allDeviceCount, allDevices.data(), nullptr);
message += "clGetDeviceIDs(获取全部设备列表) 返回值: ";
message += std::to_string(err);
message += "\n";
if (err == CL_SUCCESS && !allDevices.empty()) {
cl_device_id device = allDevices[0];
std::string deviceName = getDeviceString(device, CL_DEVICE_NAME);
std::string deviceVendor = getDeviceString(device, CL_DEVICE_VENDOR);
std::string driverVersion = getDeviceString(device, CL_DRIVER_VERSION);
std::string deviceVersion = getDeviceString(device, CL_DEVICE_VERSION);
message += "首个OpenCL设备名称: ";
message += (deviceName.empty() ? "unknown" : deviceName);
message += "\n";
message += "设备厂商: ";
message += (deviceVendor.empty() ? "unknown" : deviceVendor);
message += "\n";
message += "驱动版本: ";
message += (driverVersion.empty() ? "unknown" : driverVersion);
message += "\n";
message += "设备版本: ";
message += (deviceVersion.empty() ? "unknown" : deviceVersion);
message += "\n";
message += "\n结论: native层可以成功调用OpenCL,但没有检测到GPU类型设备;当前存在其他类型的OpenCL设备。";
dlclose(handle);
return finish(message);
}
}
message += "\n结论: native层可以加载并调用OpenCL API,但当前没有检测到可用的OpenCL设备。";
dlclose(handle);
return finish(message);
}