native-image-guidelines.md 10.1 KB
Newer Older
S
shegangbin 已提交
1
# NativeImage开发指导
2 3 4 5 6 7

## 场景介绍

NativeImage是`OpenHarmony`提供**Surface关联OpenGL外部纹理**的模块,表示图形队列的消费者端。开发者可以通过`NativeImage`接口接收和使用`Buffer`,并将`Buffer`关联输出到OpenGL外部纹理。
针对NativeImage,常见的开发场景如下:

S
shegangbin 已提交
8
* 通过`NativeImage`提供的Native API接口创建`NativeImage`实例作为消费者端,获取与该实例对应的`NativeWindow`作为生产者端。`NativeWindow`相关接口可用于填充`Buffer`内容并提交,`NativeImage``Buffer`内容更新到OpenGL外部纹理上。本模块需要配合NativeWindow、NativeBuffer、EGL、GLES3模块一起使用。
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

## 接口说明

| 接口名 | 描述 | 
| -------- | -------- |
| OH_NativeImage_Create (uint32_t textureId, uint32_t textureTarget) | 创建一个OH_NativeImage实例,该实例与OpenGL ES的纹理ID和纹理目标相关联。 | 
| OH_NativeImage_AcquireNativeWindow (OH_NativeImage \*image) | 获取与OH_NativeImage相关联的OHNativeWindow指针,该OHNativeWindow后续不再需要时需要调用 OH_NativeWindow_DestroyNativeWindow释放。 | 
| OH_NativeImage_AttachContext (OH_NativeImage \*image, uint32_t textureId) | 将OH_NativeImage实例附加到当前OpenGL ES上下文,且该OpenGL ES纹理会绑定到 GL_TEXTURE_EXTERNAL_OES,并通过OH_NativeImage进行更新。 | 
| OH_NativeImage_DetachContext (OH_NativeImage \*image) | 将OH_NativeImage实例从当前OpenGL ES上下文分离。 | 
| OH_NativeImage_UpdateSurfaceImage (OH_NativeImage \*image) | 通过OH_NativeImage获取最新帧更新相关联的OpenGL ES纹理。 | 
| OH_NativeImage_GetTimestamp (OH_NativeImage \*image) | 获取最近调用OH_NativeImage_UpdateSurfaceImage的纹理图像的相关时间戳。 | 
| OH_NativeImage_GetTransformMatrix (OH_NativeImage \*image, float matrix[16]) | 获取最近调用OH_NativeImage_UpdateSurfaceImage的纹理图像的变化矩阵。 | 
| OH_NativeImage_Destroy (OH_NativeImage \*\*image) | 销毁通过OH_NativeImage_Create创建的OH_NativeImage实例,销毁后该OH_NativeImage指针会被赋值为空。 | 

详细的接口说明请参考[native_image](../reference/native-apis/_o_h___native_image.md)

## 开发步骤

S
shegangbin 已提交
27
以下步骤描述了在**OpenHarmony**中如何使用`NativeImage`提供的Native API接口,创建`OH_NativeImage`实例作为消费者端,将数据内容更新到OpenGL外部纹理上。
S
fix  
shegangbin 已提交
28

S
shegangbin 已提交
29 30 31 32 33 34 35 36 37 38 39
**添加动态链接库**

CMakeLists.txt中添加以下lib。
```txt
libEGL.so
libGLESv3.so
libnative_image.so
libnative_window.so
libnative_buffer.so
```

S
shegangbin 已提交
40
**头文件**
S
fix  
shegangbin 已提交
41 42 43 44 45 46 47 48
```c++
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl3.h>
#include <native_image/native_image.h>
#include <native_window/external_window.h>
#include <native_buffer/native_buffer.h>
```
49 50

1. **初始化EGL环境**
S
fix  
shegangbin 已提交
51

S
shegangbin 已提交
52
    这里提供一份初始化EGL环境的代码示例
