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