• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "image_render.h"
17 #include "common/common.h"
18 #include <GLES2/gl2ext.h>
19 #include <hilog/log.h>
20 #include <memory>
21 #include <cmath>
22 #include <algorithm>
23 #include <EGL/eglext.h>
24 
25 namespace {
26     constexpr int MATRIX_SIZE = 16;
27     constexpr int MATRIX_DIAGONAL_STEP = 5;
28     constexpr float IDENTITY_DIAGONAL = 1.0f;
29     constexpr float IDENTITY_OTHER = 0.0f;
30     constexpr uint32_t NUM_VERTICES = 4;
31     constexpr uint32_t POSITION_COMPONENT_COUNT = 3;
32     constexpr uint32_t TEX_COORD_COMPONENT_COUNT = 2;
33     constexpr uint32_t STRIDE = (POSITION_COMPONENT_COUNT + TEX_COORD_COMPONENT_COUNT) * sizeof(GLfloat);
34     const char* g_vertexShaderSource = R"(
35         attribute vec4 aPosition;
36         attribute vec2 aTexCoord;
37         varying vec2 vTexCoord;
38         uniform mat4 uTransformMatrix;
39         void main() {
40             gl_Position = aPosition;
41             vTexCoord = (uTransformMatrix * vec4(aTexCoord, 0.0, 1.0)).xy;
42         }
43     )";
44 
45     const char* g_fragmentShaderSource = R"(
46         #extension GL_OES_EGL_image_external : require
47         precision mediump float;
48         uniform samplerExternalOES uTexture;
49         varying vec2 vTexCoord;
50         void main() {
51             gl_FragColor = texture2D(uTexture, vTexCoord);
52         }
53     )";
54 }
55 
ImageRender()56 ImageRender::ImageRender()
57 {
58     // Initialize transformMatrix_ as an identity matrix
59     for (int i = 0; i < MATRIX_SIZE; ++i) {
60         transformMatrix_[i] = (i % MATRIX_DIAGONAL_STEP == 0) ? IDENTITY_DIAGONAL : IDENTITY_OTHER;
61     }
62 }
63 
~ImageRender()64 ImageRender::~ImageRender()
65 {
66     Cleanup();
67 }
68 
InitEGL(EGLNativeWindowType window,uint64_t width,uint64_t height)69 bool ImageRender::InitEGL(EGLNativeWindowType window, uint64_t width, uint64_t height)
70 {
71     window_ = window;
72     width_ = width;
73     height_ = height;
74 
75     if (!InitializeEGLDisplay() || !ChooseEGLConfig() || !CreateEGLContext() || !CreateEGLSurface()) {
76         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ImageRender", "Failed to initialize EGL");
77         return false;
78     }
79 
80     if (!MakeCurrentContext()) {
81         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ImageRender", "Failed to make EGL context current");
82         return false;
83     }
84 
85     if (!CompileAndLinkShaders()) {
86         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ImageRender", "Failed to compile and link shaders");
87         return false;
88     }
89 
90     UpdateViewport();
91 
92     return true;
93 }
94 
UpdateWindowInfo(uint64_t width,uint64_t height)95 void ImageRender::UpdateWindowInfo(uint64_t width, uint64_t height)
96 {
97     width_ = width;
98     height_ = height;
99 }
100 
InitializeEGLDisplay()101 bool ImageRender::InitializeEGLDisplay()
102 {
103     display_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
104     if (display_ == EGL_NO_DISPLAY) {
105         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ImageRender", "Failed to get EGL display");
106         return false;
107     }
108 
109     if (!eglInitialize(display_, nullptr, nullptr)) {
110         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ImageRender", "Failed to initialize EGL");
111         return false;
112     }
113 
114     return true;
115 }
116 
ChooseEGLConfig()117 bool ImageRender::ChooseEGLConfig()
118 {
119     const EGLint attribs[] = {
120         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
121         EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
122         EGL_RED_SIZE, 8,
123         EGL_GREEN_SIZE, 8,
124         EGL_BLUE_SIZE, 8,
125         EGL_ALPHA_SIZE, 8,
126         EGL_NONE
127     };
128 
129     EGLint numConfigs;
130     if (!eglChooseConfig(display_, attribs, &config_, 1, &numConfigs) || numConfigs == 0) {
131         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ImageRender", "Failed to choose EGL config");
132         return false;
133     }
134     return true;
135 }
136 
CreateEGLContext()137 bool ImageRender::CreateEGLContext()
138 {
139     const EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
140     context_ = eglCreateContext(display_, config_, EGL_NO_CONTEXT, contextAttribs);
141     if (context_ == EGL_NO_CONTEXT) {
142         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ImageRender", "Failed to create EGL context");
143         return false;
144     }
145     return true;
146 }
147 
CreateEGLSurface()148 bool ImageRender::CreateEGLSurface()
149 {
150     surface_ = eglCreateWindowSurface(display_, config_, window_, nullptr);
151     if (surface_ == EGL_NO_SURFACE) {
152         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ImageRender", "Failed to create EGL surface");
153         return false;
154     }
155     return true;
156 }
157 
MakeCurrentContext()158 bool ImageRender::MakeCurrentContext()
159 {
160     if (!eglMakeCurrent(display_, surface_, surface_, context_)) {
161         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ImageRender", "Failed to make EGL context current");
162         return false;
163     }
164     return true;
165 }
166 
UpdateViewport()167 void ImageRender::UpdateViewport()
168 {
169     glViewport(0, 0, static_cast<GLsizei>(width_), static_cast<GLsizei>(height_));
170     OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "ImageRender",
171                  "Viewport updated to %{public}llu x %{public}llu", width_, height_);
172 }
173 
CompileAndLinkShaders()174 bool ImageRender::CompileAndLinkShaders()
175 {
176     GLuint vertexShader = CompileShader(GL_VERTEX_SHADER, g_vertexShaderSource);
177     if (vertexShader == 0) {
178         return false;
179     }
180 
181     GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, g_fragmentShaderSource);
182     if (fragmentShader == 0) {
183         glDeleteShader(vertexShader);
184         return false;
185     }
186 
187     shaderProgram_ = glCreateProgram();
188     glAttachShader(shaderProgram_, vertexShader);
189     glAttachShader(shaderProgram_, fragmentShader);
190     glLinkProgram(shaderProgram_);
191 
192     GLint linked;
193     glGetProgramiv(shaderProgram_, GL_LINK_STATUS, &linked);
194     if (!linked) {
195         PrintProgramLinkError(shaderProgram_);
196         glDeleteProgram(shaderProgram_);
197         glDeleteShader(vertexShader);
198         glDeleteShader(fragmentShader);
199         return false;
200     }
201 
202     glUseProgram(shaderProgram_);
203 
204     positionAttrib_ = glGetAttribLocation(shaderProgram_, "aPosition");
205     texCoordAttrib_ = glGetAttribLocation(shaderProgram_, "aTexCoord");
206     textureUniform_ = glGetUniformLocation(shaderProgram_, "uTexture");
207 
208     glDeleteShader(vertexShader);
209     glDeleteShader(fragmentShader);
210 
211     return true;
212 }
213 
PrintProgramLinkError(GLuint program)214 void ImageRender::PrintProgramLinkError(GLuint program)
215 {
216     GLint infoLen = 0;
217     glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
218     if (infoLen > 1) {
219         std::unique_ptr<char[]> infoLog = std::make_unique<char[]>(infoLen);
220         glGetProgramInfoLog(program, infoLen, nullptr, infoLog.get());
221         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN,
222                      "ImageRender", "Error linking program: %{public}s", infoLog.get());
223     }
224 }
225 
SetTransformMatrix(const float matrix[MATRIX_SIZE])226 void ImageRender::SetTransformMatrix(const float matrix[MATRIX_SIZE])
227 {
228     std::copy(matrix, matrix + MATRIX_SIZE, transformMatrix_);
229 }
230 
SetTexture(GLuint textureId,GLuint textureTarget)231 void ImageRender::SetTexture(GLuint textureId, GLuint textureTarget)
232 {
233     textureId_ = textureId;
234     textureTarget_ = textureTarget;
235 }
236 
SetupVertexAttributes()237 void ImageRender::SetupVertexAttributes()
238 {
239     static const GLfloat vertices[] = {
240         -1.0f, -1.0f, 0.0f,      0.0f, 0.0f,    // 左下
241         1.0f, -1.0f, 0.0f,      1.0f, 0.0f,     // 右下
242         -1.0f,  1.0f, 0.0f,      0.0f, 1.0f,    // 左上
243         1.0f,  1.0f, 0.0f,      1.0f, 1.0f      // 右上
244     };
245 
246     // Enable and set the position attribute
247     glEnableVertexAttribArray(positionAttrib_);
248     glVertexAttribPointer(positionAttrib_, POSITION_COMPONENT_COUNT, GL_FLOAT, GL_FALSE,
249                           STRIDE, vertices);
250 
251     // Enable and set the texture coordinate attribute
252     glEnableVertexAttribArray(texCoordAttrib_);
253     glVertexAttribPointer(texCoordAttrib_, TEX_COORD_COMPONENT_COUNT, GL_FLOAT, GL_FALSE,
254                           STRIDE, vertices + POSITION_COMPONENT_COUNT);
255 }
256 
DisableVertexAttributes()257 void ImageRender::DisableVertexAttributes()
258 {
259     // Disable the vertex attribute arrays after rendering
260     glDisableVertexAttribArray(positionAttrib_);
261     glDisableVertexAttribArray(texCoordAttrib_);
262 }
263 
Render()264 void ImageRender::Render()
265 {
266     if (surface_ == EGL_NO_SURFACE) {
267         return;
268     }
269 
270     if (!eglMakeCurrent(display_, surface_, surface_, context_)) {
271         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ImageRender", "Failed to make context current in Render");
272         return;
273     }
274 
275     // Clear the color buffer
276     glClearColor(0.0f, 1.0f, 1.0f, 1.0f);
277     glClear(GL_COLOR_BUFFER_BIT);
278 
279     // Use the shader program
280     glUseProgram(shaderProgram_);
281 
282     // Bind the texture
283     glActiveTexture(GL_TEXTURE0);
284     glBindTexture(textureTarget_, textureId_);
285 
286     // Set the texture sampler to texture unit 0
287     glUniform1i(textureUniform_, 0);
288 
289     // Set the transformation matrix
290     GLint matrixLocation = glGetUniformLocation(shaderProgram_, "uTransformMatrix");
291     if (matrixLocation != -1) {
292         glUniformMatrix4fv(matrixLocation, 1, GL_FALSE, transformMatrix_);
293     }
294 
295     // Set up vertex attributes
296     SetupVertexAttributes();
297 
298     // Draw the textured quad
299     glDrawArrays(GL_TRIANGLE_STRIP, 0, NUM_VERTICES);
300 
301     // Disable vertex attributes
302     DisableVertexAttributes();
303 
304     // Swap the buffers to display the rendered image
305     if (!eglSwapBuffers(display_, surface_)) {
306         EGLint error = eglGetError();
307         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ImageRender",
308             "eglSwapBuffers failed with error: %d", error);
309     }
310 }
311 
Cleanup()312 void ImageRender::Cleanup()
313 {
314     if (display_ != EGL_NO_DISPLAY) {
315         eglMakeCurrent(display_, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
316 
317         if (context_ != EGL_NO_CONTEXT) {
318             eglDestroyContext(display_, context_);
319             context_ = EGL_NO_CONTEXT;
320         }
321 
322         if (surface_ != EGL_NO_SURFACE) {
323             eglDestroySurface(display_, surface_);
324             surface_ = EGL_NO_SURFACE;
325         }
326 
327         eglTerminate(display_);
328         display_ = EGL_NO_DISPLAY;
329     }
330 
331     if (shaderProgram_ != 0) {
332         glDeleteProgram(shaderProgram_);
333         shaderProgram_ = 0;
334     }
335 }
336 
CompileShader(GLenum type,const char * source)337 GLuint ImageRender::CompileShader(GLenum type, const char* source)
338 {
339     GLuint shader = glCreateShader(type);
340     if (shader == 0) {
341         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ImageRender", "Failed to create shader.");
342         return 0;
343     }
344 
345     glShaderSource(shader, 1, &source, nullptr);
346     glCompileShader(shader);
347 
348     GLint compiled;
349     glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
350     if (!compiled) {
351         PrintShaderCompileError(shader);
352         glDeleteShader(shader);
353         return 0;
354     }
355     return shader;
356 }
357 
PrintShaderCompileError(GLuint shader)358 void ImageRender::PrintShaderCompileError(GLuint shader)
359 {
360     GLint infoLen = 0;
361     glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
362     if (infoLen > 1) {
363         auto infoLog = std::make_unique<char[]>(infoLen);
364         glGetShaderInfoLog(shader, infoLen, nullptr, infoLog.get());
365         OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "ImageRender",
366                      "Error compiling shader: %{public}s", infoLog.get());
367     }
368 }
369