native_window-guidelines.md 6.9 KB
Newer Older
A
andrewhw 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
# NativeWindow 开发指导

## 场景介绍

NativeWindow是`OpenHarmony`**本地平台化窗口**,包括从`Surface`构建`NativeWindow`,从`SurfaceBuffer`构建出`NativeWindowBuffer`的能力,开发者可以通过`NativeWindow`接口进行申请和提交`Buffer`
针对NativeWindow,常见的开发场景如下:

* 通过`Native C++`代码绘制内容并显示在屏幕上
* 在适配EGL层的`eglswapbuffer`接口时,进行提交和申请`Buffer`

## 接口说明

| 接口名 | 描述 | 
| -------- | -------- |
| OH_NativeWindow_CreateNativeWindowFromSurface (void \*pSurface) | 创建NativeWindow实例,每次调用都会产生一个新的NativeWindow实例。 | 
| OH_NativeWindow_DestroyNativeWindow (struct NativeWindow \*window) | 将NativeWindow对象的引用计数减1,当引用计数为0的时候,该NativeWindow对象会被析构掉。 | 
| OH_NativeWindow_CreateNativeWindowBufferFromSurfaceBuffer (void \*pSurfaceBuffer) | 创建NativeWindowBuffer实例,每次调用都会产生一个新的NativeWindowBuffer实例。 | 
| OH_NativeWindow_DestroyNativeWindowBuffer (struct NativeWindowBuffer \*buffer) | 将NativeWindowBuffer对象的引用计数减1,当引用计数为0的时候,该NativeWindowBuffer对象会被析构掉。 | 
| OH_NativeWindow_NativeWindowRequestBuffer (struct NativeWindow \*window, struct NativeWindowBuffer \*\*buffer, int \*fenceFd) | 通过NativeWindow对象申请一块NativeWindowBuffer,用以内容生产。 | 
| OH_NativeWindow_NativeWindowFlushBuffer (struct NativeWindow \*window, struct NativeWindowBuffer \*buffer, int fenceFd, Region region) | 通过NativeWindow将生产好内容的NativeWindowBuffer放回到Buffer队列中,用以内容消费。 | 
| OH_NativeWindow_NativeWindowCancelBuffer (struct NativeWindow \*window, struct NativeWindowBuffer \*buffer) | 通过NativeWindow将之前申请出来的NativeWindowBuffer返还到Buffer队列中,供下次再申请。 | 
| OH_NativeWindow_NativeWindowHandleOpt (struct NativeWindow \*window, int code,...) | 设置/获取NativeWindow的属性,包括设置/获取宽高、内容格式等。 | 
| OH_NativeWindow_GetBufferHandleFromNative (struct NativeWindowBuffer \*buffer) | 通过NativeWindowBuffer获取该buffer的BufferHandle指针。 | 
| OH_NativeWindow_NativeObjectReference (void \*obj) | 增加一个NativeObject的引用计数。 | 
| OH_NativeWindow_NativeObjectUnreference (void \*obj) | 减少一个NativeObject的引用计数,当引用计数减少为0时,该NativeObject将被析构掉。 | 
| OH_NativeWindow_GetNativeObjectMagic (void \*obj) | 获取NativeObject的MagicId。 | 

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

## 开发步骤

以下步骤描述了在**OpenHarmony**中如何利用`OH_NativeXComponent`通过`Native C++`代码绘制内容并显示在屏幕上。

1. **在页面中定义XComponent组件**,在`index.ets`中定义一个`texture`类型的`XComponent`,用于显示内容。
   ```js
    XComponent({ id: 'xcomponentId', type: 'texture', libraryname: 'nativerender'})
        .borderColor(Color.Red)
        .borderWidth(5)
        .onLoad(() => {})
        .onDestroy(() => {})
   ```

