39555c89创建于 2025年12月19日历史提交

NativeWindow Development (C/C++)

Overview

The NativeWindow module is a local platform-based window that represents the producer of a graphics queue. It provides APIs for you to request and flush a buffer and configure buffer attributes.

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.

Available APIs

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 details, see native_window.

How to Develop

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>
  1. 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.

    1. Add an XComponent to the .ets file.

      XComponent({ id: 'xcomponentId', type: 'texture', libraryname: 'nativerender' })
          .margin({ bottom: 26 })
          .onLoad((nativeWindowContext) => {
          this.nativeWindowContext = nativeWindowContext as NativeWindowContext;
          })
      
    2. 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;
      }
      
    3. 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;
      
    4. Register OH_NativeXComponent_Callback with NativeXComponent.

      OH_NativeXComponent_RegisterCallback(nativeXComponent, &callback_);
      
  2. Set the attributes of an OHNativeWindowBuffer by using OH_NativeWindow_NativeWindowHandleOpt. By default, the usage parameter of NATIVEBUFFER_USAGE_CPU_READ is carried. If the CPU is not used to read and write data, you are advised to remove this 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);
    
  3. Request an OHNativeWindowBuffer from the graphics queue.

    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);
    
  4. Map memory.

    void *mappedAddr =
        mmap(bufferHandle->virAddr, bufferHandle->size, PROT_READ | PROT_WRITE, MAP_SHARED, bufferHandle->fd, 0);
    
  5. 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 waiting for releaseFenceFd is available (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 (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;
        }
    }
    
  6. 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 = 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;
    }
    
  7. Use munmap to cancel memory mapping.

    if (munmap(mappedAddr, bufferHandle->size) < 0) {
        OH_NativeWindow_DestroyNativeWindow(nativeWindow);
        LOGE("munmap failed");
        return;
    }
    

Samples

The following samples are provided to help you better understand how to use the NativeWindow module for development: