xref: /aosp_15_r20/frameworks/base/libs/hwui/renderthread/EglManager.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
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