Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/gl/GLLibraryEGL.cpp
Line
Count
Source (jump to first uncovered line)
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 "gfxUtils.h"
10
#include "mozilla/Preferences.h"
11
#include "mozilla/Assertions.h"
12
#include "mozilla/Telemetry.h"
13
#include "mozilla/Tokenizer.h"
14
#include "mozilla/ScopeExit.h"
15
#include "mozilla/Unused.h"
16
#include "mozilla/webrender/RenderThread.h"
17
#include "nsDirectoryServiceDefs.h"
18
#include "nsDirectoryServiceUtils.h"
19
#include "nsIGfxInfo.h"
20
#include "nsPrintfCString.h"
21
#ifdef XP_WIN
22
#include "mozilla/gfx/DeviceManagerDx.h"
23
#include "nsWindowsHelpers.h"
24
25
#include <d3d11.h>
26
#endif
27
#include "OGLShaderProgram.h"
28
#include "prenv.h"
29
#include "prsystem.h"
30
#include "GLContext.h"
31
#include "GLContextProvider.h"
32
#include "gfxPrefs.h"
33
#include "ScopedGLHelpers.h"
34
#ifdef MOZ_WIDGET_GTK
35
#include <gdk/gdk.h>
36
#ifdef MOZ_WAYLAND
37
#include <gdk/gdkwayland.h>
38
#include <dlfcn.h>
39
#endif // MOZ_WIDGET_GTK
40
#endif // MOZ_WAYLAND
41
42
namespace mozilla {
43
namespace gl {
44
45
StaticMutex GLLibraryEGL::sMutex;
46
StaticRefPtr<GLLibraryEGL> GLLibraryEGL::sEGLLibrary;
47
48
// should match the order of EGLExtensions, and be null-terminated.
49
static const char* sEGLExtensionNames[] = {
50
    "EGL_KHR_image_base",
51
    "EGL_KHR_image_pixmap",
52
    "EGL_KHR_gl_texture_2D_image",
53
    "EGL_KHR_lock_surface",
54
    "EGL_ANGLE_surface_d3d_texture_2d_share_handle",
55
    "EGL_EXT_create_context_robustness",
56
    "EGL_KHR_image",
57
    "EGL_KHR_fence_sync",
58
    "EGL_ANDROID_native_fence_sync",
59
    "EGL_ANDROID_image_crop",
60
    "EGL_ANGLE_platform_angle",
61
    "EGL_ANGLE_platform_angle_d3d",
62
    "EGL_ANGLE_d3d_share_handle_client_buffer",
63
    "EGL_KHR_create_context",
64
    "EGL_KHR_stream",
65
    "EGL_KHR_stream_consumer_gltexture",
66
    "EGL_EXT_device_query",
67
    "EGL_NV_stream_consumer_gltexture_yuv",
68
    "EGL_ANGLE_stream_producer_d3d_texture",
69
    "EGL_ANGLE_device_creation",
70
    "EGL_ANGLE_device_creation_d3d11",
71
    "EGL_KHR_surfaceless_context",
72
    "EGL_KHR_create_context_no_error"
73
};
74
75
#if defined(ANDROID)
76
77
static PRLibrary* LoadApitraceLibrary()
78
{
79
    // Initialization of gfx prefs here is only needed during the unit tests...
80
    gfxPrefs::GetSingleton();
81
    if (!gfxPrefs::UseApitrace()) {
82
        return nullptr;
83
    }
84
85
    static PRLibrary* sApitraceLibrary = nullptr;
86
87
    if (sApitraceLibrary)
88
        return sApitraceLibrary;
89
90
    nsAutoCString logFile;
91
    Preferences::GetCString("gfx.apitrace.logfile", logFile);
92
    if (logFile.IsEmpty()) {
93
        logFile = "firefox.trace";
94
    }
95
96
    // The firefox process can't write to /data/local, but it can write
97
    // to $GRE_HOME/
98
    nsAutoCString logPath;
99
    logPath.AppendPrintf("%s/%s", getenv("GRE_HOME"), logFile.get());
100
101
    // apitrace uses the TRACE_FILE environment variable to determine where
102
    // to log trace output to
103
    printf_stderr("Logging GL tracing output to %s", logPath.get());
104
    setenv("TRACE_FILE", logPath.get(), false);
105
106
    printf_stderr("Attempting load of %s\n", APITRACE_LIB);
107
108
    sApitraceLibrary = PR_LoadLibrary(APITRACE_LIB);
109
110
    return sApitraceLibrary;
111
}
112
113
#endif // ANDROID
114
115
#ifdef XP_WIN
116
// see the comment in GLLibraryEGL::EnsureInitialized() for the rationale here.
117
static PRLibrary*
118
LoadLibraryForEGLOnWindows(const nsAString& filename)
119
{
120
    nsAutoString path(gfx::gfxVars::GREDirectory());
121
    path.Append(PR_GetDirectorySeparator());
122
    path.Append(filename);
123
124
    PRLibSpec lspec;
125
    lspec.type = PR_LibSpec_PathnameU;
126
    lspec.value.pathname_u = path.get();
127
    return PR_LoadLibraryWithFlags(lspec, PR_LD_LAZY | PR_LD_LOCAL);
128
}
129
130
#endif // XP_WIN
131
132
static EGLDisplay
133
GetAndInitWARPDisplay(GLLibraryEGL& egl, void* displayType)
134
0
{
135
0
    EGLint attrib_list[] = {  LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE,
136
0
                              LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE,
137
0
                              // Requires:
138
0
                              LOCAL_EGL_PLATFORM_ANGLE_TYPE_ANGLE,
139
0
                              LOCAL_EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
140
0
                              LOCAL_EGL_NONE };
141
0
    EGLDisplay display = egl.fGetPlatformDisplayEXT(LOCAL_EGL_PLATFORM_ANGLE_ANGLE,
142
0
                                                    displayType,
143
0
                                                    attrib_list);
144
0
145
0
    if (display == EGL_NO_DISPLAY) {
146
0
        const EGLint err = egl.fGetError();
147
0
        if (err != LOCAL_EGL_SUCCESS) {
148
0
            gfxCriticalError() << "Unexpected GL error: " << gfx::hexa(err);
149
0
            MOZ_CRASH("GFX: Unexpected GL error.");
150
0
        }
151
0
        return EGL_NO_DISPLAY;
152
0
    }
153
0
154
0
    if (!egl.fInitialize(display, nullptr, nullptr))
155
0
        return EGL_NO_DISPLAY;
156
0
157
0
    return display;
158
0
}
159
160
static EGLDisplay
161
GetAndInitDisplayForWebRender(GLLibraryEGL& egl, void* displayType)
162
0
{
163
#ifdef XP_WIN
164
    const EGLint attrib_list[] = {  LOCAL_EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE,
165
                                    LOCAL_EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE,
166
                                    LOCAL_EGL_NONE };
167
    RefPtr<ID3D11Device> d3d11Device = gfx::DeviceManagerDx::Get()->GetCompositorDevice();
168
    if (!d3d11Device) {
169
        gfxCriticalNote << "Failed to get compositor device for EGLDisplay";
170
        return EGL_NO_DISPLAY;
171
    }
172
    EGLDeviceEXT eglDevice = egl.fCreateDeviceANGLE(LOCAL_EGL_D3D11_DEVICE_ANGLE, reinterpret_cast<void *>(d3d11Device.get()), nullptr);
173
    if (!eglDevice) {
174
        gfxCriticalNote << "Failed to get EGLDeviceEXT of D3D11Device";
175
        return EGL_NO_DISPLAY;
176
    }
177
    // Create an EGLDisplay using the EGLDevice
178
    EGLDisplay display = egl.fGetPlatformDisplayEXT(LOCAL_EGL_PLATFORM_DEVICE_EXT, eglDevice, attrib_list);
179
    if (!display) {
180
        gfxCriticalNote << "Failed to get EGLDisplay of D3D11Device";
181
        return EGL_NO_DISPLAY;
182
    }
183
184
    if (display == EGL_NO_DISPLAY) {
185
        const EGLint err = egl.fGetError();
186
        if (err != LOCAL_EGL_SUCCESS) {
187
            gfxCriticalError() << "Unexpected GL error: " << gfx::hexa(err);
188
            MOZ_CRASH("GFX: Unexpected GL error.");
189
        }
190
        return EGL_NO_DISPLAY;
191
    }
192
193
    if (!egl.fInitialize(display, nullptr, nullptr)) {
194
        const EGLint err = egl.fGetError();
195
        if (err != LOCAL_EGL_SUCCESS) {
196
            gfxCriticalError() << "Failed to initialize EGLDisplay for WebRender error: " << gfx::hexa(err);
197
        }
198
        return EGL_NO_DISPLAY;
199
    }
200
    return display;
201
#else
202
0
    return EGL_NO_DISPLAY;
203
0
#endif
204
0
}
205
206
static bool
207
IsAccelAngleSupported(const nsCOMPtr<nsIGfxInfo>& gfxInfo,
208
                      nsACString* const out_failureId)
209
0
{
210
0
    if (wr::RenderThread::IsInRenderThread()) {
211
0
        // We can only enter here with WebRender, so assert that this is a
212
0
        // WebRender-enabled build.
213
#ifndef MOZ_BUILD_WEBRENDER
214
        MOZ_ASSERT(false);
215
#endif
216
        return true;
217
0
    }
218
0
    int32_t angleSupport;
219
0
    nsCString failureId;
220
0
    gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo,
221
0
                                         nsIGfxInfo::FEATURE_WEBGL_ANGLE,
222
0
                                         failureId,
223
0
                                         &angleSupport);
224
0
    if (failureId.IsEmpty() && angleSupport != nsIGfxInfo::FEATURE_STATUS_OK) {
225
0
        // This shouldn't happen, if we see this it's because we've missed
226
0
        // some failure paths
227
0
        failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_ACCL_ANGLE_NOT_OK");
228
0
    }
229
0
    if (out_failureId->IsEmpty()) {
230
0
        *out_failureId = failureId;
231
0
    }
232
0
    return (angleSupport == nsIGfxInfo::FEATURE_STATUS_OK);
233
0
}
234
235
static EGLDisplay
236
GetAndInitDisplay(GLLibraryEGL& egl, void* displayType)
237
0
{
238
0
    EGLDisplay display = egl.fGetDisplay(displayType);
239
0
    if (display == EGL_NO_DISPLAY)
240
0
        return EGL_NO_DISPLAY;
241
0
242
0
    if (!egl.fInitialize(display, nullptr, nullptr))
243
0
        return EGL_NO_DISPLAY;
244
0
245
0
    return display;
246
0
}
247
248
class AngleErrorReporting {
249
public:
250
    AngleErrorReporting()
251
      : mFailureId(nullptr)
252
3
    {
253
3
      // No static constructor
254
3
    }
255
256
    void SetFailureId(nsACString* const aFailureId)
257
0
    {
258
0
      mFailureId = aFailureId;
259
0
    }
260
261
    void logError(const char *errorMessage)
262
0
    {
263
0
        if (!mFailureId) {
264
0
            return;
265
0
        }
266
0
267
0
        nsCString str(errorMessage);
268
0
        Tokenizer tokenizer(str);
269
0
270
0
        // Parse "ANGLE Display::initialize error " << error.getID() << ": "
271
0
        //       << error.getMessage()
272
0
        nsCString currWord;
273
0
        Tokenizer::Token intToken;
274
0
        if (tokenizer.CheckWord("ANGLE") &&
275
0
            tokenizer.CheckWhite() &&
276
0
            tokenizer.CheckWord("Display") &&
277
0
            tokenizer.CheckChar(':') &&
278
0
            tokenizer.CheckChar(':') &&
279
0
            tokenizer.CheckWord("initialize") &&
280
0
            tokenizer.CheckWhite() &&
281
0
            tokenizer.CheckWord("error") &&
282
0
            tokenizer.CheckWhite() &&
283
0
            tokenizer.Check(Tokenizer::TOKEN_INTEGER, intToken)) {
284
0
            *mFailureId = "FAILURE_ID_ANGLE_ID_";
285
0
            mFailureId->AppendPrintf("%" PRIu64, intToken.AsInteger());
286
0
        } else {
287
0
            *mFailureId = "FAILURE_ID_ANGLE_UNKNOWN";
288
0
        }
289
0
    }
290
private:
291
    nsACString* mFailureId;
292
};
293
294
AngleErrorReporting gAngleErrorReporter;
295
296
static EGLDisplay
297
GetAndInitDisplayForAccelANGLE(GLLibraryEGL& egl, nsACString* const out_failureId)
298
0
{
299
0
    EGLDisplay ret = 0;
300
0
301
0
    if (wr::RenderThread::IsInRenderThread()) {
302
0
        return GetAndInitDisplayForWebRender(egl, EGL_DEFAULT_DISPLAY);
303
0
    }
304
0
305
0
    FeatureState& d3d11ANGLE = gfxConfig::GetFeature(Feature::D3D11_HW_ANGLE);
306
0
307
0
    if (!gfxPrefs::WebGLANGLETryD3D11())
308
0
        d3d11ANGLE.UserDisable("User disabled D3D11 ANGLE by pref",
309
0
                               NS_LITERAL_CSTRING("FAILURE_ID_ANGLE_PREF"));
310
0
311
0
    if (gfxPrefs::WebGLANGLEForceD3D11())
312
0
        d3d11ANGLE.UserForceEnable("User force-enabled D3D11 ANGLE on disabled hardware");
313
0
314
0
    gAngleErrorReporter.SetFailureId(out_failureId);
315
0
316
0
    auto guardShutdown = mozilla::MakeScopeExit([&] {
317
0
        gAngleErrorReporter.SetFailureId(nullptr);
318
0
        // NOTE: Ideally we should be calling ANGLEPlatformShutdown after the
319
0
        //       ANGLE display is destroyed. However gAngleErrorReporter
320
0
        //       will live longer than the ANGLE display so we're fine.
321
0
    });
322
0
323
0
    if (gfxConfig::IsForcedOnByUser(Feature::D3D11_HW_ANGLE)) {
324
0
        return GetAndInitDisplay(egl, LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE);
325
0
    }
326
0
327
0
    if (d3d11ANGLE.IsEnabled()) {
328
0
        ret = GetAndInitDisplay(egl, LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE);
329
0
    }
330
0
331
0
    if (!ret) {
332
0
        ret = GetAndInitDisplay(egl, EGL_DEFAULT_DISPLAY);
333
0
    }
334
0
335
0
    if (!ret && out_failureId->IsEmpty()) {
336
0
        *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_ACCL_ANGLE_NO_DISP");
337
0
    }
338
0
339
0
    return ret;
340
0
}
341
342
bool
343
GLLibraryEGL::ReadbackEGLImage(EGLImage image, gfx::DataSourceSurface* out_surface)
344
0
{
345
0
    StaticMutexAutoUnlock lock(sMutex);
346
0
    if (!mReadbackGL) {
347
0
        nsCString discardFailureId;
348
0
        mReadbackGL = gl::GLContextProvider::CreateHeadless(gl::CreateContextFlags::NONE,
349
0
                                                            &discardFailureId);
350
0
    }
351
0
352
0
    ScopedTexture destTex(mReadbackGL);
353
0
    const GLuint target = mReadbackGL->GetPreferredEGLImageTextureTarget();
354
0
    ScopedBindTexture autoTex(mReadbackGL, destTex.Texture(), target);
355
0
    mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
356
0
    mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
357
0
    mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
358
0
    mReadbackGL->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
359
0
    mReadbackGL->fEGLImageTargetTexture2D(target, image);
360
0
361
0
    ShaderConfigOGL config = ShaderConfigFromTargetAndFormat(target,
362
0
                                                             out_surface->GetFormat());
363
0
    int shaderConfig = config.mFeatures;
364
0
    mReadbackGL->ReadTexImageHelper()->ReadTexImage(out_surface, 0, target,
365
0
                                                    out_surface->GetSize(), shaderConfig);
366
0
367
0
    return true;
368
0
}
369
370
/* static */ bool
371
0
GLLibraryEGL::EnsureInitialized(bool forceAccel, nsACString* const out_failureId) {
372
0
    if (!sEGLLibrary) {
373
0
        sEGLLibrary = new GLLibraryEGL();
374
0
    }
375
0
    return sEGLLibrary->DoEnsureInitialized(forceAccel, out_failureId);
376
0
}
377
378
bool
379
GLLibraryEGL::DoEnsureInitialized(bool forceAccel, nsACString* const out_failureId)
380
0
{
381
0
    if (mInitialized && !mSymbols.fTerminate) {
382
0
        *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_DESTROYED");
383
0
        MOZ_ASSERT(false);
384
0
        return false;
385
0
    }
386
0
387
0
    if (mInitialized) {
388
0
        return true;
389
0
    }
390
0
391
0
    mozilla::ScopedGfxFeatureReporter reporter("EGL");
392
0
393
#ifdef XP_WIN
394
    if (!mEGLLibrary) {
395
        // On Windows, the GLESv2, EGL and DXSDK libraries are shipped with libxul and
396
        // we should look for them there. We have to load the libs in this
397
        // order, because libEGL.dll depends on libGLESv2.dll which depends on the DXSDK
398
        // libraries. This matters especially for WebRT apps which are in a different directory.
399
        // See bug 760323 and bug 749459
400
401
        // Also note that we intentionally leak the libs we load.
402
403
        do {
404
            // Windows 8.1+ has d3dcompiler_47.dll in the system directory.
405
            // Try it first. Note that _46 will never be in the system
406
            // directory. So there is no point trying _46 in the system
407
            // directory.
408
409
            if (LoadLibrarySystem32(L"d3dcompiler_47.dll"))
410
                break;
411
412
#ifdef MOZ_D3DCOMPILER_VISTA_DLL
413
            if (LoadLibraryForEGLOnWindows(NS_LITERAL_STRING(NS_STRINGIFY(MOZ_D3DCOMPILER_VISTA_DLL))))
414
                break;
415
#endif
416
417
            MOZ_ASSERT(false, "d3dcompiler DLL loading failed.");
418
        } while (false);
419
420
        LoadLibraryForEGLOnWindows(NS_LITERAL_STRING("libGLESv2.dll"));
421
422
        mEGLLibrary = LoadLibraryForEGLOnWindows(NS_LITERAL_STRING("libEGL.dll"));
423
424
        if (!mEGLLibrary) {
425
            *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_LOAD");
426
            return false;
427
        }
428
    }
429
430
#else // !Windows
431
432
0
    // On non-Windows (Android) we use system copies of libEGL. We look for
433
0
    // the APITrace lib, libEGL.so, and libEGL.so.1 in that order.
434
0
435
#if defined(ANDROID)
436
    if (!mEGLLibrary)
437
        mEGLLibrary = LoadApitraceLibrary();
438
#endif
439
440
0
    if (!mEGLLibrary) {
441
0
        printf_stderr("Attempting load of libEGL.so\n");
442
0
        mEGLLibrary = PR_LoadLibrary("libEGL.so");
443
0
    }
444
0
#if defined(XP_UNIX)
445
0
    if (!mEGLLibrary) {
446
0
        mEGLLibrary = PR_LoadLibrary("libEGL.so.1");
447
0
    }
448
0
#endif
449
0
450
0
    if (!mEGLLibrary) {
451
0
        NS_WARNING("Couldn't load EGL LIB.");
452
0
        *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_LOAD_2");
453
0
        return false;
454
0
    }
455
0
456
0
#endif // !Windows
457
0
458
0
#define SYMBOL(X) { (PRFuncPtr*)&mSymbols.f##X, { "egl" #X, nullptr } }
459
0
#define END_OF_SYMBOLS { nullptr, { nullptr } }
460
0
461
0
    GLLibraryLoader::SymLoadStruct earlySymbols[] = {
462
0
        SYMBOL(GetDisplay),
463
0
        SYMBOL(Terminate),
464
0
        SYMBOL(GetCurrentSurface),
465
0
        SYMBOL(GetCurrentContext),
466
0
        SYMBOL(MakeCurrent),
467
0
        SYMBOL(DestroyContext),
468
0
        SYMBOL(CreateContext),
469
0
        SYMBOL(DestroySurface),
470
0
        SYMBOL(CreateWindowSurface),
471
0
        SYMBOL(CreatePbufferSurface),
472
0
        SYMBOL(CreatePbufferFromClientBuffer),
473
0
        SYMBOL(CreatePixmapSurface),
474
0
        SYMBOL(BindAPI),
475
0
        SYMBOL(Initialize),
476
0
        SYMBOL(ChooseConfig),
477
0
        SYMBOL(GetError),
478
0
        SYMBOL(GetConfigs),
479
0
        SYMBOL(GetConfigAttrib),
480
0
        SYMBOL(WaitNative),
481
0
        SYMBOL(GetProcAddress),
482
0
        SYMBOL(SwapBuffers),
483
0
        SYMBOL(CopyBuffers),
484
0
        SYMBOL(QueryString),
485
0
        SYMBOL(QueryContext),
486
0
        SYMBOL(BindTexImage),
487
0
        SYMBOL(ReleaseTexImage),
488
0
        SYMBOL(SwapInterval),
489
0
        SYMBOL(QuerySurface),
490
0
        END_OF_SYMBOLS
491
0
    };
492
0
493
0
    if (!GLLibraryLoader::LoadSymbols(mEGLLibrary, earlySymbols)) {
494
0
        NS_WARNING("Couldn't find required entry points in EGL library (early init)");
495
0
        *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_SYM");
496
0
        return false;
497
0
    }
498
0
499
0
    {
500
0
        const char internalFuncName[] = "_Z35eglQueryStringImplementationANDROIDPvi";
501
0
        const auto& internalFunc = PR_FindFunctionSymbol(mEGLLibrary, internalFuncName);
502
0
        if (internalFunc) {
503
0
            *(PRFuncPtr*)&mSymbols.fQueryString = internalFunc;
504
0
        }
505
0
    }
506
0
507
0
    InitClientExtensions();
508
0
509
0
    const auto lookupFunction =
510
0
        (GLLibraryLoader::PlatformLookupFunction)mSymbols.fGetProcAddress;
511
0
512
0
    const auto fnLoadSymbols = [&](const GLLibraryLoader::SymLoadStruct* symbols) {
513
0
        if (GLLibraryLoader::LoadSymbols(mEGLLibrary, symbols, lookupFunction))
514
0
            return true;
515
0
516
0
        ClearSymbols(symbols);
517
0
        return false;
518
0
    };
519
0
520
0
    // Check the ANGLE support the system has
521
0
    nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
522
0
    mIsANGLE = IsExtensionSupported(ANGLE_platform_angle);
523
0
524
0
    // Client exts are ready. (But not display exts!)
525
0
526
0
    if (mIsANGLE) {
527
0
        MOZ_ASSERT(IsExtensionSupported(ANGLE_platform_angle_d3d));
528
0
        const GLLibraryLoader::SymLoadStruct angleSymbols[] = {
529
0
            SYMBOL(GetPlatformDisplayEXT),
530
0
            END_OF_SYMBOLS
531
0
        };
532
0
        if (!fnLoadSymbols(angleSymbols)) {
533
0
            gfxCriticalError() << "Failed to load ANGLE symbols!";
534
0
            return false;
535
0
        }
536
0
        MOZ_ASSERT(IsExtensionSupported(ANGLE_platform_angle_d3d));
537
0
        const GLLibraryLoader::SymLoadStruct createDeviceSymbols[] = {
538
0
            SYMBOL(CreateDeviceANGLE),
539
0
            SYMBOL(ReleaseDeviceANGLE),
540
0
            END_OF_SYMBOLS
541
0
        };
542
0
        if (!fnLoadSymbols(createDeviceSymbols)) {
543
0
            NS_ERROR("EGL supports ANGLE_device_creation without exposing its functions!");
544
0
            MarkExtensionUnsupported(ANGLE_device_creation);
545
0
        }
546
0
    }
547
0
548
0
    mEGLDisplay = CreateDisplay(forceAccel, gfxInfo, out_failureId);
549
0
    if (!mEGLDisplay) {
550
0
        return false;
551
0
    }
552
0
553
0
    InitDisplayExtensions();
554
0
555
0
    ////////////////////////////////////
556
0
    // Alright, load display exts.
557
0
558
0
    if (IsExtensionSupported(KHR_lock_surface)) {
559
0
        const GLLibraryLoader::SymLoadStruct lockSymbols[] = {
560
0
            SYMBOL(LockSurfaceKHR),
561
0
            SYMBOL(UnlockSurfaceKHR),
562
0
            END_OF_SYMBOLS
563
0
        };
564
0
        if (!fnLoadSymbols(lockSymbols)) {
565
0
            NS_ERROR("EGL supports KHR_lock_surface without exposing its functions!");
566
0
            MarkExtensionUnsupported(KHR_lock_surface);
567
0
        }
568
0
    }
569
0
570
0
    if (IsExtensionSupported(ANGLE_surface_d3d_texture_2d_share_handle)) {
571
0
        const GLLibraryLoader::SymLoadStruct d3dSymbols[] = {
572
0
            SYMBOL(QuerySurfacePointerANGLE),
573
0
            END_OF_SYMBOLS
574
0
        };
575
0
        if (!fnLoadSymbols(d3dSymbols)) {
576
0
            NS_ERROR("EGL supports ANGLE_surface_d3d_texture_2d_share_handle without exposing its functions!");
577
0
            MarkExtensionUnsupported(ANGLE_surface_d3d_texture_2d_share_handle);
578
0
        }
579
0
    }
580
0
581
0
    if (IsExtensionSupported(KHR_fence_sync)) {
582
0
        const GLLibraryLoader::SymLoadStruct syncSymbols[] = {
583
0
            SYMBOL(CreateSyncKHR),
584
0
            SYMBOL(DestroySyncKHR),
585
0
            SYMBOL(ClientWaitSyncKHR),
586
0
            SYMBOL(GetSyncAttribKHR),
587
0
            END_OF_SYMBOLS
588
0
        };
589
0
        if (!fnLoadSymbols(syncSymbols)) {
590
0
            NS_ERROR("EGL supports KHR_fence_sync without exposing its functions!");
591
0
            MarkExtensionUnsupported(KHR_fence_sync);
592
0
        }
593
0
    }
594
0
595
0
    if (IsExtensionSupported(KHR_image) || IsExtensionSupported(KHR_image_base)) {
596
0
        const GLLibraryLoader::SymLoadStruct imageSymbols[] = {
597
0
            SYMBOL(CreateImageKHR),
598
0
            SYMBOL(DestroyImageKHR),
599
0
            END_OF_SYMBOLS
600
0
        };
601
0
        if (!fnLoadSymbols(imageSymbols)) {
602
0
            NS_ERROR("EGL supports KHR_image(_base) without exposing its functions!");
603
0
            MarkExtensionUnsupported(KHR_image);
604
0
            MarkExtensionUnsupported(KHR_image_base);
605
0
            MarkExtensionUnsupported(KHR_image_pixmap);
606
0
        }
607
0
    } else {
608
0
        MarkExtensionUnsupported(KHR_image_pixmap);
609
0
    }
610
0
611
0
    if (IsExtensionSupported(ANDROID_native_fence_sync)) {
612
0
        const GLLibraryLoader::SymLoadStruct nativeFenceSymbols[] = {
613
0
            SYMBOL(DupNativeFenceFDANDROID),
614
0
            END_OF_SYMBOLS
615
0
        };
616
0
        if (!fnLoadSymbols(nativeFenceSymbols)) {
617
0
            NS_ERROR("EGL supports ANDROID_native_fence_sync without exposing its functions!");
618
0
            MarkExtensionUnsupported(ANDROID_native_fence_sync);
619
0
        }
620
0
    }
621
0
622
0
    if (IsExtensionSupported(KHR_stream)) {
623
0
        const GLLibraryLoader::SymLoadStruct streamSymbols[] = {
624
0
            SYMBOL(CreateStreamKHR),
625
0
            SYMBOL(DestroyStreamKHR),
626
0
            SYMBOL(QueryStreamKHR),
627
0
            END_OF_SYMBOLS
628
0
        };
629
0
        if (!fnLoadSymbols(streamSymbols)) {
630
0
            NS_ERROR("EGL supports KHR_stream without exposing its functions!");
631
0
            MarkExtensionUnsupported(KHR_stream);
632
0
        }
633
0
    }
634
0
635
0
    if (IsExtensionSupported(KHR_stream_consumer_gltexture)) {
636
0
        const GLLibraryLoader::SymLoadStruct streamConsumerSymbols[] = {
637
0
            SYMBOL(StreamConsumerGLTextureExternalKHR),
638
0
            SYMBOL(StreamConsumerAcquireKHR),
639
0
            SYMBOL(StreamConsumerReleaseKHR),
640
0
            END_OF_SYMBOLS
641
0
        };
642
0
        if (!fnLoadSymbols(streamConsumerSymbols)) {
643
0
            NS_ERROR("EGL supports KHR_stream_consumer_gltexture without exposing its functions!");
644
0
            MarkExtensionUnsupported(KHR_stream_consumer_gltexture);
645
0
        }
646
0
    }
647
0
648
0
    if (IsExtensionSupported(EXT_device_query)) {
649
0
        const GLLibraryLoader::SymLoadStruct queryDisplaySymbols[] = {
650
0
            SYMBOL(QueryDisplayAttribEXT),
651
0
            SYMBOL(QueryDeviceAttribEXT),
652
0
            END_OF_SYMBOLS
653
0
        };
654
0
        if (!fnLoadSymbols(queryDisplaySymbols)) {
655
0
            NS_ERROR("EGL supports EXT_device_query without exposing its functions!");
656
0
            MarkExtensionUnsupported(EXT_device_query);
657
0
        }
658
0
    }
659
0
660
0
    if (IsExtensionSupported(NV_stream_consumer_gltexture_yuv)) {
661
0
        const GLLibraryLoader::SymLoadStruct nvStreamSymbols[] = {
662
0
            SYMBOL(StreamConsumerGLTextureExternalAttribsNV),
663
0
            END_OF_SYMBOLS
664
0
        };
665
0
        if (!fnLoadSymbols(nvStreamSymbols)) {
666
0
            NS_ERROR("EGL supports NV_stream_consumer_gltexture_yuv without exposing its functions!");
667
0
            MarkExtensionUnsupported(NV_stream_consumer_gltexture_yuv);
668
0
        }
669
0
    }
670
0
671
0
    if (IsExtensionSupported(ANGLE_stream_producer_d3d_texture)) {
672
0
        const GLLibraryLoader::SymLoadStruct nvStreamSymbols[] = {
673
0
            SYMBOL(CreateStreamProducerD3DTextureANGLE),
674
0
            SYMBOL(StreamPostD3DTextureANGLE),
675
0
            END_OF_SYMBOLS
676
0
        };
677
0
        if (!fnLoadSymbols(nvStreamSymbols)) {
678
0
            NS_ERROR("EGL supports ANGLE_stream_producer_d3d_texture without exposing its functions!");
679
0
            MarkExtensionUnsupported(ANGLE_stream_producer_d3d_texture);
680
0
        }
681
0
    }
682
0
683
0
    if (IsExtensionSupported(KHR_surfaceless_context)) {
684
0
        const auto vendor = fQueryString(mEGLDisplay, LOCAL_EGL_VENDOR);
685
0
686
0
        // Bug 1464610: Mali T720 (Amazon Fire 8 HD) claims to support this extension,
687
0
        // but if you actually eglMakeCurrent() with EGL_NO_SURFACE, it fails to
688
0
        // render anything when a real surface is provided later on. We only have the
689
0
        // EGL vendor available here, so just avoid using this extension on all
690
0
        // Mali devices.
691
0
        if (strcmp((const char*)vendor, "ARM") == 0) {
692
0
            MarkExtensionUnsupported(KHR_surfaceless_context);
693
0
        }
694
0
    }
695
0
696
0
    mInitialized = true;
697
0
    reporter.SetSuccessful();
698
0
    return true;
699
0
}
700
701
#undef SYMBOL
702
#undef END_OF_SYMBOLS
703
704
void
705
GLLibraryEGL::Shutdown()
706
0
{
707
0
    if (this != sEGLLibrary) {
708
0
        return;
709
0
    }
710
0
    if (mEGLDisplay) {
711
0
        fTerminate(mEGLDisplay);
712
0
        mEGLDisplay = EGL_NO_DISPLAY;
713
0
    }
714
0
    mSymbols = {};
715
0
    sEGLLibrary = nullptr;
716
0
}
717
718
EGLDisplay
719
GLLibraryEGL::CreateDisplay(bool forceAccel, const nsCOMPtr<nsIGfxInfo>& gfxInfo, nsACString* const out_failureId)
720
0
{
721
0
    MOZ_ASSERT(!mInitialized);
722
0
723
0
    EGLDisplay chosenDisplay = nullptr;
724
0
725
0
    if (IsExtensionSupported(ANGLE_platform_angle_d3d)) {
726
0
        nsCString accelAngleFailureId;
727
0
        bool accelAngleSupport = IsAccelAngleSupported(gfxInfo, &accelAngleFailureId);
728
0
        bool shouldTryAccel = forceAccel || accelAngleSupport;
729
0
        bool shouldTryWARP = !forceAccel; // Only if ANGLE not supported or fails
730
0
731
0
        // If WARP preferred, will override ANGLE support
732
0
        if (gfxPrefs::WebGLANGLEForceWARP()) {
733
0
            shouldTryWARP = true;
734
0
            shouldTryAccel = false;
735
0
            if (accelAngleFailureId.IsEmpty()) {
736
0
                accelAngleFailureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_FORCE_WARP");
737
0
            }
738
0
        }
739
0
740
0
        // Hardware accelerated ANGLE path (supported or force accel)
741
0
        if (shouldTryAccel) {
742
0
            chosenDisplay = GetAndInitDisplayForAccelANGLE(*this, out_failureId);
743
0
        }
744
0
745
0
        // Report the acceleration status to telemetry
746
0
        if (!chosenDisplay) {
747
0
            if (accelAngleFailureId.IsEmpty()) {
748
0
                Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_ACCL_FAILURE_ID,
749
0
                                      NS_LITERAL_CSTRING("FEATURE_FAILURE_ACCL_ANGLE_UNKNOWN"));
750
0
            } else {
751
0
                Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_ACCL_FAILURE_ID,
752
0
                                      accelAngleFailureId);
753
0
            }
754
0
        } else {
755
0
            Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_ACCL_FAILURE_ID,
756
0
                                  NS_LITERAL_CSTRING("SUCCESS"));
757
0
        }
