OpenGL_wrapper

整体

OpenGL_wrapper是干什么的

RS或者应用去调用egl或者gl能力都需要走OpenGL_wrapper层。OpenHarmony在启动过程中,EGL初始化时会去load GPU驱动so,获取所有API的symbol。应用调用的API都是走到Wrapper层的诸如libEGL_impl.so声明的接口,然后通过之前获取的symbol调用GPU libGLES_mali.so中真正的实现。

相关层解释

1.OpenGL ES

它本身只是一个协议规范,定义了一套可以提供上层应用程序进行调用的 API,它抽象了 GPU 的功能,使应用开发者不必关心底层 GPU 的具体实现。

2.OpenGL ES库

OpenGL ES库就是上面 OpenGL ES 中定义的API的具体实现。由于每个显卡制造厂商的 GPU 硬件结构不同,从而导致各个厂商的OpenGL ES库也各不相同,所以系统中的OpenGL ES库通常是由硬件厂商提供的,通常存放在系统中的 /system/lib64/egl 下面或者 /vendor/lib64/egl 目录下。目前我们用的时mali gpu,因此库叫libGLES_mali.so。

3.OpenGL ES Wrapper库

OpenGL ES Wrapper 库是一个对 OpenGL ES API 进行封装的一个包裹库,它向上为应用程序提供了标准的OpenGL ES API,向下可以和不同厂商实现的 OpenGL ES库进行绑定,将OpenGL ES API和对应的实现函数一一绑定在一起。即libEGL_impl.so、libGLESv1_impl.so、libGLESv2_impl.so、libGLESv3_impl.so。
libEGL_impl.so:EGL API Wrapper库,除了包好EGL API的定义,还包括其它egl相关功能。
libGLESv1_impl.so: OpenGL ES 1.x API的Wrapper库
libGLESv2_impl.so: OpenGL ES 2.0 API的Wrapper库
libGLESv3_impl.so: OpenGL ES 3.0 API的Wrapper库

调用流程

img

1.应用调用API接口(很多地方都调用,下面举例随机一个)

static EGLDisplay GetPlatformEglDisplay(EGLenum platform, void* native_display, const EGLint* attrib_list)
{
    static GetPlatformDisplayExt eglGetPlatformDisplayExt = NULL;

    ...

    return eglGetDisplay(static_cast<EGLNativeDisplayType>(native_display));
}

2. API通过 egl_hook_entries.in文件

HOOK_API_ENTRY(EGLDisplay, eglGetDisplay, EGLNativeDisplayType type)
CALL_HOOK_API_RET(eglGetDisplay, type)

3. hook钩子函数跳转到egl.cpp中 CALL_HOOK_API_RET


