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