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

2 回复

在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表面免窗口依赖),然后利用glGetStringglGetStringi等接口获取GPU厂商、渲染器、版本、扩展等详细信息。

这种方法的关键点是:必须确保在拥有EGL上下文的线程调用查询,EGL上下文是线程绑定的;HarmonyOS Native侧已支持EGL,无需额外权限,但应用中需正确链接EGL和GLESv3库。此外,还可通过解析ro.product.gpu等系统属性或deviceinfo模块获取GPU型号,但EGL方式能提供更精确的驱动版本和特性支持情况。您提供的代码整体结构正确,使用了静态全局上下文和错误处理,适合在工具类场景使用。

回到顶部