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 #define GL_GLEXT_PROTOTYPES
17 #define EGL_EGLEXT_PROTOTYPES
18 
19 #include "gl_utils.h"
20 #include "surface_buffer.h"
21 #include "native_window.h"
22 #include "effect_trace.h"
23 #include "effect_log.h"
24 
25 #include <GLES2/gl2ext.h>
26 
27 #include <cmath>
28 #include <string>
29 #include <cstdlib>
30 
31 namespace OHOS {
32 namespace Media {
33 namespace Effect {
34 constexpr const int MSG_SIZE = 512;
35 constexpr const int BYTES_OF_RGBA16F = 8;
36 constexpr const int BYTES_OF_R32F = 4;
37 constexpr const int BYTES_OF_R8 = 1;
38 constexpr const int BYTES_OF_RGB565 = 2;
39 constexpr const int BYTES_OF_RGBA4 = 2;
40 
CreateTexture2D(GLsizei width,GLsizei height,GLsizei levels,GLenum internalFormat,GLint minFilter,GLint magFilter,GLint wrapS,GLint wrapT)41 GLuint GLUtils::CreateTexture2D(GLsizei width, GLsizei height, GLsizei levels, GLenum internalFormat, GLint minFilter,
42     GLint magFilter, GLint wrapS, GLint wrapT)
43 {
44     GLuint textureId = 0;
45     glGenTextures(1, &textureId);
46     glBindTexture(GL_TEXTURE_2D, textureId);
47     glTexStorage2D(GL_TEXTURE_2D, levels, internalFormat, width, height);
48     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
49     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
50     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
51     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
52     glBindTexture(GL_TEXTURE_2D, GL_NONE);
53     CheckError(__FILE__, __LINE__);
54     return textureId;
55 }
56 
CreateFramebuffer(unsigned int textureId)57 unsigned int GLUtils::CreateFramebuffer(unsigned int textureId)
58 {
59     GLuint fboId;
60     glGenFramebuffers(1, &fboId);
61     if (textureId != 0) {
62         glBindFramebuffer(GL_FRAMEBUFFER, fboId);
63         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0);
64         glBindFramebuffer(GL_FRAMEBUFFER, GL_NONE);
65     }
66     return fboId;
67 }
68 
CreateFramebufferWithTarget(unsigned int textureId,GLenum target)69 unsigned int GLUtils::CreateFramebufferWithTarget(unsigned int textureId, GLenum target)
70 {
71     GLuint fboId;
72     glGenFramebuffers(1, &fboId);
73     if (textureId != 0) {
74         glBindFramebuffer(GL_FRAMEBUFFER, fboId);
75         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, textureId, 0);
76         glBindFramebuffer(GL_FRAMEBUFFER, GL_NONE);
77     }
78     return fboId;
79 }
80 
DeleteFboOnly(unsigned int fbo)81 void GLUtils::DeleteFboOnly(unsigned int fbo)
82 {
83     glDeleteFramebuffers(1, &fbo);
84 }
85 
DeleteTexture(unsigned int textureId)86 void GLUtils::DeleteTexture(unsigned int textureId)
87 {
88     if (textureId == 0) {
89         return;
90     }
91     glDeleteTextures(1, &textureId);
92 }
93 
CreateTexWithStorage(GLenum target,int levels,GLenum internalFormat,int width,int height)94 GLuint GLUtils::CreateTexWithStorage(GLenum target, int levels, GLenum internalFormat,
95     int width, int height)
96 {
97     GLuint textureId = 0;
98     glGenTextures(1, &textureId);
99     glBindTexture(target, textureId);
100     glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
101     glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
102     glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
103     glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
104     glTexStorage2D(target, levels, internalFormat, width, height);
105     glBindTexture(target, 0);
106     return textureId;
107 }
108 
CheckError(const char * file,int line)109 void GLUtils::CheckError(const char *file, int line)
110 {
111     GLenum status = glGetError();
112     if (status != GL_NO_ERROR) {
113         EFFECT_LOGE("GL Error: 0x%{public}x, [%{public}s : %{public}d]", status, file, line);
114     }
115 }
116 
GetInternalFormatPixelByteSize(GLenum internalFormat)117 size_t GLUtils::GetInternalFormatPixelByteSize(GLenum internalFormat)
118 {
119     int ret = 0;
120     switch (internalFormat) {
121         case GL_RGBA8:
122         case GL_R32F:
123             ret = BYTES_OF_R32F;
124             break;
125         case GL_RGBA16F:
126             ret = BYTES_OF_RGBA16F;
127             break;
128         case GL_R8:
129             ret = BYTES_OF_R8;
130             break;
131         case GL_RGB565:
132             ret = BYTES_OF_RGB565;
133             break;
134         case GL_RGBA4:
135             ret = BYTES_OF_RGBA4;
136             break;
137         default:
138             break;
139     }
140     return ret;
141 }
142 
LoadShader(const std::string & src,unsigned int shaderType)143 unsigned int GLUtils::LoadShader(const std::string &src, unsigned int shaderType)
144 {
145     const char* tempSrc = src.c_str();
146     unsigned int shader = glCreateShader(shaderType);
147     if (shader == 0) {
148         EFFECT_LOGE("Could Not Create Shader");
149     }
150     glShaderSource(shader, 1, &tempSrc, nullptr);
151     glCompileShader(shader);
152     int status = GL_FALSE;
153     glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
154     if (status == GL_FALSE) {
155         GLchar message[MSG_SIZE] = {0};
156         glGetShaderInfoLog(shader, MSG_SIZE - 1, nullptr, &message[0]);
157         EFFECT_LOGE("LoadShader Error: %{public}s", message);
158         glDeleteShader(shader);
159         shader = 0;
160     }
161     CheckError(__FILE__, __LINE__);
162     return shader;
163 }
164 
CreateProgram(const std::string & vss,const std::string & fss)165 unsigned int GLUtils::CreateProgram(const std::string &vss, const std::string &fss)
166 {
167     unsigned int vs = LoadShader(vss, GL_VERTEX_SHADER);
168     unsigned int fs = LoadShader(fss, GL_FRAGMENT_SHADER);
169     if (vs == 0 || fs == 0) {
170         return 0;
171     }
172     unsigned int program = glCreateProgram();
173     if (program == 0) {
174         EFFECT_LOGE("CreateProgram Failed");
175     }
176     glAttachShader(program, vs);
177     glAttachShader(program, fs);
178     glLinkProgram(program);
179     CheckError(__FILE__, __LINE__);
180     int status = GL_FALSE;
181     glGetProgramiv(program, GL_LINK_STATUS, &status);
182     if (status == GL_FALSE) {
183         GLchar message[MSG_SIZE] = {0};
184         glGetShaderInfoLog(program, MSG_SIZE - 1, nullptr, &message[0]);
185         EFFECT_LOGE("LoadShader Error: %{public}s", message);
186         glDeleteProgram(program);
187         program = 0;
188     }
189     if (vs > 0) {
190         glDetachShader(program, vs);
191         glDeleteShader(vs);
192     }
193     if (fs > 0) {
194         glDetachShader(program, fs);
195         glDeleteShader(fs);
196     }
197     return program;
198 }
199 
CreateEGLImage(EGLDisplay display,SurfaceBuffer * buffer)200 EGLImageKHR GLUtils::CreateEGLImage(EGLDisplay display, SurfaceBuffer *buffer)
201 {
202     NativeWindowBuffer *nBuffer = CreateNativeWindowBufferFromSurfaceBuffer(&buffer);
203     EGLint attrsList[] = {
204         EGL_IMAGE_PRESERVED,
205         EGL_TRUE,
206         EGL_NONE,
207     };
208     EGLint *attrs = attrsList;
209     EGLImageKHR img = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_OHOS, nBuffer, attrs);
210     if (img == EGL_NO_IMAGE_KHR) {
211         EGLint error = eglGetError();
212         EFFECT_LOGE("CreateEGLImage Error: %{public}d", error);
213         eglTerminate(display);
214     }
215     CheckError(__FILE__, __LINE__);
216     return img;
217 }
218 
CreateTextureFromImage(EGLImageKHR img)219 GLuint GLUtils::CreateTextureFromImage(EGLImageKHR img)
220 {
221     GLuint textureId = 0;
222     glGenTextures(1, &textureId);
223     glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId);
224     glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, static_cast<GLeglImageOES>(img));
225     glBindTexture(GL_TEXTURE_EXTERNAL_OES, GL_NONE);
226     CheckError(__FILE__, __LINE__);
227     return textureId;
228 }
CreateTextureFromSurfaceBuffer(SurfaceBuffer * buffer)229 GLuint GLUtils::CreateTextureFromSurfaceBuffer(SurfaceBuffer *buffer)
230 {
231     if (buffer == nullptr) {
232         return 0;
233     }
234     EGLImageKHR img = CreateEGLImage(eglGetDisplay(EGL_DEFAULT_DISPLAY), buffer);
235     GLuint tex = CreateTextureFromImage(img);
236     return tex;
237 }
238 } // namespace Effect
239 } // namespace Media
240 } // namespace OHOS