xref: /aosp_15_r20/frameworks/native/cmds/flatland/GLHelper.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "GLHelper.h"
18 
19 #include <GLES2/gl2.h>
20 #include <GLES2/gl2ext.h>
21 #include <com_android_graphics_libgui_flags.h>
22 #include <gui/SurfaceComposerClient.h>
23 #include <ui/DisplayMode.h>
24 
25 namespace android {
26 
GLHelper()27 GLHelper::GLHelper() :
28     mDisplay(EGL_NO_DISPLAY),
29     mContext(EGL_NO_CONTEXT),
30     mDummySurface(EGL_NO_SURFACE),
31     mConfig(0),
32     mShaderPrograms(nullptr),
33     mDitherTexture(0) {
34 }
35 
~GLHelper()36 GLHelper::~GLHelper() {
37 }
38 
setUp(const sp<IBinder> & displayToken,const ShaderDesc * shaderDescs,size_t numShaders)39 bool GLHelper::setUp(const sp<IBinder>& displayToken, const ShaderDesc* shaderDescs,
40                      size_t numShaders) {
41     bool result;
42 
43     mDisplayToken = displayToken;
44 
45     mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
46     if (mDisplay == EGL_NO_DISPLAY) {
47         fprintf(stderr, "eglGetDisplay error: %#x\n", eglGetError());
48         return false;
49     }
50 
51     EGLint majorVersion;
52     EGLint minorVersion;
53     result = eglInitialize(mDisplay, &majorVersion, &minorVersion);
54     if (result != EGL_TRUE) {
55         fprintf(stderr, "eglInitialize error: %#x\n", eglGetError());
56         return false;
57     }
58 
59     EGLint numConfigs = 0;
60     EGLint configAttribs[] = {
61         EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
62         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
63         EGL_RED_SIZE, 8,
64         EGL_GREEN_SIZE, 8,
65         EGL_BLUE_SIZE, 8,
66         EGL_ALPHA_SIZE, 8,
67         EGL_NONE
68     };
69     result = eglChooseConfig(mDisplay, configAttribs, &mConfig, 1,
70             &numConfigs);
71     if (result != EGL_TRUE) {
72         fprintf(stderr, "eglChooseConfig error: %#x\n", eglGetError());
73         return false;
74     }
75 
76     EGLint contextAttribs[] = {
77         EGL_CONTEXT_CLIENT_VERSION, 2,
78         EGL_NONE
79     };
80     mContext = eglCreateContext(mDisplay, mConfig, EGL_NO_CONTEXT,
81             contextAttribs);
82     if (mContext == EGL_NO_CONTEXT) {
83         fprintf(stderr, "eglCreateContext error: %#x\n", eglGetError());
84         return false;
85     }
86 
87     bool resultb = createNamedSurfaceTexture(0, 1, 1, &mDummyGLConsumer,
88             &mDummySurface);
89     if (!resultb) {
90         return false;
91     }
92 
93     resultb = makeCurrent(mDummySurface);
94     if (!resultb) {
95         return false;
96     }
97 
98     resultb = setUpShaders(shaderDescs, numShaders);
99     if (!resultb) {
100         return false;
101     }
102 
103     return true;
104 }
105 
tearDown()106 void GLHelper::tearDown() {
107     if (mShaderPrograms != nullptr) {
108         delete[] mShaderPrograms;
109         mShaderPrograms = nullptr;
110     }
111 
112     if (mSurfaceComposerClient != nullptr) {
113         mSurfaceComposerClient->dispose();
114         mSurfaceComposerClient.clear();
115     }
116 
117     if (mDisplay != EGL_NO_DISPLAY) {
118         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
119                 EGL_NO_CONTEXT);
120     }
121 
122     if (mContext != EGL_NO_CONTEXT) {
123         eglDestroyContext(mDisplay, mContext);
124     }
125 
126     if (mDummySurface != EGL_NO_SURFACE) {
127         eglDestroySurface(mDisplay, mDummySurface);
128     }
129 
130     mDisplay = EGL_NO_DISPLAY;
131     mContext = EGL_NO_CONTEXT;
132     mDummySurface = EGL_NO_SURFACE;
133     mDummyGLConsumer.clear();
134     mConfig = 0;
135 }
136 
makeCurrent(EGLSurface surface)137 bool GLHelper::makeCurrent(EGLSurface surface) {
138     EGLint result;
139 
140     result = eglMakeCurrent(mDisplay, surface, surface, mContext);
141     if (result != EGL_TRUE) {
142         fprintf(stderr, "eglMakeCurrent error: %#x\n", eglGetError());
143         return false;
144     }
145 
146     EGLint w, h;
147     eglQuerySurface(mDisplay, surface, EGL_WIDTH, &w);
148     eglQuerySurface(mDisplay, surface, EGL_HEIGHT, &h);
149     glViewport(0, 0, w, h);
150 
151     return true;
152 }
153 
createSurfaceTexture(uint32_t w,uint32_t h,sp<GLConsumer> * glConsumer,EGLSurface * surface,GLuint * name)154 bool GLHelper::createSurfaceTexture(uint32_t w, uint32_t h,
155         sp<GLConsumer>* glConsumer, EGLSurface* surface,
156         GLuint* name) {
157     if (!makeCurrent(mDummySurface)) {
158         return false;
159     }
160 
161     *name = 0;
162     glGenTextures(1, name);
163     if (*name == 0) {
164         fprintf(stderr, "glGenTextures error: %#x\n", glGetError());
165         return false;
166     }
167 
168     return createNamedSurfaceTexture(*name, w, h, glConsumer, surface);
169 }
170 
destroySurface(EGLSurface * surface)171 void GLHelper::destroySurface(EGLSurface* surface) {
172     if (eglGetCurrentSurface(EGL_READ) == *surface ||
173             eglGetCurrentSurface(EGL_DRAW) == *surface) {
174         eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
175                 EGL_NO_CONTEXT);
176     }
177     eglDestroySurface(mDisplay, *surface);
178     *surface = EGL_NO_SURFACE;
179 }
180 
swapBuffers(EGLSurface surface)181 bool GLHelper::swapBuffers(EGLSurface surface) {
182     EGLint result;
183     result = eglSwapBuffers(mDisplay, surface);
184     if (result != EGL_TRUE) {
185         fprintf(stderr, "eglSwapBuffers error: %#x\n", eglGetError());
186         return false;
187     }
188     return true;
189 }
190 
getShaderProgram(const char * name,GLuint * outPgm)191 bool GLHelper::getShaderProgram(const char* name, GLuint* outPgm) {
192     for (size_t i = 0; i < mNumShaders; i++) {
193         if (strcmp(mShaderDescs[i].name, name) == 0) {
194             *outPgm = mShaderPrograms[i];
195             return true;
196         }
197     }
198 
199     fprintf(stderr, "unknown shader name: \"%s\"\n", name);
200 
201     return false;
202 }
203 
createNamedSurfaceTexture(GLuint name,uint32_t w,uint32_t h,sp<GLConsumer> * glConsumer,EGLSurface * surface)204 bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h,
205         sp<GLConsumer>* glConsumer, EGLSurface* surface) {
206 #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
207     sp<GLConsumer> glc = new GLConsumer(name, GL_TEXTURE_EXTERNAL_OES, false, true);
208     glc->setDefaultBufferSize(w, h);
209     glc->getSurface()->setMaxDequeuedBufferCount(2);
210     glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
211 
212     sp<ANativeWindow> anw = glc->getSurface();
213 #else
214     sp<IGraphicBufferProducer> producer;
215     sp<IGraphicBufferConsumer> consumer;
216     BufferQueue::createBufferQueue(&producer, &consumer);
217     sp<GLConsumer> glc = new GLConsumer(consumer, name,
218             GL_TEXTURE_EXTERNAL_OES, false, true);
219     glc->setDefaultBufferSize(w, h);
220     producer->setMaxDequeuedBufferCount(2);
221     glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
222 
223     sp<ANativeWindow> anw = new Surface(producer);
224 #endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
225     EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), nullptr);
226     if (s == EGL_NO_SURFACE) {
227         fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError());
228         return false;
229     }
230 
231     *glConsumer = glc;
232     *surface = s;
233     return true;
234 }
235 
computeWindowScale(uint32_t w,uint32_t h,float * scale)236 bool GLHelper::computeWindowScale(uint32_t w, uint32_t h, float* scale) {
237     ui::DisplayMode mode;
238     status_t err = mSurfaceComposerClient->getActiveDisplayMode(mDisplayToken, &mode);
239     if (err != NO_ERROR) {
240         fprintf(stderr, "SurfaceComposer::getActiveDisplayMode failed: %#x\n", err);
241         return false;
242     }
243 
244     float scaleX = static_cast<float>(mode.resolution.getWidth()) / w;
245     float scaleY = static_cast<float>(mode.resolution.getHeight()) / h;
246     *scale = scaleX < scaleY ? scaleX : scaleY;
247 
248     return true;
249 }
250 
createWindowSurface(uint32_t w,uint32_t h,sp<SurfaceControl> * surfaceControl,EGLSurface * surface)251 bool GLHelper::createWindowSurface(uint32_t w, uint32_t h,
252         sp<SurfaceControl>* surfaceControl, EGLSurface* surface) {
253     bool result;
254     status_t err;
255 
256     if (mSurfaceComposerClient == nullptr) {
257         mSurfaceComposerClient = new SurfaceComposerClient;
258     }
259     err = mSurfaceComposerClient->initCheck();
260     if (err != NO_ERROR) {
261         fprintf(stderr, "SurfaceComposerClient::initCheck error: %#x\n", err);
262         return false;
263     }
264 
265     sp<SurfaceControl> sc = mSurfaceComposerClient->createSurface(
266             String8("Benchmark"), w, h, PIXEL_FORMAT_RGBA_8888, 0);
267     if (sc == nullptr || !sc->isValid()) {
268         fprintf(stderr, "Failed to create SurfaceControl.\n");
269         return false;
270     }
271 
272     float scale;
273     result = computeWindowScale(w, h, &scale);
274     if (!result) {
275         return false;
276     }
277 
278     SurfaceComposerClient::Transaction{}.setLayer(sc, 0x7FFFFFFF)
279             .setMatrix(sc, scale, 0.0f, 0.0f, scale)
280             .show(sc)
281             .apply();
282 
283     sp<ANativeWindow> anw = sc->getSurface();
284     EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), nullptr);
285     if (s == EGL_NO_SURFACE) {
286         fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError());
287         return false;
288     }
289 
290     *surfaceControl = sc;
291     *surface = s;
292     return true;
293 }
294 
compileShader(GLenum shaderType,const char * src,GLuint * outShader)295 static bool compileShader(GLenum shaderType, const char* src,
296         GLuint* outShader) {
297     GLuint shader = glCreateShader(shaderType);
298     if (shader == 0) {
299         fprintf(stderr, "glCreateShader error: %#x\n", glGetError());
300         return false;
301     }
302 
303     glShaderSource(shader, 1, &src, nullptr);
304     glCompileShader(shader);
305 
306     GLint compiled = 0;
307     glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
308     if (!compiled) {
309         GLint infoLen = 0;
310         glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
311         if (infoLen) {
312             char* buf = new char[infoLen];
313             if (buf) {
314                 glGetShaderInfoLog(shader, infoLen, nullptr, buf);
315                 fprintf(stderr, "Shader compile log:\n%s\n", buf);
316                 delete[] buf;
317             }
318         }
319         glDeleteShader(shader);
320         return false;
321     }
322     *outShader = shader;
323     return true;
324 }
325 
printShaderSource(const char * const * src)326 static void printShaderSource(const char* const* src) {
327     for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != nullptr; i++) {
328         fprintf(stderr, "%3zu: %s\n", i+1, src[i]);
329     }
330 }
331 
makeShaderString(const char * const * src)332 static const char* makeShaderString(const char* const* src) {
333     size_t len = 0;
334     for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != nullptr; i++) {
335         // The +1 is for the '\n' that will be added.
336         len += strlen(src[i]) + 1;
337     }
338 
339     char* result = new char[len+1];
340     char* end = result;
341     for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != nullptr; i++) {
342         strcpy(end, src[i]);
343         end += strlen(src[i]);
344         *end = '\n';
345         end++;
346     }
347     *end = '\0';
348 
349     return result;
350 }
351 
compileShaderLines(GLenum shaderType,const char * const * lines,GLuint * outShader)352 static bool compileShaderLines(GLenum shaderType, const char* const* lines,
353         GLuint* outShader) {
354     const char* src = makeShaderString(lines);
355     bool result = compileShader(shaderType, src, outShader);
356     if (!result) {
357         fprintf(stderr, "Shader source:\n");
358         printShaderSource(lines);
359         delete[] src;
360         return false;
361     }
362     delete[] src;
363 
364     return true;
365 }
366 
linkShaderProgram(GLuint vs,GLuint fs,GLuint * outPgm)367 static bool linkShaderProgram(GLuint vs, GLuint fs, GLuint* outPgm) {
368     GLuint program = glCreateProgram();
369     if (program == 0) {
370         fprintf(stderr, "glCreateProgram error: %#x\n", glGetError());
371         return false;
372     }
373 
374     glAttachShader(program, vs);
375     glAttachShader(program, fs);
376     glLinkProgram(program);
377     GLint linkStatus = GL_FALSE;
378     glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
379     if (linkStatus != GL_TRUE) {
380         GLint bufLength = 0;
381         glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
382         if (bufLength) {
383             char* buf = new char[bufLength];
384             if (buf) {
385                 glGetProgramInfoLog(program, bufLength, nullptr, buf);
386                 fprintf(stderr, "Program link log:\n%s\n", buf);
387                 delete[] buf;
388             }
389         }
390         glDeleteProgram(program);
391         program = 0;
392     }
393 
394     *outPgm = program;
395     return program != 0;
396 }
397 
setUpShaders(const ShaderDesc * shaderDescs,size_t numShaders)398 bool GLHelper::setUpShaders(const ShaderDesc* shaderDescs, size_t numShaders) {
399     mShaderPrograms = new GLuint[numShaders];
400     bool result = true;
401 
402     for (size_t i = 0; i < numShaders && result; i++) {
403         GLuint vs, fs;
404 
405         result = compileShaderLines(GL_VERTEX_SHADER,
406                 shaderDescs[i].vertexShader, &vs);
407         if (!result) {
408             return false;
409         }
410 
411         result = compileShaderLines(GL_FRAGMENT_SHADER,
412                 shaderDescs[i].fragmentShader, &fs);
413         if (!result) {
414             glDeleteShader(vs);
415             return false;
416         }
417 
418         result = linkShaderProgram(vs, fs, &mShaderPrograms[i]);
419         glDeleteShader(vs);
420         glDeleteShader(fs);
421     }
422 
423     mNumShaders = numShaders;
424     mShaderDescs = shaderDescs;
425 
426     return result;
427 }
428 
getDitherTexture(GLuint * outTexName)429 bool GLHelper::getDitherTexture(GLuint* outTexName) {
430     if (mDitherTexture == 0) {
431         const uint8_t pattern[] = {
432              0,  8,  2, 10,
433             12,  4, 14,  6,
434              3, 11,  1,  9,
435             15,  7, 13,  5
436         };
437 
438         glGenTextures(1, &mDitherTexture);
439         glBindTexture(GL_TEXTURE_2D, mDitherTexture);
440 
441         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
442         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
443 
444         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
445         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
446 
447         glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, DITHER_KERNEL_SIZE,
448                 DITHER_KERNEL_SIZE, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &pattern);
449     }
450 
451     *outTexName = mDitherTexture;
452 
453     return true;
454 }
455 
456 }
457