1 /*
2  * Copyright (c) 2024 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 <EGL/egl.h>
17 #include <EGL/eglext.h>
18 #include <EGL/eglplatform.h>
19 #include <GLES3/gl3.h>
20 #include <hilog/log.h>
21 #include <algorithm>
22 #include "egl_core.h"
23 #include "plugin_render.h"
24 #include "common.h"
25 
26 namespace OHOS {
EglContextInit(void * window,int width,int height)27 bool EGLCore::EglContextInit(void *window, int width, int height)
28 {
29     OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "EGLCore", "EglContextInit execute");
30     if ((window == nullptr) || (width <= 0) || (height <= 0)) {
31         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "EglContextInit: param error");
32         return false;
33     }
34 
35     width_ = width;
36     height_ = height;
37     widthpercent_ = FIFTY_PERCENT * height_ / width_;
38     eglwindow_ = static_cast<EGLNativeWindowType>(window);
39 
40     // Init display.
41     egldisplay_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
42     if (egldisplay_ == EGL_NO_DISPLAY) {
43         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglGetDisplay: unable to get EGL display");
44         return false;
45     }
46 
47     EGLint majorVersion;
48     EGLint minorVersion;
49     if (!eglInitialize(egldisplay_, &majorVersion, &minorVersion)) {
50         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore",
51             "eglInitialize: unable to get initialize EGL display");
52         return false;
53     }
54 
55     // Select configuration.
56     const EGLint maxConfigSize = 1;
57     EGLint numConfigs;
58     if (!eglChooseConfig(egldisplay_, ATTRIB_LIST, &eglconfig_, maxConfigSize, &numConfigs)) {
59         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglChooseConfig: unable to choose configs");
60         return false;
61     }
62 
63     return CreateEnvironment();
64 }
65 
CreateEnvironment()66 bool EGLCore::CreateEnvironment()
67 {
68     if (eglwindow_ == nullptr) {
69         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglwindow_ is null");
70         return false;
71     }
72     eglsurface_ = eglCreateWindowSurface(egldisplay_, eglconfig_, eglwindow_, nullptr);
73     if (eglsurface_ == nullptr) {
74         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore",
75             "eglCreateWindowSurface: unable to create WindowSurface");
76         return false;
77     }
78 
79     // Create context.
80     eglcontext_ = eglCreateContext(egldisplay_, eglconfig_, EGL_NO_CONTEXT, CONTEXT_ATTRIBS);
81     if (!eglMakeCurrent(egldisplay_, eglsurface_, eglsurface_, eglcontext_)) {
82         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglMakeCurrent failed");
83         return false;
84     }
85 
86     // Create program.
87     program_ = CreateProgram(VERTEX_SHADER, FRAGMENT_SHADER);
88     if (program_ == PROGRAM_ERROR) {
89         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "CreateProgram: unable to create program");
90         return false;
91     }
92     return true;
93 }
94 
CreateProgram(const char * vertexShader,const char * fragShader)95 GLuint EGLCore::CreateProgram(const char *vertexShader, const char *fragShader)
96 {
97     if ((vertexShader == nullptr) || (fragShader == nullptr)) {
98         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore",
99                      "createProgram: vertexShader or fragShader is null");
100         return PROGRAM_ERROR;
101     }
102 
103     GLuint vertex = LoadShader(GL_VERTEX_SHADER, vertexShader);
104     if (vertex == PROGRAM_ERROR) {
105         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "createProgram vertex error");
106         return PROGRAM_ERROR;
107     }
108 
109     GLuint fragment = LoadShader(GL_FRAGMENT_SHADER, fragShader);
110     if (fragment == PROGRAM_ERROR) {
111         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "createProgram fragment error");
112         return PROGRAM_ERROR;
113     }
114 
115     GLuint program = glCreateProgram();
116     if (program == PROGRAM_ERROR) {
117         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "createProgram program error");
118         glDeleteShader(vertex);
119         glDeleteShader(fragment);
120         return PROGRAM_ERROR;
121     }
122 
123     glAttachShader(program, vertex);
124     glAttachShader(program, fragment);
125     glLinkProgram(program);
126 
127     GLint linked;
128     glGetProgramiv(program, GL_LINK_STATUS, &linked);
129     if (linked != 0) {
130         glDeleteShader(vertex);
131         glDeleteShader(fragment);
132         return program;
133     }
134 
135     OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "createProgram linked error");
136     GLint infoLen = 0;
137     glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
138     if (infoLen > 1) {
139         char *infoLog = static_cast<char*>(malloc(sizeof(char) * (infoLen + 1)));
140         std::fill(infoLog, infoLog + infoLen, 0);
141         glGetProgramInfoLog(program, infoLen, nullptr, infoLog);
142         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "glLinkProgram error = %s", infoLog);
143         free(infoLog);
144         infoLog = nullptr;
145     }
146     glDeleteShader(vertex);
147     glDeleteShader(fragment);
148     glDeleteProgram(program);
149     return PROGRAM_ERROR;
150 }
151 
LoadShader(GLenum type,const char * shaderSrc)152 GLuint EGLCore::LoadShader(GLenum type, const char *shaderSrc)
153 {
154     if ((type <= 0) || (shaderSrc == nullptr)) {
155         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "glCreateShader type or shaderSrc error");
156         return PROGRAM_ERROR;
157     }
158 
159     GLuint shader = glCreateShader(type);
160     if (shader == 0) {
161         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "glCreateShader unable to load shader");
162         return PROGRAM_ERROR;
163     }
164 
165     // The gl function has no return value.
166     glShaderSource(shader, 1, &shaderSrc, nullptr);
167     glCompileShader(shader);
168 
169     GLint compiled;
170     glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
171     if (compiled != 0) {
172         return shader;
173     }
174 
175     GLint infoLen = 0;
176     glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
177     if (infoLen <= 1) {
178         glDeleteShader(shader);
179         return PROGRAM_ERROR;
180     }
181 
182     char *infoLog = static_cast<char*>(malloc(sizeof(char) * (infoLen + 1)));
183     if (infoLog != nullptr) {
184         std::fill(infoLog, infoLog + infoLen, 0);
185         glGetShaderInfoLog(shader, infoLen, nullptr, infoLog);
186         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "glCompileShader error = %s", infoLog);
187         free(infoLog);
188         infoLog = nullptr;
189     }
190     glDeleteShader(shader);
191     return PROGRAM_ERROR;
192 }
193 
Draw()194 void EGLCore::Draw()
195 {
196     flag_ = false;
197     OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "EGLCore", "Draw");
198     GLint position = PrepareDraw();
199     if (position == POSITION_ERROR) {
200         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw get position failed");
201         return;
202     }
203 
204     if (!ExecuteDraw(position, BACKGROUND_COLOR, BACKGROUND_RECTANGLE_VERTICES,
205         sizeof(BACKGROUND_RECTANGLE_VERTICES))) {
206         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw execute draw background failed");
207         return;
208     }
209 
210     const GLfloat rectangleVertices[] = {
211         -widthpercent_, FIFTY_PERCENT,
212         widthpercent_, FIFTY_PERCENT,
213         widthpercent_, -FIFTY_PERCENT,
214         -widthpercent_, -FIFTY_PERCENT
215     };
216     if (!ExecuteDraw(position, DRAW_COLOR, rectangleVertices, sizeof(rectangleVertices))) {
217         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw execute draw rectangle failed");
218         return;
219     }
220 
221     if (!FinishDraw()) {
222         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw FinishDraw failed");
223         return;
224     }
225 
226     flag_ = true;
227 }
228 
PrepareDraw()229 GLint EGLCore::PrepareDraw()
230 {
231     if ((egldisplay_ == nullptr) || (eglsurface_ == nullptr) || (eglcontext_ == nullptr) ||
232         (!eglMakeCurrent(egldisplay_, eglsurface_, eglsurface_, eglcontext_))) {
233         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "PrepareDraw: param error");
234         return POSITION_ERROR;
235     }
236 
237     // The gl function has no return value.
238     glViewport(0, 0, width_, height_);
239     glClearColor(0, 255, 0, 1); //255 is color value, 1 is transparency
240     glClear(GL_COLOR_BUFFER_BIT);
241     glUseProgram(program_);
242 
243     return glGetAttribLocation(program_, "a_position");
244 }
245 
ExecuteDraw(GLint position,const GLfloat * color,const GLfloat rectangleVertices[],unsigned long vertSize)246 bool EGLCore::ExecuteDraw(GLint position, const GLfloat *color, const GLfloat rectangleVertices[],
247     unsigned long vertSize)
248 {
249     if ((position < 0) || (color == nullptr) || (vertSize / sizeof(rectangleVertices[0]) != RECTANGLE_VERTICES_SIZE)) {
250         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "ExecuteDraw: param error");
251         return false;
252     }
253 
254     // The gl function has no return value.
255     glVertexAttribPointer(position, POINTER_SIZE, GL_FLOAT, GL_FALSE, 0, rectangleVertices);
256     glEnableVertexAttribArray(position);
257     glVertexAttrib4fv(1, color);
258     glDrawArrays(GL_TRIANGLE_FAN, 0, TRIANGLE_FAN_SIZE);
259     glDisableVertexAttribArray(position);
260 
261     return true;
262 }
263 
FinishDraw()264 bool EGLCore::FinishDraw()
265 {
266     // The gl function has no return value.
267     glFlush();
268     glFinish();
269     return eglSwapBuffers(egldisplay_, eglsurface_);
270 }
271 
Release()272 void EGLCore::Release()
273 {
274     if ((egldisplay_ == nullptr) || (eglsurface_ == nullptr) || (!eglDestroySurface(egldisplay_, eglsurface_))) {
275         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Release eglDestroySurface failed");
276     }
277 
278     if ((egldisplay_ == nullptr) || (eglcontext_ == nullptr) || (!eglDestroyContext(egldisplay_, eglcontext_))) {
279         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Release eglDestroyContext failed");
280     }
281 
282     if ((egldisplay_ == nullptr) || (!eglTerminate(egldisplay_))) {
283         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Release eglTerminate failed");
284     }
285 }
286 } // namespace OHOS