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