blob: 01f7d30a42b14cd0d0f6e7a6d230c1fb2c33b3f4 [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 "GLHelper.h"
18
Dominik Laskowski3cb3d4e2019-11-21 11:14:45 -080019#include <GLES2/gl2.h>
20#include <GLES2/gl2ext.h>
21#include <gui/SurfaceComposerClient.h>
Marin Shalamanova7fe3042021-01-29 21:02:08 +010022#include <ui/DisplayMode.h>
Dominik Laskowski3cb3d4e2019-11-21 11:14:45 -080023
24namespace android {
Jamie Gennis9c183f22012-12-03 16:44:16 -080025
26GLHelper::GLHelper() :
Jamie Gennis9c183f22012-12-03 16:44:16 -080027 mDisplay(EGL_NO_DISPLAY),
28 mContext(EGL_NO_CONTEXT),
29 mDummySurface(EGL_NO_SURFACE),
30 mConfig(0),
Yi Kongc67f9a42018-07-20 13:39:55 -070031 mShaderPrograms(nullptr),
Jamie Gennis9c183f22012-12-03 16:44:16 -080032 mDitherTexture(0) {
33}
34
35GLHelper::~GLHelper() {
36}
37
38bool 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
102void GLHelper::tearDown() {
Yi Kongc67f9a42018-07-20 13:39:55 -0700103 if (mShaderPrograms != nullptr) {
Jamie Gennis9c183f22012-12-03 16:44:16 -0800104 delete[] mShaderPrograms;
Yi Kongc67f9a42018-07-20 13:39:55 -0700105 mShaderPrograms = nullptr;
Jamie Gennis9c183f22012-12-03 16:44:16 -0800106 }
107
Yi Kongc67f9a42018-07-20 13:39:55 -0700108 if (mSurfaceComposerClient != nullptr) {
Jamie Gennis9c183f22012-12-03 16:44:16 -0800109 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
133bool 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
150bool 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
167void 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
177bool 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
187bool 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
200bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h,
201 sp<GLConsumer>* glConsumer, EGLSurface* surface) {
Dan Stoza6780a2d2014-03-13 11:31:43 -0700202 sp<IGraphicBufferProducer> producer;
203 sp<IGraphicBufferConsumer> consumer;
Mathias Agopian0556d792017-03-22 15:49:32 -0700204 BufferQueue::createBufferQueue(&producer, &consumer);
Dan Stoza6780a2d2014-03-13 11:31:43 -0700205 sp<GLConsumer> glc = new GLConsumer(consumer, name,
Dan Stozae49ba8e2014-06-24 13:09:19 -0700206 GL_TEXTURE_EXTERNAL_OES, false, true);
Jamie Gennis9c183f22012-12-03 16:44:16 -0800207 glc->setDefaultBufferSize(w, h);
Pablo Ceballos19e3e062015-08-19 16:16:06 -0700208 producer->setMaxDequeuedBufferCount(2);
Jamie Gennis9c183f22012-12-03 16:44:16 -0800209 glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
210
Dan Stoza6780a2d2014-03-13 11:31:43 -0700211 sp<ANativeWindow> anw = new Surface(producer);
Yi Kongc67f9a42018-07-20 13:39:55 -0700212 EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), nullptr);
Jamie Gennis9c183f22012-12-03 16:44:16 -0800213 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
223bool GLHelper::computeWindowScale(uint32_t w, uint32_t h, float* scale) {
Dominik Laskowskidcb38bb2019-01-25 02:35:50 -0800224 const sp<IBinder> dpy = mSurfaceComposerClient->getInternalDisplayToken();
Yi Kongc67f9a42018-07-20 13:39:55 -0700225 if (dpy == nullptr) {
Dominik Laskowskidcb38bb2019-01-25 02:35:50 -0800226 fprintf(stderr, "SurfaceComposer::getInternalDisplayToken failed.\n");
Jamie Gennis9c183f22012-12-03 16:44:16 -0800227 return false;
228 }
229
Marin Shalamanova7fe3042021-01-29 21:02:08 +0100230 ui::DisplayMode mode;
231 status_t err = mSurfaceComposerClient->getActiveDisplayMode(dpy, &mode);
Jamie Gennis9c183f22012-12-03 16:44:16 -0800232 if (err != NO_ERROR) {
Marin Shalamanova7fe3042021-01-29 21:02:08 +0100233 fprintf(stderr, "SurfaceComposer::getActiveDisplayMode failed: %#x\n", err);
Jamie Gennis9c183f22012-12-03 16:44:16 -0800234 return false;
235 }
236
Marin Shalamanova7fe3042021-01-29 21:02:08 +0100237 float scaleX = static_cast<float>(mode.resolution.getWidth()) / w;
238 float scaleY = static_cast<float>(mode.resolution.getHeight()) / h;
Jamie Gennis9c183f22012-12-03 16:44:16 -0800239 *scale = scaleX < scaleY ? scaleX : scaleY;
240
241 return true;
242}
243
244bool GLHelper::createWindowSurface(uint32_t w, uint32_t h,
245 sp<SurfaceControl>* surfaceControl, EGLSurface* surface) {
246 bool result;
247 status_t err;
248
Yi Kongc67f9a42018-07-20 13:39:55 -0700249 if (mSurfaceComposerClient == nullptr) {
Jamie Gennis9c183f22012-12-03 16:44:16 -0800250 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);
Yi Kongc67f9a42018-07-20 13:39:55 -0700260 if (sc == nullptr || !sc->isValid()) {
Jamie Gennis9c183f22012-12-03 16:44:16 -0800261 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
Robert Carr4cdc58f2017-08-23 14:22:20 -0700271 SurfaceComposerClient::Transaction{}.setLayer(sc, 0x7FFFFFFF)
272 .setMatrix(sc, scale, 0.0f, 0.0f, scale)
273 .show(sc)
274 .apply();
Jamie Gennis9c183f22012-12-03 16:44:16 -0800275
276 sp<ANativeWindow> anw = sc->getSurface();
Yi Kongc67f9a42018-07-20 13:39:55 -0700277 EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), nullptr);
Jamie Gennis9c183f22012-12-03 16:44:16 -0800278 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
288static 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
Yi Kongc67f9a42018-07-20 13:39:55 -0700296 glShaderSource(shader, 1, &src, nullptr);
Jamie Gennis9c183f22012-12-03 16:44:16 -0800297 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) {
Yi Kongc67f9a42018-07-20 13:39:55 -0700307 glGetShaderInfoLog(shader, infoLen, nullptr, buf);
Jamie Gennis9c183f22012-12-03 16:44:16 -0800308 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
319static void printShaderSource(const char* const* src) {
Yi Kongc67f9a42018-07-20 13:39:55 -0700320 for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != nullptr; i++) {
Mark Salyzyn92dc3fc2014-03-12 13:12:44 -0700321 fprintf(stderr, "%3zu: %s\n", i+1, src[i]);
Jamie Gennis9c183f22012-12-03 16:44:16 -0800322 }
323}
324
325static const char* makeShaderString(const char* const* src) {
326 size_t len = 0;
Yi Kongc67f9a42018-07-20 13:39:55 -0700327 for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != nullptr; i++) {
Jamie Gennis9c183f22012-12-03 16:44:16 -0800328 // 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;
Yi Kongc67f9a42018-07-20 13:39:55 -0700334 for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != nullptr; i++) {
Jamie Gennis9c183f22012-12-03 16:44:16 -0800335 strcpy(end, src[i]);
336 end += strlen(src[i]);
337 *end = '\n';
338 end++;
339 }
340 *end = '\0';
341
342 return result;
343}
344
345static 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);
Manoj Gupta41221182016-11-01 17:30:24 -0700352 delete[] src;
Jamie Gennis9c183f22012-12-03 16:44:16 -0800353 return false;
354 }
355 delete[] src;
356
357 return true;
358}
359
360static 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) {
Yi Kongc67f9a42018-07-20 13:39:55 -0700378 glGetProgramInfoLog(program, bufLength, nullptr, buf);
Jamie Gennis9c183f22012-12-03 16:44:16 -0800379 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
391bool 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
422bool 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}