1 /*
2 * Copyright 2013 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 //#define LOG_NDEBUG 0
18 #undef LOG_TAG
19 #define LOG_TAG "RenderEngine"
20 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
21
22 #include <sched.h>
23 #include <cmath>
24 #include <fstream>
25 #include <sstream>
26 #include <unordered_set>
27
28 #include <GLES2/gl2.h>
29 #include <GLES2/gl2ext.h>
30 #include <android-base/stringprintf.h>
31 #include <cutils/compiler.h>
32 #include <cutils/properties.h>
33 #include <gui/DebugEGLImageTracker.h>
34 #include <renderengine/Mesh.h>
35 #include <renderengine/Texture.h>
36 #include <renderengine/private/Description.h>
37 #include <sync/sync.h>
38 #include <ui/ColorSpace.h>
39 #include <ui/DebugUtils.h>
40 #include <ui/GraphicBuffer.h>
41 #include <ui/Rect.h>
42 #include <ui/Region.h>
43 #include <utils/KeyedVector.h>
44 #include <utils/Trace.h>
45 #include "GLESRenderEngine.h"
46 #include "GLExtensions.h"
47 #include "GLFramebuffer.h"
48 #include "GLImage.h"
49 #include "Program.h"
50 #include "ProgramCache.h"
51
52 extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
53
checkGlError(const char * op,int lineNumber)54 bool checkGlError(const char* op, int lineNumber) {
55 bool errorFound = false;
56 GLint error = glGetError();
57 while (error != GL_NO_ERROR) {
58 errorFound = true;
59 error = glGetError();
60 ALOGV("after %s() (line # %d) glError (0x%x)\n", op, lineNumber, error);
61 }
62 return errorFound;
63 }
64
65 static constexpr bool outputDebugPPMs = false;
66
writePPM(const char * basename,GLuint width,GLuint height)67 void writePPM(const char* basename, GLuint width, GLuint height) {
68 ALOGV("writePPM #%s: %d x %d", basename, width, height);
69
70 std::vector<GLubyte> pixels(width * height * 4);
71 std::vector<GLubyte> outBuffer(width * height * 3);
72
73 // TODO(courtneygo): We can now have float formats, need
74 // to remove this code or update to support.
75 // Make returned pixels fit in uint32_t, one byte per component
76 glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
77 if (checkGlError(__FUNCTION__, __LINE__)) {
78 return;
79 }
80
81 std::string filename(basename);
82 filename.append(".ppm");
83 std::ofstream file(filename.c_str(), std::ios::binary);
84 if (!file.is_open()) {
85 ALOGE("Unable to open file: %s", filename.c_str());
86 ALOGE("You may need to do: \"adb shell setenforce 0\" to enable "
87 "surfaceflinger to write debug images");
88 return;
89 }
90
91 file << "P6\n";
92 file << width << "\n";
93 file << height << "\n";
94 file << 255 << "\n";
95
96 auto ptr = reinterpret_cast<char*>(pixels.data());
97 auto outPtr = reinterpret_cast<char*>(outBuffer.data());
98 for (int y = height - 1; y >= 0; y--) {
99 char* data = ptr + y * width * sizeof(uint32_t);
100
101 for (GLuint x = 0; x < width; x++) {
102 // Only copy R, G and B components
103 outPtr[0] = data[0];
104 outPtr[1] = data[1];
105 outPtr[2] = data[2];
106 data += sizeof(uint32_t);
107 outPtr += 3;
108 }
109 }
110 file.write(reinterpret_cast<char*>(outBuffer.data()), outBuffer.size());
111 }
112
113 namespace android {
114 namespace renderengine {
115 namespace gl {
116
117 using base::StringAppendF;
118 using ui::Dataspace;
119
selectConfigForAttribute(EGLDisplay dpy,EGLint const * attrs,EGLint attribute,EGLint wanted,EGLConfig * outConfig)120 static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute,
121 EGLint wanted, EGLConfig* outConfig) {
122 EGLint numConfigs = -1, n = 0;
123 eglGetConfigs(dpy, nullptr, 0, &numConfigs);
124 std::vector<EGLConfig> configs(numConfigs, EGL_NO_CONFIG_KHR);
125 eglChooseConfig(dpy, attrs, configs.data(), configs.size(), &n);
126 configs.resize(n);
127
128 if (!configs.empty()) {
129 if (attribute != EGL_NONE) {
130 for (EGLConfig config : configs) {
131 EGLint value = 0;
132 eglGetConfigAttrib(dpy, config, attribute, &value);
133 if (wanted == value) {
134 *outConfig = config;
135 return NO_ERROR;
136 }
137 }
138 } else {
139 // just pick the first one
140 *outConfig = configs[0];
141 return NO_ERROR;
142 }
143 }
144
145 return NAME_NOT_FOUND;
146 }
147
148 class EGLAttributeVector {
149 struct Attribute;
150 class Adder;
151 friend class Adder;
152 KeyedVector<Attribute, EGLint> mList;
153 struct Attribute {
Attributeandroid::renderengine::gl::EGLAttributeVector::Attribute154 Attribute() : v(0){};
Attributeandroid::renderengine::gl::EGLAttributeVector::Attribute155 explicit Attribute(EGLint v) : v(v) {}
156 EGLint v;
operator <android::renderengine::gl::EGLAttributeVector::Attribute157 bool operator<(const Attribute& other) const {
158 // this places EGL_NONE at the end
159 EGLint lhs(v);
160 EGLint rhs(other.v);
161 if (lhs == EGL_NONE) lhs = 0x7FFFFFFF;
162 if (rhs == EGL_NONE) rhs = 0x7FFFFFFF;
163 return lhs < rhs;
164 }
165 };
166 class Adder {
167 friend class EGLAttributeVector;
168 EGLAttributeVector& v;
169 EGLint attribute;
Adder(EGLAttributeVector & v,EGLint attribute)170 Adder(EGLAttributeVector& v, EGLint attribute) : v(v), attribute(attribute) {}
171
172 public:
operator =(EGLint value)173 void operator=(EGLint value) {
174 if (attribute != EGL_NONE) {
175 v.mList.add(Attribute(attribute), value);
176 }
177 }
operator EGLint() const178 operator EGLint() const { return v.mList[attribute]; }
179 };
180
181 public:
EGLAttributeVector()182 EGLAttributeVector() { mList.add(Attribute(EGL_NONE), EGL_NONE); }
remove(EGLint attribute)183 void remove(EGLint attribute) {
184 if (attribute != EGL_NONE) {
185 mList.removeItem(Attribute(attribute));
186 }
187 }
operator [](EGLint attribute)188 Adder operator[](EGLint attribute) { return Adder(*this, attribute); }
operator [](EGLint attribute) const189 EGLint operator[](EGLint attribute) const { return mList[attribute]; }
190 // cast-operator to (EGLint const*)
operator EGLint const*() const191 operator EGLint const*() const { return &mList.keyAt(0).v; }
192 };
193
selectEGLConfig(EGLDisplay display,EGLint format,EGLint renderableType,EGLConfig * config)194 static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint renderableType,
195 EGLConfig* config) {
196 // select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if
197 // it is to be used with WIFI displays
198 status_t err;
199 EGLint wantedAttribute;
200 EGLint wantedAttributeValue;
201
202 EGLAttributeVector attribs;
203 if (renderableType) {
204 attribs[EGL_RENDERABLE_TYPE] = renderableType;
205 attribs[EGL_RECORDABLE_ANDROID] = EGL_TRUE;
206 attribs[EGL_SURFACE_TYPE] = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
207 attribs[EGL_FRAMEBUFFER_TARGET_ANDROID] = EGL_TRUE;
208 attribs[EGL_RED_SIZE] = 8;
209 attribs[EGL_GREEN_SIZE] = 8;
210 attribs[EGL_BLUE_SIZE] = 8;
211 attribs[EGL_ALPHA_SIZE] = 8;
212 wantedAttribute = EGL_NONE;
213 wantedAttributeValue = EGL_NONE;
214 } else {
215 // if no renderable type specified, fallback to a simplified query
216 wantedAttribute = EGL_NATIVE_VISUAL_ID;
217 wantedAttributeValue = format;
218 }
219
220 err = selectConfigForAttribute(display, attribs, wantedAttribute, wantedAttributeValue, config);
221 if (err == NO_ERROR) {
222 EGLint caveat;
223 if (eglGetConfigAttrib(display, *config, EGL_CONFIG_CAVEAT, &caveat))
224 ALOGW_IF(caveat == EGL_SLOW_CONFIG, "EGL_SLOW_CONFIG selected!");
225 }
226
227 return err;
228 }
229
create(int hwcFormat,uint32_t featureFlags,uint32_t imageCacheSize)230 std::unique_ptr<GLESRenderEngine> GLESRenderEngine::create(int hwcFormat, uint32_t featureFlags,
231 uint32_t imageCacheSize) {
232 // initialize EGL for the default display
233 EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
234 if (!eglInitialize(display, nullptr, nullptr)) {
235 LOG_ALWAYS_FATAL("failed to initialize EGL");
236 }
237
238 GLExtensions& extensions = GLExtensions::getInstance();
239 extensions.initWithEGLStrings(eglQueryStringImplementationANDROID(display, EGL_VERSION),
240 eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS));
241
242 // The code assumes that ES2 or later is available if this extension is
243 // supported.
244 EGLConfig config = EGL_NO_CONFIG;
245 if (!extensions.hasNoConfigContext()) {
246 config = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
247 }
248
249 bool useContextPriority = extensions.hasContextPriority() &&
250 (featureFlags & RenderEngine::USE_HIGH_PRIORITY_CONTEXT);
251 EGLContext protectedContext = EGL_NO_CONTEXT;
252 if ((featureFlags & RenderEngine::ENABLE_PROTECTED_CONTEXT) &&
253 extensions.hasProtectedContent()) {
254 protectedContext = createEglContext(display, config, nullptr, useContextPriority,
255 Protection::PROTECTED);
256 ALOGE_IF(protectedContext == EGL_NO_CONTEXT, "Can't create protected context");
257 }
258
259 EGLContext ctxt = createEglContext(display, config, protectedContext, useContextPriority,
260 Protection::UNPROTECTED);
261
262 // if can't create a GL context, we can only abort.
263 LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed");
264
265 EGLSurface dummy = EGL_NO_SURFACE;
266 if (!extensions.hasSurfacelessContext()) {
267 dummy = createDummyEglPbufferSurface(display, config, hwcFormat, Protection::UNPROTECTED);
268 LOG_ALWAYS_FATAL_IF(dummy == EGL_NO_SURFACE, "can't create dummy pbuffer");
269 }
270 EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt);
271 LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current");
272 extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER),
273 glGetString(GL_VERSION), glGetString(GL_EXTENSIONS));
274
275 EGLSurface protectedDummy = EGL_NO_SURFACE;
276 if (protectedContext != EGL_NO_CONTEXT && !extensions.hasSurfacelessContext()) {
277 protectedDummy =
278 createDummyEglPbufferSurface(display, config, hwcFormat, Protection::PROTECTED);
279 ALOGE_IF(protectedDummy == EGL_NO_SURFACE, "can't create protected dummy pbuffer");
280 }
281
282 // now figure out what version of GL did we actually get
283 GlesVersion version = parseGlesVersion(extensions.getVersion());
284
285 // initialize the renderer while GL is current
286 std::unique_ptr<GLESRenderEngine> engine;
287 switch (version) {
288 case GLES_VERSION_1_0:
289 case GLES_VERSION_1_1:
290 LOG_ALWAYS_FATAL("SurfaceFlinger requires OpenGL ES 2.0 minimum to run.");
291 break;
292 case GLES_VERSION_2_0:
293 case GLES_VERSION_3_0:
294 engine = std::make_unique<GLESRenderEngine>(featureFlags, display, config, ctxt, dummy,
295 protectedContext, protectedDummy,
296 imageCacheSize);
297 break;
298 }
299
300 ALOGI("OpenGL ES informations:");
301 ALOGI("vendor : %s", extensions.getVendor());
302 ALOGI("renderer : %s", extensions.getRenderer());
303 ALOGI("version : %s", extensions.getVersion());
304 ALOGI("extensions: %s", extensions.getExtensions());
305 ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize());
306 ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims());
307
308 return engine;
309 }
310
chooseEglConfig(EGLDisplay display,int format,bool logConfig)311 EGLConfig GLESRenderEngine::chooseEglConfig(EGLDisplay display, int format, bool logConfig) {
312 status_t err;
313 EGLConfig config;
314
315 // First try to get an ES3 config
316 err = selectEGLConfig(display, format, EGL_OPENGL_ES3_BIT, &config);
317 if (err != NO_ERROR) {
318 // If ES3 fails, try to get an ES2 config
319 err = selectEGLConfig(display, format, EGL_OPENGL_ES2_BIT, &config);
320 if (err != NO_ERROR) {
321 // If ES2 still doesn't work, probably because we're on the emulator.
322 // try a simplified query
323 ALOGW("no suitable EGLConfig found, trying a simpler query");
324 err = selectEGLConfig(display, format, 0, &config);
325 if (err != NO_ERROR) {
326 // this EGL is too lame for android
327 LOG_ALWAYS_FATAL("no suitable EGLConfig found, giving up");
328 }
329 }
330 }
331
332 if (logConfig) {
333 // print some debugging info
334 EGLint r, g, b, a;
335 eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r);
336 eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
337 eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b);
338 eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
339 ALOGI("EGL information:");
340 ALOGI("vendor : %s", eglQueryString(display, EGL_VENDOR));
341 ALOGI("version : %s", eglQueryString(display, EGL_VERSION));
342 ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS));
343 ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS) ?: "Not Supported");
344 ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
345 }
346
347 return config;
348 }
349
GLESRenderEngine(uint32_t featureFlags,EGLDisplay display,EGLConfig config,EGLContext ctxt,EGLSurface dummy,EGLContext protectedContext,EGLSurface protectedDummy,uint32_t imageCacheSize)350 GLESRenderEngine::GLESRenderEngine(uint32_t featureFlags, EGLDisplay display, EGLConfig config,
351 EGLContext ctxt, EGLSurface dummy, EGLContext protectedContext,
352 EGLSurface protectedDummy, uint32_t imageCacheSize)
353 : renderengine::impl::RenderEngine(featureFlags),
354 mEGLDisplay(display),
355 mEGLConfig(config),
356 mEGLContext(ctxt),
357 mDummySurface(dummy),
358 mProtectedEGLContext(protectedContext),
359 mProtectedDummySurface(protectedDummy),
360 mVpWidth(0),
361 mVpHeight(0),
362 mFramebufferImageCacheSize(imageCacheSize),
363 mUseColorManagement(featureFlags & USE_COLOR_MANAGEMENT) {
364 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
365 glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
366
367 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
368 glPixelStorei(GL_PACK_ALIGNMENT, 4);
369
370 // Initialize protected EGL Context.
371 if (mProtectedEGLContext != EGL_NO_CONTEXT) {
372 EGLBoolean success = eglMakeCurrent(display, mProtectedDummySurface, mProtectedDummySurface,
373 mProtectedEGLContext);
374 ALOGE_IF(!success, "can't make protected context current");
375 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
376 glPixelStorei(GL_PACK_ALIGNMENT, 4);
377 success = eglMakeCurrent(display, mDummySurface, mDummySurface, mEGLContext);
378 LOG_ALWAYS_FATAL_IF(!success, "can't make default context current");
379 }
380
381 const uint16_t protTexData[] = {0};
382 glGenTextures(1, &mProtectedTexName);
383 glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
384 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
385 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
386 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
387 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
388 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData);
389
390 // mColorBlindnessCorrection = M;
391
392 if (mUseColorManagement) {
393 const ColorSpace srgb(ColorSpace::sRGB());
394 const ColorSpace displayP3(ColorSpace::DisplayP3());
395 const ColorSpace bt2020(ColorSpace::BT2020());
396
397 // no chromatic adaptation needed since all color spaces use D65 for their white points.
398 mSrgbToXyz = mat4(srgb.getRGBtoXYZ());
399 mDisplayP3ToXyz = mat4(displayP3.getRGBtoXYZ());
400 mBt2020ToXyz = mat4(bt2020.getRGBtoXYZ());
401 mXyzToSrgb = mat4(srgb.getXYZtoRGB());
402 mXyzToDisplayP3 = mat4(displayP3.getXYZtoRGB());
403 mXyzToBt2020 = mat4(bt2020.getXYZtoRGB());
404
405 // Compute sRGB to Display P3 and BT2020 transform matrix.
406 // NOTE: For now, we are limiting output wide color space support to
407 // Display-P3 and BT2020 only.
408 mSrgbToDisplayP3 = mXyzToDisplayP3 * mSrgbToXyz;
409 mSrgbToBt2020 = mXyzToBt2020 * mSrgbToXyz;
410
411 // Compute Display P3 to sRGB and BT2020 transform matrix.
412 mDisplayP3ToSrgb = mXyzToSrgb * mDisplayP3ToXyz;
413 mDisplayP3ToBt2020 = mXyzToBt2020 * mDisplayP3ToXyz;
414
415 // Compute BT2020 to sRGB and Display P3 transform matrix
416 mBt2020ToSrgb = mXyzToSrgb * mBt2020ToXyz;
417 mBt2020ToDisplayP3 = mXyzToDisplayP3 * mBt2020ToXyz;
418 }
419
420 char value[PROPERTY_VALUE_MAX];
421 property_get("debug.egl.traceGpuCompletion", value, "0");
422 if (atoi(value)) {
423 mTraceGpuCompletion = true;
424 mFlushTracer = std::make_unique<FlushTracer>(this);
425 }
426 mImageManager = std::make_unique<ImageManager>(this);
427 mImageManager->initThread();
428 mDrawingBuffer = createFramebuffer();
429 }
430
~GLESRenderEngine()431 GLESRenderEngine::~GLESRenderEngine() {
432 // Destroy the image manager first.
433 mImageManager = nullptr;
434 std::lock_guard<std::mutex> lock(mRenderingMutex);
435 unbindFrameBuffer(mDrawingBuffer.get());
436 mDrawingBuffer = nullptr;
437 while (!mFramebufferImageCache.empty()) {
438 EGLImageKHR expired = mFramebufferImageCache.front().second;
439 mFramebufferImageCache.pop_front();
440 eglDestroyImageKHR(mEGLDisplay, expired);
441 DEBUG_EGL_IMAGE_TRACKER_DESTROY();
442 }
443 mImageCache.clear();
444 eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
445 eglTerminate(mEGLDisplay);
446 }
447
createFramebuffer()448 std::unique_ptr<Framebuffer> GLESRenderEngine::createFramebuffer() {
449 return std::make_unique<GLFramebuffer>(*this);
450 }
451
createImage()452 std::unique_ptr<Image> GLESRenderEngine::createImage() {
453 return std::make_unique<GLImage>(*this);
454 }
455
getFramebufferForDrawing()456 Framebuffer* GLESRenderEngine::getFramebufferForDrawing() {
457 return mDrawingBuffer.get();
458 }
459
primeCache() const460 void GLESRenderEngine::primeCache() const {
461 ProgramCache::getInstance().primeCache(mInProtectedContext ? mProtectedEGLContext : mEGLContext,
462 mFeatureFlags & USE_COLOR_MANAGEMENT);
463 }
464
isCurrent() const465 bool GLESRenderEngine::isCurrent() const {
466 return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext();
467 }
468
flush()469 base::unique_fd GLESRenderEngine::flush() {
470 ATRACE_CALL();
471 if (!GLExtensions::getInstance().hasNativeFenceSync()) {
472 return base::unique_fd();
473 }
474
475 EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
476 if (sync == EGL_NO_SYNC_KHR) {
477 ALOGW("failed to create EGL native fence sync: %#x", eglGetError());
478 return base::unique_fd();
479 }
480
481 // native fence fd will not be populated until flush() is done.
482 glFlush();
483
484 // get the fence fd
485 base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync));
486 eglDestroySyncKHR(mEGLDisplay, sync);
487 if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
488 ALOGW("failed to dup EGL native fence sync: %#x", eglGetError());
489 }
490
491 // Only trace if we have a valid fence, as current usage falls back to
492 // calling finish() if the fence fd is invalid.
493 if (CC_UNLIKELY(mTraceGpuCompletion && mFlushTracer) && fenceFd.get() >= 0) {
494 mFlushTracer->queueSync(eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr));
495 }
496
497 return fenceFd;
498 }
499
finish()500 bool GLESRenderEngine::finish() {
501 ATRACE_CALL();
502 if (!GLExtensions::getInstance().hasFenceSync()) {
503 ALOGW("no synchronization support");
504 return false;
505 }
506
507 EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr);
508 if (sync == EGL_NO_SYNC_KHR) {
509 ALOGW("failed to create EGL fence sync: %#x", eglGetError());
510 return false;
511 }
512
513 if (CC_UNLIKELY(mTraceGpuCompletion && mFlushTracer)) {
514 mFlushTracer->queueSync(eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr));
515 }
516
517 return waitSync(sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR);
518 }
519
waitSync(EGLSyncKHR sync,EGLint flags)520 bool GLESRenderEngine::waitSync(EGLSyncKHR sync, EGLint flags) {
521 EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, flags, 2000000000 /*2 sec*/);
522 EGLint error = eglGetError();
523 eglDestroySyncKHR(mEGLDisplay, sync);
524 if (result != EGL_CONDITION_SATISFIED_KHR) {
525 if (result == EGL_TIMEOUT_EXPIRED_KHR) {
526 ALOGW("fence wait timed out");
527 } else {
528 ALOGW("error waiting on EGL fence: %#x", error);
529 }
530 return false;
531 }
532
533 return true;
534 }
535
waitFence(base::unique_fd fenceFd)536 bool GLESRenderEngine::waitFence(base::unique_fd fenceFd) {
537 if (!GLExtensions::getInstance().hasNativeFenceSync() ||
538 !GLExtensions::getInstance().hasWaitSync()) {
539 return false;
540 }
541
542 // release the fd and transfer the ownership to EGLSync
543 EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd.release(), EGL_NONE};
544 EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
545 if (sync == EGL_NO_SYNC_KHR) {
546 ALOGE("failed to create EGL native fence sync: %#x", eglGetError());
547 return false;
548 }
549
550 // XXX: The spec draft is inconsistent as to whether this should return an
551 // EGLint or void. Ignore the return value for now, as it's not strictly
552 // needed.
553 eglWaitSyncKHR(mEGLDisplay, sync, 0);
554 EGLint error = eglGetError();
555 eglDestroySyncKHR(mEGLDisplay, sync);
556 if (error != EGL_SUCCESS) {
557 ALOGE("failed to wait for EGL native fence sync: %#x", error);
558 return false;
559 }
560
561 return true;
562 }
563
clearWithColor(float red,float green,float blue,float alpha)564 void GLESRenderEngine::clearWithColor(float red, float green, float blue, float alpha) {
565 ATRACE_CALL();
566 glDisable(GL_BLEND);
567 glClearColor(red, green, blue, alpha);
568 glClear(GL_COLOR_BUFFER_BIT);
569 }
570
fillRegionWithColor(const Region & region,float red,float green,float blue,float alpha)571 void GLESRenderEngine::fillRegionWithColor(const Region& region, float red, float green, float blue,
572 float alpha) {
573 size_t c;
574 Rect const* r = region.getArray(&c);
575 Mesh mesh(Mesh::TRIANGLES, c * 6, 2);
576 Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
577 for (size_t i = 0; i < c; i++, r++) {
578 position[i * 6 + 0].x = r->left;
579 position[i * 6 + 0].y = r->top;
580 position[i * 6 + 1].x = r->left;
581 position[i * 6 + 1].y = r->bottom;
582 position[i * 6 + 2].x = r->right;
583 position[i * 6 + 2].y = r->bottom;
584 position[i * 6 + 3].x = r->left;
585 position[i * 6 + 3].y = r->top;
586 position[i * 6 + 4].x = r->right;
587 position[i * 6 + 4].y = r->bottom;
588 position[i * 6 + 5].x = r->right;
589 position[i * 6 + 5].y = r->top;
590 }
591 setupFillWithColor(red, green, blue, alpha);
592 drawMesh(mesh);
593 }
594
setScissor(const Rect & region)595 void GLESRenderEngine::setScissor(const Rect& region) {
596 glScissor(region.left, region.top, region.getWidth(), region.getHeight());
597 glEnable(GL_SCISSOR_TEST);
598 }
599
disableScissor()600 void GLESRenderEngine::disableScissor() {
601 glDisable(GL_SCISSOR_TEST);
602 }
603
genTextures(size_t count,uint32_t * names)604 void GLESRenderEngine::genTextures(size_t count, uint32_t* names) {
605 glGenTextures(count, names);
606 }
607
deleteTextures(size_t count,uint32_t const * names)608 void GLESRenderEngine::deleteTextures(size_t count, uint32_t const* names) {
609 glDeleteTextures(count, names);
610 }
611
bindExternalTextureImage(uint32_t texName,const Image & image)612 void GLESRenderEngine::bindExternalTextureImage(uint32_t texName, const Image& image) {
613 ATRACE_CALL();
614 const GLImage& glImage = static_cast<const GLImage&>(image);
615 const GLenum target = GL_TEXTURE_EXTERNAL_OES;
616
617 glBindTexture(target, texName);
618 if (glImage.getEGLImage() != EGL_NO_IMAGE_KHR) {
619 glEGLImageTargetTexture2DOES(target, static_cast<GLeglImageOES>(glImage.getEGLImage()));
620 }
621 }
622
bindExternalTextureBuffer(uint32_t texName,const sp<GraphicBuffer> & buffer,const sp<Fence> & bufferFence)623 status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName,
624 const sp<GraphicBuffer>& buffer,
625 const sp<Fence>& bufferFence) {
626 if (buffer == nullptr) {
627 return BAD_VALUE;
628 }
629
630 ATRACE_CALL();
631
632 bool found = false;
633 {
634 std::lock_guard<std::mutex> lock(mRenderingMutex);
635 auto cachedImage = mImageCache.find(buffer->getId());
636 found = (cachedImage != mImageCache.end());
637 }
638
639 // If we couldn't find the image in the cache at this time, then either
640 // SurfaceFlinger messed up registering the buffer ahead of time or we got
641 // backed up creating other EGLImages.
642 if (!found) {
643 status_t cacheResult = mImageManager->cache(buffer);
644 if (cacheResult != NO_ERROR) {
645 return cacheResult;
646 }
647 }
648
649 // Whether or not we needed to cache, re-check mImageCache to make sure that
650 // there's an EGLImage. The current threading model guarantees that we don't
651 // destroy a cached image until it's really not needed anymore (i.e. this
652 // function should not be called), so the only possibility is that something
653 // terrible went wrong and we should just bind something and move on.
654 {
655 std::lock_guard<std::mutex> lock(mRenderingMutex);
656 auto cachedImage = mImageCache.find(buffer->getId());
657
658 if (cachedImage == mImageCache.end()) {
659 // We failed creating the image if we got here, so bail out.
660 ALOGE("Failed to create an EGLImage when rendering");
661 bindExternalTextureImage(texName, *createImage());
662 return NO_INIT;
663 }
664
665 bindExternalTextureImage(texName, *cachedImage->second);
666 }
667
668 // Wait for the new buffer to be ready.
669 if (bufferFence != nullptr && bufferFence->isValid()) {
670 if (GLExtensions::getInstance().hasWaitSync()) {
671 base::unique_fd fenceFd(bufferFence->dup());
672 if (fenceFd == -1) {
673 ALOGE("error dup'ing fence fd: %d", errno);
674 return -errno;
675 }
676 if (!waitFence(std::move(fenceFd))) {
677 ALOGE("failed to wait on fence fd");
678 return UNKNOWN_ERROR;
679 }
680 } else {
681 status_t err = bufferFence->waitForever("RenderEngine::bindExternalTextureBuffer");
682 if (err != NO_ERROR) {
683 ALOGE("error waiting for fence: %d", err);
684 return err;
685 }
686 }
687 }
688
689 return NO_ERROR;
690 }
691
cacheExternalTextureBuffer(const sp<GraphicBuffer> & buffer)692 void GLESRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
693 mImageManager->cacheAsync(buffer, nullptr);
694 }
695
cacheExternalTextureBufferForTesting(const sp<GraphicBuffer> & buffer)696 std::shared_ptr<ImageManager::Barrier> GLESRenderEngine::cacheExternalTextureBufferForTesting(
697 const sp<GraphicBuffer>& buffer) {
698 auto barrier = std::make_shared<ImageManager::Barrier>();
699 mImageManager->cacheAsync(buffer, barrier);
700 return barrier;
701 }
702
cacheExternalTextureBufferInternal(const sp<GraphicBuffer> & buffer)703 status_t GLESRenderEngine::cacheExternalTextureBufferInternal(const sp<GraphicBuffer>& buffer) {
704 if (buffer == nullptr) {
705 return BAD_VALUE;
706 }
707
708 {
709 std::lock_guard<std::mutex> lock(mRenderingMutex);
710 if (mImageCache.count(buffer->getId()) > 0) {
711 // If there's already an image then fail fast here.
712 return NO_ERROR;
713 }
714 }
715 ATRACE_CALL();
716
717 // Create the image without holding a lock so that we don't block anything.
718 std::unique_ptr<Image> newImage = createImage();
719
720 bool created = newImage->setNativeWindowBuffer(buffer->getNativeBuffer(),
721 buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
722 if (!created) {
723 ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
724 buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
725 buffer->getPixelFormat());
726 return NO_INIT;
727 }
728
729 {
730 std::lock_guard<std::mutex> lock(mRenderingMutex);
731 if (mImageCache.count(buffer->getId()) > 0) {
732 // In theory it's possible for another thread to recache the image,
733 // so bail out if another thread won.
734 return NO_ERROR;
735 }
736 mImageCache.insert(std::make_pair(buffer->getId(), std::move(newImage)));
737 }
738
739 return NO_ERROR;
740 }
741
unbindExternalTextureBuffer(uint64_t bufferId)742 void GLESRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) {
743 mImageManager->releaseAsync(bufferId, nullptr);
744 }
745
unbindExternalTextureBufferForTesting(uint64_t bufferId)746 std::shared_ptr<ImageManager::Barrier> GLESRenderEngine::unbindExternalTextureBufferForTesting(
747 uint64_t bufferId) {
748 auto barrier = std::make_shared<ImageManager::Barrier>();
749 mImageManager->releaseAsync(bufferId, barrier);
750 return barrier;
751 }
752
unbindExternalTextureBufferInternal(uint64_t bufferId)753 void GLESRenderEngine::unbindExternalTextureBufferInternal(uint64_t bufferId) {
754 std::unique_ptr<Image> image;
755 {
756 std::lock_guard<std::mutex> lock(mRenderingMutex);
757 const auto& cachedImage = mImageCache.find(bufferId);
758
759 if (cachedImage != mImageCache.end()) {
760 ALOGV("Destroying image for buffer: %" PRIu64, bufferId);
761 // Move the buffer out of cache first, so that we can destroy
762 // without holding the cache's lock.
763 image = std::move(cachedImage->second);
764 mImageCache.erase(bufferId);
765 return;
766 }
767 }
768 ALOGV("Failed to find image for buffer: %" PRIu64, bufferId);
769 }
770
setupLayerCropping(const LayerSettings & layer,Mesh & mesh)771 FloatRect GLESRenderEngine::setupLayerCropping(const LayerSettings& layer, Mesh& mesh) {
772 // Translate win by the rounded corners rect coordinates, to have all values in
773 // layer coordinate space.
774 FloatRect cropWin = layer.geometry.boundaries;
775 const FloatRect& roundedCornersCrop = layer.geometry.roundedCornersCrop;
776 cropWin.left -= roundedCornersCrop.left;
777 cropWin.right -= roundedCornersCrop.left;
778 cropWin.top -= roundedCornersCrop.top;
779 cropWin.bottom -= roundedCornersCrop.top;
780 Mesh::VertexArray<vec2> cropCoords(mesh.getCropCoordArray<vec2>());
781 cropCoords[0] = vec2(cropWin.left, cropWin.top);
782 cropCoords[1] = vec2(cropWin.left, cropWin.top + cropWin.getHeight());
783 cropCoords[2] = vec2(cropWin.right, cropWin.top + cropWin.getHeight());
784 cropCoords[3] = vec2(cropWin.right, cropWin.top);
785
786 setupCornerRadiusCropSize(roundedCornersCrop.getWidth(), roundedCornersCrop.getHeight());
787 return cropWin;
788 }
789
handleRoundedCorners(const DisplaySettings & display,const LayerSettings & layer,const Mesh & mesh)790 void GLESRenderEngine::handleRoundedCorners(const DisplaySettings& display,
791 const LayerSettings& layer, const Mesh& mesh) {
792 // We separate the layer into 3 parts essentially, such that we only turn on blending for the
793 // top rectangle and the bottom rectangle, and turn off blending for the middle rectangle.
794 FloatRect bounds = layer.geometry.roundedCornersCrop;
795
796 // Firstly, we need to convert the coordination from layer native coordination space to
797 // device coordination space.
798 const auto transformMatrix = display.globalTransform * layer.geometry.positionTransform;
799 const vec4 leftTopCoordinate(bounds.left, bounds.top, 1.0, 1.0);
800 const vec4 rightBottomCoordinate(bounds.right, bounds.bottom, 1.0, 1.0);
801 const vec4 leftTopCoordinateInBuffer = transformMatrix * leftTopCoordinate;
802 const vec4 rightBottomCoordinateInBuffer = transformMatrix * rightBottomCoordinate;
803 bounds = FloatRect(leftTopCoordinateInBuffer[0], leftTopCoordinateInBuffer[1],
804 rightBottomCoordinateInBuffer[0], rightBottomCoordinateInBuffer[1]);
805
806 // Secondly, if the display is rotated, we need to undo the rotation on coordination and
807 // align the (left, top) and (right, bottom) coordination with the device coordination
808 // space.
809 switch (display.orientation) {
810 case ui::Transform::ROT_90:
811 std::swap(bounds.left, bounds.right);
812 break;
813 case ui::Transform::ROT_180:
814 std::swap(bounds.left, bounds.right);
815 std::swap(bounds.top, bounds.bottom);
816 break;
817 case ui::Transform::ROT_270:
818 std::swap(bounds.top, bounds.bottom);
819 break;
820 default:
821 break;
822 }
823
824 // Finally, we cut the layer into 3 parts, with top and bottom parts having rounded corners
825 // and the middle part without rounded corners.
826 const int32_t radius = ceil(layer.geometry.roundedCornersRadius);
827 const Rect topRect(bounds.left, bounds.top, bounds.right, bounds.top + radius);
828 setScissor(topRect);
829 drawMesh(mesh);
830 const Rect bottomRect(bounds.left, bounds.bottom - radius, bounds.right, bounds.bottom);
831 setScissor(bottomRect);
832 drawMesh(mesh);
833
834 // The middle part of the layer can turn off blending.
835 const Rect middleRect(bounds.left, bounds.top + radius, bounds.right, bounds.bottom - radius);
836 setScissor(middleRect);
837 mState.cornerRadius = 0.0;
838 disableBlending();
839 drawMesh(mesh);
840 disableScissor();
841 }
842
bindFrameBuffer(Framebuffer * framebuffer)843 status_t GLESRenderEngine::bindFrameBuffer(Framebuffer* framebuffer) {
844 ATRACE_CALL();
845 GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(framebuffer);
846 EGLImageKHR eglImage = glFramebuffer->getEGLImage();
847 uint32_t textureName = glFramebuffer->getTextureName();
848 uint32_t framebufferName = glFramebuffer->getFramebufferName();
849
850 // Bind the texture and turn our EGLImage into a texture
851 glBindTexture(GL_TEXTURE_2D, textureName);
852 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)eglImage);
853
854 // Bind the Framebuffer to render into
855 glBindFramebuffer(GL_FRAMEBUFFER, framebufferName);
856 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureName, 0);
857
858 uint32_t glStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
859
860 ALOGE_IF(glStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d",
861 glStatus);
862
863 return glStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE;
864 }
865
unbindFrameBuffer(Framebuffer *)866 void GLESRenderEngine::unbindFrameBuffer(Framebuffer* /* framebuffer */) {
867 ATRACE_CALL();
868
869 // back to main framebuffer
870 glBindFramebuffer(GL_FRAMEBUFFER, 0);
871 }
872
checkErrors() const873 void GLESRenderEngine::checkErrors() const {
874 do {
875 // there could be more than one error flag
876 GLenum error = glGetError();
877 if (error == GL_NO_ERROR) break;
878 ALOGE("GL error 0x%04x", int(error));
879 } while (true);
880 }
881
supportsProtectedContent() const882 bool GLESRenderEngine::supportsProtectedContent() const {
883 return mProtectedEGLContext != EGL_NO_CONTEXT;
884 }
885
useProtectedContext(bool useProtectedContext)886 bool GLESRenderEngine::useProtectedContext(bool useProtectedContext) {
887 if (useProtectedContext == mInProtectedContext) {
888 return true;
889 }
890 if (useProtectedContext && mProtectedEGLContext == EGL_NO_CONTEXT) {
891 return false;
892 }
893 const EGLSurface surface = useProtectedContext ? mProtectedDummySurface : mDummySurface;
894 const EGLContext context = useProtectedContext ? mProtectedEGLContext : mEGLContext;
895 const bool success = eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE;
896 if (success) {
897 mInProtectedContext = useProtectedContext;
898 }
899 return success;
900 }
createFramebufferImageIfNeeded(ANativeWindowBuffer * nativeBuffer,bool isProtected,bool useFramebufferCache)901 EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer,
902 bool isProtected,
903 bool useFramebufferCache) {
904 sp<GraphicBuffer> graphicBuffer = GraphicBuffer::from(nativeBuffer);
905 if (useFramebufferCache) {
906 std::lock_guard<std::mutex> lock(mFramebufferImageCacheMutex);
907 for (const auto& image : mFramebufferImageCache) {
908 if (image.first == graphicBuffer->getId()) {
909 return image.second;
910 }
911 }
912 }
913 EGLint attributes[] = {
914 isProtected ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
915 isProtected ? EGL_TRUE : EGL_NONE,
916 EGL_NONE,
917 };
918 EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
919 nativeBuffer, attributes);
920 if (useFramebufferCache) {
921 if (image != EGL_NO_IMAGE_KHR) {
922 std::lock_guard<std::mutex> lock(mFramebufferImageCacheMutex);
923 if (mFramebufferImageCache.size() >= mFramebufferImageCacheSize) {
924 EGLImageKHR expired = mFramebufferImageCache.front().second;
925 mFramebufferImageCache.pop_front();
926 eglDestroyImageKHR(mEGLDisplay, expired);
927 DEBUG_EGL_IMAGE_TRACKER_DESTROY();
928 }
929 mFramebufferImageCache.push_back({graphicBuffer->getId(), image});
930 }
931 }
932
933 if (image != EGL_NO_IMAGE_KHR) {
934 DEBUG_EGL_IMAGE_TRACKER_CREATE();
935 }
936 return image;
937 }
938
drawLayers(const DisplaySettings & display,const std::vector<LayerSettings> & layers,ANativeWindowBuffer * const buffer,const bool useFramebufferCache,base::unique_fd && bufferFence,base::unique_fd * drawFence)939 status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
940 const std::vector<LayerSettings>& layers,
941 ANativeWindowBuffer* const buffer,
942 const bool useFramebufferCache, base::unique_fd&& bufferFence,
943 base::unique_fd* drawFence) {
944 ATRACE_CALL();
945 if (layers.empty()) {
946 ALOGV("Drawing empty layer stack");
947 return NO_ERROR;
948 }
949
950 if (bufferFence.get() >= 0 && !waitFence(std::move(bufferFence))) {
951 ATRACE_NAME("Waiting before draw");
952 sync_wait(bufferFence.get(), -1);
953 }
954
955 if (buffer == nullptr) {
956 ALOGE("No output buffer provided. Aborting GPU composition.");
957 return BAD_VALUE;
958 }
959
960 BindNativeBufferAsFramebuffer fbo(*this, buffer, useFramebufferCache);
961
962 if (fbo.getStatus() != NO_ERROR) {
963 ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
964 buffer->handle);
965 checkErrors();
966 return fbo.getStatus();
967 }
968
969 // clear the entire buffer, sometimes when we reuse buffers we'd persist
970 // ghost images otherwise.
971 // we also require a full transparent framebuffer for overlays. This is
972 // probably not quite efficient on all GPUs, since we could filter out
973 // opaque layers.
974 clearWithColor(0.0, 0.0, 0.0, 0.0);
975
976 setViewportAndProjection(display.physicalDisplay, display.clip);
977
978 setOutputDataSpace(display.outputDataspace);
979 setDisplayMaxLuminance(display.maxLuminance);
980
981 mat4 projectionMatrix = mState.projectionMatrix * display.globalTransform;
982 mState.projectionMatrix = projectionMatrix;
983 if (!display.clearRegion.isEmpty()) {
984 glDisable(GL_BLEND);
985 fillRegionWithColor(display.clearRegion, 0.0, 0.0, 0.0, 1.0);
986 }
987
988 Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2, 2);
989 for (auto layer : layers) {
990 mState.projectionMatrix = projectionMatrix * layer.geometry.positionTransform;
991
992 const FloatRect bounds = layer.geometry.boundaries;
993 Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
994 position[0] = vec2(bounds.left, bounds.top);
995 position[1] = vec2(bounds.left, bounds.bottom);
996 position[2] = vec2(bounds.right, bounds.bottom);
997 position[3] = vec2(bounds.right, bounds.top);
998
999 setupLayerCropping(layer, mesh);
1000 setColorTransform(display.colorTransform * layer.colorTransform);
1001
1002 bool usePremultipliedAlpha = true;
1003 bool disableTexture = true;
1004 bool isOpaque = false;
1005
1006 if (layer.source.buffer.buffer != nullptr) {
1007 disableTexture = false;
1008 isOpaque = layer.source.buffer.isOpaque;
1009
1010 sp<GraphicBuffer> gBuf = layer.source.buffer.buffer;
1011 bindExternalTextureBuffer(layer.source.buffer.textureName, gBuf,
1012 layer.source.buffer.fence);
1013
1014 usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha;
1015 Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName);
1016 mat4 texMatrix = layer.source.buffer.textureTransform;
1017
1018 texture.setMatrix(texMatrix.asArray());
1019 texture.setFiltering(layer.source.buffer.useTextureFiltering);
1020
1021 texture.setDimensions(gBuf->getWidth(), gBuf->getHeight());
1022 setSourceY410BT2020(layer.source.buffer.isY410BT2020);
1023
1024 renderengine::Mesh::VertexArray<vec2> texCoords(mesh.getTexCoordArray<vec2>());
1025 texCoords[0] = vec2(0.0, 0.0);
1026 texCoords[1] = vec2(0.0, 1.0);
1027 texCoords[2] = vec2(1.0, 1.0);
1028 texCoords[3] = vec2(1.0, 0.0);
1029 setupLayerTexturing(texture);
1030 }
1031
1032 const half3 solidColor = layer.source.solidColor;
1033 const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha);
1034 // Buffer sources will have a black solid color ignored in the shader,
1035 // so in that scenario the solid color passed here is arbitrary.
1036 setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color,
1037 layer.geometry.roundedCornersRadius);
1038 if (layer.disableBlending) {
1039 glDisable(GL_BLEND);
1040 }
1041 setSourceDataSpace(layer.sourceDataspace);
1042
1043 // We only want to do a special handling for rounded corners when having rounded corners
1044 // is the only reason it needs to turn on blending, otherwise, we handle it like the
1045 // usual way since it needs to turn on blending anyway.
1046 if (layer.geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) {
1047 handleRoundedCorners(display, layer, mesh);
1048 } else {
1049 drawMesh(mesh);
1050 }
1051
1052 // Cleanup if there's a buffer source
1053 if (layer.source.buffer.buffer != nullptr) {
1054 disableBlending();
1055 setSourceY410BT2020(false);
1056 disableTexturing();
1057 }
1058 }
1059
1060 if (drawFence != nullptr) {
1061 *drawFence = flush();
1062 }
1063 // If flush failed or we don't support native fences, we need to force the
1064 // gl command stream to be executed.
1065 if (drawFence == nullptr || drawFence->get() < 0) {
1066 bool success = finish();
1067 if (!success) {
1068 ALOGE("Failed to flush RenderEngine commands");
1069 checkErrors();
1070 // Chances are, something illegal happened (either the caller passed
1071 // us bad parameters, or we messed up our shader generation).
1072 return INVALID_OPERATION;
1073 }
1074 }
1075
1076 checkErrors();
1077 return NO_ERROR;
1078 }
1079
setViewportAndProjection(size_t vpw,size_t vph,Rect sourceCrop,ui::Transform::orientation_flags rotation)1080 void GLESRenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
1081 ui::Transform::orientation_flags rotation) {
1082 setViewportAndProjection(Rect(vpw, vph), sourceCrop);
1083
1084 if (rotation == ui::Transform::ROT_0) {
1085 return;
1086 }
1087
1088 // Apply custom rotation to the projection.
1089 float rot90InRadians = 2.0f * static_cast<float>(M_PI) / 4.0f;
1090 mat4 m = mState.projectionMatrix;
1091 switch (rotation) {
1092 case ui::Transform::ROT_90:
1093 m = mat4::rotate(rot90InRadians, vec3(0, 0, 1)) * m;
1094 break;
1095 case ui::Transform::ROT_180:
1096 m = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1)) * m;
1097 break;
1098 case ui::Transform::ROT_270:
1099 m = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1)) * m;
1100 break;
1101 default:
1102 break;
1103 }
1104 mState.projectionMatrix = m;
1105 }
1106
setViewportAndProjection(Rect viewport,Rect clip)1107 void GLESRenderEngine::setViewportAndProjection(Rect viewport, Rect clip) {
1108 ATRACE_CALL();
1109 mVpWidth = viewport.getWidth();
1110 mVpHeight = viewport.getHeight();
1111
1112 // We pass the the top left corner instead of the bottom left corner,
1113 // because since we're rendering off-screen first.
1114 glViewport(viewport.left, viewport.top, mVpWidth, mVpHeight);
1115
1116 mState.projectionMatrix = mat4::ortho(clip.left, clip.right, clip.top, clip.bottom, 0, 1);
1117 }
1118
setupLayerBlending(bool premultipliedAlpha,bool opaque,bool disableTexture,const half4 & color,float cornerRadius)1119 void GLESRenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
1120 const half4& color, float cornerRadius) {
1121 mState.isPremultipliedAlpha = premultipliedAlpha;
1122 mState.isOpaque = opaque;
1123 mState.color = color;
1124 mState.cornerRadius = cornerRadius;
1125
1126 if (disableTexture) {
1127 mState.textureEnabled = false;
1128 }
1129
1130 if (color.a < 1.0f || !opaque || cornerRadius > 0.0f) {
1131 glEnable(GL_BLEND);
1132 glBlendFunc(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1133 } else {
1134 glDisable(GL_BLEND);
1135 }
1136 }
1137
setSourceY410BT2020(bool enable)1138 void GLESRenderEngine::setSourceY410BT2020(bool enable) {
1139 mState.isY410BT2020 = enable;
1140 }
1141
setSourceDataSpace(Dataspace source)1142 void GLESRenderEngine::setSourceDataSpace(Dataspace source) {
1143 mDataSpace = source;
1144 }
1145
setOutputDataSpace(Dataspace dataspace)1146 void GLESRenderEngine::setOutputDataSpace(Dataspace dataspace) {
1147 mOutputDataSpace = dataspace;
1148 }
1149
setDisplayMaxLuminance(const float maxLuminance)1150 void GLESRenderEngine::setDisplayMaxLuminance(const float maxLuminance) {
1151 mState.displayMaxLuminance = maxLuminance;
1152 }
1153
setupLayerTexturing(const Texture & texture)1154 void GLESRenderEngine::setupLayerTexturing(const Texture& texture) {
1155 GLuint target = texture.getTextureTarget();
1156 glBindTexture(target, texture.getTextureName());
1157 GLenum filter = GL_NEAREST;
1158 if (texture.getFiltering()) {
1159 filter = GL_LINEAR;
1160 }
1161 glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1162 glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1163 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
1164 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);
1165
1166 mState.texture = texture;
1167 mState.textureEnabled = true;
1168 }
1169
setupLayerBlackedOut()1170 void GLESRenderEngine::setupLayerBlackedOut() {
1171 glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
1172 Texture texture(Texture::TEXTURE_2D, mProtectedTexName);
1173 texture.setDimensions(1, 1); // FIXME: we should get that from somewhere
1174 mState.texture = texture;
1175 mState.textureEnabled = true;
1176 }
1177
setColorTransform(const mat4 & colorTransform)1178 void GLESRenderEngine::setColorTransform(const mat4& colorTransform) {
1179 mState.colorMatrix = colorTransform;
1180 }
1181
disableTexturing()1182 void GLESRenderEngine::disableTexturing() {
1183 mState.textureEnabled = false;
1184 }
1185
disableBlending()1186 void GLESRenderEngine::disableBlending() {
1187 glDisable(GL_BLEND);
1188 }
1189
setupFillWithColor(float r,float g,float b,float a)1190 void GLESRenderEngine::setupFillWithColor(float r, float g, float b, float a) {
1191 mState.isPremultipliedAlpha = true;
1192 mState.isOpaque = false;
1193 mState.color = half4(r, g, b, a);
1194 mState.textureEnabled = false;
1195 glDisable(GL_BLEND);
1196 }
1197
setupCornerRadiusCropSize(float width,float height)1198 void GLESRenderEngine::setupCornerRadiusCropSize(float width, float height) {
1199 mState.cropSize = half2(width, height);
1200 }
1201
drawMesh(const Mesh & mesh)1202 void GLESRenderEngine::drawMesh(const Mesh& mesh) {
1203 ATRACE_CALL();
1204 if (mesh.getTexCoordsSize()) {
1205 glEnableVertexAttribArray(Program::texCoords);
1206 glVertexAttribPointer(Program::texCoords, mesh.getTexCoordsSize(), GL_FLOAT, GL_FALSE,
1207 mesh.getByteStride(), mesh.getTexCoords());
1208 }
1209
1210 glVertexAttribPointer(Program::position, mesh.getVertexSize(), GL_FLOAT, GL_FALSE,
1211 mesh.getByteStride(), mesh.getPositions());
1212
1213 if (mState.cornerRadius > 0.0f) {
1214 glEnableVertexAttribArray(Program::cropCoords);
1215 glVertexAttribPointer(Program::cropCoords, mesh.getVertexSize(), GL_FLOAT, GL_FALSE,
1216 mesh.getByteStride(), mesh.getCropCoords());
1217 }
1218
1219 // By default, DISPLAY_P3 is the only supported wide color output. However,
1220 // when HDR content is present, hardware composer may be able to handle
1221 // BT2020 data space, in that case, the output data space is set to be
1222 // BT2020_HLG or BT2020_PQ respectively. In GPU fall back we need
1223 // to respect this and convert non-HDR content to HDR format.
1224 if (mUseColorManagement) {
1225 Description managedState = mState;
1226 Dataspace inputStandard = static_cast<Dataspace>(mDataSpace & Dataspace::STANDARD_MASK);
1227 Dataspace inputTransfer = static_cast<Dataspace>(mDataSpace & Dataspace::TRANSFER_MASK);
1228 Dataspace outputStandard =
1229 static_cast<Dataspace>(mOutputDataSpace & Dataspace::STANDARD_MASK);
1230 Dataspace outputTransfer =
1231 static_cast<Dataspace>(mOutputDataSpace & Dataspace::TRANSFER_MASK);
1232 bool needsXYZConversion = needsXYZTransformMatrix();
1233
1234 // NOTE: if the input standard of the input dataspace is not STANDARD_DCI_P3 or
1235 // STANDARD_BT2020, it will be treated as STANDARD_BT709
1236 if (inputStandard != Dataspace::STANDARD_DCI_P3 &&
1237 inputStandard != Dataspace::STANDARD_BT2020) {
1238 inputStandard = Dataspace::STANDARD_BT709;
1239 }
1240
1241 if (needsXYZConversion) {
1242 // The supported input color spaces are standard RGB, Display P3 and BT2020.
1243 switch (inputStandard) {
1244 case Dataspace::STANDARD_DCI_P3:
1245 managedState.inputTransformMatrix = mDisplayP3ToXyz;
1246 break;
1247 case Dataspace::STANDARD_BT2020:
1248 managedState.inputTransformMatrix = mBt2020ToXyz;
1249 break;
1250 default:
1251 managedState.inputTransformMatrix = mSrgbToXyz;
1252 break;
1253 }
1254
1255 // The supported output color spaces are BT2020, Display P3 and standard RGB.
1256 switch (outputStandard) {
1257 case Dataspace::STANDARD_BT2020:
1258 managedState.outputTransformMatrix = mXyzToBt2020;
1259 break;
1260 case Dataspace::STANDARD_DCI_P3:
1261 managedState.outputTransformMatrix = mXyzToDisplayP3;
1262 break;
1263 default:
1264 managedState.outputTransformMatrix = mXyzToSrgb;
1265 break;
1266 }
1267 } else if (inputStandard != outputStandard) {
1268 // At this point, the input data space and output data space could be both
1269 // HDR data spaces, but they match each other, we do nothing in this case.
1270 // In addition to the case above, the input data space could be
1271 // - scRGB linear
1272 // - scRGB non-linear
1273 // - sRGB
1274 // - Display P3
1275 // - BT2020
1276 // The output data spaces could be
1277 // - sRGB
1278 // - Display P3
1279 // - BT2020
1280 switch (outputStandard) {
1281 case Dataspace::STANDARD_BT2020:
1282 if (inputStandard == Dataspace::STANDARD_BT709) {
1283 managedState.outputTransformMatrix = mSrgbToBt2020;
1284 } else if (inputStandard == Dataspace::STANDARD_DCI_P3) {
1285 managedState.outputTransformMatrix = mDisplayP3ToBt2020;
1286 }
1287 break;
1288 case Dataspace::STANDARD_DCI_P3:
1289 if (inputStandard == Dataspace::STANDARD_BT709) {
1290 managedState.outputTransformMatrix = mSrgbToDisplayP3;
1291 } else if (inputStandard == Dataspace::STANDARD_BT2020) {
1292 managedState.outputTransformMatrix = mBt2020ToDisplayP3;
1293 }
1294 break;
1295 default:
1296 if (inputStandard == Dataspace::STANDARD_DCI_P3) {
1297 managedState.outputTransformMatrix = mDisplayP3ToSrgb;
1298 } else if (inputStandard == Dataspace::STANDARD_BT2020) {
1299 managedState.outputTransformMatrix = mBt2020ToSrgb;
1300 }
1301 break;
1302 }
1303 }
1304
1305 // we need to convert the RGB value to linear space and convert it back when:
1306 // - there is a color matrix that is not an identity matrix, or
1307 // - there is an output transform matrix that is not an identity matrix, or
1308 // - the input transfer function doesn't match the output transfer function.
1309 if (managedState.hasColorMatrix() || managedState.hasOutputTransformMatrix() ||
1310 inputTransfer != outputTransfer) {
1311 managedState.inputTransferFunction =
1312 Description::dataSpaceToTransferFunction(inputTransfer);
1313 managedState.outputTransferFunction =
1314 Description::dataSpaceToTransferFunction(outputTransfer);
1315 }
1316
1317 ProgramCache::getInstance().useProgram(mInProtectedContext ? mProtectedEGLContext
1318 : mEGLContext,
1319 managedState);
1320
1321 glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
1322
1323 if (outputDebugPPMs) {
1324 static uint64_t managedColorFrameCount = 0;
1325 std::ostringstream out;
1326 out << "/data/texture_out" << managedColorFrameCount++;
1327 writePPM(out.str().c_str(), mVpWidth, mVpHeight);
1328 }
1329 } else {
1330 ProgramCache::getInstance().useProgram(mInProtectedContext ? mProtectedEGLContext
1331 : mEGLContext,
1332 mState);
1333
1334 glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
1335 }
1336
1337 if (mesh.getTexCoordsSize()) {
1338 glDisableVertexAttribArray(Program::texCoords);
1339 }
1340
1341 if (mState.cornerRadius > 0.0f) {
1342 glDisableVertexAttribArray(Program::cropCoords);
1343 }
1344 }
1345
getMaxTextureSize() const1346 size_t GLESRenderEngine::getMaxTextureSize() const {
1347 return mMaxTextureSize;
1348 }
1349
getMaxViewportDims() const1350 size_t GLESRenderEngine::getMaxViewportDims() const {
1351 return mMaxViewportDims[0] < mMaxViewportDims[1] ? mMaxViewportDims[0] : mMaxViewportDims[1];
1352 }
1353
dump(std::string & result)1354 void GLESRenderEngine::dump(std::string& result) {
1355 const GLExtensions& extensions = GLExtensions::getInstance();
1356 ProgramCache& cache = ProgramCache::getInstance();
1357
1358 StringAppendF(&result, "EGL implementation : %s\n", extensions.getEGLVersion());
1359 StringAppendF(&result, "%s\n", extensions.getEGLExtensions());
1360 StringAppendF(&result, "GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
1361 extensions.getVersion());
1362 StringAppendF(&result, "%s\n", extensions.getExtensions());
1363 StringAppendF(&result, "RenderEngine supports protected context: %d\n",
1364 supportsProtectedContent());
1365 StringAppendF(&result, "RenderEngine is in protected context: %d\n", mInProtectedContext);
1366 StringAppendF(&result, "RenderEngine program cache size for unprotected context: %zu\n",
1367 cache.getSize(mEGLContext));
1368 StringAppendF(&result, "RenderEngine program cache size for protected context: %zu\n",
1369 cache.getSize(mProtectedEGLContext));
1370 StringAppendF(&result, "RenderEngine last dataspace conversion: (%s) to (%s)\n",
1371 dataspaceDetails(static_cast<android_dataspace>(mDataSpace)).c_str(),
1372 dataspaceDetails(static_cast<android_dataspace>(mOutputDataSpace)).c_str());
1373 {
1374 std::lock_guard<std::mutex> lock(mRenderingMutex);
1375 StringAppendF(&result, "RenderEngine image cache size: %zu\n", mImageCache.size());
1376 StringAppendF(&result, "Dumping buffer ids...\n");
1377 for (const auto& [id, unused] : mImageCache) {
1378 StringAppendF(&result, "0x%" PRIx64 "\n", id);
1379 }
1380 }
1381 {
1382 std::lock_guard<std::mutex> lock(mFramebufferImageCacheMutex);
1383 StringAppendF(&result, "RenderEngine framebuffer image cache size: %zu\n",
1384 mFramebufferImageCache.size());
1385 StringAppendF(&result, "Dumping buffer ids...\n");
1386 for (const auto& [id, unused] : mFramebufferImageCache) {
1387 StringAppendF(&result, "0x%" PRIx64 "\n", id);
1388 }
1389 }
1390 }
1391
parseGlesVersion(const char * str)1392 GLESRenderEngine::GlesVersion GLESRenderEngine::parseGlesVersion(const char* str) {
1393 int major, minor;
1394 if (sscanf(str, "OpenGL ES-CM %d.%d", &major, &minor) != 2) {
1395 if (sscanf(str, "OpenGL ES %d.%d", &major, &minor) != 2) {
1396 ALOGW("Unable to parse GL_VERSION string: \"%s\"", str);
1397 return GLES_VERSION_1_0;
1398 }
1399 }
1400
1401 if (major == 1 && minor == 0) return GLES_VERSION_1_0;
1402 if (major == 1 && minor >= 1) return GLES_VERSION_1_1;
1403 if (major == 2 && minor >= 0) return GLES_VERSION_2_0;
1404 if (major == 3 && minor >= 0) return GLES_VERSION_3_0;
1405
1406 ALOGW("Unrecognized OpenGL ES version: %d.%d", major, minor);
1407 return GLES_VERSION_1_0;
1408 }
1409
createEglContext(EGLDisplay display,EGLConfig config,EGLContext shareContext,bool useContextPriority,Protection protection)1410 EGLContext GLESRenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
1411 EGLContext shareContext, bool useContextPriority,
1412 Protection protection) {
1413 EGLint renderableType = 0;
1414 if (config == EGL_NO_CONFIG) {
1415 renderableType = EGL_OPENGL_ES3_BIT;
1416 } else if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType)) {
1417 LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE");
1418 }
1419 EGLint contextClientVersion = 0;
1420 if (renderableType & EGL_OPENGL_ES3_BIT) {
1421 contextClientVersion = 3;
1422 } else if (renderableType & EGL_OPENGL_ES2_BIT) {
1423 contextClientVersion = 2;
1424 } else if (renderableType & EGL_OPENGL_ES_BIT) {
1425 contextClientVersion = 1;
1426 } else {
1427 LOG_ALWAYS_FATAL("no supported EGL_RENDERABLE_TYPEs");
1428 }
1429
1430 std::vector<EGLint> contextAttributes;
1431 contextAttributes.reserve(7);
1432 contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
1433 contextAttributes.push_back(contextClientVersion);
1434 if (useContextPriority) {
1435 contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
1436 contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
1437 }
1438 if (protection == Protection::PROTECTED) {
1439 contextAttributes.push_back(EGL_PROTECTED_CONTENT_EXT);
1440 contextAttributes.push_back(EGL_TRUE);
1441 }
1442 contextAttributes.push_back(EGL_NONE);
1443
1444 EGLContext context = eglCreateContext(display, config, shareContext, contextAttributes.data());
1445
1446 if (contextClientVersion == 3 && context == EGL_NO_CONTEXT) {
1447 // eglGetConfigAttrib indicated we can create GLES 3 context, but we failed, thus
1448 // EGL_NO_CONTEXT so that we can abort.
1449 if (config != EGL_NO_CONFIG) {
1450 return context;
1451 }
1452 // If |config| is EGL_NO_CONFIG, we speculatively try to create GLES 3 context, so we should
1453 // try to fall back to GLES 2.
1454 contextAttributes[1] = 2;
1455 context = eglCreateContext(display, config, shareContext, contextAttributes.data());
1456 }
1457
1458 return context;
1459 }
1460
createDummyEglPbufferSurface(EGLDisplay display,EGLConfig config,int hwcFormat,Protection protection)1461 EGLSurface GLESRenderEngine::createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config,
1462 int hwcFormat, Protection protection) {
1463 EGLConfig dummyConfig = config;
1464 if (dummyConfig == EGL_NO_CONFIG) {
1465 dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
1466 }
1467 std::vector<EGLint> attributes;
1468 attributes.reserve(7);
1469 attributes.push_back(EGL_WIDTH);
1470 attributes.push_back(1);
1471 attributes.push_back(EGL_HEIGHT);
1472 attributes.push_back(1);
1473 if (protection == Protection::PROTECTED) {
1474 attributes.push_back(EGL_PROTECTED_CONTENT_EXT);
1475 attributes.push_back(EGL_TRUE);
1476 }
1477 attributes.push_back(EGL_NONE);
1478
1479 return eglCreatePbufferSurface(display, dummyConfig, attributes.data());
1480 }
1481
isHdrDataSpace(const Dataspace dataSpace) const1482 bool GLESRenderEngine::isHdrDataSpace(const Dataspace dataSpace) const {
1483 const Dataspace standard = static_cast<Dataspace>(dataSpace & Dataspace::STANDARD_MASK);
1484 const Dataspace transfer = static_cast<Dataspace>(dataSpace & Dataspace::TRANSFER_MASK);
1485 return standard == Dataspace::STANDARD_BT2020 &&
1486 (transfer == Dataspace::TRANSFER_ST2084 || transfer == Dataspace::TRANSFER_HLG);
1487 }
1488
1489 // For convenience, we want to convert the input color space to XYZ color space first,
1490 // and then convert from XYZ color space to output color space when
1491 // - SDR and HDR contents are mixed, either SDR content will be converted to HDR or
1492 // HDR content will be tone-mapped to SDR; Or,
1493 // - there are HDR PQ and HLG contents presented at the same time, where we want to convert
1494 // HLG content to PQ content.
1495 // In either case above, we need to operate the Y value in XYZ color space. Thus, when either
1496 // input data space or output data space is HDR data space, and the input transfer function
1497 // doesn't match the output transfer function, we would enable an intermediate transfrom to
1498 // XYZ color space.
needsXYZTransformMatrix() const1499 bool GLESRenderEngine::needsXYZTransformMatrix() const {
1500 const bool isInputHdrDataSpace = isHdrDataSpace(mDataSpace);
1501 const bool isOutputHdrDataSpace = isHdrDataSpace(mOutputDataSpace);
1502 const Dataspace inputTransfer = static_cast<Dataspace>(mDataSpace & Dataspace::TRANSFER_MASK);
1503 const Dataspace outputTransfer =
1504 static_cast<Dataspace>(mOutputDataSpace & Dataspace::TRANSFER_MASK);
1505
1506 return (isInputHdrDataSpace || isOutputHdrDataSpace) && inputTransfer != outputTransfer;
1507 }
1508
isImageCachedForTesting(uint64_t bufferId)1509 bool GLESRenderEngine::isImageCachedForTesting(uint64_t bufferId) {
1510 std::lock_guard<std::mutex> lock(mRenderingMutex);
1511 const auto& cachedImage = mImageCache.find(bufferId);
1512 return cachedImage != mImageCache.end();
1513 }
1514
isFramebufferImageCachedForTesting(uint64_t bufferId)1515 bool GLESRenderEngine::isFramebufferImageCachedForTesting(uint64_t bufferId) {
1516 std::lock_guard<std::mutex> lock(mFramebufferImageCacheMutex);
1517 return std::any_of(mFramebufferImageCache.cbegin(), mFramebufferImageCache.cend(),
1518 [=](std::pair<uint64_t, EGLImageKHR> image) {
1519 return image.first == bufferId;
1520 });
1521 }
1522
1523 // FlushTracer implementation
FlushTracer(GLESRenderEngine * engine)1524 GLESRenderEngine::FlushTracer::FlushTracer(GLESRenderEngine* engine) : mEngine(engine) {
1525 mThread = std::thread(&GLESRenderEngine::FlushTracer::loop, this);
1526 }
1527
~FlushTracer()1528 GLESRenderEngine::FlushTracer::~FlushTracer() {
1529 {
1530 std::lock_guard<std::mutex> lock(mMutex);
1531 mRunning = false;
1532 }
1533 mCondition.notify_all();
1534 if (mThread.joinable()) {
1535 mThread.join();
1536 }
1537 }
1538
queueSync(EGLSyncKHR sync)1539 void GLESRenderEngine::FlushTracer::queueSync(EGLSyncKHR sync) {
1540 std::lock_guard<std::mutex> lock(mMutex);
1541 char name[64];
1542 const uint64_t frameNum = mFramesQueued++;
1543 snprintf(name, sizeof(name), "Queueing sync for frame: %lu",
1544 static_cast<unsigned long>(frameNum));
1545 ATRACE_NAME(name);
1546 mQueue.push({sync, frameNum});
1547 ATRACE_INT("GPU Frames Outstanding", mQueue.size());
1548 mCondition.notify_one();
1549 }
1550
loop()1551 void GLESRenderEngine::FlushTracer::loop() {
1552 while (mRunning) {
1553 QueueEntry entry;
1554 {
1555 std::lock_guard<std::mutex> lock(mMutex);
1556
1557 mCondition.wait(mMutex,
1558 [&]() REQUIRES(mMutex) { return !mQueue.empty() || !mRunning; });
1559
1560 if (!mRunning) {
1561 // if mRunning is false, then FlushTracer is being destroyed, so
1562 // bail out now.
1563 break;
1564 }
1565 entry = mQueue.front();
1566 mQueue.pop();
1567 }
1568 {
1569 char name[64];
1570 snprintf(name, sizeof(name), "waiting for frame %lu",
1571 static_cast<unsigned long>(entry.mFrameNum));
1572 ATRACE_NAME(name);
1573 mEngine->waitSync(entry.mSync, 0);
1574 }
1575 }
1576 }
1577
1578 } // namespace gl
1579 } // namespace renderengine
1580 } // namespace android
1581