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