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