HarmonyOS 鸿蒙Next中通过C++获取GPU信息
HarmonyOS 鸿蒙Next中通过C++获取GPU信息
#include <cstring>
#include <string>
#include "napi/native_api.h"
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl3.h>
// EGL 上下文结构体
struct EglContext {
EGLDisplay display = EGL_NO_DISPLAY;
EGLConfig config = nullptr;
EGLContext context = EGL_NO_CONTEXT;
EGLSurface surface = EGL_NO_SURFACE;
bool initialized = false;
};
static EglContext g_eglContext;
// 初始化 EGL 上下文
static bool InitEglContext() {
if (g_eglContext.initialized) {
return true;
}
// 1. 获取 EGL Display
g_eglContext.display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (g_eglContext.display == EGL_NO_DISPLAY) {
return false;
}
// 2. 初始化 EGL
EGLint majorVersion = 0;
EGLint minorVersion = 0;
if (!eglInitialize(g_eglContext.display, &majorVersion, &minorVersion)) {
return false;
}
// 3. 选择 EGL 配置
EGLint attribs[] = {
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_NONE
};
EGLint numConfigs = 0;
if (!eglChooseConfig(g_eglContext.display, attribs, &g_eglContext.config, 1, &numConfigs)
|| numConfigs == 0) {
eglTerminate(g_eglContext.display);
g_eglContext.display = EGL_NO_DISPLAY;
return false;
}
// 4. 创建 PBuffer Surface (不需要窗口)
EGLint surfaceAttribs[] = {
EGL_WIDTH, 1,
EGL_HEIGHT, 1,
EGL_NONE
};
g_eglContext.surface = eglCreatePbufferSurface(g_eglContext.display,
g_eglContext.config, surfaceAttribs);
if (g_eglContext.surface == EGL_NO_SURFACE) {
eglTerminate(g_eglContext.display);
g_eglContext.display = EGL_NO_DISPLAY;
return false;
}
// 5. 创建 EGL Context
EGLint contextAttribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
g_eglContext.context = eglCreateContext(g_eglContext.display,
g_eglContext.config,
EGL_NO_CONTEXT, contextAttribs);
if (g_eglContext.context == EGL_NO_CONTEXT) {
eglDestroySurface(g_eglContext.display, g_eglContext.surface);
eglTerminate(g_eglContext.display);
g_eglContext.display = EGL_NO_DISPLAY;
return false;
}
// 6. 绑定上下文
if (!eglMakeCurrent(g_eglContext.display, g_eglContext.surface,
g_eglContext.surface, g_eglContext.context)) {
eglDestroyContext(g_eglContext.display, g_eglContext.context);
eglDestroySurface(g_eglContext.display, g_eglContext.surface);
eglTerminate(g_eglContext.display);
g_eglContext.display = EGL_NO_DISPLAY;
return false;
}
g_eglContext.initialized = true;
return true;
}
// 释放 EGL 上下文
static void ReleaseEglContext() {
if (!g_eglContext.initialized) {
return;
}
eglMakeCurrent(g_eglContext.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(g_eglContext.display, g_eglContext.context);
eglDestroySurface(g_eglContext.display, g_eglContext.surface);
eglTerminate(g_eglContext.display);
g_eglContext.display = EGL_NO_DISPLAY;
g_eglContext.config = nullptr;
g_eglContext.context = EGL_NO_CONTEXT;
g_eglContext.surface = EGL_NO_SURFACE;
g_eglContext.initialized = false;
}
// ==================== GPU 信息获取函数 ====================
// 获取 GPU 供应商
napi_value GetGpuVendor(napi_env env, napi_callback_info info) {
std::string vendor = "未知";
if (InitEglContext()) {
const char* glVendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
if (glVendor != nullptr) {
vendor = glVendor;
}
}
napi_value result;
napi_create_string_utf8(env, vendor.c_str(), vendor.length(), &result);
return result;
}
// 获取 GPU 渲染器名称 (型号)
napi_value GetGpuRenderer(napi_env env, napi_callback_info info) {
std::string renderer = "未知";
if (InitEglContext()) {
const char* glRenderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
if (glRenderer != nullptr) {
renderer = glRenderer;
}
}
napi_value result;
napi_create_string_utf8(env, renderer.c_str(), renderer.length(), &result);
return result;
}
// 获取 OpenGL ES 版本
napi_value GetGpuGlVersion(napi_env env, napi_callback_info info) {
std::string version = "未知";
if (InitEglContext()) {
const char* glVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
if (glVersion != nullptr) {
version = glVersion;
}
}
napi_value result;
napi_create_string_utf8(env, version.c_str(), version.length(), &result);
return result;
}
// 获取着色语言版本
napi_value GetGpuGlslVersion(napi_env env, napi_callback_info info) {
std::string glslVersion = "未知";
if (InitEglContext()) {
const char* glGlslVersion = reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION));
if (glGlslVersion != nullptr) {
glslVersion = glGlslVersion;
}
}
napi_value result;
napi_create_string_utf8(env, glslVersion.c_str(), glslVersion.length(), &result);
return result;
}
// 获取 OpenGL ES 扩展列表
napi_value GetGpuExtensions(napi_env env, napi_callback_info info) {
std::string extensions = "";
if (InitEglContext()) {
// OpenGL ES 3.0+ 使用 glGetIntegerv 获取扩展数量
GLint numExtensions = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
if (numExtensions > 0) {
// 使用 glGetStringi 获取每个扩展
for (GLint i = 0; i < numExtensions; i++) {
const char* ext = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i));
if (ext != nullptr) {
if (i > 0) {
extensions += "\n";
}
extensions += ext;
}
}
} else {
// OpenGL ES 2.0 兼容方式
const char* exts = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
if (exts != nullptr) {
// 将空格替换为换行符,便于显示
extensions = exts;
size_t pos = 0;
while ((pos = extensions.find(' ', pos)) != std::string::npos) {
extensions.replace(pos, 1, "\n");
pos += 1;
}
}
}
}
if (extensions.empty()) {
extensions = "无扩展信息";
}
napi_value result;
napi_create_string_utf8(env, extensions.c_str(), extensions.length(), &result);
return result;
}
// 获取扩展数量
napi_value GetGpuExtensionCount(napi_env env, napi_callback_info info) {
int count = 0;
if (InitEglContext()) {
GLint numExtensions = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
count = numExtensions;
// 如果获取不到,尝试解析扩展字符串
if (count == 0) {
const char* exts = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
if (exts != nullptr) {
std::string extStr = exts;
for (size_t i = 0; i < extStr.length(); i++) {
if (extStr[i] == ' ') {
count++;
}
}
if (!extStr.empty()) {
count++; // 最后一个扩展
}
}
}
}
napi_value result;
napi_create_int32(env, count, &result);
return result;
}
// 检查是否支持特定扩展
napi_value CheckGpuExtension(napi_env env, napi_callback_info info) {
bool supported = false;
size_t argc = 1;
napi_value args[1];
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
if (argc < 1) {
napi_value result;
napi_get_boolean(env, false, &result);
return result;
}
size_t extNameLen = 0;
napi_get_value_string_utf8(env, args[0], nullptr, 0, &extNameLen);
char* extName = new char[extNameLen + 1];
napi_get_value_string_utf8(env, args[0], extName, extNameLen + 1, &extNameLen);
if (InitEglContext()) {
GLint numExtensions = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
if (numExtensions > 0) {
for (GLint i = 0; i < numExtensions; i++) {
const char* ext = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i));
if (ext != nullptr && strcmp(ext, extName) == 0) {
supported = true;
break;
}
}
} else {
const char* exts = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
if (exts != nullptr) {
std::string extStr = exts;
std::string target = extName;
// 在扩展字符串中查找
size_t pos = 0;
while ((pos = extStr.find(target, pos)) != std::string::npos) {
// 检查边界
bool validStart = (pos == 0 || extStr[pos - 1] == ' ');
bool validEnd = (pos + target.length() == extStr.length() ||
extStr[pos + target.length()] == ' ');
if (validStart && validEnd) {
supported = true;
break;
}
pos++;
}
}
}
}
delete[] extName;
napi_value result;
napi_get_boolean(env, supported, &result);
return result;
}
// 获取 EGL 版本
napi_value GetEglVersion(napi_env env, napi_callback_info info) {
std::string eglVersion = "未知";
if (InitEglContext()) {
EGLint major = 0, minor = 0;
eglQueryContext(g_eglContext.display, g_eglContext.context,
EGL_CONTEXT_CLIENT_VERSION, &major);
// 尝试获取 EGL 版本
if (eglInitialize(g_eglContext.display, &major, &minor)) {
eglVersion = std::to_string(major) + "." + std::to_string(minor);
}
}
napi_value result;
napi_create_string_utf8(env, eglVersion.c_str(), eglVersion.length(), &result);
return result;
}
// 获取 GPU 完整信息对象
napi_value GetGpuInfo(napi_env env, napi_callback_info info) {
napi_value result;
napi_create_object(env, &result);
if (!InitEglContext()) {
// 初始化失败,返回默认值
napi_value vendor, renderer, version, glslVersion, extensions, extCount;
napi_create_string_utf8(env, "初始化失败", strlen("初始化失败"), &vendor);
napi_create_string_utf8(env, "初始化失败", strlen("初始化失败"), &renderer);
napi_create_string_utf8(env, "初始化失败", strlen("初始化失败"), &version);
napi_create_string_utf8(env, "初始化失败", strlen("初始化失败"), &glslVersion);
napi_create_string_utf8(env, "", 0, &extensions);
napi_create_int32(env, 0, &extCount);
napi_set_named_property(env, result, "vendor", vendor);
napi_set_named_property(env, result, "renderer", renderer);
napi_set_named_property(env, result, "glVersion", version);
napi_set_named_property(env, result, "glslVersion", glslVersion);
napi_set_named_property(env, result, "extensions", extensions);
napi_set_named_property(env, result, "extensionCount", extCount);
return result;
}
// 获取各项信息
const char* glVendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
const char* glRenderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
const char* glVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
const char* glGlslVersion = reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION));
// 设置属性
napi_value vendorVal, rendererVal, versionVal, glslVal;
std::string vendorStr = glVendor ? glVendor : "未知";
std::string rendererStr = glRenderer ? glRenderer : "未知";
std::string versionStr = glVersion ? glVersion : "未知";
std::string glslStr = glGlslVersion ? glGlslVersion : "未知";
napi_create_string_utf8(env, vendorStr.c_str(), vendorStr.length(), &vendorVal);
napi_create_string_utf8(env, rendererStr.c_str(), rendererStr.length(), &rendererVal);
napi_create_string_utf8(env, versionStr.c_str(), versionStr.length(), &versionVal);
napi_create_string_utf8(env, glslStr.c_str(), glslStr.length(), &glslVal);
napi_set_named_property(env, result, "vendor", vendorVal);
napi_set_named_property(env, result, "renderer", rendererVal);
napi_set_named_property(env, result, "glVersion", versionVal);
napi_set_named_property(env, result, "glslVersion", glslVal);
// 扩展数量
GLint numExtensions = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
napi_value extCountVal;
napi_create_int32(env, numExtensions, &extCountVal);
napi_set_named_property(env, result, "extensionCount", extCountVal);
return result;
}
// 释放资源
napi_value ReleaseGpuResources(napi_env env, napi_callback_info info) {
ReleaseEglContext();
napi_value result;
napi_get_undefined(env, &result);
return result;
}
// ==================== GPU 函数导出声明 ====================
// 这些函数将在 cpu_info.cpp 的模块注册中导出
更多关于HarmonyOS 鸿蒙Next中通过C++获取GPU信息的实战教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS Next中,通过C++获取GPU信息可调用Vulkan API:使用vkEnumeratePhysicalDevices枚举设备,再调用vkGetPhysicalDeviceProperties获取设备名称、类型、驱动版本等。若基于OpenGL ES,可用eglQueryString(eglGetDisplay(EGL_DEFAULT_DISPLAY), EGL_RENDERER)获取渲染器字符串。需正确链接libEGL、libvulkan等库。
更多关于HarmonyOS 鸿蒙Next中通过C++获取GPU信息的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS Next中,通过C++获取GPU信息时,使用EGL/OpenGL ES是一种可行的方式。您提供的代码创建了EGL上下文(借助Pbuffer表面免窗口依赖),然后利用glGetString、glGetStringi等接口获取GPU厂商、渲染器、版本、扩展等详细信息。
这种方法的关键点是:必须确保在拥有EGL上下文的线程调用查询,EGL上下文是线程绑定的;HarmonyOS Native侧已支持EGL,无需额外权限,但应用中需正确链接EGL和GLESv3库。此外,还可通过解析ro.product.gpu等系统属性或deviceinfo模块获取GPU型号,但EGL方式能提供更精确的驱动版本和特性支持情况。您提供的代码整体结构正确,使用了静态全局上下文和错误处理,适合在工具类场景使用。

