1 /*
2  * Copyright (c) 2022 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 "native_image.h"
17 
18 #include <cstddef>
19 #include <iostream>
20 #include <ostream>
21 #include <thread>
22 #include <unistd.h>
23 #include <EGL/egl.h>
24 #include <EGL/eglext.h>
25 #include "graphic_common_c.h"
26 #include "surface_type.h"
27 #include "window.h"
28 #include "GLES/gl.h"
29 
30 namespace {
31 using GetPlatformDisplayExt = PFNEGLGETPLATFORMDISPLAYEXTPROC;
32 constexpr const char* EGL_EXT_PLATFORM_WAYLAND = "EGL_EXT_platform_wayland";
33 constexpr const char* EGL_KHR_PLATFORM_WAYLAND = "EGL_KHR_platform_wayland";
34 constexpr int32_t EGL_CONTEXT_CLIENT_VERSION_NUM = 2;
35 constexpr char CHARACTER_WHITESPACE = ' ';
36 constexpr const char* CHARACTER_STRING_WHITESPACE = " ";
37 constexpr const char* EGL_GET_PLATFORM_DISPLAY_EXT = "eglGetPlatformDisplayEXT";
38 EGLDisplay g_eglDisplay = EGL_NO_DISPLAY;
39 EGLContext g_eglContext = EGL_NO_CONTEXT;
40 EGLConfig g_config;
41 
CheckEglExtension(const char * extensions,const char * extension)42 static bool CheckEglExtension(const char* extensions, const char* extension)
43 {
44     size_t extlen = strlen(extension);
45     const char* end = extensions + strlen(extensions);
46 
47     while (extensions < end) {
48         size_t n = 0;
49         /* Skip whitespaces, if any */
50         if (*extensions == CHARACTER_WHITESPACE) {
51             extensions++;
52             continue;
53         }
54         n = strcspn(extensions, CHARACTER_STRING_WHITESPACE);
55         /* Compare strings */
56         if (n == extlen && strncmp(extension, extensions, n) == 0) {
57             return true; /* Found */
58         }
59         extensions += n;
60     }
61     /* Not found */
62     return false;
63 }
64 
GetPlatformEglDisplay(EGLenum platform,void * nativeDisplay,const EGLint * attribList)65 static EGLDisplay GetPlatformEglDisplay(EGLenum platform, void* nativeDisplay, const EGLint* attribList)
66 {
67     static GetPlatformDisplayExt eglGetPlatformDisplayExt = NULL;
68 
69     if (!eglGetPlatformDisplayExt) {
70         const char* extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
71         if (extensions &&
72             (CheckEglExtension(extensions, EGL_EXT_PLATFORM_WAYLAND) ||
73                 CheckEglExtension(extensions, EGL_KHR_PLATFORM_WAYLAND))) {
74             eglGetPlatformDisplayExt =
75                 static_cast<GetPlatformDisplayExt>(eglGetProcAddress(EGL_GET_PLATFORM_DISPLAY_EXT));
76         }
77     }
78 
79     if (eglGetPlatformDisplayExt) {
80         return eglGetPlatformDisplayExt(platform, nativeDisplay, attribList);
81     }
82 
83     return eglGetDisplay(static_cast<EGLNativeDisplayType>(nativeDisplay));
84 }
85 
AddBuffer(OHNativeWindow * nativeWindow)86 void AddBuffer(OHNativeWindow* nativeWindow)
87 {
88     int code = SET_USAGE;
89     int32_t usage = OHOS::BUFFER_USAGE_CPU_READ | OHOS::BUFFER_USAGE_CPU_WRITE | OHOS::BUFFER_USAGE_MEM_DMA;
90     int32_t ret = NativeWindowHandleOpt(nativeWindow, code, usage);
91     if (ret != GSERROR_OK) {
92         std::cout << "NativeWindowHandleOpt SET_USAGE faile" << std::endl;
93     }
94     code = SET_BUFFER_GEOMETRY;
95     int32_t width = 0x100;
96     int32_t height = 0x100;
97     ret = NativeWindowHandleOpt(nativeWindow, code, width, height);
98     if (ret != GSERROR_OK) {
99         std::cout << "NativeWindowHandleOpt SET_BUFFER_GEOMETRY failed" << std::endl;
100     }
101     code = SET_STRIDE;
102     int32_t stride = 0x8;
103     ret = NativeWindowHandleOpt(nativeWindow, code, stride);
104     if (ret != GSERROR_OK) {
105         std::cout << "NativeWindowHandleOpt SET_STRIDE failed" << std::endl;
106     }
107     code = SET_FORMAT;
108     int32_t format = GRAPHIC_PIXEL_FMT_RGBA_8888;
109     ret = NativeWindowHandleOpt(nativeWindow, code, format);
110     if (ret != GSERROR_OK) {
111         std::cout << "NativeWindowHandleOpt SET_FORMAT failed" << std::endl;
112     }
113 
114     NativeWindowBuffer* nativeWindowBuffer = nullptr;
115     int fenceFd = -1;
116     ret = OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow, &nativeWindowBuffer, &fenceFd);
117     if (ret != GSERROR_OK) {
118         std::cout << "NativeWindowHandleOpt SET_FORMAT failed" << std::endl;
119     }
120 
121     struct Region *region = new Region();
122     struct Region::Rect *rect = new Region::Rect();
123     rect->x = 0x100;
124     rect->y = 0x100;
125     rect->w = 0x100;
126     rect->h = 0x100;
127     region->rects = rect;
128     ret = OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow, nativeWindowBuffer, fenceFd, *region);
129     if (ret != GSERROR_OK) {
130         std::cout << "NativeWindowHandleOpt SET_FORMAT failed" << std::endl;
131     }
132     delete region;
133 }
134 
GetData(OH_NativeImage * image,OHNativeWindow * nativeWindow)135 int32_t GetData(OH_NativeImage* image, OHNativeWindow* nativeWindow)
136 {
137     AddBuffer(nativeWindow);
138     int32_t ret = OH_NativeImage_UpdateSurfaceImage(image);
139     if (ret != SURFACE_ERROR_OK) {
140         std::cout << "OH_NativeImage_UpdateSurfaceImage failed" << std::endl;
141         return -1;
142     }
143 
144     int64_t timeStamp = OH_NativeImage_GetTimestamp(image);
145     if (timeStamp == SURFACE_ERROR_ERROR) {
146         std::cout << "OH_NativeImage_GetTimestamp failed" << std::endl;
147         return -1;
148     }
149 
150     float matrix[16];
151     ret = OH_NativeImage_GetTransformMatrix(image, matrix);
152     if (ret != SURFACE_ERROR_OK) {
153         std::cout << "OH_NativeImage_GetTransformMatrix failed" << std::endl;
154         return -1;
155     }
156     return SURFACE_ERROR_OK;
157 }
158 
InitEglContext()159 void InitEglContext()
160 {
161     if (g_eglContext != EGL_NO_DISPLAY) {
162         return;
163     }
164 
165     std::cout << "Creating EGLContext!!!" << std::endl;
166     g_eglDisplay = GetPlatformEglDisplay(EGL_PLATFORM_OHOS_KHR, EGL_DEFAULT_DISPLAY, NULL);
167     if (g_eglDisplay == EGL_NO_DISPLAY) {
168         std::cout << "Failed to create EGLDisplay gl errno : " << eglGetError() << std::endl;
169         return;
170     }
171 
172     EGLint major, minor;
173     if (eglInitialize(g_eglDisplay, &major, &minor) == EGL_FALSE) {
174         std::cout << "Failed to initialize EGLDisplay" << std::endl;
175         return;
176     }
177 
178     if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
179         std::cout << "Failed to bind OpenGL ES API" << std::endl;
180         return;
181     }
182 
183     unsigned int ret;
184     EGLint count;
185     EGLint configAttribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8,
186         EGL_ALPHA_SIZE, 8, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT, EGL_NONE };
187 
188     ret = eglChooseConfig(g_eglDisplay, configAttribs, &g_config, 1, &count);
189     if (!(ret && static_cast<unsigned int>(count) >= 1)) {
190         std::cout << "Failed to eglChooseConfig" << std::endl;
191         return;
192     }
193 
194     static const EGLint CONTEXT_ATTRIBS[] = { EGL_CONTEXT_CLIENT_VERSION, EGL_CONTEXT_CLIENT_VERSION_NUM, EGL_NONE };
195 
196     g_eglContext = eglCreateContext(g_eglDisplay, g_config, EGL_NO_CONTEXT, CONTEXT_ATTRIBS);
197     if (g_eglContext == EGL_NO_CONTEXT) {
198         std::cout << "Failed to create egl context %{public}x, error:" << eglGetError() << std::endl;
199         return;
200     }
201 
202     eglMakeCurrent(g_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, g_eglContext);
203 
204     std::cout << "Create EGL context successfully, version" << major << "." << minor << std::endl;
205 }
206 
Deinit()207 void Deinit()
208 {
209     if (g_eglDisplay == EGL_NO_DISPLAY) {
210         return;
211     }
212     eglDestroyContext(g_eglDisplay, g_eglContext);
213     eglMakeCurrent(g_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
214     eglTerminate(g_eglDisplay);
215     eglReleaseThread();
216 
217     g_eglDisplay = EGL_NO_DISPLAY;
218     g_eglContext = EGL_NO_CONTEXT;
219 }
220 
221 }
222 
main(int32_t argc,const char * argv[])223 int32_t main(int32_t argc, const char *argv[])
224 {
225     std::cout << "sample start" << std::endl;
226     InitEglContext();
227     GLuint textureId;
228     glGenTextures(1, &textureId);
229 
230     OH_NativeImage* image = OH_NativeImage_Create(textureId, GL_TEXTURE_2D);
231 
232     OHNativeWindow* nativeWindow = OH_NativeImage_AcquireNativeWindow(image);
233     if (nativeWindow == nullptr) {
234         std::cout << "OH_NativeImage_AcquireNativeWindow failed" << std::endl;
235         return -1;
236     }
237 
238     int32_t ret = GetData(image, nativeWindow);
239     if (ret != SURFACE_ERROR_OK) {
240         return -1;
241     }
242 
243     GLuint textureId2;
244     glGenTextures(1, &textureId2);
245     ret = OH_NativeImage_AttachContext(image, textureId2);
246     if (ret != SURFACE_ERROR_OK) {
247         std::cout << "OH_NativeImage_AttachContext textureId2 failed" << std::endl;
248         return -1;
249     }
250 
251     ret = GetData(image, nativeWindow);
252     if (ret != SURFACE_ERROR_OK) {
253         return -1;
254     }
255 
256     ret = OH_NativeImage_DetachContext(image);
257     if (ret != SURFACE_ERROR_OK) {
258         std::cout << "OH_NativeImage_DetachContext failed" << std::endl;
259         return -1;
260     }
261 
262     ret = OH_NativeImage_AttachContext(image, textureId2);
263     if (ret != SURFACE_ERROR_OK) {
264         std::cout << "OH_NativeImage_AttachContext after OH_NativeImage_DetachContext failed" << std::endl;
265         return -1;
266     }
267 
268     ret = GetData(image, nativeWindow);
269     if (ret != SURFACE_ERROR_OK) {
270         return -1;
271     }
272 
273     OH_NativeImage_Destroy(&image);
274     if (image != nullptr) {
275         std::cout << "OH_NativeImage_Destroy failed" << std::endl;
276         return -1;
277     }
278 
279     Deinit();
280     std::cout << "sample end successfully" << std::endl;
281     return 0;
282 }