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