#undef CALL_HOOK_API
#define CALL_HOOK_API(api, ...)                                         \
    do {                                                                \
        if (OHOS::EglCoreInit() && OHOS::CheckEglWrapperApi(#api)) {    \
            OHOS::gWrapperHook.wrapper.api(__VA_ARGS__);                \
        } else {                                                        \
            WLOGE("%{public}s is invalid.", #api);                      \
        }                                                               \
    } while (0);                                                        \
}

#undef CALL_HOOK_API_RET
#define CALL_HOOK_API_RET(api, ...)                                     \
    do {                                                                \
        if (OHOS::EglCoreInit() && OHOS::CheckEglWrapperApi(#api)) {    \
            return OHOS::gWrapperHook.wrapper.api(__VA_ARGS__);         \
        } else {                                                        \
            WLOGE("%{public}s is invalid.", #api);                      \
            return 0;                                                   \
        }                                                               \
    } while (0);                                                        \
}

4. 如果是第一次通过wrapper调用API,则需初始化 EglCoreInit()

bool EglCoreInit()
{
    std::lock_guard<std::mutex> lock(gInitMutex);

    if (gWrapperHook.isLoad) {
        return true;
    }

    if (!preInitializer.InitStat()) {
        WLOGE("preInit Error.");
        return false;
    }

    WrapperHookTableInit();
    EglWrapperLoader& loader(EglWrapperLoader::GetInstance());
    if (!loader.Load(&gWrapperHook)) {
        WLOGE("EglWrapperLoader Load Failed.");
        return false;
    }

    EglWrapperLayer& layer(EglWrapperLayer::GetInstance());
    if (!layer.Init(&gWrapperHook)) {
        WLOGE("EglWrapperLayer Init Failed.");
    }

#if USE_IGRAPHICS_EXTENDS_HOOKS
    if (!layer.GetIGraphicsLogicStatus()) {
        return true;
    }

    EglWrapperHook& hookLayer(EglWrapperHook::GetInstance());
    if (!hookLayer.Hook(&gWrapperHook)) {
        WLOGE("EglWrapperHookLayer init Failed!");
    } else {
        WLOGI("EglWrapperHookLayer init Success!");
    }
#endif
    return true;
}

5.load对应的GPU驱动so,通过in文件获取所有的API

img


constexpr const char *LIB_EGL_NAME = "libEGL_impl.so";
constexpr const char *LIB_GLESV1_NAME = "libGLESv1_impl.so";
constexpr const char *LIB_GLESV2_NAME = "libGLESv2_impl.so";
constexpr const char *LIB_GLESV3_NAME = "libGLESv3_impl.so";

bool EglWrapperLoader::LoadVendorDriver(EglWrapperDispatchTable *table)
{
    WLOGD("EGL");
    if (!LoadEgl(LIB_EGL_NAME, &table->egl)) {
        WLOGE("LoadEgl Failed.");
        return false;
    }

    WLOGD("GLESV1");
    dlGlHandle1_ = LoadGl(LIB_GLESV1_NAME, gGlApiNames1, (FunctionPointerType *)&table->gl.table1);
    if (!dlEglHandle_) {
        WLOGE("LoadGl GLESV1 Failed.");
        return false;
    }

    WLOGD("GLESV2");
    dlGlHandle2_ = LoadGl(LIB_GLESV2_NAME, gGlApiNames2, (FunctionPointerType *)&table->gl.table2);
    if (!dlGlHandle2_) {
        WLOGE("LoadGl GLESV2 Failed.");
        return false;
    }

    WLOGD("GLESV3");
    dlGlHandle3_ = LoadGl(LIB_GLESV3_NAME, gGlApiNames3, (FunctionPointerType *)&table->gl.table3);
    if (!dlGlHandle3_) {
        WLOGE("LoadGl GLESV3 Failed.");
        return false;
    }

    return true;
}

6.初始化LayerLoader对象

bool EglWrapperLayer::Init(EglWrapperDispatchTable *table)
{
    WLOGD("");
    if (initialized_) {
        WLOGI("EglWrapperLayer is already loaded.");
        return true;
    }

    if (table == nullptr) {
        WLOGE("table is nullptr.");
        return false;
    }

    if (!LoadLayers()) {
        WLOGE("LoadLayers failed.");
        return false;
    }

    InitLayers(table);

    initialized_ = true;
    return true;
}

7. 设置 wrapper 以及 OpenGL 的功能表。更新各个API条目的信息,并将这些条目与适当的函数指针进行关联。该过程确保在使用 EGL 和 OpenGL 时能够正确地调用对应版本的方法。


void EglWrapperLayer::SetupLayerFuncTbl(EglWrapperDispatchTable *table)
{
    // 调整 layerFuncTbl_ 的大小,增加一个元素以容纳所有层的函数表
    layerFuncTbl_.resize(layerSetup_.size() + 1);

    // 声明指向 API 名称数组的指针和当前函数指针的位置
    char const * const *entries;
    EglWrapperFuncPointer *curr;

    // 设置 wrapper API 的条目
    entries = gWrapperApiNames; // 获取 wrapper API 名称数组
    curr = reinterpret_cast<EglWrapperFuncPointer*>(&table->wrapper); // 获取 table 中 wrapper 的函数指针位置
    SetupFuncMaps(layerFuncTbl_[0], entries, curr); // 将函数映射到第一个层

    // 设置 OpenGL 2.x API 的条目
    entries = gGlApiNames2; // 获取 OpenGL 2.x API 名称数组
    curr = reinterpret_cast<EglWrapperFuncPointer*>(&table->gl.table2); // 获取 table 中 gl.table2 的函数指针位置
    SetupFuncMaps(layerFuncTbl_[0], entries, curr); // 将函数映射到第一个层

    // 设置 OpenGL 3.x API 的条目
    entries = gGlApiNames3; // 获取 OpenGL 3.x API 名称数组
    curr = reinterpret_cast<EglWrapperFuncPointer*>(&table->gl.table3); // 获取 table 中 gl.table3 的函数指针位置
    SetupFuncMaps(layerFuncTbl_[0], entries, curr); // 将函数映射到第一个层

    // 遍历所有设置的层并初始化相应的功能表
    for (uint32_t i = 0; i < layerSetup_.size(); i++) {
        layerInit_[i](reinterpret_cast<void*>(&layerFuncTbl_[i],
            reinterpret_cast<GetNextLayerAddr>(GetNextLayerProcAddr)); 
        // 初始化当前层的功能表,并获取下一个层的地址

        entries = gWrapperApiNames; 
        curr = reinterpret_cast<EglWrapperFuncPointer *>(&table->wrapper); 
        UpdateApiEntries(layerSetup_[i], curr, entries); 
        SetupFuncMaps(layerFuncTbl_[i + 1], entries, curr);

        entries = gGlApiNames2; 
        curr = reinterpret_cast<EglWrapperFuncPointer*>(&table->gl.table2);
        UpdateApiEntries(layerSetup_[i], curr, entries);
        SetupFuncMaps(layerFuncTbl_[i + 1], entries, curr);

        entries = gGlApiNames3;
        curr = reinterpret_cast<EglWrapperFuncPointer*>(&table->gl.table3);
        UpdateApiEntries(layerSetup_[i], curr, entries);
        SetupFuncMaps(layerFuncTbl_[i + 1], entries, curr);

        // 更新和设置每个图形库版本对应的 API 条目和映射关系。
   }
}

8. 检查调用的API是否在WrapperMap中

bool CheckEglWrapperApi(const std::string &name)
{
    if (gEglWrapperMap.find(name) != gEglWrapperMap.end()) {
        return true;
    }
    return false;
}

9. 若在其中,则调用WrapperMap中API能力

    return OHOS::gWrapperHook.wrapper.api(__VA_ARGS__);  
Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