1 /*
2  * Copyright (c) 2021 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 <iostream>
17 #include <surface.h>
18 #include <sys/time.h>
19 
20 #include <hilog/log.h>
21 #include "core/ui/rs_display_node.h"
22 #include "core/ui/rs_surface_node.h"
23 #include "window.h"
24 
25 #include <EGL/egl.h>
26 #include <EGL/eglext.h>
27 #include <GLES2/gl2.h>
28 #include <GLES2/gl2ext.h>
29 
30 #define LOGD(fmt, ...)                                                                  \
31     ::OHOS::HiviewDFX::HiLog::Debug(                                                    \
32         ::OHOS::HiviewDFX::HiLogLabel { LOG_CORE, 0, "opengl_wrapper_native_test" },    \
33         "%{public}s:%{public}d " fmt, __func__, __LINE__, ##__VA_ARGS__)
34 #define LOGI(fmt, ...)                                                                  \
35     ::OHOS::HiviewDFX::HiLog::Info(                                                     \
36         ::OHOS::HiviewDFX::HiLogLabel { LOG_CORE, 0, "opengl_wrapper_native_test" },    \
37         "%{public}s:%{public}d " fmt, __func__, __LINE__, ##__VA_ARGS__)
38 #define LOGW(fmt, ...)                                                                  \
39     ::OHOS::HiviewDFX::HiLog::Warn(                                                     \
40         ::OHOS::HiviewDFX::HiLogLabel { LOG_CORE, 0, "opengl_wrapper_native_test" },    \
41         "%{public}s:%{public}d " fmt, __func__, __LINE__, ##__VA_ARGS__)
42 #define LOGE(fmt, ...)                                                                  \
43     ::OHOS::HiviewDFX::HiLog::Error(                                                    \
44         ::OHOS::HiviewDFX::HiLogLabel { LOG_CORE, 0, "opengl_wrapper_native_test" },    \
45         "%{public}s:%{public}d " fmt, __func__, __LINE__, ##__VA_ARGS__)
46 
47 using namespace OHOS;
48 using namespace Rosen;
49 using namespace std;
50 
51 using TestFunc = std::function<void(uint32_t, uint32_t)>;
52 static std::vector<TestFunc> testFuncVec;
53 constexpr static int32_t WIDTH = 720;
54 constexpr static int32_t HEIGHT = 1280;
55 constexpr static int32_t LOOP_COUNT = 5000;
56 constexpr static int32_t FRAME_UPDATE_TIME_INTERVAL = 16000;
57 constexpr int32_t EGL_CONTEXT_CLIENT_VERSION_NUM = 3;
58 static EGLDisplay gEglDisplay = EGL_NO_DISPLAY;
59 static EGLContext gEglContext = EGL_NO_CONTEXT;
60 static EGLSurface gEglSurface = EGL_NO_SURFACE;
61 static EGLConfig gConfig;
62 static struct NativeWindow *gWindow = nullptr;
63 static GLuint gProgram;
64 static GLuint gPos;
65 static GLuint gColor;
66 static GLuint gOffsetUniform;
67 
68 static const char *gFragShaderText =
69     "precision mediump float;\n"
70     "varying vec4 v_color;\n"
71     "void main() {\n"
72     "  gl_FragColor = v_color + 0.1;\n"
73     "}\n";
74 
75 static const char *gVertShaderText =
76     "uniform float offset;\n"
77     "attribute vec4 pos;\n"
78     "attribute vec4 color;\n"
79     "varying vec4 v_color;\n"
80     "void main() {\n"
81     "  gl_Position = pos + vec4(offset, offset, 0.1, 0.1);\n"
82     "  v_color = color;\n"
83     "}\n";
84 
CreateShader(const char * source,GLenum shaderType)85 static GLuint CreateShader(const char *source, GLenum shaderType)
86 {
87     GLuint shader;
88     GLint status;
89 
90     shader = glCreateShader(shaderType);
91     if (shader == 0) {
92         LOGE("glCreateShader error!");
93         return 0;
94     }
95 
96     glShaderSource(shader, 1, (const char **) &source, NULL);
97     glCompileShader(shader);
98 
99     glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
100     if (!status) {
101         LOGE("glGetShaderiv status error!");
102         return 0;
103     }
104 
105     return shader;
106 }
107 
CreateAndLinkProgram(GLuint vert,GLuint frag)108 static GLuint CreateAndLinkProgram(GLuint vert, GLuint frag)
109 {
110     GLint status;
111     GLuint program = glCreateProgram();
112 
113     glAttachShader(program, vert);
114     glAttachShader(program, frag);
115     glLinkProgram(program);
116 
117     glGetProgramiv(program, GL_LINK_STATUS, &status);
118     if (!status) {
119         LOGE("glGetProgramiv status error!");
120         return 0;
121     }
122 
123     return program;
124 }
125 
SetUpGl()126 static bool SetUpGl()
127 {
128     GLuint vert = CreateShader(gVertShaderText, GL_VERTEX_SHADER);
129     GLuint frag = CreateShader(gFragShaderText, GL_FRAGMENT_SHADER);
130 
131     gProgram = CreateAndLinkProgram(vert, frag);
132 
133     glDeleteShader(vert);
134     glDeleteShader(frag);
135 
136     gPos = glGetAttribLocation(gProgram, "pos");
137     gColor = glGetAttribLocation(gProgram, "color");
138 
139     glUseProgram(gProgram);
140 
141     gOffsetUniform = glGetUniformLocation(gProgram, "offset");
142 
143     return gProgram != 0;
144 }
145 
render()146 static void render()
147 {
148     /* Complete a movement iteration in 5000 ms. */
149     static const uint64_t iterationMs = 5000;
150     static const GLfloat verts[4][2] = {
151         { -0.5, -0.5 },
152         { -0.5,  0.5 },
153         {  0.5, -0.5 },
154         {  0.5,  0.5 }
155     };
156     static const GLfloat colors[4][3] = {
157         { 1, 0, 0 },
158         { 0, 1, 0 },
159         { 0, 0, 1 },
160         { 1, 1, 0 }
161     };
162     GLfloat offset;
163     struct timeval tv;
164     uint64_t timeMs;
165 
166     gettimeofday(&tv, nullptr);
167     const int timeConversionRate = 1000;
168     timeMs = tv.tv_sec * timeConversionRate + tv.tv_usec / timeConversionRate;
169 
170     /* Split timeMs in repeating windows of [0, iterationMs) and map them
171      * to offsets in the [-0.5, 0.5) range. */
172     const float range = 0.5;
173     offset = (timeMs % iterationMs) / (float) iterationMs - range;
174 
175     glUniform1f(gOffsetUniform, offset);
176 
177     glClearColor(1.0, 1.0, 1.0, 1.0);
178     glClear(GL_COLOR_BUFFER_BIT);
179 
180     const int32_t vertsCnt = 2;
181     glVertexAttribPointer(gPos, vertsCnt, GL_FLOAT, GL_FALSE, 0, verts);
182     const int32_t colorsCnt = 3;
183     glVertexAttribPointer(gColor, colorsCnt, GL_FLOAT, GL_FALSE, 0, colors);
184     glEnableVertexAttribArray(gPos);
185     glEnableVertexAttribArray(gColor);
186 
187     const int32_t pointsCnt = 4;
188     glDrawArrays(GL_TRIANGLE_STRIP, 0, pointsCnt);
189 
190     glDisableVertexAttribArray(gPos);
191     glDisableVertexAttribArray(gColor);
192 }
193 
TestDraw(uint32_t width,uint32_t height)194 static void TestDraw(uint32_t width, uint32_t height)
195 {
196     LOGI("+++++++ TestDraw");
197 
198     LOGI("width=%{public}d, height=%{public}d\n", width, height);
199 
200     EGLint w, h;
201     eglQuerySurface(gEglDisplay, gEglSurface, EGL_WIDTH, &w);
202     eglQuerySurface(gEglDisplay, gEglSurface, EGL_HEIGHT, &h);
203 
204     LOGI("w=%{public}d, h=%{public}d\n", w, h);
205 
206     glViewport(0, 0, w, h);
207 
208     for (int i = 0; i < LOOP_COUNT; i++) {
209         render();
210         eglSwapBuffers(gEglDisplay, gEglSurface);
211         usleep(FRAME_UPDATE_TIME_INTERVAL);
212     }
213 
214     LOGI("+++++++ TestDraw");
215 }
216 
InitEglContext()217 static void InitEglContext()
218 {
219     LOGI("Creating EGLContext!!!");
220     gEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
221     if (gEglDisplay == EGL_NO_DISPLAY) {
222         LOGW("Failed to create EGLDisplay gl errno : %{public}x", eglGetError());
223         return;
224     }
225 
226     EGLint major, minor;
227     if (eglInitialize(gEglDisplay, &major, &minor) == EGL_FALSE) {
228         LOGE("Failed to initialize EGLDisplay");
229         return;
230     }
231 
232     if (eglBindAPI(EGL_OPENGL_ES_API) == EGL_FALSE) {
233         LOGE("Failed to bind OpenGL ES API");
234         return;
235     }
236 
237     unsigned int ret;
238     EGLint count;
239     EGLint configAttribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8,
240         EGL_ALPHA_SIZE, 8, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE };
241 
242     ret = eglChooseConfig(gEglDisplay, configAttribs, &gConfig, 1, &count);
243     if (!(ret && static_cast<unsigned int>(count) >= 1)) {
244         LOGE("Failed to eglChooseConfig");
245         return;
246     }
247 
248     static const EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, EGL_CONTEXT_CLIENT_VERSION_NUM, EGL_NONE };
249 
250     gEglContext = eglCreateContext(gEglDisplay, gConfig, EGL_NO_CONTEXT, contextAttribs);
251     if (gEglContext == EGL_NO_CONTEXT) {
252         LOGE("Failed to create egl context %{public}x", eglGetError());
253         return;
254     }
255 
256     eglMakeCurrent(gEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, gEglContext);
257 
258     EGLint winAttribs[] = { EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR, EGL_NONE };
259     gEglSurface = eglCreateWindowSurface(gEglDisplay, gConfig, gWindow, winAttribs);
260     if (gEglSurface == EGL_NO_SURFACE) {
261         LOGW("Failed to create eglsurface!!! %{public}x", eglGetError());
262         return;
263     }
264 
265     LOGW("Create EGL context successfully, version %{public}d.%{public}d", major, minor);
266 
267     eglMakeCurrent(gEglDisplay, gEglSurface, gEglSurface, gEglContext);
268 
269     SetUpGl();
270 }
271 
Deinit()272 static void Deinit()
273 {
274     if (gEglDisplay == EGL_NO_DISPLAY) {
275         return;
276     }
277     eglDestroySurface(gEglDisplay, gEglSurface);
278     eglDestroyContext(gEglDisplay, gEglContext);
279     eglMakeCurrent(gEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
280     eglTerminate(gEglDisplay);
281     eglReleaseThread();
282 
283     gEglDisplay = EGL_NO_DISPLAY;
284     gEglContext = EGL_NO_CONTEXT;
285     gEglSurface = EGL_NO_SURFACE;
286 }
287 
DrawSurface(int32_t width,int32_t height,size_t index)288 static void DrawSurface(int32_t width, int32_t height, size_t index)
289 {
290     InitEglContext();
291     testFuncVec[index](WIDTH, HEIGHT);
292     Deinit();
293 }
294 
CreateSurface()295 static std::shared_ptr<RSSurfaceNode> CreateSurface()
296 {
297     RSSurfaceNodeConfig config;
298     auto surfaceNode = RSSurfaceNode::Create(config);
299     sptr<Surface> surf = surfaceNode->GetSurface();
300     gWindow = CreateNativeWindowFromSurface(&surf);
301 
302     NativeWindowHandleOpt(gWindow, SET_USAGE, BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA);
303     NativeWindowHandleOpt(gWindow, SET_BUFFER_GEOMETRY, WIDTH, HEIGHT);
304     NativeWindowHandleOpt(gWindow, SET_COLOR_GAMUT, ColorGamut::COLOR_GAMUT_SRGB);
305 
306     return surfaceNode;
307 }
308 
main()309 int main()
310 {
311     testFuncVec.push_back(TestDraw);
312     auto surfaceNode = CreateSurface();
313     RSDisplayNodeConfig config;
314     RSDisplayNode::SharedPtr displayNode = RSDisplayNode::Create(config);
315     for (size_t i = 0; i < testFuncVec.size(); i++) {
316         auto transactionProxy = RSTransactionProxy::GetInstance();
317         if (transactionProxy == nullptr) {
318             continue;
319         }
320         // sleep 2s
321         sleep(2);
322         displayNode->AddChild(surfaceNode, -1);
323         surfaceNode->SetBounds(0, 0, WIDTH, HEIGHT);
324         transactionProxy->FlushImplicitTransaction();
325 
326         DrawSurface(WIDTH, HEIGHT, i);
327 
328         // sleep 8s
329         sleep(8);
330         displayNode->RemoveChild(surfaceNode);
331         transactionProxy->FlushImplicitTransaction();
332     }
333 
334     return 0;
335 }
336