tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

GLContextProviderEGL.cpp (40319B)


      1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #if defined(MOZ_WIDGET_GTK)
      7 #  define GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget) \
      8    ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_EGL_WINDOW))
      9 #  define GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget) \
     10    (aWidget->AsGTK()->GetEGLNativeWindow())
     11 #elif defined(MOZ_WIDGET_ANDROID)
     12 #  define GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget) \
     13    ((EGLNativeWindowType)aWidget->GetNativeData(NS_JAVA_SURFACE))
     14 #  define GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget) \
     15    (aWidget->AsAndroid()->GetEGLNativeWindow())
     16 #elif defined(XP_WIN)
     17 #  define GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget) \
     18    ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW))
     19 #  define GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget) \
     20    ((EGLNativeWindowType)aWidget->AsWindows()->GetHwnd())
     21 #else
     22 #  define GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget) \
     23    ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW))
     24 #  define GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget)     \
     25    ((EGLNativeWindowType)aWidget->RealWidget()->GetNativeData( \
     26        NS_NATIVE_WINDOW))
     27 #endif
     28 
     29 #if defined(XP_UNIX)
     30 #  ifdef MOZ_WIDGET_ANDROID
     31 #    include <android/native_window.h>
     32 #    include <android/native_window_jni.h>
     33 #    include "mozilla/jni/Utils.h"
     34 #    include "mozilla/widget/AndroidCompositorWidget.h"
     35 #  endif
     36 
     37 #  define GLES2_LIB "libGLESv2.so"
     38 #  define GLES2_LIB2 "libGLESv2.so.2"
     39 
     40 #elif defined(XP_WIN)
     41 #  include "mozilla/widget/WinCompositorWidget.h"
     42 #  include "nsIFile.h"
     43 
     44 #  define GLES2_LIB "libGLESv2.dll"
     45 
     46 #  ifndef WIN32_LEAN_AND_MEAN
     47 #    define WIN32_LEAN_AND_MEAN 1
     48 #  endif
     49 
     50 #  include <windows.h>
     51 #else
     52 #  error "Platform not recognized"
     53 #endif
     54 
     55 #include "gfxCrashReporterUtils.h"
     56 #include "gfxFailure.h"
     57 #include "gfxPlatform.h"
     58 #include "gfxUtils.h"
     59 #include "GLBlitHelper.h"
     60 #include "GLContextEGL.h"
     61 #include "GLContextProvider.h"
     62 #include "GLLibraryEGL.h"
     63 #include "GLLibraryLoader.h"
     64 #include "mozilla/Preferences.h"
     65 #include "mozilla/Services.h"
     66 #include "mozilla/StaticPrefs_gfx.h"
     67 #include "mozilla/gfx/gfxVars.h"
     68 #include "mozilla/gfx/BuildConstants.h"
     69 #include "mozilla/gfx/Logging.h"
     70 #include "mozilla/layers/CompositorOptions.h"
     71 #include "mozilla/widget/CompositorWidget.h"
     72 #include "nsDebug.h"
     73 #include "nsIWidget.h"
     74 #include "nsThreadUtils.h"
     75 #include "ScopedGLHelpers.h"
     76 
     77 #if defined(MOZ_WIDGET_GTK)
     78 #  include "mozilla/widget/GtkCompositorWidget.h"
     79 #  if defined(MOZ_WAYLAND)
     80 #    include <gdk/gdkwayland.h>
     81 #    include <wayland-egl.h>
     82 #    include "mozilla/WidgetUtilsGtk.h"
     83 #    include "mozilla/widget/nsWaylandDisplay.h"
     84 #  endif
     85 #endif
     86 
     87 struct wl_egl_window;
     88 
     89 using namespace mozilla::gfx;
     90 
     91 namespace mozilla {
     92 namespace gl {
     93 
     94 using namespace mozilla::widget;
     95 
     96 #if defined(MOZ_WAYLAND)
     97 class WaylandOffscreenGLSurface {
     98 public:
     99  WaylandOffscreenGLSurface(struct wl_surface* aWaylandSurface,
    100                            struct wl_egl_window* aEGLWindow);
    101  ~WaylandOffscreenGLSurface();
    102 
    103 private:
    104  struct wl_surface* mWaylandSurface = nullptr;
    105  struct wl_egl_window* mEGLWindow = nullptr;
    106 };
    107 
    108 MOZ_RUNINIT static nsTHashMap<nsPtrHashKey<void>, WaylandOffscreenGLSurface*>
    109    sWaylandOffscreenGLSurfaces;
    110 
    111 void DeleteWaylandOffscreenGLSurface(EGLSurface surface) {
    112  auto entry = sWaylandOffscreenGLSurfaces.Lookup(surface);
    113  if (entry) {
    114    delete entry.Data();
    115    entry.Remove();
    116  }
    117 }
    118 #endif
    119 
    120 static bool CreateConfigScreen(EglDisplay&, EGLConfig* const aConfig,
    121                               const bool aEnableDepthBuffer,
    122                               const bool aUseGles);
    123 
    124 // append three zeros at the end of attribs list to work around
    125 // EGL implementation bugs that iterate until they find 0, instead of
    126 // EGL_NONE. See bug 948406.
    127 #define EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS \
    128  LOCAL_EGL_NONE, 0, 0, 0
    129 
    130 static EGLint kTerminationAttribs[] = {
    131    EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS};
    132 
    133 static int next_power_of_two(int v) {
    134  v--;
    135  v |= v >> 1;
    136  v |= v >> 2;
    137  v |= v >> 4;
    138  v |= v >> 8;
    139  v |= v >> 16;
    140  v++;
    141 
    142  return v;
    143 }
    144 
    145 static bool is_power_of_two(int v) {
    146  NS_ASSERTION(v >= 0, "bad value");
    147 
    148  if (v == 0) return true;
    149 
    150  return (v & (v - 1)) == 0;
    151 }
    152 
    153 static EGLSurface CreateFallbackSurface(EglDisplay& egl,
    154                                        const EGLConfig& config) {
    155  if (egl.IsExtensionSupported(EGLExtension::KHR_surfaceless_context)) {
    156    // We don't need a PBuffer surface in this case
    157    return EGL_NO_SURFACE;
    158  }
    159 
    160  std::vector<EGLint> pbattrs;
    161  pbattrs.push_back(LOCAL_EGL_WIDTH);
    162  pbattrs.push_back(1);
    163  pbattrs.push_back(LOCAL_EGL_HEIGHT);
    164  pbattrs.push_back(1);
    165 
    166  for (const auto& cur : kTerminationAttribs) {
    167    pbattrs.push_back(cur);
    168  }
    169 
    170  EGLSurface surface = egl.fCreatePbufferSurface(config, pbattrs.data());
    171  if (!surface) {
    172    MOZ_CRASH("Failed to create fallback EGLSurface");
    173  }
    174 
    175  return surface;
    176 }
    177 
    178 static EGLSurface CreateSurfaceFromNativeWindow(
    179    EglDisplay& egl, const EGLNativeWindowType window, const EGLConfig config) {
    180  MOZ_ASSERT(window);
    181  EGLSurface newSurface = EGL_NO_SURFACE;
    182 
    183 #ifdef MOZ_WIDGET_ANDROID
    184  JNIEnv* const env = jni::GetEnvForThread();
    185  ANativeWindow* const nativeWindow =
    186      ANativeWindow_fromSurface(env, reinterpret_cast<jobject>(window));
    187  if (!nativeWindow) {
    188    gfxCriticalNote << "Failed to obtain native window from Surface";
    189    return EGL_NO_SURFACE;
    190  }
    191  const auto& display = egl.mLib->fGetDisplay(EGL_DEFAULT_DISPLAY);
    192  newSurface = egl.mLib->fCreateWindowSurface(display, config, nativeWindow, 0);
    193  ANativeWindow_release(nativeWindow);
    194 #else
    195  newSurface = egl.fCreateWindowSurface(config, window, 0);
    196 #endif
    197  if (!newSurface) {
    198    const auto err = egl.mLib->fGetError();
    199    gfxCriticalNote << "Failed to create EGLSurface!: " << gfx::hexa(err);
    200  }
    201  return newSurface;
    202 }
    203 
    204 /* GLContextEGLFactory class was added as a friend of GLContextEGL
    205 * so that it could access  GLContextEGL::CreateGLContext. This was
    206 * done so that a new function would not need to be added to the shared
    207 * GLContextProvider interface.
    208 */
    209 class GLContextEGLFactory {
    210 public:
    211  static already_AddRefed<GLContext> Create(EGLNativeWindowType aWindow,
    212                                            bool aHardwareWebRender);
    213  static already_AddRefed<GLContext> CreateImpl(EGLNativeWindowType aWindow,
    214                                                bool aHardwareWebRender,
    215                                                bool aUseGles);
    216 
    217 private:
    218  GLContextEGLFactory() = default;
    219  ~GLContextEGLFactory() = default;
    220 };
    221 
    222 already_AddRefed<GLContext> GLContextEGLFactory::CreateImpl(
    223    EGLNativeWindowType aWindow, bool aHardwareWebRender, bool aUseGles) {
    224  nsCString failureId;
    225  const auto lib = GLLibraryEGL::Get(&failureId);
    226  if (!lib) {
    227    gfxCriticalNote << "Failed[3] to load EGL library: " << failureId.get();
    228    return nullptr;
    229  }
    230  const auto egl = lib->CreateDisplay(true, false, &failureId);
    231  if (!egl) {
    232    gfxCriticalNote << "Failed[3] to create EGL library  display: "
    233                    << failureId.get();
    234    return nullptr;
    235  }
    236 
    237  bool doubleBuffered = true;
    238 
    239  EGLConfig config;
    240  if (aHardwareWebRender && egl->mLib->IsANGLE()) {
    241    // Force enable alpha channel to make sure ANGLE use correct framebuffer
    242    // formart
    243    const int bpp = 32;
    244    if (!CreateConfig(*egl, &config, bpp, false, aUseGles)) {
    245      gfxCriticalNote << "Failed to create EGLConfig for WebRender ANGLE!";
    246      return nullptr;
    247    }
    248  } else if (kIsLinux) {
    249    const int bpp = 32;
    250    if (!CreateConfig(*egl, &config, bpp, false, aUseGles)) {
    251      gfxCriticalNote << "Failed to create EGLConfig for WebRender!";
    252      return nullptr;
    253    }
    254  } else {
    255    if (!CreateConfigScreen(*egl, &config,
    256                            /* aEnableDepthBuffer */ false, aUseGles)) {
    257      gfxCriticalNote << "Failed to create EGLConfig!";
    258      return nullptr;
    259    }
    260  }
    261 
    262  EGLSurface surface = EGL_NO_SURFACE;
    263  if (aWindow) {
    264    surface = mozilla::gl::CreateSurfaceFromNativeWindow(*egl, aWindow, config);
    265    if (!surface) {
    266      return nullptr;
    267    }
    268  }
    269 
    270  CreateContextFlags flags = CreateContextFlags::NONE;
    271  if (aHardwareWebRender &&
    272      StaticPrefs::gfx_webrender_prefer_robustness_AtStartup()) {
    273    flags |= CreateContextFlags::PREFER_ROBUSTNESS;
    274  }
    275  if (aHardwareWebRender && aUseGles) {
    276    flags |= CreateContextFlags::PREFER_ES3;
    277  }
    278  if (!aHardwareWebRender) {
    279    flags |= CreateContextFlags::REQUIRE_COMPAT_PROFILE;
    280  }
    281 
    282  const auto desc = GLContextDesc{{flags}, false};
    283  RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(
    284      egl, desc, config, surface, aUseGles, config, &failureId);
    285  if (!gl) {
    286    const auto err = egl->mLib->fGetError();
    287    gfxCriticalNote << "Failed to create EGLContext!: " << gfx::hexa(err);
    288    GLContextEGL::DestroySurface(*egl, surface);
    289    return nullptr;
    290  }
    291 
    292  gl->MakeCurrent();
    293  gl->SetIsDoubleBuffered(doubleBuffered);
    294 
    295 #ifdef MOZ_WIDGET_GTK
    296  if (surface) {
    297    const int interval = gfxVars::SwapIntervalEGL() ? 1 : 0;
    298    egl->fSwapInterval(interval);
    299  }
    300 #endif
    301  if (aHardwareWebRender && egl->mLib->IsANGLE()) {
    302    MOZ_ASSERT(doubleBuffered);
    303    const int interval = gfxVars::SwapIntervalEGL() ? 1 : 0;
    304    egl->fSwapInterval(interval);
    305  }
    306  return gl.forget();
    307 }
    308 
    309 already_AddRefed<GLContext> GLContextEGLFactory::Create(
    310    EGLNativeWindowType aWindow, bool aHardwareWebRender) {
    311  bool preferGles;
    312 #if defined(MOZ_WIDGET_ANDROID)
    313  preferGles = true;
    314 #else
    315  preferGles = StaticPrefs::gfx_egl_prefer_gles_enabled_AtStartup();
    316 #endif  // defined(MOZ_WIDGET_ANDROID)
    317 
    318  RefPtr<GLContext> glContext =
    319      CreateImpl(aWindow, aHardwareWebRender, preferGles);
    320 #if !defined(MOZ_WIDGET_ANDROID)
    321  if (!glContext) {
    322    glContext = CreateImpl(aWindow, aHardwareWebRender, !preferGles);
    323  }
    324 #endif  // !defined(MOZ_WIDGET_ANDROID)
    325  return glContext.forget();
    326 }
    327 
    328 /* static */
    329 EGLSurface GLContextEGL::CreateEGLSurfaceForCompositorWidget(
    330    widget::CompositorWidget* aCompositorWidget, const EGLConfig aConfig) {
    331  nsCString discardFailureId;
    332  const auto egl = DefaultEglDisplay(&discardFailureId);
    333  if (!egl) {
    334    gfxCriticalNote << "Failed to load EGL library 6!";
    335    return EGL_NO_SURFACE;
    336  }
    337 
    338  MOZ_ASSERT(aCompositorWidget);
    339  EGLNativeWindowType window =
    340      GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aCompositorWidget);
    341  if (!window) {
    342 #ifdef MOZ_WIDGET_GTK
    343    // RenderCompositorEGL does not like EGL_NO_SURFACE as it fallbacks
    344    // to SW rendering or claims itself as paused.
    345    // In case we're missing valid native window because aCompositorWidget
    346    // hidden, just create a fallback EGLSurface. Actual EGLSurface will be
    347    // created by widget code later when aCompositorWidget becomes visible.
    348    mozilla::gfx::IntSize pbSize(16, 16);
    349 #  ifdef MOZ_WAYLAND
    350    if (GdkIsWaylandDisplay()) {
    351      return CreateWaylandOffscreenSurface(*egl, aConfig, pbSize);
    352    } else
    353 #  endif
    354    {
    355      return CreatePBufferSurfaceTryingPowerOfTwo(*egl, aConfig, LOCAL_EGL_NONE,
    356                                                  pbSize);
    357    }
    358 #else
    359    gfxCriticalNote << "window is null";
    360    return EGL_NO_SURFACE;
    361 #endif
    362  }
    363 
    364  return mozilla::gl::CreateSurfaceFromNativeWindow(*egl, window, aConfig);
    365 }
    366 
    367 GLContextEGL::GLContextEGL(const std::shared_ptr<EglDisplay> egl,
    368                           const GLContextDesc& desc, EGLConfig surfaceConfig,
    369                           EGLSurface surface, EGLContext context)
    370    : GLContext(desc, nullptr, false),
    371      mEgl(egl),
    372      mSurfaceConfig(surfaceConfig),
    373      mContext(context),
    374      mSurface(surface),
    375      mFallbackSurface(CreateFallbackSurface(*mEgl, mSurfaceConfig)) {
    376 #ifdef DEBUG
    377  printf_stderr("Initializing context %p surface %p on display %p\n", mContext,
    378                mSurface, mEgl->mDisplay);
    379 #endif
    380 }
    381 
    382 void GLContextEGL::OnMarkDestroyed() {
    383  if (mSurfaceOverride != EGL_NO_SURFACE) {
    384    SetEGLSurfaceOverride(EGL_NO_SURFACE);
    385  }
    386 }
    387 
    388 GLContextEGL::~GLContextEGL() {
    389  MarkDestroyed();
    390 
    391  // Wrapped context should not destroy eglContext/Surface
    392  if (!mOwnsContext) {
    393    return;
    394  }
    395 
    396 #ifdef DEBUG
    397  printf_stderr("Destroying context %p surface %p on display %p\n", mContext,
    398                mSurface, mEgl->mDisplay);
    399 #endif
    400 
    401  mEgl->fDestroyContext(mContext);
    402 
    403  DestroySurface(*mEgl, mSurface);
    404  DestroySurface(*mEgl, mFallbackSurface);
    405 }
    406 
    407 bool GLContextEGL::Init() {
    408  if (!GLContext::Init()) return false;
    409 
    410  bool current = MakeCurrent();
    411  if (!current) {
    412    gfx::LogFailure("Couldn't get device attachments for device."_ns);
    413    return false;
    414  }
    415 
    416  mShareWithEGLImage =
    417      mEgl->HasKHRImageBase() &&
    418      mEgl->IsExtensionSupported(EGLExtension::KHR_gl_texture_2D_image) &&
    419      IsExtensionSupported(OES_EGL_image);
    420 
    421 #if MOZ_WIDGET_ANDROID
    422  // We see crashes in eglTerminate on devices with Xclipse GPUs running
    423  // Android 14. Choose to leak the EGLDisplays in order to avoid the crashes.
    424  // See bug 1868825 and bug 1903810.
    425  if (Renderer() == GLRenderer::SamsungXclipse && jni::GetAPIVersion() >= 34) {
    426    mEgl->SetShouldLeakEGLDisplay();
    427  }
    428 #endif
    429 
    430  return true;
    431 }
    432 
    433 bool GLContextEGL::BindTexImage() {
    434  if (!mSurface) return false;
    435 
    436  if (mBound && !ReleaseTexImage()) return false;
    437 
    438  EGLBoolean success =
    439      mEgl->fBindTexImage((EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER);
    440  if (success == LOCAL_EGL_FALSE) return false;
    441 
    442  mBound = true;
    443  return true;
    444 }
    445 
    446 bool GLContextEGL::ReleaseTexImage() {
    447  if (!mBound) return true;
    448 
    449  if (!mSurface) return false;
    450 
    451  EGLBoolean success;
    452  success = mEgl->fReleaseTexImage((EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER);
    453  if (success == LOCAL_EGL_FALSE) return false;
    454 
    455  mBound = false;
    456  return true;
    457 }
    458 
    459 void GLContextEGL::SetEGLSurfaceOverride(EGLSurface surf) {
    460  mSurfaceOverride = surf;
    461  DebugOnly<bool> ok = MakeCurrent(true);
    462  MOZ_ASSERT(ok);
    463 }
    464 
    465 bool GLContextEGL::MakeCurrentImpl() const {
    466  EGLSurface surface =
    467      (mSurfaceOverride != EGL_NO_SURFACE) ? mSurfaceOverride : mSurface;
    468  if (!surface) {
    469    surface = mFallbackSurface;
    470  }
    471 
    472  const bool succeeded = mEgl->fMakeCurrent(surface, surface, mContext);
    473  if (!succeeded) {
    474    const auto eglError = mEgl->mLib->fGetError();
    475    if (eglError == LOCAL_EGL_CONTEXT_LOST) {
    476      OnContextLostError();
    477    } else {
    478      NS_WARNING("Failed to make GL context current!");
    479 #ifdef DEBUG
    480      printf_stderr("EGL Error: 0x%04x\n", eglError);
    481 #endif
    482    }
    483  }
    484 
    485  return succeeded;
    486 }
    487 
    488 bool GLContextEGL::IsCurrentImpl() const {
    489  return mEgl->mLib->fGetCurrentContext() == mContext;
    490 }
    491 
    492 bool GLContextEGL::RenewSurface(CompositorWidget* aWidget) {
    493  if (!mOwnsContext) {
    494    return false;
    495  }
    496  // unconditionally release the surface and create a new one. Don't try to
    497  // optimize this away. If we get here, then by definition we know that we want
    498  // to get a new surface.
    499  ReleaseSurface();
    500  MOZ_ASSERT(aWidget);
    501 
    502  EGLNativeWindowType nativeWindow =
    503      GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget);
    504  if (nativeWindow) {
    505    mSurface = mozilla::gl::CreateSurfaceFromNativeWindow(*mEgl, nativeWindow,
    506                                                          mSurfaceConfig);
    507    if (!mSurface) {
    508      NS_WARNING("Failed to create EGLSurface from native window");
    509      return false;
    510    }
    511  }
    512  const bool ok = MakeCurrent(true);
    513  MOZ_ASSERT(ok);
    514 #ifdef MOZ_WIDGET_GTK
    515  if (mSurface) {
    516    const int interval = gfxVars::SwapIntervalEGL() ? 1 : 0;
    517    mEgl->fSwapInterval(interval);
    518  }
    519 #endif
    520  return ok;
    521 }
    522 
    523 void GLContextEGL::ReleaseSurface() {
    524  if (mOwnsContext) {
    525    DestroySurface(*mEgl, mSurface);
    526  }
    527  if (mSurface == mSurfaceOverride) {
    528    mSurfaceOverride = EGL_NO_SURFACE;
    529  }
    530  mSurface = EGL_NO_SURFACE;
    531 }
    532 
    533 Maybe<SymbolLoader> GLContextEGL::GetSymbolLoader() const {
    534  return mEgl->mLib->GetSymbolLoader();
    535 }
    536 
    537 bool GLContextEGL::SwapBuffers() {
    538  EGLSurface surface =
    539      mSurfaceOverride != EGL_NO_SURFACE ? mSurfaceOverride : mSurface;
    540  if (surface) {
    541    if ((mEgl->IsExtensionSupported(
    542             EGLExtension::EXT_swap_buffers_with_damage) ||
    543         mEgl->IsExtensionSupported(
    544             EGLExtension::KHR_swap_buffers_with_damage))) {
    545      std::vector<EGLint> rects;
    546      for (auto iter = mDamageRegion.RectIter(); !iter.Done(); iter.Next()) {
    547        const IntRect& r = iter.Get();
    548        rects.push_back(r.X());
    549        rects.push_back(r.Y());
    550        rects.push_back(r.Width());
    551        rects.push_back(r.Height());
    552      }
    553      mDamageRegion.SetEmpty();
    554      return mEgl->fSwapBuffersWithDamage(surface, rects.data(),
    555                                          rects.size() / 4);
    556    }
    557    return mEgl->fSwapBuffers(surface);
    558  } else {
    559    return false;
    560  }
    561 }
    562 
    563 void GLContextEGL::SetDamage(const nsIntRegion& aDamageRegion) {
    564  mDamageRegion = aDamageRegion;
    565 }
    566 
    567 void GLContextEGL::GetWSIInfo(nsCString* const out) const {
    568  out->AppendLiteral("EGL_VENDOR: ");
    569  out->Append(
    570      (const char*)mEgl->mLib->fQueryString(mEgl->mDisplay, LOCAL_EGL_VENDOR));
    571 
    572  out->AppendLiteral("\nEGL_VERSION: ");
    573  out->Append(
    574      (const char*)mEgl->mLib->fQueryString(mEgl->mDisplay, LOCAL_EGL_VERSION));
    575 
    576  out->AppendLiteral("\nEGL_EXTENSIONS: ");
    577  out->Append((const char*)mEgl->mLib->fQueryString(mEgl->mDisplay,
    578                                                    LOCAL_EGL_EXTENSIONS));
    579 
    580 #ifndef ANDROID  // This query will crash some old android.
    581  out->AppendLiteral("\nEGL_EXTENSIONS(nullptr): ");
    582  out->Append(
    583      (const char*)mEgl->mLib->fQueryString(nullptr, LOCAL_EGL_EXTENSIONS));
    584 #endif
    585 }
    586 
    587 bool GLContextEGL::HasExtBufferAge() const {
    588  return mEgl->IsExtensionSupported(EGLExtension::EXT_buffer_age);
    589 }
    590 
    591 bool GLContextEGL::HasKhrPartialUpdate() const {
    592  return mEgl->IsExtensionSupported(EGLExtension::KHR_partial_update);
    593 }
    594 
    595 GLint GLContextEGL::GetBufferAge() const {
    596  EGLSurface surface =
    597      mSurfaceOverride != EGL_NO_SURFACE ? mSurfaceOverride : mSurface;
    598 
    599  if (surface && (HasExtBufferAge() || HasKhrPartialUpdate())) {
    600    EGLint result;
    601    mEgl->fQuerySurface(surface, LOCAL_EGL_BUFFER_AGE_EXT, &result);
    602    return result;
    603  }
    604 
    605  return 0;
    606 }
    607 
    608 #define LOCAL_EGL_CONTEXT_PROVOKING_VERTEX_DONT_CARE_MOZ 0x6000
    609 
    610 RefPtr<GLContextEGL> GLContextEGL::CreateGLContext(
    611    const std::shared_ptr<EglDisplay> egl, const GLContextDesc& desc,
    612    EGLConfig surfaceConfig, EGLSurface surface, const bool useGles,
    613    EGLConfig contextConfig, nsACString* const out_failureId) {
    614  const auto& flags = desc.flags;
    615 
    616  std::vector<EGLint> required_attribs;
    617 
    618  if (useGles) {
    619    // TODO: This fBindAPI could be more thread-safe
    620    if (egl->mLib->fBindAPI(LOCAL_EGL_OPENGL_ES_API) == LOCAL_EGL_FALSE) {
    621      *out_failureId = "FEATURE_FAILURE_EGL_ES"_ns;
    622      NS_WARNING("Failed to bind API to GLES!");
    623      return nullptr;
    624    }
    625    required_attribs.push_back(LOCAL_EGL_CONTEXT_MAJOR_VERSION);
    626    if (flags & CreateContextFlags::PREFER_ES3) {
    627      required_attribs.push_back(3);
    628    } else {
    629      required_attribs.push_back(2);
    630    }
    631  } else {
    632    if (egl->mLib->fBindAPI(LOCAL_EGL_OPENGL_API) == LOCAL_EGL_FALSE) {
    633      *out_failureId = "FEATURE_FAILURE_EGL"_ns;
    634      NS_WARNING("Failed to bind API to GL!");
    635      return nullptr;
    636    }
    637    if (flags & CreateContextFlags::REQUIRE_COMPAT_PROFILE) {
    638      required_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_PROFILE_MASK);
    639      required_attribs.push_back(
    640          LOCAL_EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT);
    641      required_attribs.push_back(LOCAL_EGL_CONTEXT_MAJOR_VERSION);
    642      required_attribs.push_back(2);
    643    } else {
    644      // !REQUIRE_COMPAT_PROFILE means core profle.
    645      required_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_PROFILE_MASK);
    646      required_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT);
    647      required_attribs.push_back(LOCAL_EGL_CONTEXT_MAJOR_VERSION);
    648      required_attribs.push_back(3);
    649      required_attribs.push_back(LOCAL_EGL_CONTEXT_MINOR_VERSION);
    650      required_attribs.push_back(2);
    651    }
    652  }
    653 
    654  if ((flags & CreateContextFlags::PREFER_EXACT_VERSION) &&
    655      egl->mLib->IsANGLE()) {
    656    required_attribs.push_back(
    657        LOCAL_EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE);
    658    required_attribs.push_back(LOCAL_EGL_FALSE);
    659  }
    660 
    661  const auto debugFlags = GLContext::ChooseDebugFlags(flags);
    662  if (!debugFlags && flags & CreateContextFlags::NO_VALIDATION &&
    663      egl->IsExtensionSupported(EGLExtension::KHR_create_context_no_error)) {
    664    required_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_NO_ERROR_KHR);
    665    required_attribs.push_back(LOCAL_EGL_TRUE);
    666  }
    667 
    668  if (flags & CreateContextFlags::PROVOKING_VERTEX_DONT_CARE &&
    669      egl->IsExtensionSupported(
    670          EGLExtension::MOZ_create_context_provoking_vertex_dont_care)) {
    671    required_attribs.push_back(
    672        LOCAL_EGL_CONTEXT_PROVOKING_VERTEX_DONT_CARE_MOZ);
    673    required_attribs.push_back(LOCAL_EGL_TRUE);
    674  }
    675 
    676  std::vector<EGLint> ext_robustness_attribs;
    677  std::vector<EGLint> ext_rbab_attribs;  // RBAB: Robust Buffer Access Behavior
    678  std::vector<EGLint> khr_robustness_attribs;
    679  std::vector<EGLint> khr_rbab_attribs;  // RBAB: Robust Buffer Access Behavior
    680  if (flags & CreateContextFlags::PREFER_ROBUSTNESS) {
    681    std::vector<EGLint> base_robustness_attribs = required_attribs;
    682    if (egl->IsExtensionSupported(
    683            EGLExtension::NV_robustness_video_memory_purge)) {
    684      base_robustness_attribs.push_back(
    685          LOCAL_EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV);
    686      base_robustness_attribs.push_back(LOCAL_EGL_TRUE);
    687    }
    688 
    689    if (egl->IsExtensionSupported(
    690            EGLExtension::EXT_create_context_robustness)) {
    691      ext_robustness_attribs = base_robustness_attribs;
    692      ext_robustness_attribs.push_back(
    693          LOCAL_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT);
    694      ext_robustness_attribs.push_back(LOCAL_EGL_LOSE_CONTEXT_ON_RESET_EXT);
    695 
    696      if (gfxVars::AllowEglRbab()) {
    697        ext_rbab_attribs = ext_robustness_attribs;
    698        ext_rbab_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT);
    699        ext_rbab_attribs.push_back(LOCAL_EGL_TRUE);
    700      }
    701    }
    702 
    703    if (egl->IsExtensionSupported(EGLExtension::KHR_create_context)) {
    704      khr_robustness_attribs = base_robustness_attribs;
    705      khr_robustness_attribs.push_back(
    706          LOCAL_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR);
    707      khr_robustness_attribs.push_back(LOCAL_EGL_LOSE_CONTEXT_ON_RESET_KHR);
    708 
    709      khr_rbab_attribs = khr_robustness_attribs;
    710      khr_rbab_attribs.push_back(LOCAL_EGL_CONTEXT_FLAGS_KHR);
    711      khr_rbab_attribs.push_back(
    712          LOCAL_EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR);
    713    }
    714  }
    715 
    716  const auto fnCreate = [&](const std::vector<EGLint>& attribs) {
    717    auto terminated_attribs = attribs;
    718 
    719    for (const auto& cur : kTerminationAttribs) {
    720      terminated_attribs.push_back(cur);
    721    }
    722 
    723    return egl->fCreateContext(contextConfig, EGL_NO_CONTEXT,
    724                               terminated_attribs.data());
    725  };
    726 
    727  EGLContext context;
    728  do {
    729    if (!khr_rbab_attribs.empty()) {
    730      context = fnCreate(khr_rbab_attribs);
    731      if (context) break;
    732      NS_WARNING("Failed to create EGLContext with khr_rbab_attribs");
    733    }
    734 
    735    if (!ext_rbab_attribs.empty()) {
    736      context = fnCreate(ext_rbab_attribs);
    737      if (context) break;
    738      NS_WARNING("Failed to create EGLContext with ext_rbab_attribs");
    739    }
    740 
    741    if (!khr_robustness_attribs.empty()) {
    742      context = fnCreate(khr_robustness_attribs);
    743      if (context) break;
    744      NS_WARNING("Failed to create EGLContext with khr_robustness_attribs");
    745    }
    746 
    747    if (!ext_robustness_attribs.empty()) {
    748      context = fnCreate(ext_robustness_attribs);
    749      if (context) break;
    750      NS_WARNING("Failed to create EGLContext with ext_robustness_attribs");
    751    }
    752 
    753    context = fnCreate(required_attribs);
    754    if (context) break;
    755    NS_WARNING("Failed to create EGLContext with required_attribs");
    756 
    757    *out_failureId = "FEATURE_FAILURE_EGL_CREATE"_ns;
    758    return nullptr;
    759  } while (false);
    760  MOZ_ASSERT(context);
    761 
    762  RefPtr<GLContextEGL> glContext =
    763      new GLContextEGL(egl, desc, surfaceConfig, surface, context);
    764  if (!glContext->Init()) {
    765    *out_failureId = "FEATURE_FAILURE_EGL_INIT"_ns;
    766    return nullptr;
    767  }
    768 
    769  if (GLContext::ShouldSpew()) {
    770    printf_stderr("new GLContextEGL %p on EGLDisplay %p\n", glContext.get(),
    771                  egl->mDisplay);
    772  }
    773 
    774  return glContext;
    775 }
    776 
    777 // static
    778 EGLSurface GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(
    779    EglDisplay& egl, EGLConfig config, EGLenum bindToTextureFormat,
    780    mozilla::gfx::IntSize& pbsize) {
    781  nsTArray<EGLint> pbattrs(16);
    782  EGLSurface surface = nullptr;
    783 
    784 TRY_AGAIN_POWER_OF_TWO:
    785  pbattrs.Clear();
    786  pbattrs.AppendElement(LOCAL_EGL_WIDTH);
    787  pbattrs.AppendElement(pbsize.width);
    788  pbattrs.AppendElement(LOCAL_EGL_HEIGHT);
    789  pbattrs.AppendElement(pbsize.height);
    790 
    791  if (bindToTextureFormat != LOCAL_EGL_NONE) {
    792    pbattrs.AppendElement(LOCAL_EGL_TEXTURE_TARGET);
    793    pbattrs.AppendElement(LOCAL_EGL_TEXTURE_2D);
    794 
    795    pbattrs.AppendElement(LOCAL_EGL_TEXTURE_FORMAT);
    796    pbattrs.AppendElement(bindToTextureFormat);
    797  }
    798 
    799  for (const auto& cur : kTerminationAttribs) {
    800    pbattrs.AppendElement(cur);
    801  }
    802 
    803  surface = egl.fCreatePbufferSurface(config, &pbattrs[0]);
    804  if (!surface) {
    805    if (!is_power_of_two(pbsize.width) || !is_power_of_two(pbsize.height)) {
    806      if (!is_power_of_two(pbsize.width))
    807        pbsize.width = next_power_of_two(pbsize.width);
    808      if (!is_power_of_two(pbsize.height))
    809        pbsize.height = next_power_of_two(pbsize.height);
    810 
    811      NS_WARNING("Failed to create pbuffer, trying power of two dims");
    812      goto TRY_AGAIN_POWER_OF_TWO;
    813    }
    814 
    815    NS_WARNING("Failed to create pbuffer surface");
    816    return nullptr;
    817  }
    818 
    819  return surface;
    820 }
    821 
    822 #if defined(MOZ_WAYLAND)
    823 WaylandOffscreenGLSurface::WaylandOffscreenGLSurface(
    824    struct wl_surface* aWaylandSurface, struct wl_egl_window* aEGLWindow)
    825    : mWaylandSurface(aWaylandSurface), mEGLWindow(aEGLWindow) {}
    826 
    827 WaylandOffscreenGLSurface::~WaylandOffscreenGLSurface() {
    828  if (mEGLWindow) {
    829    wl_egl_window_destroy(mEGLWindow);
    830  }
    831  if (mWaylandSurface) {
    832    wl_surface_destroy(mWaylandSurface);
    833  }
    834 }
    835 
    836 // static
    837 EGLSurface GLContextEGL::CreateWaylandOffscreenSurface(
    838    EglDisplay& egl, EGLConfig config, mozilla::gfx::IntSize& pbsize) {
    839  wl_egl_window* eglwindow = nullptr;
    840 
    841  struct wl_compositor* compositor =
    842      gdk_wayland_display_get_wl_compositor(gdk_display_get_default());
    843  struct wl_surface* wlsurface = wl_compositor_create_surface(compositor);
    844  eglwindow = wl_egl_window_create(wlsurface, pbsize.width, pbsize.height);
    845  if (!eglwindow) return nullptr;
    846 
    847  const auto surface = egl.fCreateWindowSurface(
    848      config, reinterpret_cast<EGLNativeWindowType>(eglwindow), 0);
    849  if (surface) {
    850    MOZ_DIAGNOSTIC_ASSERT(!sWaylandOffscreenGLSurfaces.Contains(surface));
    851    sWaylandOffscreenGLSurfaces.LookupOrInsert(
    852        surface, new WaylandOffscreenGLSurface(wlsurface, eglwindow));
    853  }
    854  return surface;
    855 }
    856 #endif
    857 
    858 static const EGLint kEGLConfigAttribsRGB16[] = {
    859    LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
    860    LOCAL_EGL_RED_SIZE,     5,
    861    LOCAL_EGL_GREEN_SIZE,   6,
    862    LOCAL_EGL_BLUE_SIZE,    5,
    863    LOCAL_EGL_ALPHA_SIZE,   0};
    864 
    865 static const EGLint kEGLConfigAttribsRGB24[] = {
    866    LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
    867    LOCAL_EGL_RED_SIZE,     8,
    868    LOCAL_EGL_GREEN_SIZE,   8,
    869    LOCAL_EGL_BLUE_SIZE,    8,
    870    LOCAL_EGL_ALPHA_SIZE,   0};
    871 
    872 static const EGLint kEGLConfigAttribsRGBA32[] = {
    873    LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
    874    LOCAL_EGL_RED_SIZE,     8,
    875    LOCAL_EGL_GREEN_SIZE,   8,
    876    LOCAL_EGL_BLUE_SIZE,    8,
    877    LOCAL_EGL_ALPHA_SIZE,   8};
    878 
    879 bool CreateConfig(EglDisplay& aEgl, EGLConfig* aConfig, int32_t aDepth,
    880                  bool aEnableDepthBuffer, bool aUseGles, bool aAllowFallback) {
    881  EGLConfig configs[64];
    882  std::vector<EGLint> attribs;
    883  EGLint ncfg = std::size(configs);
    884 
    885  switch (aDepth) {
    886    case 16:
    887      for (const auto& cur : kEGLConfigAttribsRGB16) {
    888        attribs.push_back(cur);
    889      }
    890      break;
    891    case 24:
    892      for (const auto& cur : kEGLConfigAttribsRGB24) {
    893        attribs.push_back(cur);
    894      }
    895      break;
    896    case 32:
    897      for (const auto& cur : kEGLConfigAttribsRGBA32) {
    898        attribs.push_back(cur);
    899      }
    900      break;
    901    default:
    902      NS_ERROR("Unknown pixel depth");
    903      return false;
    904  }
    905 
    906  if (aUseGles) {
    907    attribs.push_back(LOCAL_EGL_RENDERABLE_TYPE);
    908    attribs.push_back(LOCAL_EGL_OPENGL_ES2_BIT);
    909  }
    910  for (const auto& cur : kTerminationAttribs) {
    911    attribs.push_back(cur);
    912  }
    913 
    914  if (!aEgl.fChooseConfig(attribs.data(), configs, ncfg, &ncfg) || ncfg < 1) {
    915    return false;
    916  }
    917 
    918  Maybe<EGLConfig> fallbackConfig;
    919 
    920  for (int j = 0; j < ncfg; ++j) {
    921    EGLConfig config = configs[j];
    922    EGLint r, g, b, a;
    923    if (aEgl.fGetConfigAttrib(config, LOCAL_EGL_RED_SIZE, &r) &&
    924        aEgl.fGetConfigAttrib(config, LOCAL_EGL_GREEN_SIZE, &g) &&
    925        aEgl.fGetConfigAttrib(config, LOCAL_EGL_BLUE_SIZE, &b) &&
    926        aEgl.fGetConfigAttrib(config, LOCAL_EGL_ALPHA_SIZE, &a) &&
    927        ((aDepth == 16 && r == 5 && g == 6 && b == 5) ||
    928         (aDepth == 24 && r == 8 && g == 8 && b == 8) ||
    929         (aDepth == 32 && r == 8 && g == 8 && b == 8 && a == 8))) {
    930      EGLint z;
    931      if (aEnableDepthBuffer) {
    932        if (!aEgl.fGetConfigAttrib(config, LOCAL_EGL_DEPTH_SIZE, &z) ||
    933            z != 24) {
    934          continue;
    935        }
    936      }
    937 #ifdef MOZ_X11
    938      if (GdkIsX11Display()) {
    939        int configVisualID;
    940        if (!aEgl.fGetConfigAttrib(config, LOCAL_EGL_NATIVE_VISUAL_ID,
    941                                   &configVisualID)) {
    942          continue;
    943        }
    944 
    945        XVisualInfo visual_info_template, *visual_info;
    946        int num_visuals;
    947 
    948        visual_info_template.visualid = configVisualID;
    949        visual_info =
    950            XGetVisualInfo(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()),
    951                           VisualIDMask, &visual_info_template, &num_visuals);
    952 
    953        if (!visual_info || visual_info->depth != aDepth) {
    954          if (aAllowFallback && !fallbackConfig) {
    955            fallbackConfig = Some(config);
    956          }
    957          continue;
    958        }
    959      }
    960 #endif
    961      *aConfig = config;
    962      return true;
    963    }
    964  }
    965 
    966  if (kIsLinux && fallbackConfig) {
    967    *aConfig = fallbackConfig.value();
    968    return true;
    969  }
    970 
    971  return false;
    972 }
    973 
    974 // Return true if a suitable EGLConfig was found and pass it out
    975 // through aConfig.  Return false otherwise.
    976 //
    977 // NB: It's entirely legal for the returned EGLConfig to be valid yet
    978 // have the value null.
    979 static bool CreateConfigScreen(EglDisplay& egl, EGLConfig* const aConfig,
    980                               const bool aEnableDepthBuffer,
    981                               const bool aUseGles) {
    982  int32_t depth = gfxVars::PrimaryScreenDepth();
    983  if (CreateConfig(egl, aConfig, depth, aEnableDepthBuffer, aUseGles)) {
    984    return true;
    985  }
    986 #ifdef MOZ_WIDGET_ANDROID
    987  // Bug 736005
    988  // Android doesn't always support 16 bit so also try 24 bit
    989  if (depth == 16) {
    990    return CreateConfig(egl, aConfig, 24, aEnableDepthBuffer, aUseGles);
    991  }
    992  // Bug 970096
    993  // Some devices that have 24 bit screens only support 16 bit OpenGL?
    994  if (depth == 24) {
    995    return CreateConfig(egl, aConfig, 16, aEnableDepthBuffer, aUseGles);
    996  }
    997 #endif
    998  return false;
    999 }
   1000 
   1001 already_AddRefed<GLContext> GLContextProviderEGL::CreateForCompositorWidget(
   1002    CompositorWidget* aCompositorWidget, bool aHardwareWebRender,
   1003    bool /*aForceAccelerated*/) {
   1004  EGLNativeWindowType window = nullptr;
   1005  if (aCompositorWidget) {
   1006    window = GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aCompositorWidget);
   1007  }
   1008  return GLContextEGLFactory::Create(window, aHardwareWebRender);
   1009 }
   1010 
   1011 EGLSurface GLContextEGL::CreateCompatibleSurface(void* aWindow) const {
   1012  MOZ_ASSERT(aWindow);
   1013  MOZ_RELEASE_ASSERT(mSurfaceConfig != EGL_NO_CONFIG);
   1014 
   1015  // NOTE: aWindow is an ANativeWindow
   1016  EGLSurface surface = mEgl->fCreateWindowSurface(
   1017      mSurfaceConfig, reinterpret_cast<EGLNativeWindowType>(aWindow), nullptr);
   1018  if (!surface) {
   1019    gfxCriticalError() << "CreateCompatibleSurface failed: "
   1020                       << hexa(GetError());
   1021  }
   1022  return surface;
   1023 }
   1024 
   1025 static void FillContextAttribs(bool es3, bool useGles, nsTArray<EGLint>* out) {
   1026  out->AppendElement(LOCAL_EGL_SURFACE_TYPE);
   1027 #ifdef MOZ_WAYLAND
   1028  if (GdkIsWaylandDisplay()) {
   1029    // Wayland on desktop does not support PBuffer or FBO.
   1030    // We create a dummy wl_egl_window instead.
   1031    out->AppendElement(LOCAL_EGL_WINDOW_BIT);
   1032  } else
   1033 #endif
   1034  {
   1035    out->AppendElement(LOCAL_EGL_PBUFFER_BIT);
   1036  }
   1037 
   1038  if (useGles) {
   1039    out->AppendElement(LOCAL_EGL_RENDERABLE_TYPE);
   1040    if (es3) {
   1041      out->AppendElement(LOCAL_EGL_OPENGL_ES3_BIT_KHR);
   1042    } else {
   1043      out->AppendElement(LOCAL_EGL_OPENGL_ES2_BIT);
   1044    }
   1045  }
   1046 
   1047  out->AppendElement(LOCAL_EGL_RED_SIZE);
   1048  out->AppendElement(8);
   1049 
   1050  out->AppendElement(LOCAL_EGL_GREEN_SIZE);
   1051  out->AppendElement(8);
   1052 
   1053  out->AppendElement(LOCAL_EGL_BLUE_SIZE);
   1054  out->AppendElement(8);
   1055 
   1056  out->AppendElement(LOCAL_EGL_ALPHA_SIZE);
   1057  out->AppendElement(8);
   1058 
   1059  out->AppendElement(LOCAL_EGL_DEPTH_SIZE);
   1060  out->AppendElement(0);
   1061 
   1062  out->AppendElement(LOCAL_EGL_STENCIL_SIZE);
   1063  out->AppendElement(0);
   1064 
   1065  // EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
   1066  out->AppendElement(LOCAL_EGL_NONE);
   1067  out->AppendElement(0);
   1068 
   1069  out->AppendElement(0);
   1070  out->AppendElement(0);
   1071 }
   1072 
   1073 /*
   1074 /// Useful for debugging, but normally unused.
   1075 static GLint GetAttrib(GLLibraryEGL* egl, EGLConfig config, EGLint attrib) {
   1076  EGLint bits = 0;
   1077  egl->fGetConfigAttrib(config, attrib, &bits);
   1078  MOZ_ASSERT(egl->fGetError() == LOCAL_EGL_SUCCESS);
   1079 
   1080  return bits;
   1081 }
   1082 */
   1083 
   1084 static EGLConfig ChooseConfig(EglDisplay& egl, const GLContextCreateDesc& desc,
   1085                              const bool useGles) {
   1086  nsTArray<EGLint> configAttribList;
   1087  FillContextAttribs(bool(desc.flags & CreateContextFlags::PREFER_ES3), useGles,
   1088                     &configAttribList);
   1089 
   1090  const EGLint* configAttribs = configAttribList.Elements();
   1091 
   1092  // The sorting dictated by the spec for eglChooseConfig reasonably assures
   1093  // that a reasonable 'best' config is on top.
   1094  const EGLint kMaxConfigs = 1;
   1095  EGLConfig configs[kMaxConfigs];
   1096  EGLint foundConfigs = 0;
   1097  if (!egl.fChooseConfig(configAttribs, configs, kMaxConfigs, &foundConfigs) ||
   1098      foundConfigs == 0) {
   1099    return EGL_NO_CONFIG;
   1100  }
   1101 
   1102  EGLConfig config = configs[0];
   1103  return config;
   1104 }
   1105 
   1106 #ifdef MOZ_X11
   1107 /* static */
   1108 bool GLContextEGL::FindVisual(int* const out_visualId) {
   1109  nsCString discardFailureId;
   1110  const auto egl = DefaultEglDisplay(&discardFailureId);
   1111  if (!egl) {
   1112    gfxCriticalNote
   1113        << "GLContextEGL::FindVisual(): Failed to load EGL library!";
   1114    return false;
   1115  }
   1116 
   1117  EGLConfig config;
   1118  const int bpp = 32;
   1119  if (!CreateConfig(*egl, &config, bpp, /* aEnableDepthBuffer */ false,
   1120                    /* aUseGles */ false, /* aAllowFallback */ false)) {
   1121    // We are on a buggy driver. Do not return a visual so a fallback path can
   1122    // be used. See https://gitlab.freedesktop.org/mesa/mesa/-/issues/149
   1123    return false;
   1124  }
   1125  if (egl->fGetConfigAttrib(config, LOCAL_EGL_NATIVE_VISUAL_ID, out_visualId)) {
   1126    return true;
   1127  }
   1128  return false;
   1129 }
   1130 #endif
   1131 
   1132 /*static*/
   1133 RefPtr<GLContextEGL> GLContextEGL::CreateWithoutSurface(
   1134    const std::shared_ptr<EglDisplay> egl, const GLContextCreateDesc& desc,
   1135    nsACString* const out_failureId) {
   1136  const auto WithUseGles = [&](const bool useGles) -> RefPtr<GLContextEGL> {
   1137 #ifdef MOZ_WIDGET_GTK
   1138    // First try creating a context with no config and no surface, this is what
   1139    // we really want, and seems to be the only way to make selecting software
   1140    // Mesa init properly when it's not the first device.
   1141    if (egl->IsExtensionSupported(EGLExtension::KHR_no_config_context) &&
   1142        egl->IsExtensionSupported(EGLExtension::KHR_surfaceless_context)) {
   1143      // These extensions have been supported by mesa and nvidia drivers
   1144      // since 2014 or earlier, this is the preferred code path
   1145      auto fullDesc = GLContextDesc{desc};
   1146      fullDesc.isOffscreen = true;
   1147      RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(
   1148          egl, fullDesc, EGL_NO_CONFIG, EGL_NO_SURFACE, useGles, EGL_NO_CONFIG,
   1149          out_failureId);
   1150      if (gl) {
   1151        return gl;
   1152      }
   1153      NS_WARNING(
   1154          "Failed to create GLContext with no config and no surface, will try "
   1155          "ChooseConfig");
   1156    }
   1157 #endif
   1158 
   1159    const EGLConfig surfaceConfig = ChooseConfig(*egl, desc, useGles);
   1160    if (surfaceConfig == EGL_NO_CONFIG) {
   1161      *out_failureId = "FEATURE_FAILURE_EGL_NO_CONFIG"_ns;
   1162      NS_WARNING("Failed to find a compatible config.");
   1163      return nullptr;
   1164    }
   1165 
   1166    if (GLContext::ShouldSpew()) {
   1167      egl->DumpEGLConfig(surfaceConfig);
   1168    }
   1169    const EGLConfig contextConfig =
   1170        egl->IsExtensionSupported(EGLExtension::KHR_no_config_context)
   1171            ? nullptr
   1172            : surfaceConfig;
   1173 
   1174    auto dummySize = mozilla::gfx::IntSize{16, 16};
   1175    EGLSurface surface = nullptr;
   1176 #ifdef MOZ_WAYLAND
   1177    if (GdkIsWaylandDisplay()) {
   1178      surface = GLContextEGL::CreateWaylandOffscreenSurface(*egl, surfaceConfig,
   1179                                                            dummySize);
   1180    } else
   1181 #endif
   1182    {
   1183      surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(
   1184          *egl, surfaceConfig, LOCAL_EGL_NONE, dummySize);
   1185    }
   1186    if (!surface) {
   1187      *out_failureId = "FEATURE_FAILURE_EGL_POT"_ns;
   1188      NS_WARNING("Failed to create PBuffer for context!");
   1189      return nullptr;
   1190    }
   1191 
   1192    auto fullDesc = GLContextDesc{desc};
   1193    fullDesc.isOffscreen = true;
   1194    RefPtr<GLContextEGL> gl =
   1195        GLContextEGL::CreateGLContext(egl, fullDesc, surfaceConfig, surface,
   1196                                      useGles, contextConfig, out_failureId);
   1197    if (!gl) {
   1198      NS_WARNING("Failed to create GLContext from PBuffer");
   1199      egl->fDestroySurface(surface);
   1200 #if defined(MOZ_WAYLAND)
   1201      DeleteWaylandOffscreenGLSurface(surface);
   1202 #endif
   1203      return nullptr;
   1204    }
   1205 
   1206    return gl;
   1207  };
   1208 
   1209  bool preferGles;
   1210 #if defined(MOZ_WIDGET_ANDROID)
   1211  preferGles = true;
   1212 #else
   1213  preferGles = StaticPrefs::gfx_egl_prefer_gles_enabled_AtStartup();
   1214 #endif  // defined(MOZ_WIDGET_ANDROID)
   1215  RefPtr<GLContextEGL> gl = WithUseGles(preferGles);
   1216 #if !defined(MOZ_WIDGET_ANDROID)
   1217  if (!gl) {
   1218    gl = WithUseGles(!preferGles);
   1219  }
   1220 #endif  // !defined(MOZ_WIDGET_ANDROID)
   1221  return gl;
   1222 }
   1223 
   1224 /*static*/
   1225 void GLContextEGL::DestroySurface(EglDisplay& aEgl, const EGLSurface aSurface) {
   1226  if (aSurface != EGL_NO_SURFACE) {
   1227    if (!aEgl.fMakeCurrent(EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
   1228      const EGLint err = aEgl.mLib->fGetError();
   1229      gfxCriticalNote << "Error in eglMakeCurrent: " << gfx::hexa(err);
   1230    }
   1231    if (!aEgl.fDestroySurface(aSurface)) {
   1232      const EGLint err = aEgl.mLib->fGetError();
   1233      gfxCriticalNote << "Error in eglDestroySurface: " << gfx::hexa(err);
   1234    }
   1235 #if defined(MOZ_WAYLAND)
   1236    DeleteWaylandOffscreenGLSurface(aSurface);
   1237 #endif
   1238  }
   1239 }
   1240 
   1241 /*static*/
   1242 already_AddRefed<GLContext> GLContextProviderEGL::CreateHeadless(
   1243    const GLContextCreateDesc& desc, nsACString* const out_failureId) {
   1244  bool useSoftwareDisplay =
   1245      static_cast<bool>(desc.flags & CreateContextFlags::FORBID_HARDWARE);
   1246  const auto display = useSoftwareDisplay
   1247                           ? CreateSoftwareEglDisplay(out_failureId)
   1248                           : DefaultEglDisplay(out_failureId);
   1249  if (!display) {
   1250    return nullptr;
   1251  }
   1252  auto ret = GLContextEGL::CreateWithoutSurface(display, desc, out_failureId);
   1253  return ret.forget();
   1254 }
   1255 
   1256 // Don't want a global context on Android as 1) share groups across 2 threads
   1257 // fail on many Tegra drivers (bug 759225) and 2) some mobile devices have a
   1258 // very strict limit on global number of GL contexts (bug 754257) and 3) each
   1259 // EGL context eats 750k on B2G (bug 813783)
   1260 /*static*/
   1261 GLContext* GLContextProviderEGL::GetGlobalContext() { return nullptr; }
   1262 
   1263 // -
   1264 
   1265 /*static*/ void GLContextProviderEGL::Shutdown() { GLLibraryEGL::Shutdown(); }
   1266 
   1267 } /* namespace gl */
   1268 } /* namespace mozilla */
   1269 
   1270 #undef EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS