• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #undef LOG_TAG
19 #define LOG_TAG "RenderEngine"
20 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
21 
22 #include "SkiaGLRenderEngine.h"
23 
24 #include <EGL/egl.h>
25 #include <EGL/eglext.h>
26 #include <GrContextOptions.h>
27 #include <android-base/stringprintf.h>
28 #include <gl/GrGLInterface.h>
29 #include <gui/TraceUtils.h>
30 #include <sync/sync.h>
31 #include <ui/DebugUtils.h>
32 #include <utils/Trace.h>
33 
34 #include <cmath>
35 #include <cstdint>
36 #include <memory>
37 #include <numeric>
38 
39 #include "../gl/GLExtensions.h"
40 #include "log/log_main.h"
41 
42 bool checkGlError(const char* op, int lineNumber);
43 
44 namespace android {
45 namespace renderengine {
46 namespace skia {
47 
48 using base::StringAppendF;
49 
selectConfigForAttribute(EGLDisplay dpy,EGLint const * attrs,EGLint attribute,EGLint wanted,EGLConfig * outConfig)50 static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute,
51                                          EGLint wanted, EGLConfig* outConfig) {
52     EGLint numConfigs = -1, n = 0;
53     eglGetConfigs(dpy, nullptr, 0, &numConfigs);
54     std::vector<EGLConfig> configs(numConfigs, EGL_NO_CONFIG_KHR);
55     eglChooseConfig(dpy, attrs, configs.data(), configs.size(), &n);
56     configs.resize(n);
57 
58     if (!configs.empty()) {
59         if (attribute != EGL_NONE) {
60             for (EGLConfig config : configs) {
61                 EGLint value = 0;
62                 eglGetConfigAttrib(dpy, config, attribute, &value);
63                 if (wanted == value) {
64                     *outConfig = config;
65                     return NO_ERROR;
66                 }
67             }
68         } else {
69             // just pick the first one
70             *outConfig = configs[0];
71             return NO_ERROR;
72         }
73     }
74 
75     return NAME_NOT_FOUND;
76 }
77 
selectEGLConfig(EGLDisplay display,EGLint format,EGLint renderableType,EGLConfig * config)78 static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint renderableType,
79                                 EGLConfig* config) {
80     // select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if
81     // it is to be used with WIFI displays
82     status_t err;
83     EGLint wantedAttribute;
84     EGLint wantedAttributeValue;
85 
86     std::vector<EGLint> attribs;
87     if (renderableType) {
88         const ui::PixelFormat pixelFormat = static_cast<ui::PixelFormat>(format);
89         const bool is1010102 = pixelFormat == ui::PixelFormat::RGBA_1010102;
90 
91         // Default to 8 bits per channel.
92         const EGLint tmpAttribs[] = {
93                 EGL_RENDERABLE_TYPE,
94                 renderableType,
95                 EGL_RECORDABLE_ANDROID,
96                 EGL_TRUE,
97                 EGL_SURFACE_TYPE,
98                 EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
99                 EGL_FRAMEBUFFER_TARGET_ANDROID,
100                 EGL_TRUE,
101                 EGL_RED_SIZE,
102                 is1010102 ? 10 : 8,
103                 EGL_GREEN_SIZE,
104                 is1010102 ? 10 : 8,
105                 EGL_BLUE_SIZE,
106                 is1010102 ? 10 : 8,
107                 EGL_ALPHA_SIZE,
108                 is1010102 ? 2 : 8,
109                 EGL_NONE,
110         };
111         std::copy(tmpAttribs, tmpAttribs + (sizeof(tmpAttribs) / sizeof(EGLint)),
112                   std::back_inserter(attribs));
113         wantedAttribute = EGL_NONE;
114         wantedAttributeValue = EGL_NONE;
115     } else {
116         // if no renderable type specified, fallback to a simplified query
117         wantedAttribute = EGL_NATIVE_VISUAL_ID;
118         wantedAttributeValue = format;
119     }
120 
121     err = selectConfigForAttribute(display, attribs.data(), wantedAttribute, wantedAttributeValue,
122                                    config);
123     if (err == NO_ERROR) {
124         EGLint caveat;
125         if (eglGetConfigAttrib(display, *config, EGL_CONFIG_CAVEAT, &caveat))
126             ALOGW_IF(caveat == EGL_SLOW_CONFIG, "EGL_SLOW_CONFIG selected!");
127     }
128 
129     return err;
130 }
131 
create(const RenderEngineCreationArgs & args)132 std::unique_ptr<SkiaGLRenderEngine> SkiaGLRenderEngine::create(
133         const RenderEngineCreationArgs& args) {
134     // initialize EGL for the default display
135     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
136     if (!eglInitialize(display, nullptr, nullptr)) {
137         LOG_ALWAYS_FATAL("failed to initialize EGL");
138     }
139 
140     const auto eglVersion = eglQueryString(display, EGL_VERSION);
141     if (!eglVersion) {
142         checkGlError(__FUNCTION__, __LINE__);
143         LOG_ALWAYS_FATAL("eglQueryString(EGL_VERSION) failed");
144     }
145 
146     const auto eglExtensions = eglQueryString(display, EGL_EXTENSIONS);
147     if (!eglExtensions) {
148         checkGlError(__FUNCTION__, __LINE__);
149         LOG_ALWAYS_FATAL("eglQueryString(EGL_EXTENSIONS) failed");
150     }
151 
152     auto& extensions = gl::GLExtensions::getInstance();
153     extensions.initWithEGLStrings(eglVersion, eglExtensions);
154 
155     // The code assumes that ES2 or later is available if this extension is
156     // supported.
157     EGLConfig config = EGL_NO_CONFIG_KHR;
158     if (!extensions.hasNoConfigContext()) {
159         config = chooseEglConfig(display, args.pixelFormat, /*logConfig*/ true);
160     }
161 
162     EGLContext protectedContext = EGL_NO_CONTEXT;
163     const std::optional<RenderEngine::ContextPriority> priority = createContextPriority(args);
164     if (args.enableProtectedContext && extensions.hasProtectedContent()) {
165         protectedContext =
166                 createEglContext(display, config, nullptr, priority, Protection::PROTECTED);
167         ALOGE_IF(protectedContext == EGL_NO_CONTEXT, "Can't create protected context");
168     }
169 
170     EGLContext ctxt =
171             createEglContext(display, config, protectedContext, priority, Protection::UNPROTECTED);
172 
173     // if can't create a GL context, we can only abort.
174     LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed");
175 
176     EGLSurface placeholder = EGL_NO_SURFACE;
177     if (!extensions.hasSurfacelessContext()) {
178         placeholder = createPlaceholderEglPbufferSurface(display, config, args.pixelFormat,
179                                                          Protection::UNPROTECTED);
180         LOG_ALWAYS_FATAL_IF(placeholder == EGL_NO_SURFACE, "can't create placeholder pbuffer");
181     }
182     EGLBoolean success = eglMakeCurrent(display, placeholder, placeholder, ctxt);
183     LOG_ALWAYS_FATAL_IF(!success, "can't make placeholder pbuffer current");
184     extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER),
185                                  glGetString(GL_VERSION), glGetString(GL_EXTENSIONS));
186 
187     EGLSurface protectedPlaceholder = EGL_NO_SURFACE;
188     if (protectedContext != EGL_NO_CONTEXT && !extensions.hasSurfacelessContext()) {
189         protectedPlaceholder = createPlaceholderEglPbufferSurface(display, config, args.pixelFormat,
190                                                                   Protection::PROTECTED);
191         ALOGE_IF(protectedPlaceholder == EGL_NO_SURFACE,
192                  "can't create protected placeholder pbuffer");
193     }
194 
195     // initialize the renderer while GL is current
196     std::unique_ptr<SkiaGLRenderEngine> engine(new SkiaGLRenderEngine(args, display, ctxt,
197                                                                       placeholder, protectedContext,
198                                                                       protectedPlaceholder));
199     engine->ensureGrContextsCreated();
200 
201     ALOGI("OpenGL ES informations:");
202     ALOGI("vendor    : %s", extensions.getVendor());
203     ALOGI("renderer  : %s", extensions.getRenderer());
204     ALOGI("version   : %s", extensions.getVersion());
205     ALOGI("extensions: %s", extensions.getExtensions());
206     ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize());
207     ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims());
208 
209     return engine;
210 }
211 
chooseEglConfig(EGLDisplay display,int format,bool logConfig)212 EGLConfig SkiaGLRenderEngine::chooseEglConfig(EGLDisplay display, int format, bool logConfig) {
213     status_t err;
214     EGLConfig config;
215 
216     // First try to get an ES3 config
217     err = selectEGLConfig(display, format, EGL_OPENGL_ES3_BIT, &config);
218     if (err != NO_ERROR) {
219         // If ES3 fails, try to get an ES2 config
220         err = selectEGLConfig(display, format, EGL_OPENGL_ES2_BIT, &config);
221         if (err != NO_ERROR) {
222             // If ES2 still doesn't work, probably because we're on the emulator.
223             // try a simplified query
224             ALOGW("no suitable EGLConfig found, trying a simpler query");
225             err = selectEGLConfig(display, format, 0, &config);
226             if (err != NO_ERROR) {
227                 // this EGL is too lame for android
228                 LOG_ALWAYS_FATAL("no suitable EGLConfig found, giving up");
229             }
230         }
231     }
232 
233     if (logConfig) {
234         // print some debugging info
235         EGLint r, g, b, a;
236         eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r);
237         eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
238         eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b);
239         eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
240         ALOGI("EGL information:");
241         ALOGI("vendor    : %s", eglQueryString(display, EGL_VENDOR));
242         ALOGI("version   : %s", eglQueryString(display, EGL_VERSION));
243         ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS));
244         ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS) ?: "Not Supported");
245         ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
246     }
247 
248     return config;
249 }
250 
SkiaGLRenderEngine(const RenderEngineCreationArgs & args,EGLDisplay display,EGLContext ctxt,EGLSurface placeholder,EGLContext protectedContext,EGLSurface protectedPlaceholder)251 SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display,
252                                        EGLContext ctxt, EGLSurface placeholder,
253                                        EGLContext protectedContext, EGLSurface protectedPlaceholder)
254       : SkiaRenderEngine(args.renderEngineType,
255                          static_cast<PixelFormat>(args.pixelFormat),
256                          args.useColorManagement, args.supportsBackgroundBlur),
257         mEGLDisplay(display),
258         mEGLContext(ctxt),
259         mPlaceholderSurface(placeholder),
260         mProtectedEGLContext(protectedContext),
261         mProtectedPlaceholderSurface(protectedPlaceholder) { }
262 
~SkiaGLRenderEngine()263 SkiaGLRenderEngine::~SkiaGLRenderEngine() {
264     finishRenderingAndAbandonContext();
265     if (mPlaceholderSurface != EGL_NO_SURFACE) {
266         eglDestroySurface(mEGLDisplay, mPlaceholderSurface);
267     }
268     if (mProtectedPlaceholderSurface != EGL_NO_SURFACE) {
269         eglDestroySurface(mEGLDisplay, mProtectedPlaceholderSurface);
270     }
271     if (mEGLContext != EGL_NO_CONTEXT) {
272         eglDestroyContext(mEGLDisplay, mEGLContext);
273     }
274     if (mProtectedEGLContext != EGL_NO_CONTEXT) {
275         eglDestroyContext(mEGLDisplay, mProtectedEGLContext);
276     }
277     eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
278     eglTerminate(mEGLDisplay);
279     eglReleaseThread();
280 }
281 
createDirectContexts(const GrContextOptions & options)282 SkiaRenderEngine::Contexts SkiaGLRenderEngine::createDirectContexts(
283     const GrContextOptions& options) {
284 
285     LOG_ALWAYS_FATAL_IF(isProtected(),
286                         "Cannot setup contexts while already in protected mode");
287 
288     sk_sp<const GrGLInterface> glInterface = GrGLMakeNativeInterface();
289 
290     LOG_ALWAYS_FATAL_IF(!glInterface.get(), "GrGLMakeNativeInterface() failed");
291 
292     SkiaRenderEngine::Contexts contexts;
293     contexts.first = GrDirectContext::MakeGL(glInterface, options);
294     if (supportsProtectedContentImpl()) {
295         useProtectedContextImpl(GrProtected::kYes);
296         contexts.second = GrDirectContext::MakeGL(glInterface, options);
297         useProtectedContextImpl(GrProtected::kNo);
298     }
299 
300     return contexts;
301 }
302 
supportsProtectedContentImpl() const303 bool SkiaGLRenderEngine::supportsProtectedContentImpl() const {
304     return mProtectedEGLContext != EGL_NO_CONTEXT;
305 }
306 
useProtectedContextImpl(GrProtected isProtected)307 bool SkiaGLRenderEngine::useProtectedContextImpl(GrProtected isProtected) {
308     const EGLSurface surface =
309         (isProtected == GrProtected::kYes) ?
310         mProtectedPlaceholderSurface : mPlaceholderSurface;
311     const EGLContext context = (isProtected == GrProtected::kYes) ?
312         mProtectedEGLContext : mEGLContext;
313 
314     return eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE;
315 }
316 
waitFence(GrDirectContext *,base::borrowed_fd fenceFd)317 void SkiaGLRenderEngine::waitFence(GrDirectContext*, base::borrowed_fd fenceFd) {
318     if (fenceFd.get() >= 0 && !waitGpuFence(fenceFd)) {
319         ATRACE_NAME("SkiaGLRenderEngine::waitFence");
320         sync_wait(fenceFd.get(), -1);
321     }
322 }
323 
flushAndSubmit(GrDirectContext * grContext)324 base::unique_fd SkiaGLRenderEngine::flushAndSubmit(GrDirectContext* grContext) {
325     base::unique_fd drawFence = flush();
326 
327     bool requireSync = drawFence.get() < 0;
328     if (requireSync) {
329         ATRACE_BEGIN("Submit(sync=true)");
330     } else {
331         ATRACE_BEGIN("Submit(sync=false)");
332     }
333     bool success = grContext->submit(requireSync);
334     ATRACE_END();
335     if (!success) {
336         ALOGE("Failed to flush RenderEngine commands");
337         // Chances are, something illegal happened (Skia's internal GPU object
338         // doesn't exist, or the context was abandoned).
339         return drawFence;
340     }
341 
342     return drawFence;
343 }
344 
waitGpuFence(base::borrowed_fd fenceFd)345 bool SkiaGLRenderEngine::waitGpuFence(base::borrowed_fd fenceFd) {
346     if (!gl::GLExtensions::getInstance().hasNativeFenceSync() ||
347         !gl::GLExtensions::getInstance().hasWaitSync()) {
348         return false;
349     }
350 
351     // Duplicate the fence for passing to eglCreateSyncKHR.
352     base::unique_fd fenceDup(dup(fenceFd.get()));
353     if (fenceDup.get() < 0) {
354         ALOGE("failed to create duplicate fence fd: %d", fenceDup.get());
355         return false;
356     }
357 
358     // release the fd and transfer the ownership to EGLSync
359     EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceDup.release(), EGL_NONE};
360     EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
361     if (sync == EGL_NO_SYNC_KHR) {
362         ALOGE("failed to create EGL native fence sync: %#x", eglGetError());
363         return false;
364     }
365 
366     // XXX: The spec draft is inconsistent as to whether this should return an
367     // EGLint or void.  Ignore the return value for now, as it's not strictly
368     // needed.
369     eglWaitSyncKHR(mEGLDisplay, sync, 0);
370     EGLint error = eglGetError();
371     eglDestroySyncKHR(mEGLDisplay, sync);
372     if (error != EGL_SUCCESS) {
373         ALOGE("failed to wait for EGL native fence sync: %#x", error);
374         return false;
375     }
376 
377     return true;
378 }
379 
flush()380 base::unique_fd SkiaGLRenderEngine::flush() {
381     ATRACE_CALL();
382     if (!gl::GLExtensions::getInstance().hasNativeFenceSync()) {
383         return base::unique_fd();
384     }
385 
386     EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
387     if (sync == EGL_NO_SYNC_KHR) {
388         ALOGW("failed to create EGL native fence sync: %#x", eglGetError());
389         return base::unique_fd();
390     }
391 
392     // native fence fd will not be populated until flush() is done.
393     glFlush();
394 
395     // get the fence fd
396     base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync));
397     eglDestroySyncKHR(mEGLDisplay, sync);
398     if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
399         ALOGW("failed to dup EGL native fence sync: %#x", eglGetError());
400     }
401 
402     return fenceFd;
403 }
404 
createEglContext(EGLDisplay display,EGLConfig config,EGLContext shareContext,std::optional<ContextPriority> contextPriority,Protection protection)405 EGLContext SkiaGLRenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
406                                                 EGLContext shareContext,
407                                                 std::optional<ContextPriority> contextPriority,
408                                                 Protection protection) {
409     EGLint renderableType = 0;
410     if (config == EGL_NO_CONFIG_KHR) {
411         renderableType = EGL_OPENGL_ES3_BIT;
412     } else if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType)) {
413         LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE");
414     }
415     EGLint contextClientVersion = 0;
416     if (renderableType & EGL_OPENGL_ES3_BIT) {
417         contextClientVersion = 3;
418     } else if (renderableType & EGL_OPENGL_ES2_BIT) {
419         contextClientVersion = 2;
420     } else if (renderableType & EGL_OPENGL_ES_BIT) {
421         contextClientVersion = 1;
422     } else {
423         LOG_ALWAYS_FATAL("no supported EGL_RENDERABLE_TYPEs");
424     }
425 
426     std::vector<EGLint> contextAttributes;
427     contextAttributes.reserve(7);
428     contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
429     contextAttributes.push_back(contextClientVersion);
430     if (contextPriority) {
431         contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
432         switch (*contextPriority) {
433             case ContextPriority::REALTIME:
434                 contextAttributes.push_back(EGL_CONTEXT_PRIORITY_REALTIME_NV);
435                 break;
436             case ContextPriority::MEDIUM:
437                 contextAttributes.push_back(EGL_CONTEXT_PRIORITY_MEDIUM_IMG);
438                 break;
439             case ContextPriority::LOW:
440                 contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LOW_IMG);
441                 break;
442             case ContextPriority::HIGH:
443             default:
444                 contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
445                 break;
446         }
447     }
448     if (protection == Protection::PROTECTED) {
449         contextAttributes.push_back(EGL_PROTECTED_CONTENT_EXT);
450         contextAttributes.push_back(EGL_TRUE);
451     }
452     contextAttributes.push_back(EGL_NONE);
453 
454     EGLContext context = eglCreateContext(display, config, shareContext, contextAttributes.data());
455 
456     if (contextClientVersion == 3 && context == EGL_NO_CONTEXT) {
457         // eglGetConfigAttrib indicated we can create GLES 3 context, but we failed, thus
458         // EGL_NO_CONTEXT so that we can abort.
459         if (config != EGL_NO_CONFIG_KHR) {
460             return context;
461         }
462         // If |config| is EGL_NO_CONFIG_KHR, we speculatively try to create GLES 3 context, so we
463         // should try to fall back to GLES 2.
464         contextAttributes[1] = 2;
465         context = eglCreateContext(display, config, shareContext, contextAttributes.data());
466     }
467 
468     return context;
469 }
470 
createContextPriority(const RenderEngineCreationArgs & args)471 std::optional<RenderEngine::ContextPriority> SkiaGLRenderEngine::createContextPriority(
472         const RenderEngineCreationArgs& args) {
473     if (!gl::GLExtensions::getInstance().hasContextPriority()) {
474         return std::nullopt;
475     }
476 
477     switch (args.contextPriority) {
478         case RenderEngine::ContextPriority::REALTIME:
479             if (gl::GLExtensions::getInstance().hasRealtimePriority()) {
480                 return RenderEngine::ContextPriority::REALTIME;
481             } else {
482                 ALOGI("Realtime priority unsupported, degrading gracefully to high priority");
483                 return RenderEngine::ContextPriority::HIGH;
484             }
485         case RenderEngine::ContextPriority::HIGH:
486         case RenderEngine::ContextPriority::MEDIUM:
487         case RenderEngine::ContextPriority::LOW:
488             return args.contextPriority;
489         default:
490             return std::nullopt;
491     }
492 }
493 
createPlaceholderEglPbufferSurface(EGLDisplay display,EGLConfig config,int hwcFormat,Protection protection)494 EGLSurface SkiaGLRenderEngine::createPlaceholderEglPbufferSurface(EGLDisplay display,
495                                                                   EGLConfig config, int hwcFormat,
496                                                                   Protection protection) {
497     EGLConfig placeholderConfig = config;
498     if (placeholderConfig == EGL_NO_CONFIG_KHR) {
499         placeholderConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
500     }
501     std::vector<EGLint> attributes;
502     attributes.reserve(7);
503     attributes.push_back(EGL_WIDTH);
504     attributes.push_back(1);
505     attributes.push_back(EGL_HEIGHT);
506     attributes.push_back(1);
507     if (protection == Protection::PROTECTED) {
508         attributes.push_back(EGL_PROTECTED_CONTENT_EXT);
509         attributes.push_back(EGL_TRUE);
510     }
511     attributes.push_back(EGL_NONE);
512 
513     return eglCreatePbufferSurface(display, placeholderConfig, attributes.data());
514 }
515 
getContextPriority()516 int SkiaGLRenderEngine::getContextPriority() {
517     int value;
518     eglQueryContext(mEGLDisplay, mEGLContext, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &value);
519     return value;
520 }
521 
appendBackendSpecificInfoToDump(std::string & result)522 void SkiaGLRenderEngine::appendBackendSpecificInfoToDump(std::string& result) {
523     const gl::GLExtensions& extensions = gl::GLExtensions::getInstance();
524     StringAppendF(&result, "\n ------------RE GLES------------\n");
525     StringAppendF(&result, "EGL implementation : %s\n", extensions.getEGLVersion());
526     StringAppendF(&result, "%s\n", extensions.getEGLExtensions());
527     StringAppendF(&result, "GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
528                   extensions.getVersion());
529     StringAppendF(&result, "%s\n", extensions.getExtensions());
530 }
531 
532 } // namespace skia
533 } // namespace renderengine
534 } // namespace android
535