• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "NativeImageAdaptor.h"
17 #include "logger_common.h"
18 
19 namespace NativeWindowSample {
20 using GetPlatformDisplayExt = PFNEGLGETPLATFORMDISPLAYEXTPROC;
21 constexpr const char *EGL_EXT_PLATFORM_WAYLAND = "EGL_EXT_platform_wayland";
22 constexpr const char *EGL_KHR_PLATFORM_WAYLAND = "EGL_KHR_platform_wayland";
23 constexpr int32_t EGL_CONTEXT_CLIENT_VERSION_NUM = 2;
24 constexpr char CHARACTER_WHITESPACE = ' ';
25 constexpr const char *CHARACTER_STRING_WHITESPACE = " ";
26 constexpr const char *EGL_GET_PLATFORM_DISPLAY_EXT = "eglGetPlatformDisplayEXT";
GetInstance()27 NativeImageAdaptor *NativeImageAdaptor::GetInstance()
28 {
29     static NativeImageAdaptor imageAdaptor;
30     return &imageAdaptor;
31 };
32 
CheckEglExtension(const char * eglExtensions,const char * eglExtension)33 bool NativeImageAdaptor::CheckEglExtension(const char *eglExtensions, const char *eglExtension)
34 {
35     // Check egl extension
36     size_t extLenth = strlen(eglExtension);
37     const char *endPos = eglExtensions + strlen(eglExtensions);
38 
39     while (eglExtensions < endPos) {
40         size_t len = 0;
41         if (*eglExtensions == CHARACTER_WHITESPACE) {
42             eglExtensions++;
43             continue;
44         }
45         len = strcspn(eglExtensions, CHARACTER_STRING_WHITESPACE);
46         if (len == extLenth && strncmp(eglExtension, eglExtensions, len) == 0) {
47             return true;
48         }
49         eglExtensions += len;
50     }
51     return false;
52 }
53 
GetPlatformEglDisplay(EGLenum platform,void * native_display,const EGLint * attrib_list)54 EGLDisplay NativeImageAdaptor::GetPlatformEglDisplay(EGLenum platform, void *native_display, const EGLint *attrib_list)
55 {
56     static GetPlatformDisplayExt eglGetPlatformDisplayExt = NULL;
57     if (!eglGetPlatformDisplayExt) {
58         const char *extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
59         if (extensions && (CheckEglExtension(extensions, EGL_EXT_PLATFORM_WAYLAND) ||
60                            CheckEglExtension(extensions, EGL_KHR_PLATFORM_WAYLAND))) {
61             eglGetPlatformDisplayExt = (GetPlatformDisplayExt)eglGetProcAddress(EGL_GET_PLATFORM_DISPLAY_EXT);
62         }
63     }
64 
65     if (eglGetPlatformDisplayExt) {
66         return eglGetPlatformDisplayExt(platform, native_display, attrib_list);
67     }
68 
69     return eglGetDisplay((EGLNativeDisplayType)native_display);
70 }
71 
InitEGLEnv()72 void NativeImageAdaptor::InitEGLEnv()
73 {
74     LOGD("NativeImageAdaptor::InitEGLEnv begin");
75     // Obtain the current display device
76     eglDisplay_ = GetPlatformEglDisplay(EGL_PLATFORM_OHOS_KHR, EGL_DEFAULT_DISPLAY, NULL);
77     if (eglDisplay_ == EGL_NO_DISPLAY) {
78         LOGE("NativeImageAdaptor::InitEGLEnv fail");
79     }
80 
81     EGLint major, minor;
82     // Initialize EGLDisplay
83     if (eglInitialize(eglDisplay_, &major, &minor) == EGL_FALSE) {
84         LOGE("NativeImageAdaptor::eglInitialize fail");
85     }
86     // The API for binding graphic drawing is OpenGLES
87     if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
88         LOGE("eglBindAPI fail");
89     }
90     unsigned int ret;
91     EGLint count;
92     EGLint config_attribs[] = {EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE,
93                                8, EGL_ALPHA_SIZE, 8, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT, EGL_NONE};
94 
95     // Obtain a valid system configuration information
96     ret = eglChooseConfig(eglDisplay_, config_attribs, &config_, 1, &count);
97     if (!(ret && static_cast<unsigned int>(count) >= 1)) {
98         LOGE("eglChooseConfig fail");
99     }
100     static const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, EGL_CONTEXT_CLIENT_VERSION_NUM, EGL_NONE};
101     eglContext_ = eglCreateContext(eglDisplay_, config_, EGL_NO_CONTEXT, context_attribs);
102     if (eglContext_ == EGL_NO_CONTEXT) {
103         LOGE("eglCreateContext fail");
104     }
105     // Associated Context
106     eglMakeCurrent(eglDisplay_, EGL_NO_SURFACE, EGL_NO_SURFACE, eglContext_);
107     LOGD("Create EGL context successfully");
108 }
109 
Export(napi_env env,napi_value exports)110 bool NativeImageAdaptor::Export(napi_env env, napi_value exports)
111 {
112     napi_property_descriptor desc[] = {
113         {"GetAvailableCount", nullptr, NativeImageAdaptor::GetAvailableCount, nullptr, nullptr, nullptr, napi_default,
114          nullptr},
115         {"ProduceBuffer", nullptr, NativeImageAdaptor::NapiOnProduceBuffer, nullptr, nullptr, nullptr, napi_default,
116          nullptr},
117     };
118     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
119 
120     eglContext_ = EGL_NO_CONTEXT;
121     eglDisplay_ = EGL_NO_DISPLAY;
122     availableBufferCount_ = 0;
123     // Creating OpenGL textures
124     InitEGLEnv();
125     GLuint textureId;
126     glGenTextures(1, &textureId);
127     // Create a NativeImage instance and associate it with OpenGL textures
128     image_ = OH_NativeImage_Create(textureId, GL_TEXTURE_2D);
129     // Obtain Producer NativeWindow
130     nativeWindow_ = OH_NativeImage_AcquireNativeWindow(image_);
131 
132     int code = SET_BUFFER_GEOMETRY;
133     width_ = 0x100;
134     height_ = 0x100;
135     int32_t ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow_, code, width_, height_);
136     if (ret != 0) {
137         LOGE("NativeImageAdaptor OH_NativeWindow_NativeWindowHandleOpt fail");
138     }
139 
140     code = SET_USAGE;
141     int32_t usage = NATIVEBUFFER_USAGE_CPU_READ | NATIVEBUFFER_USAGE_CPU_WRITE | NATIVEBUFFER_USAGE_MEM_DMA;
142     ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow_, code, usage);
143 
144     OH_OnFrameAvailableListener listener;
145     listener.context = static_cast<void*>(image_);
146     listener.onFrameAvailable = NativeImageAdaptor::OnFrameAvailable;
147     ret = OH_NativeImage_SetOnFrameAvailableListener(image_, listener);
148 
149     uint64_t surfaceId;
150     ret = OH_NativeImage_GetSurfaceId(image_, &surfaceId);
151     if (ret != 0) {
152         LOGE("OH_NativeImage_GetSurfaceId fail");
153     }
154     return true;
155 }
156 
NapiOnProduceBuffer(napi_env env,napi_callback_info info)157 napi_value NativeImageAdaptor::NapiOnProduceBuffer(napi_env env, napi_callback_info info)
158 {
159     NativeImageAdaptor::GetInstance()->ProduceBuffer(0x00);
160     return nullptr;
161 }
162 
ProduceBuffer(uint32_t value)163 void NativeImageAdaptor::ProduceBuffer(uint32_t value)
164 {
165     NativeWindowBuffer *buffer = nullptr;
166     int fenceFd = -1;
167     int ret = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow_, &buffer, &fenceFd);
168     if (ret != 0) {
169         LOGE("OH_NativeWindow_NativeWindowRequestBuffer fail");
170         return;
171     }
172 
173     BufferHandle *handle = OH_NativeWindow_GetBufferHandleFromNative(buffer);
174     // Obtain the memory virtual address of bufferHandle using the system mmap interface
175     void *mappedAddr = mmap(handle->virAddr, handle->size, PROT_READ | PROT_WRITE, MAP_SHARED, handle->fd, 0);
176     uint32_t *pixel = static_cast<uint32_t *>(mappedAddr);
177     for (uint32_t x = 0; x < width_; x++) {
178         for (uint32_t y = 0; y < height_; y++) {
179             *pixel++ = value;
180         }
181     }
182     // Remember to remove memory mapping after using memory
183     int result = munmap(mappedAddr, handle->size);
184     if (result == -1) {
185         LOGE("munmap fail");
186     }
187 
188     struct Region *region = new Region();
189     struct Region::Rect *rect = new Region::Rect();
190     rect->x = 0x100;
191     rect->y = 0x100;
192     rect->w = 0x100;
193     rect->h = 0x100;
194     region->rects = rect;
195     ret = OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow_, buffer, fenceFd, *region);
196     if (ret != 0) {
197         LOGE("OH_NativeWindow_NativeWindowFlushBuffer fail");
198         return;
199     }
200     delete region;
201 }
202 
OnFrameAvailable(void * context)203 void NativeImageAdaptor::OnFrameAvailable(void *context)
204 {
205     NativeImageAdaptor::GetInstance()->DealCallback(context);
206     return;
207 }
208 
DealCallback(void * context)209 void NativeImageAdaptor::DealCallback(void *context)
210 {
211     std::lock_guard<std::mutex> lockGuard(opMutex_);
212     LOGD("NativeImageAdaptor success OnFrameAvailable, %{public}d", availableBufferCount_);
213     availableBufferCount_++;
214     int32_t ret = OH_NativeImage_UpdateSurfaceImage(image_);
215     if (ret != 0) {
216         LOGE("OH_NativeImage_UpdateSurfaceImage fail");
217     }
218     return;
219 }
220 
GetCount()221 int32_t NativeImageAdaptor::GetCount()
222 {
223     std::lock_guard<std::mutex> lockGuard(opMutex_);
224     return availableBufferCount_;
225 }
226 
GetAvailableCount(napi_env env,napi_callback_info info)227 napi_value NativeImageAdaptor::GetAvailableCount(napi_env env, napi_callback_info info)
228 {
229     napi_value val = nullptr;
230     int32_t count = NativeImageAdaptor::GetInstance()->GetCount();
231     (void)napi_create_int32(env, count, &val);
232     return val;
233 }
234 
~NativeImageAdaptor()235 NativeImageAdaptor::~NativeImageAdaptor()
236 {
237     OH_NativeImage_UnsetOnFrameAvailableListener(image_);
238     OH_NativeWindow_DestroyNativeWindow(nativeWindow_);
239     OH_NativeImage_Destroy(&image_);
240 }
241 }