• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     auto [glc, surf] = GLConsumer::create(name, GL_TEXTURE_EXTERNAL_OES, false, true);
207     glc->setDefaultBufferSize(w, h);
208     glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
209     surf->setMaxDequeuedBufferCount(2);
210     sp<ANativeWindow> anw = surf;
211 
212     EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), nullptr);
213     if (s == EGL_NO_SURFACE) {
214         fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError());
215         return false;
216     }
217 
218     *glConsumer = glc;
219     *surface = s;
220     return true;
221 }
222 
computeWindowScale(uint32_t w,uint32_t h,float * scale)223 bool GLHelper::computeWindowScale(uint32_t w, uint32_t h, float* scale) {
224     ui::DisplayMode mode;
225     status_t err = mSurfaceComposerClient->getActiveDisplayMode(mDisplayToken, &mode);
226     if (err != NO_ERROR) {
227         fprintf(stderr, "SurfaceComposer::getActiveDisplayMode failed: %#x\n", err);
228         return false;
229     }
230 
231     float scaleX = static_cast<float>(mode.resolution.getWidth()) / w;
232     float scaleY = static_cast<float>(mode.resolution.getHeight()) / h;
233     *scale = scaleX < scaleY ? scaleX : scaleY;
234 
235     return true;
236 }
237 
createWindowSurface(uint32_t w,uint32_t h,sp<SurfaceControl> * surfaceControl,EGLSurface * surface)238 bool GLHelper::createWindowSurface(uint32_t w, uint32_t h,
239         sp<SurfaceControl>* surfaceControl, EGLSurface* surface) {
240     bool result;
241     status_t err;
242 
243     if (mSurfaceComposerClient == nullptr) {
244         mSurfaceComposerClient = sp<SurfaceComposerClient>::make();
245     }
246     err = mSurfaceComposerClient->initCheck();
247     if (err != NO_ERROR) {
248         fprintf(stderr, "SurfaceComposerClient::initCheck error: %#x\n", err);
249         return false;
250     }
251 
252     sp<SurfaceControl> sc = mSurfaceComposerClient->createSurface(
253             String8("Benchmark"), w, h, PIXEL_FORMAT_RGBA_8888, 0);
254     if (sc == nullptr || !sc->isValid()) {
255         fprintf(stderr, "Failed to create SurfaceControl.\n");
256         return false;
257     }
258 
259     float scale;
260     result = computeWindowScale(w, h, &scale);
261     if (!result) {
262         return false;
263     }
264 
265     SurfaceComposerClient::Transaction{}.setLayer(sc, 0x7FFFFFFF)
266             .setMatrix(sc, scale, 0.0f, 0.0f, scale)
267             .show(sc)
268             .apply();
269 
270     sp<ANativeWindow> anw = sc->getSurface();
271     EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), nullptr);
272     if (s == EGL_NO_SURFACE) {
273         fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError());
274         return false;
275     }
276 
277     *surfaceControl = sc;
278     *surface = s;
279     return true;
280 }
281 
compileShader(GLenum shaderType,const char * src,GLuint * outShader)282 static bool compileShader(GLenum shaderType, const char* src,
283         GLuint* outShader) {
284     GLuint shader = glCreateShader(shaderType);
285     if (shader == 0) {
286         fprintf(stderr, "glCreateShader error: %#x\n", glGetError());
287         return false;
288     }
289 
290     glShaderSource(shader, 1, &src, nullptr);
291     glCompileShader(shader);
292 
293     GLint compiled = 0;
294     glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
295     if (!compiled) {
296         GLint infoLen = 0;
297         glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
298         if (infoLen) {
299             char* buf = new char[infoLen];
300             if (buf) {
301                 glGetShaderInfoLog(shader, infoLen, nullptr, buf);
302                 fprintf(stderr, "Shader compile log:\n%s\n", buf);
303                 delete[] buf;
304             }
305         }
306         glDeleteShader(shader);
307         return false;
308     }
309     *outShader = shader;
310     return true;
311 }
312 
printShaderSource(const char * const * src)313 static void printShaderSource(const char* const* src) {
314     for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != nullptr; i++) {
315         fprintf(stderr, "%3zu: %s\n", i+1, src[i]);
316     }
317 }
318 
makeShaderString(const char * const * src)319 static const char* makeShaderString(const char* const* src) {
320     size_t len = 0;
321     for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != nullptr; i++) {
322         // The +1 is for the '\n' that will be added.
323         len += strlen(src[i]) + 1;
324     }
325 
326     char* result = new char[len+1];
327     char* end = result;
328     for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != nullptr; i++) {
329         strcpy(end, src[i]);
330         end += strlen(src[i]);
331         *end = '\n';
332         end++;
333     }
334     *end = '\0';
335 
336     return result;
337 }
338 
compileShaderLines(GLenum shaderType,const char * const * lines,GLuint * outShader)339 static bool compileShaderLines(GLenum shaderType, const char* const* lines,
340         GLuint* outShader) {
341     const char* src = makeShaderString(lines);
342     bool result = compileShader(shaderType, src, outShader);
343     if (!result) {
344         fprintf(stderr, "Shader source:\n");
345         printShaderSource(lines);
346         delete[] src;
347         return false;
348     }
349     delete[] src;
350 
351     return true;
352 }
353 
linkShaderProgram(GLuint vs,GLuint fs,GLuint * outPgm)354 static bool linkShaderProgram(GLuint vs, GLuint fs, GLuint* outPgm) {
355     GLuint program = glCreateProgram();
356     if (program == 0) {
357         fprintf(stderr, "glCreateProgram error: %#x\n", glGetError());
358         return false;
359     }
360 
361     glAttachShader(program, vs);
362     glAttachShader(program, fs);
363     glLinkProgram(program);
364     GLint linkStatus = GL_FALSE;
365     glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
366     if (linkStatus != GL_TRUE) {
367         GLint bufLength = 0;
368         glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
369         if (bufLength) {
370             char* buf = new char[bufLength];
371             if (buf) {
372                 glGetProgramInfoLog(program, bufLength, nullptr, buf);
373                 fprintf(stderr, "Program link log:\n%s\n", buf);
374                 delete[] buf;
375             }
376         }
377         glDeleteProgram(program);
378         program = 0;
379     }
380 
381     *outPgm = program;
382     return program != 0;
383 }
384 
setUpShaders(const ShaderDesc * shaderDescs,size_t numShaders)385 bool GLHelper::setUpShaders(const ShaderDesc* shaderDescs, size_t numShaders) {
386     mShaderPrograms = new GLuint[numShaders];
387     bool result = true;
388 
389     for (size_t i = 0; i < numShaders && result; i++) {
390         GLuint vs, fs;
391 
392         result = compileShaderLines(GL_VERTEX_SHADER,
393                 shaderDescs[i].vertexShader, &vs);
394         if (!result) {
395             return false;
396         }
397 
398         result = compileShaderLines(GL_FRAGMENT_SHADER,
399                 shaderDescs[i].fragmentShader, &fs);
400         if (!result) {
401             glDeleteShader(vs);
402             return false;
403         }
404 
405         result = linkShaderProgram(vs, fs, &mShaderPrograms[i]);
406         glDeleteShader(vs);
407         glDeleteShader(fs);
408     }
409 
410     mNumShaders = numShaders;
411     mShaderDescs = shaderDescs;
412 
413     return result;
414 }
415 
getDitherTexture(GLuint * outTexName)416 bool GLHelper::getDitherTexture(GLuint* outTexName) {
417     if (mDitherTexture == 0) {
418         const uint8_t pattern[] = {
419              0,  8,  2, 10,
420             12,  4, 14,  6,
421              3, 11,  1,  9,
422             15,  7, 13,  5
423         };
424 
425         glGenTextures(1, &mDitherTexture);
426         glBindTexture(GL_TEXTURE_2D, mDitherTexture);
427 
428         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
429         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
430 
431         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
432         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
433 
434         glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, DITHER_KERNEL_SIZE,
435                 DITHER_KERNEL_SIZE, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &pattern);
436     }
437 
438     *outTexName = mDitherTexture;
439 
440     return true;
441 }
442 
443 }
444