53
    ```c++
S
shegangbin 已提交
54 55 56 57 58 59 60 61 62 63 64 65 66
    #include <EGL/egl.h>
    #include <EGL/eglext.h>
    using GetPlatformDisplayExt = PFNEGLGETPLATFORMDISPLAYEXTPROC;
    constexpr const char* EGL_EXT_PLATFORM_WAYLAND = "EGL_EXT_platform_wayland";
    constexpr const char* EGL_KHR_PLATFORM_WAYLAND = "EGL_KHR_platform_wayland";
    constexpr int32_t EGL_CONTEXT_CLIENT_VERSION_NUM = 2;
    constexpr char CHARACTER_WHITESPACE = ' ';
    constexpr const char* CHARACTER_STRING_WHITESPACE = " ";
    constexpr const char* EGL_GET_PLATFORM_DISPLAY_EXT = "eglGetPlatformDisplayEXT";
    EGLContext eglContext_ = EGL_NO_CONTEXT;
    EGLDisplay eglDisplay_ = EGL_NO_DISPLAY;
    static inline EGLConfig config_;

S
fix  
shegangbin 已提交
67
    // 检查egl扩展
S
shegangbin 已提交
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
    static bool CheckEglExtension(const char* extensions, const char* extension)
    {
        size_t extlen = strlen(extension);
        const char* end = extensions + strlen(extensions);

        while (extensions < end) {
            size_t n = 0;
            if (*extensions == CHARACTER_WHITESPACE) {
                extensions++;
                continue;
            }
            n = strcspn(extensions, CHARACTER_STRING_WHITESPACE);
            if (n == extlen && strncmp(extension, extensions, n) == 0) {
                return true;
            }
            extensions += n;
        }
        return false;
86 87
    }

S
fix  
shegangbin 已提交
88
    // 获取当前的显示设备
S
shegangbin 已提交
89 90 91 92 93 94 95 96 97 98 99 100
    static EGLDisplay GetPlatformEglDisplay(EGLenum platform, void* native_display, const EGLint* attrib_list)
    {
        static GetPlatformDisplayExt eglGetPlatformDisplayExt = NULL;

        if (!eglGetPlatformDisplayExt) {
            const char* extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
            if (extensions &&
                (CheckEglExtension(extensions, EGL_EXT_PLATFORM_WAYLAND) ||
                    CheckEglExtension(extensions, EGL_KHR_PLATFORM_WAYLAND))) {
                eglGetPlatformDisplayExt = (GetPlatformDisplayExt)eglGetProcAddress(EGL_GET_PLATFORM_DISPLAY_EXT);
            }
        }
101

S
shegangbin 已提交
102 103 104
        if (eglGetPlatformDisplayExt) {
            return eglGetPlatformDisplayExt(platform, native_display, attrib_list);
        }
105

S
shegangbin 已提交
106
        return eglGetDisplay((EGLNativeDisplayType)native_display);
107 108
    }

S
shegangbin 已提交
109 110
    static void InitEGLEnv()
    {
S
fix  
shegangbin 已提交
111
        // 获取当前的显示设备
S
shegangbin 已提交
112 113 114 115 116 117
        eglDisplay_ = GetPlatformEglDisplay(EGL_PLATFORM_OHOS_KHR, EGL_DEFAULT_DISPLAY, NULL);
        if (eglDisplay_ == EGL_NO_DISPLAY) {
            std::cout << "Failed to create EGLDisplay gl errno : " << eglGetError() << std::endl;
        }
        
        EGLint major, minor;
S
fix  
shegangbin 已提交
118
        // 初始化EGLDisplay
S
shegangbin 已提交
119 120 121 122
        if (eglInitialize(eglDisplay_, &major, &minor) == EGL_FALSE) {
            std::cout << "Failed to initialize EGLDisplay" << std::endl;
        }
        
S
fix  
shegangbin 已提交
123
        // 绑定图形绘制的API为OpenGLES
S
shegangbin 已提交
124 125 126 127 128 129 130 131 132
        if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
            std::cout << "Failed to bind OpenGL ES API" << std::endl;
        }
        
        unsigned int ret;
        EGLint count;
        EGLint config_attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8,
            EGL_ALPHA_SIZE, 8, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT, EGL_NONE };
        
S
fix  
shegangbin 已提交
133
        // 获取一个有效的系统配置信息
S
shegangbin 已提交
134 135 136 137 138 139 140
        ret = eglChooseConfig(eglDisplay_, config_attribs, &config_, 1, &count);
        if (!(ret && static_cast<unsigned int>(count) >= 1)) {
            std::cout << "Failed to eglChooseConfig" << std::endl;
        }
        
        static const EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, EGL_CONTEXT_CLIENT_VERSION_NUM, EGL_NONE };
        
S
fix  
shegangbin 已提交
141
        // 创建上下文
S
shegangbin 已提交
142 143 144 145 146
        eglContext_ = eglCreateContext(eglDisplay_, config_, EGL_NO_CONTEXT, context_attribs);
        if (eglContext_ == EGL_NO_CONTEXT) {
            std::cout << "Failed to create egl context %{public}x, error:" << eglGetError() << std::endl;
        }
        
S
fix  
shegangbin 已提交
147
        // 关联上下文
S
shegangbin 已提交
148 149
        eglMakeCurrent(eglDisplay_, EGL_NO_SURFACE, EGL_NO_SURFACE, eglContext_);
        
S
fix  
shegangbin 已提交
150
        // EGL环境初始化完成
S
shegangbin 已提交
151
        std::cout << "Create EGL context successfully, version" << major << "." << minor << std::endl;
152 153 154
    }
    ```
   
