tor-browser

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

GLLibraryEGL.cpp (34152B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "GLLibraryEGL.h"
      6 
      7 #include "gfxConfig.h"
      8 #include "gfxCrashReporterUtils.h"
      9 #include "gfxEnv.h"
     10 #include "gfxUtils.h"
     11 #include "mozilla/Preferences.h"
     12 #include "mozilla/Assertions.h"
     13 #include "mozilla/gfx/gfxVars.h"
     14 #include "mozilla/gfx/Logging.h"
     15 #include "mozilla/glean/DomCanvasMetrics.h"
     16 #include "mozilla/Tokenizer.h"
     17 #include "mozilla/ScopeExit.h"
     18 #include "mozilla/StaticPrefs_gfx.h"
     19 #include "mozilla/StaticPrefs_webgl.h"
     20 #include "nsDirectoryServiceDefs.h"
     21 #include "nsDirectoryServiceUtils.h"
     22 #include "nsPrintfCString.h"
     23 #ifdef XP_WIN
     24 #  include "mozilla/gfx/DeviceManagerDx.h"
     25 #  include "nsWindowsHelpers.h"
     26 #  include "prerror.h"
     27 
     28 #  include <d3d11.h>
     29 #endif
     30 #include "OGLShaderProgram.h"
     31 #include "prenv.h"
     32 #include "prsystem.h"
     33 #include "GLContext.h"
     34 #include "GLContextProvider.h"
     35 #include "GLLibraryLoader.h"
     36 #include "GLReadTexImageHelper.h"
     37 #include "ScopedGLHelpers.h"
     38 #ifdef MOZ_WIDGET_GTK
     39 #  include "mozilla/WidgetUtilsGtk.h"
     40 #  include "mozilla/widget/DMABufDevice.h"
     41 #  ifdef MOZ_WAYLAND
     42 #    include "mozilla/widget/nsWaylandDisplay.h"
     43 #  endif  // MOZ_WIDGET_GTK
     44 #  include <gdk/gdk.h>
     45 #endif  // MOZ_WAYLAND
     46 
     47 #include <mutex>  // for call_once
     48 
     49 namespace mozilla {
     50 namespace gl {
     51 
     52 StaticMutex GLLibraryEGL::sMutex;
     53 StaticRefPtr<GLLibraryEGL> GLLibraryEGL::sInstance;
     54 
     55 // should match the order of EGLExtensions, and be null-terminated.
     56 static const char* sEGLLibraryExtensionNames[] = {
     57    "EGL_ANDROID_get_native_client_buffer",
     58    "EGL_ANGLE_device_creation",
     59    "EGL_ANGLE_device_creation_d3d11",
     60    "EGL_ANGLE_platform_angle",
     61    "EGL_ANGLE_platform_angle_d3d",
     62    "EGL_EXT_device_enumeration",
     63    "EGL_EXT_device_query",
     64    "EGL_EXT_platform_device",
     65    "EGL_MESA_platform_surfaceless"};
     66 
     67 // should match the order of EGLExtensions, and be null-terminated.
     68 static const char* sEGLExtensionNames[] = {
     69    "EGL_KHR_image_base",
     70    "EGL_KHR_image_pixmap",
     71    "EGL_KHR_gl_texture_2D_image",
     72    "EGL_ANGLE_surface_d3d_texture_2d_share_handle",
     73    "EGL_EXT_create_context_robustness",
     74    "EGL_KHR_image",
     75    "EGL_KHR_fence_sync",
     76    "EGL_KHR_wait_sync",
     77    "EGL_ANDROID_native_fence_sync",
     78    "EGL_ANDROID_image_crop",
     79    "EGL_ANGLE_d3d_share_handle_client_buffer",
     80    "EGL_KHR_create_context",
     81    "EGL_KHR_stream",
     82    "EGL_KHR_stream_consumer_gltexture",
     83    "EGL_NV_stream_consumer_gltexture_yuv",
     84    "EGL_ANGLE_stream_producer_d3d_texture",
     85    "EGL_KHR_surfaceless_context",
     86    "EGL_KHR_create_context_no_error",
     87    "EGL_MOZ_create_context_provoking_vertex_dont_care",
     88    "EGL_EXT_swap_buffers_with_damage",
     89    "EGL_KHR_swap_buffers_with_damage",
     90    "EGL_EXT_buffer_age",
     91    "EGL_KHR_partial_update",
     92    "EGL_NV_robustness_video_memory_purge",
     93    "EGL_EXT_image_dma_buf_import",
     94    "EGL_EXT_image_dma_buf_import_modifiers",
     95    "EGL_MESA_image_dma_buf_export",
     96    "EGL_KHR_no_config_context",
     97 };
     98 
     99 PRLibrary* LoadApitraceLibrary() {
    100  const char* path = nullptr;
    101 
    102 #ifdef ANDROID
    103  // We only need to explicitly dlopen egltrace
    104  // on android as we can use LD_PRELOAD or other tricks
    105  // on other platforms. We look for it in /data/local
    106  // as that's writeable by all users.
    107  path = "/data/local/tmp/egltrace.so";
    108 #endif
    109  if (!path) return nullptr;
    110 
    111  // Initialization of gfx prefs here is only needed during the unit tests...
    112  if (!StaticPrefs::gfx_apitrace_enabled_AtStartup()) {
    113    return nullptr;
    114  }
    115 
    116  static PRLibrary* sApitraceLibrary = nullptr;
    117  if (sApitraceLibrary) return sApitraceLibrary;
    118 
    119  nsAutoCString logFile;
    120  Preferences::GetCString("gfx.apitrace.logfile", logFile);
    121  if (logFile.IsEmpty()) {
    122    logFile = "firefox.trace";
    123  }
    124 
    125  // The firefox process can't write to /data/local, but it can write
    126  // to $GRE_HOME/
    127  nsAutoCString logPath;
    128  logPath.AppendPrintf("%s/%s", getenv("GRE_HOME"), logFile.get());
    129 
    130 #ifndef XP_WIN  // Windows is missing setenv and forbids PR_LoadLibrary.
    131  // apitrace uses the TRACE_FILE environment variable to determine where
    132  // to log trace output to
    133  printf_stderr("Logging GL tracing output to %s", logPath.get());
    134  setenv("TRACE_FILE", logPath.get(), false);
    135 
    136  printf_stderr("Attempting load of %s\n", path);
    137  sApitraceLibrary = PR_LoadLibrary(path);
    138 #endif
    139 
    140  return sApitraceLibrary;
    141 }
    142 
    143 #ifdef XP_WIN
    144 // see the comment in GLLibraryEGL::EnsureInitialized() for the rationale here.
    145 static PRLibrary* LoadLibraryForEGLOnWindows(const nsAString& filename) {
    146  nsAutoString path(gfx::gfxVars::GREDirectory());
    147  path.Append(PR_GetDirectorySeparator());
    148  path.Append(filename);
    149 
    150  PRLibSpec lspec;
    151  lspec.type = PR_LibSpec_PathnameU;
    152  lspec.value.pathname_u = path.get();
    153  PRLibrary* lib = PR_LoadLibraryWithFlags(lspec, PR_LD_LAZY | PR_LD_LOCAL);
    154  if (!lib) {
    155    gfxCriticalNote << "Failed to load " << path.get() << " " << PR_GetError()
    156                    << " " << PR_GetOSError();
    157  }
    158  return lib;
    159 }
    160 
    161 #endif  // XP_WIN
    162 
    163 static std::shared_ptr<EglDisplay> GetAndInitDisplay(
    164    GLLibraryEGL& egl, void* displayType,
    165    const StaticMutexAutoLock& aProofOfLock) {
    166  const auto display = egl.fGetDisplay(displayType);
    167  if (!display) return nullptr;
    168  return EglDisplay::Create(egl, display, false, aProofOfLock);
    169 }
    170 
    171 #ifdef MOZ_WIDGET_GTK
    172 static std::shared_ptr<EglDisplay> GetAndInitDeviceDisplay(
    173    GLLibraryEGL& egl, const StaticMutexAutoLock& aProofOfLock) {
    174  nsAutoCString drmRenderDevice(gfx::gfxVars::DrmRenderDevice());
    175  if (drmRenderDevice.IsEmpty() ||
    176      !egl.IsExtensionSupported(EGLLibExtension::EXT_platform_device) ||
    177      !egl.IsExtensionSupported(EGLLibExtension::EXT_device_enumeration)) {
    178    return nullptr;
    179  }
    180 
    181  EGLint maxDevices;
    182  if (!egl.fQueryDevicesEXT(0, nullptr, &maxDevices)) {
    183    return nullptr;
    184  }
    185 
    186  std::vector<EGLDeviceEXT> devices(maxDevices);
    187  EGLint numDevices;
    188  if (!egl.fQueryDevicesEXT(devices.size(), devices.data(), &numDevices)) {
    189    return nullptr;
    190  }
    191  devices.resize(numDevices);
    192 
    193  EGLDisplay display = EGL_NO_DISPLAY;
    194  for (const auto& device : devices) {
    195    const char* renderNodeString =
    196        egl.fQueryDeviceStringEXT(device, LOCAL_EGL_DRM_RENDER_NODE_FILE_EXT);
    197    if (renderNodeString &&
    198        strcmp(renderNodeString, drmRenderDevice.get()) == 0) {
    199      const EGLAttrib attrib_list[] = {LOCAL_EGL_NONE};
    200      display = egl.fGetPlatformDisplay(LOCAL_EGL_PLATFORM_DEVICE_EXT, device,
    201                                        attrib_list);
    202      break;
    203    }
    204  }
    205  if (!display) {
    206    return nullptr;
    207  }
    208 
    209  return EglDisplay::Create(egl, display, true, aProofOfLock);
    210 }
    211 
    212 static std::shared_ptr<EglDisplay> GetAndInitSoftwareDisplay(
    213    GLLibraryEGL& egl, const StaticMutexAutoLock& aProofOfLock) {
    214  if (!egl.IsExtensionSupported(EGLLibExtension::EXT_platform_device) ||
    215      !egl.IsExtensionSupported(EGLLibExtension::EXT_device_enumeration)) {
    216    return nullptr;
    217  }
    218 
    219  EGLint maxDevices;
    220  if (!egl.fQueryDevicesEXT(0, nullptr, &maxDevices)) {
    221    return nullptr;
    222  }
    223 
    224  std::vector<EGLDeviceEXT> devices(maxDevices);
    225  EGLint numDevices;
    226  if (!egl.fQueryDevicesEXT(devices.size(), devices.data(), &numDevices)) {
    227    return nullptr;
    228  }
    229  devices.resize(numDevices);
    230 
    231  EGLDisplay display = EGL_NO_DISPLAY;
    232  for (const auto& device : devices) {
    233    const char* renderNodeString =
    234        egl.fQueryDeviceStringEXT(device, LOCAL_EGL_DRM_RENDER_NODE_FILE_EXT);
    235    // We are looking for a device with no file
    236    if (!renderNodeString || *renderNodeString == 0) {
    237      const EGLAttrib attrib_list[] = {LOCAL_EGL_NONE};
    238      display = egl.fGetPlatformDisplay(LOCAL_EGL_PLATFORM_DEVICE_EXT, device,
    239                                        attrib_list);
    240      break;
    241    }
    242  }
    243  if (!display) {
    244    return nullptr;
    245  }
    246 
    247  return EglDisplay::Create(egl, display, true, aProofOfLock);
    248 }
    249 
    250 static std::shared_ptr<EglDisplay> GetAndInitSurfacelessDisplay(
    251    GLLibraryEGL& egl, const StaticMutexAutoLock& aProofOfLock) {
    252  if (!egl.IsExtensionSupported(EGLLibExtension::MESA_platform_surfaceless)) {
    253    return nullptr;
    254  }
    255 
    256  const EGLAttrib attrib_list[] = {LOCAL_EGL_NONE};
    257  const EGLDisplay display = egl.fGetPlatformDisplay(
    258      LOCAL_EGL_PLATFORM_SURFACELESS_MESA, EGL_DEFAULT_DISPLAY, attrib_list);
    259  if (display == EGL_NO_DISPLAY) {
    260    return nullptr;
    261  }
    262  return EglDisplay::Create(egl, display, true, aProofOfLock);
    263 }
    264 #endif
    265 
    266 static auto EglDebugLayersEnabled() {
    267  EGLAttrib ret = LOCAL_EGL_FALSE;
    268 #ifdef XP_WIN
    269  if (StaticPrefs::gfx_direct3d11_enable_debug_layer_AtStartup()) {
    270    ret = LOCAL_EGL_TRUE;
    271  }
    272 #endif
    273  return ret;
    274 }
    275 
    276 static std::shared_ptr<EglDisplay> GetAndInitWARPDisplay(
    277    GLLibraryEGL& egl, void* displayType,
    278    const StaticMutexAutoLock& aProofOfLock) {
    279  const EGLAttrib attrib_list[] = {
    280      LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE,
    281      LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE,
    282      LOCAL_EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE,
    283      EglDebugLayersEnabled(),
    284      // Requires:
    285      LOCAL_EGL_PLATFORM_ANGLE_TYPE_ANGLE,
    286      LOCAL_EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, LOCAL_EGL_NONE};
    287  const EGLDisplay display = egl.fGetPlatformDisplay(
    288      LOCAL_EGL_PLATFORM_ANGLE_ANGLE, displayType, attrib_list);
    289 
    290  if (display == EGL_NO_DISPLAY) {
    291    const EGLint err = egl.fGetError();
    292    if (err != LOCAL_EGL_SUCCESS) {
    293      gfxCriticalError() << "Unexpected GL error: " << gfx::hexa(err);
    294      MOZ_CRASH("GFX: Unexpected GL error.");
    295    }
    296    return nullptr;
    297  }
    298 
    299  return EglDisplay::Create(egl, display, true, aProofOfLock);
    300 }
    301 
    302 std::shared_ptr<EglDisplay> GLLibraryEGL::CreateDisplay(
    303    ID3D11Device* const d3d11Device) {
    304  StaticMutexAutoLock lock(sMutex);
    305  EGLDeviceEXT eglDevice =
    306      fCreateDeviceANGLE(LOCAL_EGL_D3D11_DEVICE_ANGLE, d3d11Device, nullptr);
    307  if (!eglDevice) {
    308    gfxCriticalNote << "Failed to get EGLDeviceEXT of D3D11Device";
    309    return nullptr;
    310  }
    311  const char* features[] = {"allowES3OnFL10_0", nullptr};
    312  // Create an EGLDisplay using the EGLDevice
    313  const EGLAttrib attrib_list[] = {LOCAL_EGL_FEATURE_OVERRIDES_ENABLED_ANGLE,
    314                                   reinterpret_cast<EGLAttrib>(features),
    315                                   LOCAL_EGL_NONE};
    316  const auto display = fGetPlatformDisplay(LOCAL_EGL_PLATFORM_DEVICE_EXT,
    317                                           eglDevice, attrib_list);
    318  if (!display) {
    319    gfxCriticalNote << "Failed to get EGLDisplay of D3D11Device";
    320    return nullptr;
    321  }
    322 
    323  if (!display) {
    324    const EGLint err = fGetError();
    325    if (err != LOCAL_EGL_SUCCESS) {
    326      gfxCriticalError() << "Unexpected GL error: " << gfx::hexa(err);
    327      MOZ_CRASH("GFX: Unexpected GL error.");
    328    }
    329    return nullptr;
    330  }
    331 
    332  const auto ret = EglDisplay::Create(*this, display, false, lock);
    333 
    334  if (!ret) {
    335    const EGLint err = fGetError();
    336    if (err != LOCAL_EGL_SUCCESS) {
    337      gfxCriticalError()
    338          << "Failed to initialize EGLDisplay for WebRender error: "
    339          << gfx::hexa(err);
    340    }
    341    return nullptr;
    342  }
    343  return ret;
    344 }
    345 
    346 static bool IsAccelAngleSupported(nsACString* const out_failureId) {
    347  if (!gfx::gfxVars::AllowWebglAccelAngle()) {
    348    if (out_failureId->IsEmpty()) {
    349      *out_failureId = "FEATURE_FAILURE_ACCL_ANGLE_NOT_OK"_ns;
    350    }
    351    return false;
    352  }
    353  return true;
    354 }
    355 
    356 class AngleErrorReporting {
    357 public:
    358  AngleErrorReporting() : mFailureId(nullptr) {
    359    // No static constructor
    360  }
    361 
    362  void SetFailureId(nsACString* const aFailureId) { mFailureId = aFailureId; }
    363 
    364  void logError(const char* errorMessage) {
    365    if (!mFailureId) {
    366      return;
    367    }
    368 
    369    nsCString str(errorMessage);
    370    Tokenizer tokenizer(str);
    371 
    372    // Parse "ANGLE Display::initialize error " << error.getID() << ": "
    373    //       << error.getMessage()
    374    nsCString currWord;
    375    Tokenizer::Token intToken;
    376    if (tokenizer.CheckWord("ANGLE") && tokenizer.CheckWhite() &&
    377        tokenizer.CheckWord("Display") && tokenizer.CheckChar(':') &&
    378        tokenizer.CheckChar(':') && tokenizer.CheckWord("initialize") &&
    379        tokenizer.CheckWhite() && tokenizer.CheckWord("error") &&
    380        tokenizer.CheckWhite() &&
    381        tokenizer.Check(Tokenizer::TOKEN_INTEGER, intToken)) {
    382      *mFailureId = "FAILURE_ID_ANGLE_ID_";
    383      mFailureId->AppendPrintf("%" PRIu64, intToken.AsInteger());
    384    } else {
    385      *mFailureId = "FAILURE_ID_ANGLE_UNKNOWN";
    386    }
    387  }
    388 
    389 private:
    390  nsACString* mFailureId;
    391 };
    392 
    393 MOZ_RUNINIT AngleErrorReporting gAngleErrorReporter;
    394 
    395 static std::shared_ptr<EglDisplay> GetAndInitDisplayForAccelANGLE(
    396    GLLibraryEGL& egl, nsACString* const out_failureId,
    397    const StaticMutexAutoLock& aProofOfLock) {
    398  gfx::FeatureState& d3d11ANGLE =
    399      gfx::gfxConfig::GetFeature(gfx::Feature::D3D11_HW_ANGLE);
    400 
    401  if (!StaticPrefs::webgl_angle_try_d3d11()) {
    402    d3d11ANGLE.UserDisable("User disabled D3D11 ANGLE by pref",
    403                           "FAILURE_ID_ANGLE_PREF"_ns);
    404  }
    405  if (StaticPrefs::webgl_angle_force_d3d11()) {
    406    d3d11ANGLE.UserForceEnable(
    407        "User force-enabled D3D11 ANGLE on disabled hardware");
    408  }
    409  gAngleErrorReporter.SetFailureId(out_failureId);
    410 
    411  auto guardShutdown = mozilla::MakeScopeExit([&] {
    412    gAngleErrorReporter.SetFailureId(nullptr);
    413    // NOTE: Ideally we should be calling ANGLEPlatformShutdown after the
    414    //       ANGLE display is destroyed. However gAngleErrorReporter
    415    //       will live longer than the ANGLE display so we're fine.
    416  });
    417 
    418  if (gfx::gfxConfig::IsForcedOnByUser(gfx::Feature::D3D11_HW_ANGLE)) {
    419    return GetAndInitDisplay(egl, LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE,
    420                             aProofOfLock);
    421  }
    422 
    423  std::shared_ptr<EglDisplay> ret;
    424  if (d3d11ANGLE.IsEnabled()) {
    425    ret = GetAndInitDisplay(egl, LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE,
    426                            aProofOfLock);
    427  }
    428 
    429  if (!ret) {
    430    ret = GetAndInitDisplay(egl, EGL_DEFAULT_DISPLAY, aProofOfLock);
    431  }
    432 
    433  if (!ret && out_failureId->IsEmpty()) {
    434    *out_failureId = "FEATURE_FAILURE_ACCL_ANGLE_NO_DISP"_ns;
    435  }
    436 
    437  return ret;
    438 }
    439 
    440 // -
    441 
    442 #if defined(XP_UNIX)
    443 #  define GLES2_LIB "libGLESv2.so"
    444 #  define GLES2_LIB2 "libGLESv2.so.2"
    445 #  define GL_LIB "libGL.so"
    446 #  define GL_LIB2 "libGL.so.1"
    447 #elif defined(XP_WIN)
    448 #  define GLES2_LIB "libGLESv2.dll"
    449 #else
    450 #  error "Platform not recognized"
    451 #endif
    452 
    453 Maybe<SymbolLoader> GLLibraryEGL::GetSymbolLoader() const {
    454  auto ret = SymbolLoader(mSymbols.fGetProcAddress);
    455  ret.mLib = mGLLibrary;
    456  return Some(ret);
    457 }
    458 
    459 // -
    460 
    461 /* static */
    462 RefPtr<GLLibraryEGL> GLLibraryEGL::Get(nsACString* const out_failureId) {
    463  StaticMutexAutoLock lock(sMutex);
    464  if (!sInstance) {
    465    sInstance = new GLLibraryEGL;
    466    if (NS_WARN_IF(!sInstance->Init(out_failureId))) {
    467      sInstance = nullptr;
    468    }
    469  }
    470  return sInstance;
    471 }
    472 
    473 /* static */ void GLLibraryEGL::Shutdown() {
    474  StaticMutexAutoLock lock(sMutex);
    475  sInstance = nullptr;
    476 }
    477 
    478 bool GLLibraryEGL::Init(nsACString* const out_failureId) {
    479  MOZ_RELEASE_ASSERT(!mSymbols.fTerminate);
    480 
    481  mozilla::ScopedGfxFeatureReporter reporter("EGL");
    482 
    483 #ifdef XP_WIN
    484  if (!mEGLLibrary) {
    485    // On Windows, the GLESv2, EGL and DXSDK libraries are shipped with libxul
    486    // and we should look for them there. We have to load the libs in this
    487    // order, because libEGL.dll depends on libGLESv2.dll which depends on the
    488    // DXSDK libraries. This matters especially for WebRT apps which are in a
    489    // different directory. See bug 760323 and bug 749459
    490 
    491    // Also note that we intentionally leak the libs we load.
    492 
    493    do {
    494      // Windows 8.1+ has d3dcompiler_47.dll in the system directory.
    495      if (LoadLibrarySystem32(L"d3dcompiler_47.dll")) break;
    496 
    497      MOZ_ASSERT(false, "d3dcompiler DLL loading failed.");
    498    } while (false);
    499 
    500    mGLLibrary = LoadLibraryForEGLOnWindows(u"libGLESv2.dll"_ns);
    501 
    502    mEGLLibrary = LoadLibraryForEGLOnWindows(u"libEGL.dll"_ns);
    503  }
    504 
    505 #else  // !Windows
    506 
    507  // On non-Windows (Android) we use system copies of libEGL. We look for
    508  // the APITrace lib, libEGL.so, and libEGL.so.1 in that order.
    509 
    510 #  if defined(ANDROID)
    511  if (!mEGLLibrary) mEGLLibrary = LoadApitraceLibrary();
    512 #  endif
    513 
    514  if (!mEGLLibrary) {
    515    mEGLLibrary = PR_LoadLibrary("libEGL.so");
    516  }
    517 #  if defined(XP_UNIX)
    518  if (!mEGLLibrary) {
    519    mEGLLibrary = PR_LoadLibrary("libEGL.so.1");
    520  }
    521 #  endif
    522 
    523 #  ifdef APITRACE_LIB
    524  if (!mGLLibrary) {
    525    mGLLibrary = PR_LoadLibrary(APITRACE_LIB);
    526  }
    527 #  endif
    528 
    529 #  ifdef GL_LIB
    530  if (!mGLLibrary) {
    531    mGLLibrary = PR_LoadLibrary(GL_LIB);
    532  }
    533 #  endif
    534 
    535 #  ifdef GL_LIB2
    536  if (!mGLLibrary) {
    537    mGLLibrary = PR_LoadLibrary(GL_LIB2);
    538  }
    539 #  endif
    540 
    541  if (!mGLLibrary) {
    542    mGLLibrary = PR_LoadLibrary(GLES2_LIB);
    543  }
    544 
    545 #  ifdef GLES2_LIB2
    546  if (!mGLLibrary) {
    547    mGLLibrary = PR_LoadLibrary(GLES2_LIB2);
    548  }
    549 #  endif
    550 
    551 #endif  // !Windows
    552 
    553  if (!mEGLLibrary || !mGLLibrary) {
    554    NS_WARNING("Couldn't load EGL LIB.");
    555    *out_failureId = "FEATURE_FAILURE_EGL_LOAD_3"_ns;
    556    return false;
    557  }
    558 
    559 #define SYMBOL(X)                 \
    560  {                               \
    561    (PRFuncPtr*)&mSymbols.f##X, { \
    562      {                           \
    563        "egl" #X                  \
    564      }                           \
    565    }                             \
    566  }
    567 #define END_OF_SYMBOLS \
    568  {                    \
    569    nullptr, {}        \
    570  }
    571 
    572  SymLoadStruct earlySymbols[] = {SYMBOL(GetDisplay),
    573                                  SYMBOL(Terminate),
    574                                  SYMBOL(GetCurrentSurface),
    575                                  SYMBOL(GetCurrentContext),
    576                                  SYMBOL(MakeCurrent),
    577                                  SYMBOL(DestroyContext),
    578                                  SYMBOL(CreateContext),
    579                                  SYMBOL(DestroySurface),
    580                                  SYMBOL(CreateWindowSurface),
    581                                  SYMBOL(CreatePbufferSurface),
    582                                  SYMBOL(CreatePbufferFromClientBuffer),
    583                                  SYMBOL(CreatePixmapSurface),
    584                                  SYMBOL(BindAPI),
    585                                  SYMBOL(Initialize),
    586                                  SYMBOL(ChooseConfig),
    587                                  SYMBOL(GetError),
    588                                  SYMBOL(GetConfigs),
    589                                  SYMBOL(GetConfigAttrib),
    590                                  SYMBOL(WaitNative),
    591                                  SYMBOL(GetProcAddress),
    592                                  SYMBOL(SwapBuffers),
    593                                  SYMBOL(CopyBuffers),
    594                                  SYMBOL(QueryString),
    595                                  SYMBOL(QueryContext),
    596                                  SYMBOL(BindTexImage),
    597                                  SYMBOL(ReleaseTexImage),
    598                                  SYMBOL(SwapInterval),
    599                                  SYMBOL(QuerySurface),
    600                                  END_OF_SYMBOLS};
    601 
    602  {
    603    const SymbolLoader libLoader(*mEGLLibrary);
    604    if (!libLoader.LoadSymbols(earlySymbols)) {
    605      NS_WARNING(
    606          "Couldn't find required entry points in EGL library (early init)");
    607      *out_failureId = "FEATURE_FAILURE_EGL_SYM"_ns;
    608      return false;
    609    }
    610  }
    611 
    612  {
    613    const char internalFuncName[] =
    614        "_Z35eglQueryStringImplementationANDROIDPvi";
    615    const auto& internalFunc =
    616        PR_FindFunctionSymbol(mEGLLibrary, internalFuncName);
    617    if (internalFunc) {
    618      *(PRFuncPtr*)&mSymbols.fQueryString = internalFunc;
    619    }
    620  }
    621 
    622  // -
    623 
    624  InitLibExtensions();
    625 
    626  const SymbolLoader pfnLoader(mSymbols.fGetProcAddress);
    627 
    628  const auto fnLoadSymbols = [&](const SymLoadStruct* symbols) {
    629    const bool shouldWarn = gfxEnv::MOZ_GL_SPEW();
    630    if (pfnLoader.LoadSymbols(symbols, shouldWarn)) return true;
    631 
    632    ClearSymbols(symbols);
    633    return false;
    634  };
    635 
    636  // Check the ANGLE support the system has
    637  mIsANGLE = IsExtensionSupported(EGLLibExtension::ANGLE_platform_angle);
    638 
    639  // Client exts are ready. (But not display exts!)
    640 
    641  if (mIsANGLE) {
    642    MOZ_ASSERT(IsExtensionSupported(EGLLibExtension::ANGLE_platform_angle_d3d));
    643    const SymLoadStruct angleSymbols[] = {SYMBOL(GetPlatformDisplay),
    644                                          END_OF_SYMBOLS};
    645    if (!fnLoadSymbols(angleSymbols)) {
    646      gfxCriticalError() << "Failed to load ANGLE symbols!";
    647      return false;
    648    }
    649    MOZ_ASSERT(IsExtensionSupported(EGLLibExtension::ANGLE_platform_angle_d3d));
    650    const SymLoadStruct createDeviceSymbols[] = {
    651        SYMBOL(CreateDeviceANGLE), SYMBOL(ReleaseDeviceANGLE), END_OF_SYMBOLS};
    652    if (!fnLoadSymbols(createDeviceSymbols)) {
    653      NS_ERROR(
    654          "EGL supports ANGLE_device_creation without exposing its functions!");
    655      MarkExtensionUnsupported(EGLLibExtension::ANGLE_device_creation);
    656    }
    657  }
    658 
    659  // ANDROID_get_native_client_buffer isn't necessarily enumerated in lib exts,
    660  // but it is one.
    661  {
    662    const SymLoadStruct symbols[] = {SYMBOL(GetNativeClientBufferANDROID),
    663                                     END_OF_SYMBOLS};
    664    if (fnLoadSymbols(symbols)) {
    665      mAvailableExtensions[UnderlyingValue(
    666          EGLLibExtension::ANDROID_get_native_client_buffer)] = true;
    667    }
    668  }
    669 
    670  // -
    671  // Load possible display ext symbols.
    672 
    673  {
    674    const SymLoadStruct symbols[] = {SYMBOL(QuerySurfacePointerANGLE),
    675                                     END_OF_SYMBOLS};
    676    (void)fnLoadSymbols(symbols);
    677  }
    678  {
    679    const SymLoadStruct symbols[] = {
    680        SYMBOL(CreateSyncKHR), SYMBOL(DestroySyncKHR),
    681        SYMBOL(ClientWaitSyncKHR), SYMBOL(GetSyncAttribKHR), END_OF_SYMBOLS};
    682    (void)fnLoadSymbols(symbols);
    683  }
    684  {
    685    const SymLoadStruct symbols[] = {SYMBOL(CreateImageKHR),
    686                                     SYMBOL(DestroyImageKHR), END_OF_SYMBOLS};
    687    (void)fnLoadSymbols(symbols);
    688  }
    689  {
    690    const SymLoadStruct symbols[] = {SYMBOL(WaitSyncKHR), END_OF_SYMBOLS};
    691    (void)fnLoadSymbols(symbols);
    692  }
    693  {
    694    const SymLoadStruct symbols[] = {SYMBOL(DupNativeFenceFDANDROID),
    695                                     END_OF_SYMBOLS};
    696    (void)fnLoadSymbols(symbols);
    697  }
    698  {
    699    const SymLoadStruct symbols[] = {SYMBOL(CreateStreamKHR),
    700                                     SYMBOL(DestroyStreamKHR),
    701                                     SYMBOL(QueryStreamKHR), END_OF_SYMBOLS};
    702    (void)fnLoadSymbols(symbols);
    703  }
    704  {
    705    const SymLoadStruct symbols[] = {SYMBOL(StreamConsumerGLTextureExternalKHR),
    706                                     SYMBOL(StreamConsumerAcquireKHR),
    707                                     SYMBOL(StreamConsumerReleaseKHR),
    708                                     END_OF_SYMBOLS};
    709    (void)fnLoadSymbols(symbols);
    710  }
    711  {
    712    const SymLoadStruct symbols[] = {
    713        SYMBOL(QueryDisplayAttribEXT), SYMBOL(QueryDeviceAttribEXT),
    714        SYMBOL(QueryDeviceStringEXT), END_OF_SYMBOLS};
    715    (void)fnLoadSymbols(symbols);
    716  }
    717  {
    718    const SymLoadStruct symbols[] = {
    719        SYMBOL(StreamConsumerGLTextureExternalAttribsNV), END_OF_SYMBOLS};
    720    (void)fnLoadSymbols(symbols);
    721  }
    722  {
    723    const SymLoadStruct symbols[] = {
    724        SYMBOL(CreateStreamProducerD3DTextureANGLE),
    725        SYMBOL(StreamPostD3DTextureANGLE), END_OF_SYMBOLS};
    726    (void)fnLoadSymbols(symbols);
    727  }
    728  {
    729    const SymLoadStruct symbols[] = {
    730        {(PRFuncPtr*)&mSymbols.fSwapBuffersWithDamage,
    731         {{"eglSwapBuffersWithDamageEXT"}}},
    732        END_OF_SYMBOLS};
    733    (void)fnLoadSymbols(symbols);
    734  }
    735  {
    736    const SymLoadStruct symbols[] = {
    737        {(PRFuncPtr*)&mSymbols.fSwapBuffersWithDamage,
    738         {{"eglSwapBuffersWithDamageKHR"}}},
    739        END_OF_SYMBOLS};
    740    (void)fnLoadSymbols(symbols);
    741  }
    742  {
    743    const SymLoadStruct symbols[] = {
    744        {(PRFuncPtr*)&mSymbols.fSetDamageRegion, {{"eglSetDamageRegionKHR"}}},
    745        END_OF_SYMBOLS};
    746    (void)fnLoadSymbols(symbols);
    747  }
    748  {
    749    const SymLoadStruct symbols[] = {SYMBOL(GetPlatformDisplay),
    750                                     END_OF_SYMBOLS};
    751    (void)fnLoadSymbols(symbols);
    752  }
    753  {
    754    const SymLoadStruct symbols[] = {SYMBOL(ExportDMABUFImageQueryMESA),
    755                                     SYMBOL(ExportDMABUFImageMESA),
    756                                     END_OF_SYMBOLS};
    757    (void)fnLoadSymbols(symbols);
    758  }
    759  {
    760    const SymLoadStruct symbols[] = {SYMBOL(QueryDevicesEXT), END_OF_SYMBOLS};
    761    (void)fnLoadSymbols(symbols);
    762  }
    763 
    764  return true;
    765 }
    766 
    767 // -
    768 
    769 template <size_t N>
    770 static void MarkExtensions(const char* rawExtString, bool shouldDumpExts,
    771                           const char* extType, const char* const (&names)[N],
    772                           std::bitset<N>* const out) {
    773  MOZ_ASSERT(rawExtString);
    774 
    775  const nsDependentCString extString(rawExtString);
    776 
    777  std::vector<nsCString> extList;
    778  SplitByChar(extString, ' ', &extList);
    779 
    780  if (shouldDumpExts) {
    781    printf_stderr("%u EGL %s extensions: (*: recognized)\n",
    782                  (uint32_t)extList.size(), extType);
    783  }
    784 
    785  MarkBitfieldByStrings(extList, shouldDumpExts, names, out);
    786 }
    787 
    788 // -
    789 
    790 // static
    791 std::shared_ptr<EglDisplay> EglDisplay::Create(
    792    GLLibraryEGL& lib, const EGLDisplay display, const bool isWarp,
    793    const StaticMutexAutoLock& aProofOfLock) {
    794  // Retrieve the EglDisplay if it already exists
    795  {
    796    const auto itr = lib.mActiveDisplays.find(display);
    797    if (itr != lib.mActiveDisplays.end()) {
    798      const auto ret = itr->second.lock();
    799      if (ret) {
    800        return ret;
    801      }
    802    }
    803  }
    804 
    805  if (!lib.fInitialize(display, nullptr, nullptr)) {
    806    return nullptr;
    807  }
    808 
    809  static std::once_flag sMesaLeakFlag;
    810  std::call_once(sMesaLeakFlag, MesaMemoryLeakWorkaround);
    811 
    812  const auto ret =
    813      std::make_shared<EglDisplay>(PrivateUseOnly{}, lib, display, isWarp);
    814  lib.mActiveDisplays.insert({display, ret});
    815  return ret;
    816 }
    817 
    818 EglDisplay::EglDisplay(const PrivateUseOnly&, GLLibraryEGL& lib,
    819                       const EGLDisplay disp, const bool isWarp)
    820    : mLib(&lib), mDisplay(disp), mIsWARP(isWarp) {
    821  const bool shouldDumpExts = GLContext::ShouldDumpExts();
    822 
    823  auto rawExtString =
    824      (const char*)mLib->fQueryString(mDisplay, LOCAL_EGL_EXTENSIONS);
    825  if (!rawExtString) {
    826    NS_WARNING("Failed to query EGL display extensions!.");
    827    rawExtString = "";
    828  }
    829  MarkExtensions(rawExtString, shouldDumpExts, "display", sEGLExtensionNames,
    830                 &mAvailableExtensions);
    831 
    832  // -
    833 
    834  if (!HasKHRImageBase()) {
    835    MarkExtensionUnsupported(EGLExtension::KHR_image_pixmap);
    836  }
    837 
    838  if (IsExtensionSupported(EGLExtension::KHR_surfaceless_context)) {
    839    const auto vendor =
    840        (const char*)mLib->fQueryString(mDisplay, LOCAL_EGL_VENDOR);
    841 
    842    // Bug 1464610: Mali T720 (Amazon Fire 8 HD) claims to support this
    843    // extension, but if you actually eglMakeCurrent() with EGL_NO_SURFACE, it
    844    // fails to render anything when a real surface is provided later on. We
    845    // only have the EGL vendor available here, so just avoid using this
    846    // extension on all Mali devices.
    847    if (vendor && (strcmp(vendor, "ARM") == 0)) {
    848      MarkExtensionUnsupported(EGLExtension::KHR_surfaceless_context);
    849    }
    850  }
    851 
    852  // ANDROID_native_fence_sync isn't necessarily enumerated in display ext,
    853  // but it is one.
    854  if (mLib->mSymbols.fDupNativeFenceFDANDROID) {
    855    mAvailableExtensions[UnderlyingValue(
    856        EGLExtension::ANDROID_native_fence_sync)] = true;
    857  }
    858 }
    859 
    860 EglDisplay::~EglDisplay() {
    861  StaticMutexAutoLock lock(GLLibraryEGL::sMutex);
    862  fTerminate();
    863  mLib->mActiveDisplays.erase(mDisplay);
    864 }
    865 
    866 // -
    867 
    868 std::shared_ptr<EglDisplay> GLLibraryEGL::DefaultDisplay(
    869    nsACString* const out_failureId) {
    870  StaticMutexAutoLock lock(sMutex);
    871  auto ret = mDefaultDisplay.lock();
    872  if (ret) return ret;
    873 
    874  ret = CreateDisplayLocked(false, false, out_failureId, lock);
    875  mDefaultDisplay = ret;
    876  return ret;
    877 }
    878 
    879 std::shared_ptr<EglDisplay> GLLibraryEGL::CreateDisplay(
    880    const bool forceAccel, const bool forceSoftware,
    881    nsACString* const out_failureId) {
    882  StaticMutexAutoLock lock(sMutex);
    883  return CreateDisplayLocked(forceAccel, forceSoftware, out_failureId, lock);
    884 }
    885 
    886 std::shared_ptr<EglDisplay> GLLibraryEGL::CreateDisplayLocked(
    887    const bool forceAccel, const bool forceSoftware,
    888    nsACString* const out_failureId, const StaticMutexAutoLock& aProofOfLock) {
    889  std::shared_ptr<EglDisplay> ret;
    890 
    891  if (IsExtensionSupported(EGLLibExtension::ANGLE_platform_angle_d3d)) {
    892    nsCString accelAngleFailureId;
    893    bool accelAngleSupport = IsAccelAngleSupported(&accelAngleFailureId);
    894    bool shouldTryAccel = (forceAccel || accelAngleSupport) && !forceSoftware;
    895    bool shouldTryWARP = !forceAccel;  // Only if ANGLE not supported or fails
    896 
    897    // If WARP preferred, will override ANGLE support
    898    if (StaticPrefs::webgl_angle_force_warp()) {
    899      shouldTryWARP = true;
    900      shouldTryAccel = false;
    901      if (accelAngleFailureId.IsEmpty()) {
    902        accelAngleFailureId = "FEATURE_FAILURE_FORCE_WARP"_ns;
    903      }
    904    }
    905 
    906    // Hardware accelerated ANGLE path (supported or force accel)
    907    if (shouldTryAccel) {
    908      ret = GetAndInitDisplayForAccelANGLE(*this, out_failureId, aProofOfLock);
    909    }
    910 
    911    // Report the acceleration status to telemetry
    912    if (!ret) {
    913      if (accelAngleFailureId.IsEmpty()) {
    914        glean::canvas::webgl_accl_failure_id
    915            .Get("FEATURE_FAILURE_ACCL_ANGLE_UNKNOWN"_ns)
    916            .Add(1);
    917      } else {
    918        glean::canvas::webgl_accl_failure_id.Get(accelAngleFailureId).Add(1);
    919      }
    920    } else {
    921      glean::canvas::webgl_accl_failure_id.Get("SUCCESS"_ns).Add(1);
    922    }
    923 
    924    // Fallback to a WARP display if ANGLE fails, or if WARP is forced
    925    if (!ret && shouldTryWARP) {
    926      ret = GetAndInitWARPDisplay(*this, EGL_DEFAULT_DISPLAY, aProofOfLock);
    927      if (!ret) {
    928        if (out_failureId->IsEmpty()) {
    929          *out_failureId = "FEATURE_FAILURE_WARP_FALLBACK"_ns;
    930        }
    931        NS_ERROR("Fallback WARP context failed to initialize.");
    932        return nullptr;
    933      }
    934    }
    935  } else {
    936    void* nativeDisplay = EGL_DEFAULT_DISPLAY;
    937 #ifdef MOZ_WIDGET_GTK
    938    if (!ret && (!gfx::gfxVars::WebglUseHardware() || forceSoftware)) {
    939      // Initialize a swrast egl device such as llvmpipe
    940      ret = GetAndInitSoftwareDisplay(*this, aProofOfLock);
    941    }
    942    // Initialize the display the normal way
    943    if (!ret && !gdk_display_get_default() && !forceSoftware) {
    944      ret = GetAndInitDeviceDisplay(*this, aProofOfLock);
    945      if (!ret) {
    946        ret = GetAndInitSurfacelessDisplay(*this, aProofOfLock);
    947      }
    948    }
    949 #  ifdef MOZ_WAYLAND
    950    else if (!ret && widget::GdkIsWaylandDisplay() && !forceSoftware) {
    951      // Wayland does not support EGL_DEFAULT_DISPLAY
    952      nativeDisplay = widget::WaylandDisplayGetWLDisplay();
    953      if (!nativeDisplay) {
    954        NS_WARNING("Failed to get wl_display.");
    955        return nullptr;
    956      }
    957    }
    958 #  endif
    959 #endif
    960    if (!ret && !forceSoftware) {
    961      ret = GetAndInitDisplay(*this, nativeDisplay, aProofOfLock);
    962    }
    963  }
    964 
    965  if (!ret) {
    966    if (out_failureId->IsEmpty()) {
    967      *out_failureId = "FEATURE_FAILURE_NO_DISPLAY"_ns;
    968    }
    969    NS_WARNING("Failed to initialize a display.");
    970    return nullptr;
    971  }
    972 
    973  return ret;
    974 }
    975 
    976 void GLLibraryEGL::InitLibExtensions() {
    977  const bool shouldDumpExts = GLContext::ShouldDumpExts();
    978 
    979  const char* rawExtString = nullptr;
    980 
    981 #ifndef ANDROID
    982  // Bug 1209612: Crashes on a number of android drivers.
    983  // Ideally we would only blocklist this there, but for now we don't need the
    984  // client extension list on ANDROID (we mostly need it on ANGLE), and we'd
    985  // rather not crash.
    986  rawExtString = (const char*)fQueryString(nullptr, LOCAL_EGL_EXTENSIONS);
    987 #endif
    988 
    989  if (!rawExtString) {
    990    if (shouldDumpExts) {
    991      printf_stderr("No EGL lib extensions.\n");
    992    }
    993    return;
    994  }
    995 
    996  MarkExtensions(rawExtString, shouldDumpExts, "lib", sEGLLibraryExtensionNames,
    997                 &mAvailableExtensions);
    998 }
    999 
   1000 void EglDisplay::DumpEGLConfig(EGLConfig cfg) const {
   1001 #define ATTR(_x)                                                     \
   1002  do {                                                               \
   1003    int attrval = 0;                                                 \
   1004    mLib->fGetConfigAttrib(mDisplay, cfg, LOCAL_EGL_##_x, &attrval); \
   1005    const auto err = mLib->fGetError();                              \
   1006    if (err != 0x3000) {                                             \
   1007      printf_stderr("  %s: ERROR (0x%04x)\n", #_x, err);             \
   1008    } else {                                                         \
   1009      printf_stderr("  %s: %d (0x%04x)\n", #_x, attrval, attrval);   \
   1010    }                                                                \
   1011  } while (0)
   1012 
   1013  printf_stderr("EGL Config: %d [%p]\n", (int)(intptr_t)cfg, cfg);
   1014 
   1015  ATTR(BUFFER_SIZE);
   1016  ATTR(ALPHA_SIZE);
   1017  ATTR(BLUE_SIZE);
   1018  ATTR(GREEN_SIZE);
   1019  ATTR(RED_SIZE);
   1020  ATTR(DEPTH_SIZE);
   1021  ATTR(STENCIL_SIZE);
   1022  ATTR(CONFIG_CAVEAT);
   1023  ATTR(CONFIG_ID);
   1024  ATTR(LEVEL);
   1025  ATTR(MAX_PBUFFER_HEIGHT);
   1026  ATTR(MAX_PBUFFER_PIXELS);
   1027  ATTR(MAX_PBUFFER_WIDTH);
   1028  ATTR(NATIVE_RENDERABLE);
   1029  ATTR(NATIVE_VISUAL_ID);
   1030  ATTR(NATIVE_VISUAL_TYPE);
   1031  ATTR(PRESERVED_RESOURCES);
   1032  ATTR(SAMPLES);
   1033  ATTR(SAMPLE_BUFFERS);
   1034  ATTR(SURFACE_TYPE);
   1035  ATTR(TRANSPARENT_TYPE);
   1036  ATTR(TRANSPARENT_RED_VALUE);
   1037  ATTR(TRANSPARENT_GREEN_VALUE);
   1038  ATTR(TRANSPARENT_BLUE_VALUE);
   1039  ATTR(BIND_TO_TEXTURE_RGB);
   1040  ATTR(BIND_TO_TEXTURE_RGBA);
   1041  ATTR(MIN_SWAP_INTERVAL);
   1042  ATTR(MAX_SWAP_INTERVAL);
   1043  ATTR(LUMINANCE_SIZE);
   1044  ATTR(ALPHA_MASK_SIZE);
   1045  ATTR(COLOR_BUFFER_TYPE);
   1046  ATTR(RENDERABLE_TYPE);
   1047  ATTR(CONFORMANT);
   1048 
   1049 #undef ATTR
   1050 }
   1051 
   1052 void EglDisplay::DumpEGLConfigs() const {
   1053  int nc = 0;
   1054  mLib->fGetConfigs(mDisplay, nullptr, 0, &nc);
   1055  std::vector<EGLConfig> ec(nc);
   1056  mLib->fGetConfigs(mDisplay, ec.data(), ec.size(), &nc);
   1057 
   1058  for (int i = 0; i < nc; ++i) {
   1059    printf_stderr("========= EGL Config %d ========\n", i);
   1060    DumpEGLConfig(ec[i]);
   1061  }
   1062 }
   1063 
   1064 static bool ShouldTrace() {
   1065  static bool ret = gfxEnv::MOZ_GL_DEBUG_VERBOSE();
   1066  return ret;
   1067 }
   1068 
   1069 void BeforeEGLCall(const char* glFunction) {
   1070  if (ShouldTrace()) {
   1071    printf_stderr("[egl] > %s\n", glFunction);
   1072  }
   1073 }
   1074 
   1075 void AfterEGLCall(const char* glFunction) {
   1076  if (ShouldTrace()) {
   1077    printf_stderr("[egl] < %s\n", glFunction);
   1078  }
   1079 }
   1080 
   1081 } /* namespace gl */
   1082 } /* namespace mozilla */