758
0
759
0
        // Fallback to a WARP display if ANGLE fails, or if WARP is forced
760
0
        if (!chosenDisplay && shouldTryWARP) {
761
0
            chosenDisplay = GetAndInitWARPDisplay(*this, EGL_DEFAULT_DISPLAY);
762
0
            if (!chosenDisplay) {
763
0
                if (out_failureId->IsEmpty()) {
764
0
                    *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WARP_FALLBACK");
765
0
                }
766
0
                NS_ERROR("Fallback WARP context failed to initialize.");
767
0
                return nullptr;
768
0
            }
769
0
            mIsWARP = true;
770
0
        }
771
0
    } else {
772
0
        void *nativeDisplay = EGL_DEFAULT_DISPLAY;
773
#ifdef MOZ_WAYLAND
774
        // Some drivers doesn't support EGL_DEFAULT_DISPLAY
775
        GdkDisplay *gdkDisplay = gdk_display_get_default();
776
        if (GDK_IS_WAYLAND_DISPLAY(gdkDisplay)) {
777
            static auto sGdkWaylandDisplayGetWlDisplay =
778
                (wl_display *(*)(GdkDisplay *))
779
                dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_display");
780
            nativeDisplay = sGdkWaylandDisplayGetWlDisplay(gdkDisplay);
781
            if (!nativeDisplay) {
782
                NS_WARNING("Failed to get wl_display.");
783
                return nullptr;
784
            }
785
        }
786
#endif
787
        chosenDisplay = GetAndInitDisplay(*this, nativeDisplay);
788
0
    }
