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