NativeWindow is a local platform window that represents the producer end of a graphics queue. It is primarily used in scenarios that require efficient graphics data processing. When you develop graphics-intensive apps such as video playback, camera preview, and game rendering, you need to efficiently write and submit graphics data in graphics buffers. In such cases, you can use NativeWindow APIs to request and submit Buffer objects and configure Buffer attribute information.
The following scenarios are common for NativeWindow development:
Request a graphics buffer by using the NativeWindow API, write the produced graphics content to the buffer, and flush the buffer to the graphics queue.
Request and flush a buffer when adapting to the eglswapbuffer interface at the EGL.
| API | Description |
|---|---|
| OH_NativeWindow_NativeWindowRequestBuffer (OHNativeWindow *window, OHNativeWindowBuffer **buffer, int *fenceFd) | Requests an OHNativeWindowBuffer through an OHNativeWindow instance for content production. |
| OH_NativeWindow_NativeWindowFlushBuffer (OHNativeWindow *window, OHNativeWindowBuffer *buffer, int fenceFd, Region region) | Flushes the OHNativeWindowBuffer filled with the produced content to the buffer queue through an OHNativeWindow instance for content consumption. |
| OH_NativeWindow_NativeWindowHandleOpt (OHNativeWindow *window, int code,...) | Sets or obtains the attributes of an OHNativeWindow instance, including the width, height, and content format. |
For detailed interface descriptions, see NativeWindow.
Request a graphics buffer by using the NativeWindow API, write the produced graphics content to the buffer, and flush the buffer to the graphics queue.
Adding Dynamic Link Libraries
Add the following libraries to CMakeLists.txt:
libace_ndk.z.so libnative_window.so
Including Header Files
#include <sys/poll.h> #include <sys/mman.h> #include <unistd.h> #include <ace/xcomponent/native_interface_xcomponent.h> #include <native_window/external_window.h>
Obtain an OHNativeWindow instance.
You can obtain the OHNativeWindow instance via the OH_NativeXComponent_Callback API. The sample code is as follows. For details about how to use the XComponent module, see XComponent Development Guidelines.
Add an XComponent to the .ets file.
XComponent({ id: 'xcomponentId', type: XComponentType.TEXTURE, libraryname: 'nativerender' })
.margin({ bottom: 26 })
.onLoad((nativeWindowContext) => {
this.nativeWindowContext = nativeWindowContext as NativeWindowContext;
}) Obtain NativeXComponent at the native C++ layer.
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;
} Define 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; Register OH_NativeXComponent_Callback with NativeXComponent.
OH_NativeXComponent_RegisterCallback(nativeXComponent, &callback_);
Set the attributes of an OHNativeWindowBuffer by using OH_NativeWindow_NativeWindowHandleOpt. By default, the NATIVEBUFFER_USAGE_CPU_READ usage parameter is carried. If the CPU is not used to read and write data, you are advised to remove the NATIVEBUFFER_USAGE_CPU_READ usage parameter. For details, see How do I proactively disable CPU access to window buffers to reduce power consumption?.
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);
Request an OHNativeWindowBuffer from the graphics queue.
int releaseFenceFd = -1;
OHNativeWindowBuffer *nativeWindowBuffer = nullptr;
ret = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow, &nativeWindowBuffer, &releaseFenceFd);
if (ret != 0 || nativeWindowBuffer == nullptr) {
return;
}
BufferHandle *bufferHandle = OH_NativeWindow_GetBufferHandleFromNative(nativeWindowBuffer); Map memory.
void *mappedAddr =
mmap(bufferHandle->virAddr, bufferHandle->size, PROT_READ | PROT_WRITE, MAP_SHARED, bufferHandle->fd, 0); Write the produced content to the OHNativeWindowBuffer. Before this operation, wait until releaseFenceFd is available. Note that poll needs to be called only when releaseFenceFd is not -1. If no data is available for the releaseFenceFd event (POLLIN), problems such as artifacts, cracks, and High Efficiency Bandwidth Compression (HEBC) faults may occur. releaseFenceFd is a file handle created by the consumer process to indicate that the consumer has consumed the buffer, the buffer is readable, and the producer can start to fill in the buffer.
int retCode = -1;
uint32_t timeout = 3000;
if (releaseFenceFd != -1) {
struct pollfd pollfds = {0};
pollfds.fd = releaseFenceFd;
pollfds.events = POLLIN;
do {
retCode = poll(&pollfds, 1, timeout);
} while (retCode == -1 && (errno == EINTR || errno == EAGAIN));
close(releaseFenceFd);
}
uint32_t *pixel = static_cast<uint32_t *>(mappedAddr);
uint32_t value = flag_ ? 0xfff0000f : 0xff00ffff;
for (uint64_t x = 0; x < bufferHandle->width; x++) {
for (uint64_t y = 0; y < bufferHandle->height; y++) {
*pixel++ = value;
}
} Flush the OHNativeWindowBuffer to the graphics queue. Note that acquireFenceFd of OH_NativeWindow_NativeWindowFlushBuffer cannot be the same as releaseFenceFd obtained by OH_NativeWindow_NativeWindowRequestBuffer. acquireFenceFd is the file handle passed in by the producer, and the default value -1 can be passed. Based on acquireFenceFd, the consumer, after obtaining the buffer, determines when to render and display the buffered content.
struct Region region = {0};
int acquireFenceFd = -1;
ret = OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow, nativeWindowBuffer, acquireFenceFd, region);
if (ret != NATIVE_ERROR_OK) {
LOGE("flush failed");
(void)OH_NativeWindow_NativeWindowAbortBuffer(nativeWindow, nativeWindowBuffer);
return;
} Use munmap to cancel memory mapping.
if (munmap(mappedAddr, bufferHandle->size) < 0) {
OH_NativeWindow_DestroyNativeWindow(nativeWindow);
LOGE("munmap failed");
return;
}