NativeWindow开发指导 (C/C++)
场景介绍
NativeWindow是本地平台化窗口,表示图形队列的生产者端。开发者可以通过NativeWindow接口进行申请和提交Buffer,配置Buffer属性信息。
针对NativeWindow,常见的开发场景如下:
- 通过
NativeWindow提供的Native API接口申请图形Buffer,并将生成的图形内容写入图形Buffer,最终提交Buffer到图形队列。 - 在适配EGL层的
eglswapbuffer接口时,进行申请和提交Buffer。
接口说明
| 接口名 | 描述 |
|---|---|
| OH_NativeWindow_NativeWindowRequestBuffer (OHNativeWindow *window, OHNativeWindowBuffer **buffer, int *fenceFd) | 通过OHNativeWindow对象申请一块OHNativeWindowBuffer,用以内容生产。 |
| OH_NativeWindow_NativeWindowFlushBuffer (OHNativeWindow *window, OHNativeWindowBuffer *buffer, int fenceFd, Region region) | 通过OHNativeWindow将生产好内容的OHNativeWindowBuffer放回到Buffer队列中,用以内容消费。 |
| OH_NativeWindow_NativeWindowHandleOpt (OHNativeWindow *window, int code,...) | 设置/获取OHNativeWindow的属性,包括设置/获取宽高、内容格式等。 |
详细的接口说明请参考native_window。
开发步骤
以下步骤描述了如何使用NativeWindow提供的Native API接口申请图形Buffer,写入图形内容,并提交Buffer到图形队列。
添加动态链接库
CMakeLists.txt中添加以下lib。
libace_ndk.z.so
libnative_window.so
头文件
#include <sys/poll.h>
#include <sys/mman.h>
#include <unistd.h>
#include <ace/xcomponent/native_interface_xcomponent.h>
#include <native_window/external_window.h>
-
获取OHNativeWindow实例。
可通过
OH_NativeXComponent_Callback接口获取OHNativeWindow。代码示例如下。关于XComponent模块的使用方法,详见XComponent开发指导。-
在xxx.ets中添加一个XComponent组件。
XComponent({ id: 'xcomponentId', type: 'texture', libraryname: 'nativerender' }) .margin({ bottom: 26 }) .onLoad((nativeWindowContext) => { this.nativeWindowContext = nativeWindowContext as NativeWindowContext; }) -
在 native c++ 层获取 NativeXComponent。
napi_value exportInstance = nullptr; OH_NativeXComponent *nativeXComponent = nullptr; int32_t ret; char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; status = napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance); if (status != napi_ok) { return false; } status = napi_unwrap(env, exportInstance, reinterpret_cast<void**>(&nativeXComponent)); if (status != napi_ok) { return false; } ret = OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize); if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { return false; } -
定义 OH_NativeXComponent_Callback。
void OnSurfaceCreatedCB(OH_NativeXComponent* component, void* window) { // ··· OHNativeWindow* nativeWindow = static_cast<OHNativeWindow*>(window); // ··· } void OnSurfaceChangedCB(OH_NativeXComponent* component, void* window) { // ··· OHNativeWindow* nativeWindow = static_cast<OHNativeWindow*>(window); // ··· } void OnSurfaceDestroyedCB(OH_NativeXComponent* component, void* window) { // ··· OHNativeWindow* nativeWindow = static_cast<OHNativeWindow*>(window); // ··· } void DispatchTouchEventCB(OH_NativeXComponent* component, void* window) { // ··· OHNativeWindow* nativeWindow = static_cast<OHNativeWindow*>(window); } // ··· callback_.OnSurfaceCreated = OnSurfaceCreatedCB; callback_.OnSurfaceChanged = OnSurfaceChangedCB; callback_.OnSurfaceDestroyed = OnSurfaceDestroyedCB; callback_.DispatchTouchEvent = DispatchTouchEventCB; -
将OH_NativeXComponent_Callback 注册给 NativeXComponent。
OH_NativeXComponent_RegisterCallback(nativeXComponent, &callback_);
-
-
设置OHNativeWindowBuffer的属性。使用
OH_NativeWindow_NativeWindowHandleOpt设置OHNativeWindowBuffer的属性(默认携带NATIVEBUFFER_USAGE_CPU_READ usage参数,如果不使用CPU读写数据,建议去除NATIVEBUFFER_USAGE_CPU_READ usage参数,具体可见关闭CPU访问窗口缓冲区数据)。int code = SET_BUFFER_GEOMETRY; int32_t bufferHeight = static_cast<int32_t>(height_ / 4); int32_t bufferWidth = static_cast<int32_t>(width_ / 2); OH_NativeWindow_NativeWindowHandleOpt(nativeWindow_, code, bufferWidth, bufferHeight); -
从图形队列申请OHNativeWindowBuffer。
int fenceFd = -1; OHNativeWindowBuffer *nativeWindowBuffer = nullptr; ret = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow, &nativeWindowBuffer, &fenceFd); if (ret != 0 || nativeWindowBuffer == nullptr) { return; } BufferHandle *bufferHandle = OH_NativeWindow_GetBufferHandleFromNative(nativeWindowBuffer); -
内存映射mmap。
void *mappedAddr = mmap(bufferHandle->virAddr, bufferHandle->size, PROT_READ | PROT_WRITE, MAP_SHARED, bufferHandle->fd, 0); -
将生产的内容写入OHNativeWindowBuffer,在这之前需要等待releaseFenceFd可用(注意releaseFenceFd不等于-1才需要调用poll)。如果没有等待releaseFenceFd事件的数据可用(POLLIN),则可能造成花屏、裂屏、HEBC(High Efficiency Bandwidth Compression,高效带宽压缩) fault等问题。releaseFenceFd是消费者进程创建的一个文件句柄,代表消费者消费buffer完毕,buffer可读,生产者可以开始填充buffer内容。
int retCode = -1; uint32_t timeout = 3000; if (fenceFd != -1) { struct pollfd pollfds = {0}; pollfds.fd = fenceFd; pollfds.events = POLLIN; do { retCode = poll(&pollfds, 1, timeout); } while (retCode == -1 && (errno == EINTR || errno == EAGAIN)); close(fenceFd); } uint32_t *pixel = static_cast<uint32_t *>(mappedAddr); for (uint64_t x = 0; x < bufferHandle->width; x++) { for (uint64_t y = 0; y < bufferHandle->height; y++) { *pixel++ = value; } } -
提交OHNativeWindowBuffer到图形队列。请注意OH_NativeWindow_NativeWindowFlushBuffer接口的acquireFenceFd不可以和OH_NativeWindow_NativeWindowRequestBuffer接口获取的releaseFenceFd相同,acquireFenceFd可传入默认值-1。acquireFenceFd是生产者需要传入的文件句柄,消费者获取到buffer后可根据生产者传入的acquireFenceFd决定何时去渲染并上屏buffer内容。
struct Region *region = new Region(); ret = OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow, nativeWindowBuffer, fenceFd, *region); if (ret != NATIVE_ERROR_OK) { LOGE("flush failed"); (void)OH_NativeWindow_NativeWindowAbortBuffer(nativeWindow, nativeWindowBuffer); return; } -
使用munmap取消内存映射。
if (munmap(mappedAddr, bufferHandle->size) < 0) { OH_NativeWindow_DestroyNativeWindow(nativeWindow); LOGE("munmap failed"); return; }
相关实例
针对NativeWindow的开发,有以下相关实例可供参考: