blob: c163095c50a72791d34513718ca72cc1adfdf553 [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
Huihong Luo31b5ac22022-08-15 20:38:10 -070038bool GLHelper::setUp(const sp<IBinder>& displayToken, const ShaderDesc* shaderDescs,
39 size_t numShaders) {
Jamie Gennis9c183f22012-12-03 16:44:16 -080040 bool result;
41
Huihong Luo31b5ac22022-08-15 20:38:10 -070042 mDisplayToken = displayToken;
43
Jamie Gennis9c183f22012-12-03 16:44:16 -080044 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
105void GLHelper::tearDown() {
Yi Kongc67f9a42018-07-20 13:39:55 -0700106 if (mShaderPrograms != nullptr) {
Jamie Gennis9c183f22012-12-03 16:44:16 -0800107 delete[] mShaderPrograms;
Yi Kongc67f9a42018-07-20 13:39:55 -0700108 mShaderPrograms = nullptr;
Jamie Gennis9c183f22012-12-03 16:44:16 -0800109 }
110
Yi Kongc67f9a42018-07-20 13:39:55 -0700111 if (mSurfaceComposerClient != nullptr) {
Jamie Gennis9c183f22012-12-03 16:44:16 -0800112 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
136bool 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
153bool 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
170void 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
180bool 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
190bool 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
203bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h,
204 sp<GLConsumer>* glConsumer, EGLSurface* surface) {
Dan Stoza6780a2d2014-03-13 11:31:43 -0700205 sp<IGraphicBufferProducer> producer;
206 sp<IGraphicBufferConsumer> consumer;
Mathias Agopian0556d792017-03-22 15:49:32 -0700207 BufferQueue::createBufferQueue(&producer, &consumer);
Dan Stoza6780a2d2014-03-13 11:31:43 -0700208 sp<GLConsumer> glc = new GLConsumer(consumer, name,
Dan Stozae49ba8e2014-06-24 13:09:19 -0700209 GL_TEXTURE_EXTERNAL_OES, false, true);
Jamie Gennis9c183f22012-12-03 16:44:16 -0800210 glc->setDefaultBufferSize(w, h);
Pablo Ceballos19e3e062015-08-19 16:16:06 -0700211 producer->setMaxDequeuedBufferCount(2);
Jamie Gennis9c183f22012-12-03 16:44:16 -0800212 glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
213
Dan Stoza6780a2d2014-03-13 11:31:43 -0700214 sp<ANativeWindow> anw = new Surface(producer);
Yi Kongc67f9a42018-07-20 13:39:55 -0700215 EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), nullptr);
Jamie Gennis9c183f22012-12-03 16:44:16 -0800216 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
226bool GLHelper::computeWindowScale(uint32_t w, uint32_t h, float* scale) {
Marin Shalamanova7fe3042021-01-29 21:02:08 +0100227 ui::DisplayMode mode;
Huihong Luo31b5ac22022-08-15 20:38:10 -0700228 status_t err = mSurfaceComposerClient->getActiveDisplayMode(mDisplayToken, &mode);
Jamie Gennis9c183f22012-12-03 16:44:16 -0800229 if (err != NO_ERROR) {
Marin Shalamanova7fe3042021-01-29 21:02:08 +0100230 fprintf(stderr, "SurfaceComposer::getActiveDisplayMode failed: %#x\n", err);
Jamie Gennis9c183f22012-12-03 16:44:16 -0800231 return false;
232 }
233
Marin Shalamanova7fe3042021-01-29 21:02:08 +0100234 float scaleX = static_cast<float>(mode.resolution.getWidth()) / w;
235 float scaleY = static_cast<float>(mode.resolution.getHeight()) / h;
Jamie Gennis9c183f22012-12-03 16:44:16 -0800236 *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
Yi Kongc67f9a42018-07-20 13:39:55 -0700246 if (mSurfaceComposerClient == nullptr) {
Jamie Gennis9c183f22012-12-03 16:44:16 -0800247 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);
Yi Kongc67f9a42018-07-20 13:39:55 -0700257 if (sc == nullptr || !sc->isValid()) {
Jamie Gennis9c183f22012-12-03 16:44:16 -0800258 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
Robert Carr4cdc58f2017-08-23 14:22:20 -0700268 SurfaceComposerClient::Transaction{}.setLayer(sc, 0x7FFFFFFF)
269 .setMatrix(sc, scale, 0.0f, 0.0f, scale)
270 .show(sc)
271 .apply();
Jamie Gennis9c183f22012-12-03 16:44:16 -0800272
273 sp<ANativeWindow> anw = sc->getSurface();
Yi Kongc67f9a42018-07-20 13:39:55 -0700274 EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), nullptr);
Jamie Gennis9c183f22012-12-03 16:44:16 -0800275 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
285static 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
Yi Kongc67f9a42018-07-20 13:39:55 -0700293 glShaderSource(shader, 1, &src, nullptr);
Jamie Gennis9c183f22012-12-03 16:44:16 -0800294 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) {
Yi Kongc67f9a42018-07-20 13:39:55 -0700304 glGetShaderInfoLog(shader, infoLen, nullptr, buf);
Jamie Gennis9c183f22012-12-03 16:44:16 -0800305 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
316static void printShaderSource(const char* const* src) {
Yi Kongc67f9a42018-07-20 13:39:55 -0700317 for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != nullptr; i++) {
Mark Salyzyn92dc3fc2014-03-12 13:12:44 -0700318 fprintf(stderr, "%3zu: %s\n", i+1, src[i]);
Jamie Gennis9c183f22012-12-03 16:44:16 -0800319 }
320}
321
322static const char* makeShaderString(const char* const* src) {
323 size_t len = 0;
Yi Kongc67f9a42018-07-20 13:39:55 -0700324 for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != nullptr; i++) {
Jamie Gennis9c183f22012-12-03 16:44:16 -0800325 // 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;
Yi Kongc67f9a42018-07-20 13:39:55 -0700331 for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != nullptr; i++) {
Jamie Gennis9c183f22012-12-03 16:44:16 -0800332 strcpy(end, src[i]);
333 end += strlen(src[i]);
334 *end = '\n';
335 end++;
336 }
337 *end = '\0';
338
339 return result;
340}
341
342static 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);
Manoj Gupta41221182016-11-01 17:30:24 -0700349 delete[] src;
Jamie Gennis9c183f22012-12-03 16:44:16 -0800350 return false;
351 }
352 delete[] src;
353
354 return true;
355}
356
357static 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) {
Yi Kongc67f9a42018-07-20 13:39:55 -0700375 glGetProgramInfoLog(program, bufLength, nullptr, buf);
Jamie Gennis9c183f22012-12-03 16:44:16 -0800376 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
388bool 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
419bool 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}