S
shegangbin 已提交
155
2. **创建OH_NativeImage实例**
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
    ```c++
    // 创建 OpenGL 纹理
    GLuint textureId;
    glGenTextures(1, &textureId);
    // 创建 NativeImage 实例,关联 OpenGL 纹理
    OH_NativeImage* image = OH_NativeImage_Create(textureId, GL_TEXTURE_2D);
    ```

3. **获取对应的数据生产者端NativeWindow**
    ```c++
    // 获取生产者NativeWindow
    OHNativeWindow* nativeWindow = OH_NativeImage_AcquireNativeWindow(image);
    ```

4. **将生产的内容写入NativeWindowBuffer**
S
shegangbin 已提交
171
    1. 从NativeWindow中获取NativeWindowBuffer
172
    ```c++
S
shegangbin 已提交
173 174 175 176 177 178 179
    OHNativeWindowBuffer* buffer = nullptr;
    int fenceFd;
    // 通过 OH_NativeWindow_NativeWindowRequestBuffer 获取 OHNativeWindowBuffer 实例
    OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow, &buffer, &fenceFd);
    
    BufferHandle *handle = OH_NativeWindow_GetBufferHandleFromNative(buffer);
    int code = SET_BUFFER_GEOMETRY;
180 181 182 183 184 185 186 187
    int32_t width = 0x100;
    int32_t height = 0x100;
    ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, code, width, height);
    ```
    3. 将生产的内容写入NativeWindowBuffer
    ```c++
    static uint32_t value = 0x00;
    value++;
S
shegangbin 已提交
188
    uint32_t *pixel = static_cast<uint32_t *>(handle->virAddr);
189 190 191 192 193 194
    for (uint32_t x = 0; x < width; x++) {
        for (uint32_t y = 0;  y < height; y++) {
            *pixel++ = value;
        }
    }
    ```
S
shegangbin 已提交
195
    4. 将NativeWindowBuffer提交到NativeWindow
196 197 198 199 200 201
    ```c++
    // 设置刷新区域,如果Region中的Rect为nullptr,或者rectNumber为0,则认为NativeWindowBuffer全部有内容更改。
    Region region{nullptr, 0};
    // 通过OH_NativeWindow_NativeWindowFlushBuffer 提交给消费者使用,例如:显示在屏幕上。
    OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow, buffer, fenceFd, region);
    ```
S
fix  
shegangbin 已提交
202 203 204 205
    5. 用完需要销毁NativeWindow
    ```c++
    OH_NativeWindow_DestroyNativeWindow(nativeWindow);
    ```
206 207 208 209 210

5. **更新内容到OpenGL纹理**
    ```c++
    // 更新内容到OpenGL纹理。
    int32_t ret = OH_NativeImage_UpdateSurfaceImage(image);
S
fix  
shegangbin 已提交
211
    if (ret != 0) {
212 213 214 215 216 217
        std::cout << "OH_NativeImage_UpdateSurfaceImage failed" << std::endl;
    }
    // 获取最近调用OH_NativeImage_UpdateSurfaceImage的纹理图像的时间戳和变化矩阵。
    int64_t timeStamp = OH_NativeImage_GetTimestamp(image);
    float matrix[16];
    ret = OH_NativeImage_GetTransformMatrix(image, matrix);
S
fix  
shegangbin 已提交
218
    if (ret != 0) {
219 220 221 222 223 224 225 226
        std::cout << "OH_NativeImage_GetTransformMatrix failed" << std::endl;
    }
    ```

6. **解绑OpenGL纹理,绑定到新的外部纹理上**
    ```c++
    // 将OH_NativeImage实例从当前OpenGL ES上下文分离
    ret = OH_NativeImage_DetachContext(image);
S
fix  
shegangbin 已提交
227
    if (ret != 0) {
228 229 230 231 232 233 234
        std::cout << "OH_NativeImage_DetachContext failed" << std::endl;
    }
    // 将OH_NativeImage实例附加到当前OpenGL ES上下文, 且该OpenGL ES纹理会绑定到 GL_TEXTURE_EXTERNAL_OES, 并通过OH_NativeImage进行更新
    GLuint textureId2;
    glGenTextures(1, &textureId2);
    ret = OH_NativeImage_AttachContext(image, textureId2);
    ```
S
fix  
shegangbin 已提交
235 236 237 238 239 240

7. **OH_NativeImage实例使用完需要销毁掉**
    ```c++
    // 销毁OH_NativeImage实例
    OH_NativeImage_Destroy(&image);
    ```