789
0
790
0
    if (!chosenDisplay) {
791
0
        if (out_failureId->IsEmpty()) {
792
0
            *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_NO_DISPLAY");
793
0
        }
794
0
        NS_WARNING("Failed to initialize a display.");
795
0
        return nullptr;
796
0
    }
797
0
    return chosenDisplay;
798
0
}
799
800
template<size_t N>
801
static void
802
MarkExtensions(const char* rawExtString, bool shouldDumpExts, const char* extType,
803
               std::bitset<N>* const out)
804
0
{
805
0
    MOZ_ASSERT(rawExtString);
806
0
807
0
    const nsDependentCString extString(rawExtString);
808
0
809
0
    std::vector<nsCString> extList;
810
0
    SplitByChar(extString, ' ', &extList);
811
0
812
0
    if (shouldDumpExts) {
813
0
        printf_stderr("%u EGL %s extensions: (*: recognized)\n",
814
0
                      (uint32_t)extList.size(), extType);
815
0
    }
816
0
817
0
    MarkBitfieldByStrings(extList, shouldDumpExts, sEGLExtensionNames, out);
818
0
}
819
820
void
821
GLLibraryEGL::InitClientExtensions()
822
0
{
823
0
    const bool shouldDumpExts = GLContext::ShouldDumpExts();
824
0
825
0
    const char* rawExtString = nullptr;
826
0
827
0
#ifndef ANDROID
828
0
    // Bug 1209612: Crashes on a number of android drivers.
829
0
    // Ideally we would only blocklist this there, but for now we don't need the client
830
0
    // extension list on ANDROID (we mostly need it on ANGLE), and we'd rather not crash.
831
0
    rawExtString = (const char*)fQueryString(nullptr, LOCAL_EGL_EXTENSIONS);
832
0
#endif
833
0
834
0
    if (!rawExtString) {
835
0
        if (shouldDumpExts) {
836
0
            printf_stderr("No EGL client extensions.\n");
837
0
        }
838
0
        return;
839
0
    }
840
0
841
0
    MarkExtensions(rawExtString, shouldDumpExts, "client", &mAvailableExtensions);
842
0
}
843
844
void
845
GLLibraryEGL::InitDisplayExtensions()
846
0
{
847
0
    MOZ_ASSERT(mEGLDisplay);
848
0
849
0
    const bool shouldDumpExts = GLContext::ShouldDumpExts();
850
0
851
0
    const auto rawExtString = (const char*)fQueryString(mEGLDisplay,
852
0
                                                        LOCAL_EGL_EXTENSIONS);
853
0
    if (!rawExtString) {
854
0
        NS_WARNING("Failed to query EGL display extensions!.");
855
0
        return;
856
0
    }
857
0
858
0
    MarkExtensions(rawExtString, shouldDumpExts, "display", &mAvailableExtensions);
859
0
}
860
861
void
862
GLLibraryEGL::DumpEGLConfig(EGLConfig cfg)
863
0
{
864
0
    int attrval;
865
0
    int err;
866
0
867
0
#define ATTR(_x) do {                                                   \
868
0
        fGetConfigAttrib(mEGLDisplay, cfg, LOCAL_EGL_##_x, &attrval);  \
869
0
        if ((err = fGetError()) != 0x3000) {                        \
870
0
            printf_stderr("  %s: ERROR (0x%04x)\n", #_x, err);        \
871
0
        } else {                                                    \
872
0
            printf_stderr("  %s: %d (0x%04x)\n", #_x, attrval, attrval); \
873
0
        }                                                           \
874
0
    } while(0)
875
0
876
0
    printf_stderr("EGL Config: %d [%p]\n", (int)(intptr_t)cfg, cfg);
877
0
878
0
    ATTR(BUFFER_SIZE);
879
0
    ATTR(ALPHA_SIZE);
880
0
    ATTR(BLUE_SIZE);
881
0
    ATTR(GREEN_SIZE);
882
0
    ATTR(RED_SIZE);
883
0
    ATTR(DEPTH_SIZE);
884
0
    ATTR(STENCIL_SIZE);
885
0
    ATTR(CONFIG_CAVEAT);
886
0
    ATTR(CONFIG_ID);
887
0
    ATTR(LEVEL);
888
0
    ATTR(MAX_PBUFFER_HEIGHT);
889
0
    ATTR(MAX_PBUFFER_PIXELS);
890
0
    ATTR(MAX_PBUFFER_WIDTH);
891
0
    ATTR(NATIVE_RENDERABLE);
892
0
    ATTR(NATIVE_VISUAL_ID);
893
0
    ATTR(NATIVE_VISUAL_TYPE);
894
0
    ATTR(PRESERVED_RESOURCES);
895
0
    ATTR(SAMPLES);
896
0
    ATTR(SAMPLE_BUFFERS);
897
0
    ATTR(SURFACE_TYPE);
898
0
    ATTR(TRANSPARENT_TYPE);
899
0
    ATTR(TRANSPARENT_RED_VALUE);
900
0
    ATTR(TRANSPARENT_GREEN_VALUE);
901
0
    ATTR(TRANSPARENT_BLUE_VALUE);
902
0
    ATTR(BIND_TO_TEXTURE_RGB);
903
0
    ATTR(BIND_TO_TEXTURE_RGBA);
904
0
    ATTR(MIN_SWAP_INTERVAL);
905
0
    ATTR(MAX_SWAP_INTERVAL);
906
0
    ATTR(LUMINANCE_SIZE);
907
0
    ATTR(ALPHA_MASK_SIZE);
908
0
    ATTR(COLOR_BUFFER_TYPE);
909
0
    ATTR(RENDERABLE_TYPE);
910
0
    ATTR(CONFORMANT);
911
0
912
0
#undef ATTR
913
0
}
914
915
void
916
GLLibraryEGL::DumpEGLConfigs()
917
0
{
918
0
    int nc = 0;
919
0
    fGetConfigs(mEGLDisplay, nullptr, 0, &nc);
920
0
    EGLConfig* ec = new EGLConfig[nc];
921
0
    fGetConfigs(mEGLDisplay, ec, nc, &nc);
922
0
923
0
    for (int i = 0; i < nc; ++i) {
924
0
        printf_stderr("========= EGL Config %d ========\n", i);
925
0
        DumpEGLConfig(ec[i]);
926
0
    }
927
0
928
0
    delete [] ec;
929
0
}
930
931
static bool
932
ShouldTrace()
933
0
{
934
0
    static bool ret = gfxEnv::GlDebugVerbose();
935
0
    return ret;
936
0
}
937
938
void
939
BeforeEGLCall(const char* glFunction)
940
0
{
941
0
    if (ShouldTrace()) {
942
0
        printf_stderr("[egl] > %s\n", glFunction);
943
0
    }
944
0
}
945
946
void
947
AfterEGLCall(const char* glFunction)
948
0
{
949
0
    if (ShouldTrace()) {
950
0
        printf_stderr("[egl] < %s\n", glFunction);
951
0
    }
952
0
}
953
954
} /* namespace gl */
955
} /* namespace mozilla */