1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "EglManager.h"
18
19 #include <EGL/eglext.h>
20 #include <GLES/gl.h>
21 #include <cutils/properties.h>
22 #include <graphicsenv/GpuStatsInfo.h>
23 #include <log/log.h>
24 #include <sync/sync.h>
25 #include <utils/Trace.h>
26
27 #include <string>
28 #include <vector>
29
30 #include "Frame.h"
31 #include "Properties.h"
32 #include "RenderEffectCapabilityQuery.h"
33 #include "utils/Color.h"
34 #include "utils/StringUtils.h"
35
36 #define GLES_VERSION 2
37
38 // Android-specific addition that is used to show when frames began in systrace
39 EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
40
41 static constexpr auto P3_XRB = static_cast<android_dataspace>(
42 ADATASPACE_STANDARD_DCI_P3 | ADATASPACE_TRANSFER_SRGB | ADATASPACE_RANGE_EXTENDED);
43
44 namespace android {
45 namespace uirenderer {
46 namespace renderthread {
47
48 #define ERROR_CASE(x) \
49 case x: \
50 return #x;
egl_error_str(EGLint error)51 static const char* egl_error_str(EGLint error) {
52 switch (error) {
53 ERROR_CASE(EGL_SUCCESS)
54 ERROR_CASE(EGL_NOT_INITIALIZED)
55 ERROR_CASE(EGL_BAD_ACCESS)
56 ERROR_CASE(EGL_BAD_ALLOC)
57 ERROR_CASE(EGL_BAD_ATTRIBUTE)
58 ERROR_CASE(EGL_BAD_CONFIG)
59 ERROR_CASE(EGL_BAD_CONTEXT)
60 ERROR_CASE(EGL_BAD_CURRENT_SURFACE)
61 ERROR_CASE(EGL_BAD_DISPLAY)
62 ERROR_CASE(EGL_BAD_MATCH)
63 ERROR_CASE(EGL_BAD_NATIVE_PIXMAP)
64 ERROR_CASE(EGL_BAD_NATIVE_WINDOW)
65 ERROR_CASE(EGL_BAD_PARAMETER)
66 ERROR_CASE(EGL_BAD_SURFACE)
67 ERROR_CASE(EGL_CONTEXT_LOST)
68 default:
69 return "Unknown error";
70 }
71 }
eglErrorString()72 const char* EglManager::eglErrorString() {
73 return egl_error_str(eglGetError());
74 }
75
76 static struct {
77 bool bufferAge = false;
78 bool setDamage = false;
79 bool noConfigContext = false;
80 bool pixelFormatFloat = false;
81 bool glColorSpace = false;
82 bool scRGB = false;
83 bool displayP3 = false;
84 bool hdr = false;
85 bool contextPriority = false;
86 bool surfacelessContext = false;
87 bool nativeFenceSync = false;
88 bool fenceSync = false;
89 bool waitSync = false;
90 } EglExtensions;
91
EglManager()92 EglManager::EglManager()
93 : mEglDisplay(EGL_NO_DISPLAY)
94 , mEglConfig(nullptr)
95 , mEglConfigF16(nullptr)
96 , mEglConfig1010102(nullptr)
97 , mEglConfigA8(nullptr)
98 , mEglContext(EGL_NO_CONTEXT)
99 , mPBufferSurface(EGL_NO_SURFACE)
100 , mCurrentSurface(EGL_NO_SURFACE)
101 , mHasWideColorGamutSupport(false) {}
102
~EglManager()103 EglManager::~EglManager() {
104 if (hasEglContext()) {
105 ALOGW("~EglManager() leaked an EGL context");
106 }
107 }
108
initialize()109 void EglManager::initialize() {
110 if (hasEglContext()) return;
111
112 ATRACE_NAME("Creating EGLContext");
113
114 mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
115 LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
116 eglErrorString());
117
118 EGLint major, minor;
119 LOG_ALWAYS_FATAL_IF(eglInitialize(mEglDisplay, &major, &minor) == EGL_FALSE,
120 "Failed to initialize display %p! err=%s", mEglDisplay, eglErrorString());
121
122 ALOGV("Initialized EGL, version %d.%d", (int)major, (int)minor);
123
124 initExtensions();
125
126 // Now that extensions are loaded, pick a swap behavior
127 if (Properties::enablePartialUpdates) {
128 // An Adreno driver bug is causing rendering problems for SkiaGL with
129 // buffer age swap behavior (b/31957043). To temporarily workaround,
130 // we will use preserved swap behavior.
131 if (Properties::useBufferAge && EglExtensions.bufferAge) {
132 mSwapBehavior = SwapBehavior::BufferAge;
133 } else {
134 mSwapBehavior = SwapBehavior::Preserved;
135 }
136 }
137
138 loadConfigs();
139 createContext();
140 createPBufferSurface();
141 makeCurrent(mPBufferSurface, nullptr, /* force */ true);
142
143 skcms_Matrix3x3 wideColorGamut;
144 LOG_ALWAYS_FATAL_IF(!DeviceInfo::get()->getWideColorSpace()->toXYZD50(&wideColorGamut),
145 "Could not get gamut matrix from wideColorSpace");
146 bool hasWideColorSpaceExtension = false;
147 if (memcmp(&wideColorGamut, &SkNamedGamut::kDisplayP3, sizeof(wideColorGamut)) == 0) {
148 hasWideColorSpaceExtension = EglExtensions.displayP3;
149 } else if (memcmp(&wideColorGamut, &SkNamedGamut::kSRGB, sizeof(wideColorGamut)) == 0) {
150 hasWideColorSpaceExtension = EglExtensions.scRGB;
151 } else {
152 LOG_ALWAYS_FATAL("Unsupported wide color space.");
153 }
154 mHasWideColorGamutSupport = EglExtensions.glColorSpace && hasWideColorSpaceExtension;
155
156 auto* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
157 auto* version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
158 Properties::enableRenderEffectCache = supportsRenderEffectCache(
159 vendor, version);
160 ALOGV("RenderEffectCache supported %d on driver version %s",
161 Properties::enableRenderEffectCache, version);
162 }
163
load8BitsConfig(EGLDisplay display,EglManager::SwapBehavior swapBehavior)164 EGLConfig EglManager::load8BitsConfig(EGLDisplay display, EglManager::SwapBehavior swapBehavior) {
165 EGLint eglSwapBehavior =
166 (swapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
167 EGLint attribs[] = {EGL_RENDERABLE_TYPE,
168 EGL_OPENGL_ES2_BIT,
169 EGL_RED_SIZE,
170 8,
171 EGL_GREEN_SIZE,
172 8,
173 EGL_BLUE_SIZE,
174 8,
175 EGL_ALPHA_SIZE,
176 8,
177 EGL_DEPTH_SIZE,
178 0,
179 EGL_CONFIG_CAVEAT,
180 EGL_NONE,
181 EGL_STENCIL_SIZE,
182 STENCIL_BUFFER_SIZE,
183 EGL_SURFACE_TYPE,
184 EGL_WINDOW_BIT | eglSwapBehavior,
185 EGL_NONE};
186 EGLConfig config = EGL_NO_CONFIG_KHR;
187 EGLint numConfigs = 1;
188 if (!eglChooseConfig(display, attribs, &config, numConfigs, &numConfigs) || numConfigs != 1) {
189 return EGL_NO_CONFIG_KHR;
190 }
191 return config;
192 }
193
load1010102Config(EGLDisplay display,SwapBehavior swapBehavior)194 EGLConfig EglManager::load1010102Config(EGLDisplay display, SwapBehavior swapBehavior) {
195 EGLint eglSwapBehavior =
196 (swapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
197 // If we reached this point, we have a valid swap behavior
198 EGLint attribs[] = {EGL_RENDERABLE_TYPE,
199 EGL_OPENGL_ES2_BIT,
200 EGL_RED_SIZE,
201 10,
202 EGL_GREEN_SIZE,
203 10,
204 EGL_BLUE_SIZE,
205 10,
206 EGL_ALPHA_SIZE,
207 2,
208 EGL_DEPTH_SIZE,
209 0,
210 EGL_STENCIL_SIZE,
211 STENCIL_BUFFER_SIZE,
212 EGL_SURFACE_TYPE,
213 EGL_WINDOW_BIT | eglSwapBehavior,
214 EGL_NONE};
215 EGLConfig config = EGL_NO_CONFIG_KHR;
216 EGLint numConfigs = 1;
217 if (!eglChooseConfig(display, attribs, &config, numConfigs, &numConfigs) || numConfigs != 1) {
218 return EGL_NO_CONFIG_KHR;
219 }
220 return config;
221 }
222
loadFP16Config(EGLDisplay display,SwapBehavior swapBehavior)223 EGLConfig EglManager::loadFP16Config(EGLDisplay display, SwapBehavior swapBehavior) {
224 EGLint eglSwapBehavior =
225 (swapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
226 // If we reached this point, we have a valid swap behavior
227 EGLint attribs[] = {EGL_RENDERABLE_TYPE,
228 EGL_OPENGL_ES2_BIT,
229 EGL_COLOR_COMPONENT_TYPE_EXT,
230 EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT,
231 EGL_RED_SIZE,
232 16,
233 EGL_GREEN_SIZE,
234 16,
235 EGL_BLUE_SIZE,
236 16,
237 EGL_ALPHA_SIZE,
238 16,
239 EGL_DEPTH_SIZE,
240 0,
241 EGL_STENCIL_SIZE,
242 STENCIL_BUFFER_SIZE,
243 EGL_SURFACE_TYPE,
244 EGL_WINDOW_BIT | eglSwapBehavior,
245 EGL_NONE};
246 EGLConfig config = EGL_NO_CONFIG_KHR;
247 EGLint numConfigs = 1;
248 if (!eglChooseConfig(display, attribs, &config, numConfigs, &numConfigs) || numConfigs != 1) {
249 return EGL_NO_CONFIG_KHR;
250 }
251 return config;
252 }
253
loadA8Config(EGLDisplay display,EglManager::SwapBehavior swapBehavior)254 EGLConfig EglManager::loadA8Config(EGLDisplay display, EglManager::SwapBehavior swapBehavior) {
255 EGLint eglSwapBehavior =
256 (swapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
257 EGLint attribs[] = {EGL_RENDERABLE_TYPE,
258 EGL_OPENGL_ES2_BIT,
259 EGL_RED_SIZE,
260 8,
261 EGL_GREEN_SIZE,
262 0,
263 EGL_BLUE_SIZE,
264 0,
265 EGL_ALPHA_SIZE,
266 0,
267 EGL_DEPTH_SIZE,
268 0,
269 EGL_SURFACE_TYPE,
270 EGL_WINDOW_BIT | eglSwapBehavior,
271 EGL_NONE};
272 EGLint numConfigs = 1;
273 if (!eglChooseConfig(display, attribs, nullptr, numConfigs, &numConfigs)) {
274 return EGL_NO_CONFIG_KHR;
275 }
276
277 std::vector<EGLConfig> configs(numConfigs, EGL_NO_CONFIG_KHR);
278 if (!eglChooseConfig(display, attribs, configs.data(), numConfigs, &numConfigs)) {
279 return EGL_NO_CONFIG_KHR;
280 }
281
282 // The component sizes passed to eglChooseConfig are minimums, so configs
283 // contains entries that exceed them. Choose one that matches the sizes
284 // exactly.
285 for (EGLConfig config : configs) {
286 EGLint r{0}, g{0}, b{0}, a{0};
287 eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r);
288 eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
289 eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b);
290 eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
291 if (8 == r && 0 == g && 0 == b && 0 == a) {
292 return config;
293 }
294 }
295 return EGL_NO_CONFIG_KHR;
296 }
297
initExtensions()298 void EglManager::initExtensions() {
299 auto extensions = StringUtils::split(eglQueryString(mEglDisplay, EGL_EXTENSIONS));
300
301 // For our purposes we don't care if EGL_BUFFER_AGE is a result of
302 // EGL_EXT_buffer_age or EGL_KHR_partial_update as our usage is covered
303 // under EGL_KHR_partial_update and we don't need the expanded scope
304 // that EGL_EXT_buffer_age provides.
305 EglExtensions.bufferAge =
306 extensions.has("EGL_EXT_buffer_age") || extensions.has("EGL_KHR_partial_update");
307 EglExtensions.setDamage = extensions.has("EGL_KHR_partial_update");
308 LOG_ALWAYS_FATAL_IF(!extensions.has("EGL_KHR_swap_buffers_with_damage"),
309 "Missing required extension EGL_KHR_swap_buffers_with_damage");
310
311 EglExtensions.glColorSpace = extensions.has("EGL_KHR_gl_colorspace");
312 EglExtensions.noConfigContext = extensions.has("EGL_KHR_no_config_context");
313 EglExtensions.pixelFormatFloat = extensions.has("EGL_EXT_pixel_format_float");
314 EglExtensions.scRGB = extensions.has("EGL_EXT_gl_colorspace_scrgb");
315 EglExtensions.displayP3 = extensions.has("EGL_EXT_gl_colorspace_display_p3_passthrough");
316 EglExtensions.hdr = extensions.has("EGL_EXT_gl_colorspace_bt2020_pq");
317 EglExtensions.contextPriority = extensions.has("EGL_IMG_context_priority");
318 EglExtensions.surfacelessContext = extensions.has("EGL_KHR_surfaceless_context");
319 EglExtensions.fenceSync = extensions.has("EGL_KHR_fence_sync");
320 EglExtensions.waitSync = extensions.has("EGL_KHR_wait_sync");
321 EglExtensions.nativeFenceSync = extensions.has("EGL_ANDROID_native_fence_sync");
322 }
323
hasEglContext()324 bool EglManager::hasEglContext() {
325 return mEglDisplay != EGL_NO_DISPLAY;
326 }
327
loadConfigs()328 void EglManager::loadConfigs() {
329 // Note: The default pixel format is RGBA_8888, when other formats are
330 // available, we should check the target pixel format and configure the
331 // attributes list properly.
332 mEglConfig = load8BitsConfig(mEglDisplay, mSwapBehavior);
333 if (mEglConfig == EGL_NO_CONFIG_KHR) {
334 if (mSwapBehavior == SwapBehavior::Preserved) {
335 // Try again without dirty regions enabled
336 ALOGW("Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...");
337 mSwapBehavior = SwapBehavior::Discard;
338 mEglConfig = load8BitsConfig(mEglDisplay, mSwapBehavior);
339 } else {
340 // Failed to get a valid config
341 LOG_ALWAYS_FATAL("Failed to choose config, error = %s", eglErrorString());
342 }
343 }
344
345 // When we reach this point, we have a valid swap behavior
346 if (EglExtensions.pixelFormatFloat) {
347 mEglConfigF16 = loadFP16Config(mEglDisplay, mSwapBehavior);
348 if (mEglConfigF16 == EGL_NO_CONFIG_KHR) {
349 ALOGE("Device claims wide gamut support, cannot find matching config, error = %s",
350 eglErrorString());
351 EglExtensions.pixelFormatFloat = false;
352 }
353 }
354 mEglConfig1010102 = load1010102Config(mEglDisplay, mSwapBehavior);
355 if (mEglConfig1010102 == EGL_NO_CONFIG_KHR) {
356 ALOGW("Failed to initialize 101010-2 format, error = %s",
357 eglErrorString());
358 }
359 }
360
createContext()361 void EglManager::createContext() {
362 std::vector<EGLint> contextAttributes;
363 contextAttributes.reserve(5);
364 contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
365 contextAttributes.push_back(GLES_VERSION);
366 if (Properties::contextPriority != 0 && EglExtensions.contextPriority) {
367 contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
368 contextAttributes.push_back(Properties::contextPriority);
369 }
370 if (Properties::skipTelemetry) {
371 contextAttributes.push_back(EGL_TELEMETRY_HINT_ANDROID);
372 contextAttributes.push_back(android::GpuStatsInfo::SKIP_TELEMETRY);
373 }
374 contextAttributes.push_back(EGL_NONE);
375 mEglContext = eglCreateContext(
376 mEglDisplay, EglExtensions.noConfigContext ? ((EGLConfig) nullptr) : mEglConfig,
377 EGL_NO_CONTEXT, contextAttributes.data());
378 LOG_ALWAYS_FATAL_IF(mEglContext == EGL_NO_CONTEXT, "Failed to create context, error = %s",
379 eglErrorString());
380 }
381
createPBufferSurface()382 void EglManager::createPBufferSurface() {
383 LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY,
384 "usePBufferSurface() called on uninitialized GlobalContext!");
385
386 if (mPBufferSurface == EGL_NO_SURFACE && !EglExtensions.surfacelessContext) {
387 EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
388 mPBufferSurface = eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs);
389 LOG_ALWAYS_FATAL_IF(mPBufferSurface == EGL_NO_SURFACE,
390 "Failed to create a pixel buffer display=%p, "
391 "mEglConfig=%p, error=%s",
392 mEglDisplay, mEglConfig, eglErrorString());
393 }
394 }
395
createSurface(EGLNativeWindowType window,ColorMode colorMode,sk_sp<SkColorSpace> colorSpace)396 Result<EGLSurface, EGLint> EglManager::createSurface(EGLNativeWindowType window,
397 ColorMode colorMode,
398 sk_sp<SkColorSpace> colorSpace) {
399 LOG_ALWAYS_FATAL_IF(!hasEglContext(), "Not initialized");
400
401 if (!EglExtensions.noConfigContext) {
402 // The caller shouldn't use A8 if we cannot switch modes.
403 LOG_ALWAYS_FATAL_IF(colorMode == ColorMode::A8,
404 "Cannot use A8 without EGL_KHR_no_config_context!");
405
406 // Cannot switch modes without EGL_KHR_no_config_context.
407 colorMode = ColorMode::Default;
408 }
409 // The color space we want to use depends on whether linear blending is turned
410 // on and whether the app has requested wide color gamut rendering. When wide
411 // color gamut rendering is off, the app simply renders in the display's native
412 // color gamut.
413 //
414 // When wide gamut rendering is off:
415 // - Blending is done by default in gamma space, which requires using a
416 // linear EGL color space (the GPU uses the color values as is)
417 // - If linear blending is on, we must use the non-linear EGL color space
418 // (the GPU will perform sRGB to linear and linear to SRGB conversions
419 // before and after blending)
420 //
421 // When wide gamut rendering is on we cannot rely on the GPU performing
422 // linear blending for us. We use two different color spaces to tag the
423 // surface appropriately for SurfaceFlinger:
424 // - Gamma blending (default) requires the use of the non-linear color space
425 // - Linear blending requires the use of the linear color space
426
427 // Not all Android targets support the EGL_GL_COLORSPACE_KHR extension
428 // We insert to placeholders to set EGL_GL_COLORSPACE_KHR and its value.
429 // According to section 3.4.1 of the EGL specification, the attributes
430 // list is considered empty if the first entry is EGL_NONE
431 EGLint attribs[] = {EGL_NONE, EGL_NONE, EGL_NONE};
432
433 EGLConfig config = mEglConfig;
434 bool overrideWindowDataSpaceForHdr = false;
435 if (colorMode == ColorMode::A8) {
436 // A8 doesn't use a color space
437 if (!mEglConfigA8) {
438 mEglConfigA8 = loadA8Config(mEglDisplay, mSwapBehavior);
439 LOG_ALWAYS_FATAL_IF(!mEglConfigA8,
440 "Requested ColorMode::A8, but EGL lacks support! error = %s",
441 eglErrorString());
442 }
443 config = mEglConfigA8;
444 } else {
445 if (!mHasWideColorGamutSupport) {
446 colorMode = ColorMode::Default;
447 }
448
449 // TODO: maybe we want to get rid of the WCG check if overlay properties just works?
450 bool canUseFp16 = DeviceInfo::get()->isSupportFp16ForHdr() ||
451 DeviceInfo::get()->getWideColorType() == kRGBA_F16_SkColorType;
452
453 if (colorMode == ColorMode::Hdr) {
454 if (canUseFp16 && !DeviceInfo::get()->isSupportRgba10101010ForHdr()) {
455 if (mEglConfigF16 == EGL_NO_CONFIG_KHR) {
456 // If the driver doesn't support fp16 then fallback to 8-bit
457 canUseFp16 = false;
458 } else {
459 config = mEglConfigF16;
460 }
461 }
462 }
463
464 if (EglExtensions.glColorSpace) {
465 attribs[0] = EGL_GL_COLORSPACE_KHR;
466 switch (colorMode) {
467 case ColorMode::Default:
468 attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
469 break;
470 case ColorMode::Hdr:
471 if (canUseFp16) {
472 attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT;
473 break;
474 // No fp16 support so fallthrough to HDR10
475 }
476 // We don't have an EGL colorspace for extended range P3 that's used for HDR
477 // So override it after configuring the EGL context
478 case ColorMode::Hdr10:
479 overrideWindowDataSpaceForHdr = true;
480 attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
481 break;
482 case ColorMode::WideColorGamut: {
483 skcms_Matrix3x3 colorGamut;
484 LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&colorGamut),
485 "Could not get gamut matrix from color space");
486 if (memcmp(&colorGamut, &SkNamedGamut::kDisplayP3, sizeof(colorGamut)) == 0) {
487 attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
488 } else if (memcmp(&colorGamut, &SkNamedGamut::kSRGB, sizeof(colorGamut)) == 0) {
489 attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT;
490 } else if (memcmp(&colorGamut, &SkNamedGamut::kRec2020, sizeof(colorGamut)) ==
491 0) {
492 attribs[1] = EGL_GL_COLORSPACE_BT2020_PQ_EXT;
493 } else {
494 LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
495 }
496 break;
497 }
498 case ColorMode::A8:
499 LOG_ALWAYS_FATAL("Unreachable: A8 doesn't use a color space");
500 break;
501 }
502 }
503 }
504
505 EGLSurface surface = eglCreateWindowSurface(mEglDisplay, config, window, attribs);
506 if (surface == EGL_NO_SURFACE) {
507 return Error<EGLint>{eglGetError()};
508 }
509
510 if (mSwapBehavior != SwapBehavior::Preserved) {
511 LOG_ALWAYS_FATAL_IF(eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR,
512 EGL_BUFFER_DESTROYED) == EGL_FALSE,
513 "Failed to set swap behavior to destroyed for window %p, eglErr = %s",
514 (void*)window, eglErrorString());
515 }
516
517 if (overrideWindowDataSpaceForHdr) {
518 // This relies on knowing that EGL will not re-set the dataspace after the call to
519 // eglCreateWindowSurface. Since the handling of the colorspace extension is largely
520 // implemented in libEGL in the platform, we can safely assume this is the case
521 int32_t err = ANativeWindow_setBuffersDataSpace(window, P3_XRB);
522 LOG_ALWAYS_FATAL_IF(err, "Failed to ANativeWindow_setBuffersDataSpace %d", err);
523 }
524
525 return surface;
526 }
527
destroySurface(EGLSurface surface)528 void EglManager::destroySurface(EGLSurface surface) {
529 if (isCurrent(surface)) {
530 makeCurrent(EGL_NO_SURFACE);
531 }
532 if (!eglDestroySurface(mEglDisplay, surface)) {
533 ALOGW("Failed to destroy surface %p, error=%s", (void*)surface, eglErrorString());
534 }
535 }
536
destroy()537 void EglManager::destroy() {
538 if (mEglDisplay == EGL_NO_DISPLAY) return;
539
540 eglDestroyContext(mEglDisplay, mEglContext);
541 if (mPBufferSurface != EGL_NO_SURFACE) {
542 eglDestroySurface(mEglDisplay, mPBufferSurface);
543 }
544 eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
545 eglTerminate(mEglDisplay);
546 eglReleaseThread();
547
548 mEglDisplay = EGL_NO_DISPLAY;
549 mEglContext = EGL_NO_CONTEXT;
550 mPBufferSurface = EGL_NO_SURFACE;
551 mCurrentSurface = EGL_NO_SURFACE;
552 }
553
makeCurrent(EGLSurface surface,EGLint * errOut,bool force)554 bool EglManager::makeCurrent(EGLSurface surface, EGLint* errOut, bool force) {
555 if (!force && isCurrent(surface)) return false;
556
557 if (surface == EGL_NO_SURFACE) {
558 // Ensure we always have a valid surface & context
559 surface = mPBufferSurface;
560 }
561 if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) {
562 if (errOut) {
563 *errOut = eglGetError();
564 ALOGW("Failed to make current on surface %p, error=%s", (void*)surface,
565 egl_error_str(*errOut));
566 } else {
567 LOG_ALWAYS_FATAL("Failed to make current on surface %p, error=%s", (void*)surface,
568 eglErrorString());
569 }
570 }
571 mCurrentSurface = surface;
572 if (Properties::disableVsync) {
573 eglSwapInterval(mEglDisplay, 0);
574 }
575 return true;
576 }
577
queryBufferAge(EGLSurface surface)578 EGLint EglManager::queryBufferAge(EGLSurface surface) {
579 switch (mSwapBehavior) {
580 case SwapBehavior::Discard:
581 return 0;
582 case SwapBehavior::Preserved:
583 return 1;
584 case SwapBehavior::BufferAge:
585 EGLint bufferAge;
586 eglQuerySurface(mEglDisplay, surface, EGL_BUFFER_AGE_EXT, &bufferAge);
587 return bufferAge;
588 }
589 return 0;
590 }
591
beginFrame(EGLSurface surface)592 Frame EglManager::beginFrame(EGLSurface surface) {
593 LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE, "Tried to beginFrame on EGL_NO_SURFACE!");
594 makeCurrent(surface);
595 Frame frame;
596 frame.mSurface = surface;
597 eglQuerySurface(mEglDisplay, surface, EGL_WIDTH, &frame.mWidth);
598 eglQuerySurface(mEglDisplay, surface, EGL_HEIGHT, &frame.mHeight);
599 frame.mBufferAge = queryBufferAge(surface);
600 eglBeginFrame(mEglDisplay, surface);
601 return frame;
602 }
603
damageFrame(const Frame & frame,const SkRect & dirty)604 void EglManager::damageFrame(const Frame& frame, const SkRect& dirty) {
605 #ifdef EGL_KHR_partial_update
606 if (EglExtensions.setDamage && mSwapBehavior == SwapBehavior::BufferAge) {
607 EGLint rects[4];
608 frame.map(dirty, rects);
609 if (!eglSetDamageRegionKHR(mEglDisplay, frame.mSurface, rects, 1)) {
610 LOG_ALWAYS_FATAL("Failed to set damage region on surface %p, error=%s",
611 (void*)frame.mSurface, eglErrorString());
612 }
613 }
614 #endif
615 }
616
damageRequiresSwap()617 bool EglManager::damageRequiresSwap() {
618 return EglExtensions.setDamage && mSwapBehavior == SwapBehavior::BufferAge;
619 }
620
swapBuffers(const Frame & frame,const SkRect & screenDirty)621 bool EglManager::swapBuffers(const Frame& frame, const SkRect& screenDirty) {
622 if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
623 ATRACE_NAME("Finishing GPU work");
624 fence();
625 }
626
627 EGLint rects[4];
628 frame.map(screenDirty, rects);
629 eglSwapBuffersWithDamageKHR(mEglDisplay, frame.mSurface, rects, screenDirty.isEmpty() ? 0 : 1);
630
631 EGLint err = eglGetError();
632 if (CC_LIKELY(err == EGL_SUCCESS)) {
633 return true;
634 }
635 if (err == EGL_BAD_SURFACE || err == EGL_BAD_NATIVE_WINDOW) {
636 // For some reason our surface was destroyed out from under us
637 // This really shouldn't happen, but if it does we can recover easily
638 // by just not trying to use the surface anymore
639 ALOGW("swapBuffers encountered EGL error %d on %p, halting rendering...", err,
640 frame.mSurface);
641 return false;
642 }
643 LOG_ALWAYS_FATAL("Encountered EGL error %d %s during rendering", err, egl_error_str(err));
644 // Impossible to hit this, but the compiler doesn't know that
645 return false;
646 }
647
fence()648 void EglManager::fence() {
649 EGLSyncKHR fence = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_FENCE_KHR, NULL);
650 eglClientWaitSyncKHR(mEglDisplay, fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR);
651 eglDestroySyncKHR(mEglDisplay, fence);
652 }
653
setPreserveBuffer(EGLSurface surface,bool preserve)654 bool EglManager::setPreserveBuffer(EGLSurface surface, bool preserve) {
655 if (mSwapBehavior != SwapBehavior::Preserved) return false;
656
657 bool preserved = eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR,
658 preserve ? EGL_BUFFER_PRESERVED : EGL_BUFFER_DESTROYED);
659 if (!preserved) {
660 ALOGW("Failed to set EGL_SWAP_BEHAVIOR on surface %p, error=%s", (void*)surface,
661 eglErrorString());
662 // Maybe it's already set?
663 EGLint swapBehavior;
664 if (eglQuerySurface(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, &swapBehavior)) {
665 preserved = (swapBehavior == EGL_BUFFER_PRESERVED);
666 } else {
667 ALOGW("Failed to query EGL_SWAP_BEHAVIOR on surface %p, error=%p", (void*)surface,
668 eglErrorString());
669 }
670 }
671
672 return preserved;
673 }
674
waitForeverOnFence(int fence,const char * logname)675 static status_t waitForeverOnFence(int fence, const char* logname) {
676 ATRACE_CALL();
677 if (fence == -1) {
678 return NO_ERROR;
679 }
680 constexpr int warningTimeout = 3000;
681 int err = sync_wait(fence, warningTimeout);
682 if (err < 0 && errno == ETIME) {
683 ALOGE("%s: fence %d didn't signal in %d ms", logname, fence, warningTimeout);
684 err = sync_wait(fence, -1);
685 }
686 return err < 0 ? -errno : status_t(NO_ERROR);
687 }
688
fenceWait(int fence)689 status_t EglManager::fenceWait(int fence) {
690 if (!hasEglContext()) {
691 ALOGE("EglManager::fenceWait: EGLDisplay not initialized");
692 return INVALID_OPERATION;
693 }
694
695 if (EglExtensions.waitSync && EglExtensions.nativeFenceSync) {
696 // Block GPU on the fence.
697 // Create an EGLSyncKHR from the current fence.
698 int fenceFd = ::dup(fence);
699 if (fenceFd == -1) {
700 ALOGE("EglManager::fenceWait: error dup'ing fence fd: %d", errno);
701 return -errno;
702 }
703 EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
704 EGLSyncKHR sync = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
705 if (sync == EGL_NO_SYNC_KHR) {
706 close(fenceFd);
707 ALOGE("EglManager::fenceWait: error creating EGL fence: %#x", eglGetError());
708 return UNKNOWN_ERROR;
709 }
710
711 // XXX: The spec draft is inconsistent as to whether this should
712 // return an EGLint or void. Ignore the return value for now, as
713 // it's not strictly needed.
714 eglWaitSyncKHR(mEglDisplay, sync, 0);
715 EGLint eglErr = eglGetError();
716 eglDestroySyncKHR(mEglDisplay, sync);
717 if (eglErr != EGL_SUCCESS) {
718 ALOGE("EglManager::fenceWait: error waiting for EGL fence: %#x", eglErr);
719 return UNKNOWN_ERROR;
720 }
721 } else {
722 // Block CPU on the fence.
723 status_t err = waitForeverOnFence(fence, "EglManager::fenceWait");
724 if (err != NO_ERROR) {
725 ALOGE("EglManager::fenceWait: error waiting for fence: %d", err);
726 return err;
727 }
728 }
729 return OK;
730 }
731
createReleaseFence(bool useFenceSync,EGLSyncKHR * eglFence,int * nativeFence)732 status_t EglManager::createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, int* nativeFence) {
733 *nativeFence = -1;
734 if (!hasEglContext()) {
735 ALOGE("EglManager::createReleaseFence: EGLDisplay not initialized");
736 return INVALID_OPERATION;
737 }
738
739 if (EglExtensions.nativeFenceSync) {
740 EGLSyncKHR sync = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
741 if (sync == EGL_NO_SYNC_KHR) {
742 ALOGE("EglManager::createReleaseFence: error creating EGL fence: %#x", eglGetError());
743 return UNKNOWN_ERROR;
744 }
745 glFlush();
746 int fenceFd = eglDupNativeFenceFDANDROID(mEglDisplay, sync);
747 eglDestroySyncKHR(mEglDisplay, sync);
748 if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
749 ALOGE("EglManager::createReleaseFence: error dup'ing native fence "
750 "fd: %#x",
751 eglGetError());
752 return UNKNOWN_ERROR;
753 }
754 *nativeFence = fenceFd;
755 *eglFence = EGL_NO_SYNC_KHR;
756 } else if (useFenceSync && EglExtensions.fenceSync) {
757 if (*eglFence != EGL_NO_SYNC_KHR) {
758 // There is already a fence for the current slot. We need to
759 // wait on that before replacing it with another fence to
760 // ensure that all outstanding buffer accesses have completed
761 // before the producer accesses it.
762 EGLint result = eglClientWaitSyncKHR(mEglDisplay, *eglFence, 0, 1000000000);
763 if (result == EGL_FALSE) {
764 ALOGE("EglManager::createReleaseFence: error waiting for previous fence: %#x",
765 eglGetError());
766 return UNKNOWN_ERROR;
767 } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
768 ALOGE("EglManager::createReleaseFence: timeout waiting for previous fence");
769 return TIMED_OUT;
770 }
771 eglDestroySyncKHR(mEglDisplay, *eglFence);
772 }
773
774 // Create a fence for the outstanding accesses in the current
775 // OpenGL ES context.
776 *eglFence = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_FENCE_KHR, nullptr);
777 if (*eglFence == EGL_NO_SYNC_KHR) {
778 ALOGE("EglManager::createReleaseFence: error creating fence: %#x", eglGetError());
779 return UNKNOWN_ERROR;
780 }
781 glFlush();
782 }
783 return OK;
784 }
785
786 } /* namespace renderthread */
787 } /* namespace uirenderer */
788 } /* namespace android */
789