1# Native Window Development (C/C++) 2 3## When to Use 4 5The native window 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. 6 7The following scenarios are common for native window development: 8 9* Request a graphics buffer by using the native window API, write the produced graphics content to the buffer, and flush the buffer to the graphics queue. 10* Request and flush a buffer when adapting to the **eglswapbuffer** interface at the EGL. 11 12## Available APIs 13 14| API| Description| 15| -------- | -------- | 16| OH_NativeWindow_NativeWindowRequestBuffer (OHNativeWindow \*window, OHNativeWindowBuffer \*\*buffer, int \*fenceFd) | Requests an **OHNativeWindowBuffer** through an **OHNativeWindow** instance for content production.| 17| 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.| 18| OH_NativeWindow_NativeWindowHandleOpt (OHNativeWindow \*window, int code,...) | Sets or obtains the attributes of an **OHNativeWindow** instance, including the width, height, and content format.| 19 20For details about the APIs, see [native_window](../reference/apis-arkgraphics2d/_native_window.md). 21 22## How to Develop 23 24The following describes how to use the native window APIs to request a graphics buffer, write the produced graphics content to the buffer, and flush the buffer to the graphics queue. 25 26**Adding Dynamic Link Libraries** 27 28Add the following libraries to **CMakeLists.txt**: 29```txt 30libace_ndk.z.so 31libnative_window.so 32``` 33 34**Including Header Files** 35```c++ 36#include <sys/poll.h> 37#include <sys/mman.h> 38#include <unistd.h> 39#include <ace/xcomponent/native_interface_xcomponent.h> 40#include <native_window/external_window.h> 41``` 42 431. Obtain an **OHNativeWindow** instance. 44 45 You can call the APIs provided by [OH_NativeXComponent_Callback](../reference/apis-arkui/_o_h___native_x_component___callback.md) to obtain an **OHNativeWindow** instance. An example code snippet is provided below. For details about how to use the **XComponent**, see [XComponent Development](../ui/napi-xcomponent-guidelines.md). 46 47 1. Add an **XComponent** to the .ets file. 48 49 ```ts 50 XComponent({ id: 'xcomponentId', type: 'surface', libraryname: 'entry'}) 51 .width(360) 52 .height(360) 53 ``` 54 2. Obtain **NativeXComponent** at the native C++ layer. 55 56 ```c++ 57 napi_value exportInstance = nullptr; 58 // Parse the attribute of the wrapped NativeXComponent pointer. 59 napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance); 60 OH_NativeXComponent *nativeXComponent = nullptr; 61 // Use the napi_unwrap API to parse the NativeXComponent instance pointer. 62 napi_unwrap(env, exportInstance, reinterpret_cast<void**>(&nativeXComponent)); 63 // Obtain the XComponent ID. 64 char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; 65 uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; 66 OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize); 67 ``` 68 3. Define **OH_NativeXComponent_Callback**. 69 70 ```c++ 71 // Define the callback. 72 void OnSurfaceCreatedCB(OH_NativeXComponent* component, void* window) 73 { 74 // Obtain an OHNativeWindow instance. 75 OHNativeWindow* nativeWindow = static_cast<OHNativeWindow*>(window); 76 // After this callback is triggered, the reference count for the window is initialized to 1. If the window-related APIs and XComponent destructor are concurrently used, 77 // you must manually adjust the reference count by using OH_NativeWindow_NativeObjectReference to increase it and OH_NativeWindow_NativeObjectUnreference to decrease it. 78 // This manual management of the reference count by 1 helps to avoid issues with dangling or null pointers that could occur during concurrent calls to window APIs following the destruction of an XComponent. 79 } 80 void OnSurfaceChangedCB(OH_NativeXComponent* component, void* window) 81 { 82 // Obtain an OHNativeWindow instance. 83 OHNativeWindow* nativeWindow = static_cast<OHNativeWindow*>(window); 84 // ... 85 } 86 void OnSurfaceDestroyedCB(OH_NativeXComponent* component, void* window) 87 { 88 // Obtain an OHNativeWindow instance. 89 OHNativeWindow* nativeWindow = static_cast<OHNativeWindow*>(window); 90 // After this callback is triggered, the reference count for the window is decremented by 1. When the reference count reaches 0, the window is destructed. 91 // Once the window is destructed, no further API calls should be made through the window. This operation results in a crash caused by dangling or null pointers. 92 } 93 void DispatchTouchEventCB(OH_NativeXComponent* component, void* window) 94 { 95 // Obtain an OHNativeWindow instance. 96 OHNativeWindow* nativeWindow = static_cast<OHNativeWindow*>(window); 97 // ... 98 } 99 ``` 100 101 ```c++ 102 // Initialize OH_NativeXComponent_Callback. 103 OH_NativeXComponent_Callback callback; 104 callback.OnSurfaceCreated = OnSurfaceCreatedCB; 105 callback.OnSurfaceChanged = OnSurfaceChangedCB; 106 callback.OnSurfaceDestroyed = OnSurfaceDestroyedCB; 107 callback.DispatchTouchEvent = DispatchTouchEventCB; 108 ``` 109 110 4. Register **OH_NativeXComponent_Callback** with **NativeXComponent**. 111 112 ```c++ 113 // Register the callback. 114 OH_NativeXComponent_RegisterCallback(nativeXComponent, &callback); 115 ``` 116 1172. Set the attributes of an **OHNativeWindowBuffer** by using **OH_NativeWindow_NativeWindowHandleOpt**. 118 119 ```c++ 120 // Set the width and height of the OHNativeWindowBuffer. 121 int32_t code = SET_BUFFER_GEOMETRY; 122 int32_t width = 0x100; 123 int32_t height = 0x100; 124 // The nativeWindow instance is obtained from the callback in the previous step. 125 int32_t ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, code, width, height); 126 ``` 127 1283. Request an **OHNativeWindowBuffer** from the graphics queue. 129 130 ```c++ 131 OHNativeWindowBuffer* buffer = nullptr; 132 int releaseFenceFd = -1; 133 // Obtain the OHNativeWindowBuffer instance by calling OH_NativeWindow_NativeWindowRequestBuffer. 134 ret = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow, &buffer, &releaseFenceFd); 135 if (ret != 0 || buffer == nullptr) { 136 return; 137 } 138 // Obtain the buffer handle by calling OH_NativeWindow_GetBufferHandleFromNative. 139 BufferHandle* bufferHandle = OH_NativeWindow_GetBufferHandleFromNative(buffer); 140 ``` 141 1424. Map memory. 143 144 ```c++ 145 #include <sys/mman.h> 146 147 // Use mmap() to map the shared memory allocated to the buffer handle to the user space. Image data can be written to the buffer handle by using the obtained virtual address. 148 // bufferHandle->virAddr indicates the start address of the buffer handle in the shared memory, and bufferHandle->size indicates the memory usage of the buffer handle in the shared memory. 149 void* mappedAddr = mmap(bufferHandle->virAddr, bufferHandle->size, PROT_READ | PROT_WRITE, MAP_SHARED, bufferHandle->fd, 0); 150 if (mappedAddr == MAP_FAILED) { 151 // mmap failed 152 } 153 ``` 154 1555. Write the produced content to the **OHNativeWindowBuffer**. 156 157 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. 158 ```c++ 159 int retCode = -1; 160 uint32_t timeout = 3000; 161 if (releaseFenceFd != -1) { 162 struct pollfd pollfds = {0}; 163 pollfds.fd = releaseFenceFd; 164 pollfds.events = POLLIN; 165 do { 166 retCode = poll(&pollfds, 1, timeout); 167 } while (retCode == -1 && (errno == EINTR || errno == EAGAIN)); 168 close(releaseFenceFd); // Prevent FD leakage. 169 } 170 171 static uint32_t value = 0x00; 172 value++; 173 uint32_t *pixel = static_cast<uint32_t *>(mappedAddr); // Use the address obtained by mmap() to access the memory. 174 for (uint32_t x = 0; x < width; x++) { 175 for (uint32_t y = 0; y < height; y++) { 176 *pixel++ = value; 177 } 178 } 179 ``` 180 1816. Flush the **OHNativeWindowBuffer** to the graphics queue. 182 183 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. 184 ```c++ 185 // Set the refresh region. If Rect in Region is a null pointer or rectNumber is 0, all contents in the OHNativeWindowBuffer are changed. 186 Region region{nullptr, 0}; 187 int acquireFenceFd = -1; 188 // Flush the buffer to the consumer through OH_NativeWindow_NativeWindowFlushBuffer, for example, by displaying it on the screen. 189 OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow, buffer, acquireFenceFd, region); 190 ``` 191 1927. Unmap memory. 193 194 ```c++ 195 // Unmap the memory when the memory is no longer required. 196 int result = munmap(mappedAddr, bufferHandle->size); 197 if (result == -1) { 198 // munmap failed 199 } 200 ``` 201 202