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