2. **获取OH_NativeXComponent实例**。使用 `napi_get_named_property` 接口获取一个`OH_NativeXComponent`实例 `nativeXComponent`,通过注册该实例的回调接口获取`NativeWindow`实例。

    ```c++
    // 定义 napi instance
    napi_value exportInstance = nullptr;
    // 定义一个 OH_NativeXComponent 实例
    OH_NativeXComponent *nativeXComponent = nullptr;
    // 通过 OH_NATIVE_XCOMPONENT_OBJ export 实例
    napi_getname_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance);
    // 将 napi instance 转化为 OH_NativeXComponent 实例
    napi_unwarp(env, exportInstance, reinterpret_cast<void**>(&nativeXComponent));
    ```

3. **定义回调函数OnSurfaceCreated**。用于在`Surface`创建时,通过回调函数初始化开发者的渲染环境,例如`Skia`渲染环境。并将要显示的内容写入`NativeWindow`

    ```c++
    void OnSufaceCreatedCB(NativeXComponent* component, void* window) {
        //获取 native window 的宽高
        uint64_t width_ = 0, height_ = 0;
        OH_NativeXComponent_GetXComponentSize(nativeXComponent, window, &width_, &height_);
        // 将void* 转换为 NativeWindow 实例,NativeWindow 定义在 native_window/external_window.h 中
        NativeWindow* nativeWindow_ = (NativeWindow*)(window);

        // 通过 OH_NativeWindow_NativeWindowHandleOpt 设置或者获取NativeWindow的属性
        // 1.通过 SET_USAGE 设置 Native Window 的 usage 属性, 例如:HBM_USE_CPU_READ
        OH_NativeWindow_NativeWindowHandleOpt(nativeWindow_, SET_USAGE, HBM_USE_CPU_READ | HBM_USE_CPU_WRITE |HBM_USE_MEM_DMA);
        // 2.通过 SET_BUFFER_GEOMETRY 设置 Native Window 的 宽高属性
        OH_NativeWindow_NativeWindowHandleOpt(nativeWindow_, SET_BUFFER_GEOMETRY, width_, height_);
        // 3.通过 SET_FORMAT 设置 Native Window 的 format 属性, 例如:PIXEL_FMT_RGBA_8888
        OH_NativeWindow_NativeWindowHandleOpt(nativeWindow_, SET_FORMAT, PIXEL_FMT_RGBA_8888);
        // 4.通过 SET_STRIDE 设置 Native Window 的 stride 属性
        OH_NativeWindow_NativeWindowHandleOpt(nativeWindow_, SET_STRIDE, 0x8);

        // 通过 OH_NativeWindow_NativeWindowRequestBuffer 获取 NativeWindowBuffer 实例
        struct NativeWindowBuffer* buffer = nullptr;
        int fenceFd;
        OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow_, &buffer, &fenceFd);

        // 通过 OH_NativeWindow_GetNativeBufferHandleFromNative 获取 buffer handle
        BufferHandle* bufferHandle = OH_NativeWindow_GetNativeBufferHandleFromNative(buffer);

        // 通过 BufferHandle 创建Skia Bitmap
        SkBitmap bitmap;
        SkImageInfo imageInfo = ...
        bitmap.setInfo(imageInfo, bufferHandle->stride);
        bitmap.setPixels(bufferHandle->virAddr);
        //创建 Skia Canvas 并将内容写入naitve window
        ...

        //写入完成后,通过OH_NativeWindwo_NativeWindowFlushBuffer 提交给消费者使用,例如:显示在屏幕上
        Regoin region{nullptr, 0};
        OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow_, buffer, fenceFd, region)
    }
    ```

4. **注册回调函数OnSurfaceCreated等**。使用 `OH_NativeXComponent_RegisterCallback` 接口注册上一步中创建的回调函数。

    ```c++
    OH_NativeXComponent_Callback &callback_;
    callback_->OnSurfaceCreated = OnSufaceCreatedCB;
    callback_->OnSurfaceChanged = OnSufaceChangedCB;
    callback_->OnSurfaceDestoryed = OnSufaceDestoryedCB;
    callback_->DispatchTouchEvent = DispatchTouchEventCB;
    OH_NativeXComponent_RegisterCallback(nativeXComponent, callback_)
    ```