Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/gl/GLContextProviderEGL.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
0
    #define GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_EGL_WINDOW))
8
0
    #define GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget) ((EGLNativeWindowType)aWidget->RealWidget()->GetNativeData(NS_NATIVE_EGL_WINDOW))
9
#elif defined(MOZ_WIDGET_ANDROID)
10
    #define GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_JAVA_SURFACE))
11
    #define GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget) (aWidget->AsAndroid()->GetEGLNativeWindow())
12
#elif defined(XP_WIN)
13
    #define GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW))
14
    #define GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget) ((EGLNativeWindowType)aWidget->AsWindows()->GetHwnd())
15
#else
16
    #define GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW))
17
    #define GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget) ((EGLNativeWindowType)aWidget->RealWidget()->GetNativeData(NS_NATIVE_WINDOW))
18
#endif
19
20
#if defined(XP_UNIX)
21
    #ifdef MOZ_WIDGET_ANDROID
22
        #include <android/native_window.h>
23
        #include <android/native_window_jni.h>
24
        #include "mozilla/widget/AndroidCompositorWidget.h"
25
    #endif
26
27
0
    #define GLES2_LIB "libGLESv2.so"
28
0
    #define GLES2_LIB2 "libGLESv2.so.2"
29
30
#elif defined(XP_WIN)
31
    #include "mozilla/widget/WinCompositorWidget.h"
32
    #include "nsIFile.h"
33
34
    #define GLES2_LIB "libGLESv2.dll"
35
36
    #ifndef WIN32_LEAN_AND_MEAN
37
        #define WIN32_LEAN_AND_MEAN 1
38
    #endif
39
40
    #include <windows.h>
41
#else
42
    #error "Platform not recognized"
43
#endif
44
45
#include "gfxASurface.h"
46
#include "gfxCrashReporterUtils.h"
47
#include "gfxFailure.h"
48
#include "gfxPlatform.h"
49
#include "gfxUtils.h"
50
#include "GLBlitHelper.h"
51
#include "GLContextEGL.h"
52
#include "GLContextProvider.h"
53
#include "GLLibraryEGL.h"
54
#include "LayersLogging.h"
55
#include "mozilla/ArrayUtils.h"
56
#include "mozilla/Preferences.h"
57
#include "mozilla/gfx/gfxVars.h"
58
#include "mozilla/layers/CompositorOptions.h"
59
#include "mozilla/widget/CompositorWidget.h"
60
#include "nsDebug.h"
61
#include "nsIWidget.h"
62
#include "nsThreadUtils.h"
63
#include "ScopedGLHelpers.h"
64
#include "TextureImageEGL.h"
65
66
#if defined(MOZ_WAYLAND)
67
#include "nsAutoPtr.h"
68
#include "nsDataHashtable.h"
69
70
#include <gtk/gtk.h>
71
#include <gdk/gdkx.h>
72
#include <gdk/gdkwayland.h>
73
#include <wayland-egl.h>
74
#include <dlfcn.h>
75
#endif
76
77
using namespace mozilla::gfx;
78
79
namespace mozilla {
80
namespace gl {
81
82
using namespace mozilla::widget;
83
84
#if defined(MOZ_WAYLAND)
85
class WaylandGLSurface {
86
public:
87
    WaylandGLSurface(struct wl_surface *aWaylandSurface,
88
                         struct wl_egl_window *aEGLWindow);
89
    ~WaylandGLSurface();
90
private:
91
    struct wl_surface     *mWaylandSurface;
92
    struct wl_egl_window  *mEGLWindow;
93
};
94
95
static nsDataHashtable<nsPtrHashKey<void>, WaylandGLSurface*>
96
        sWaylandGLSurface;
97
98
void
99
DeleteWaylandGLSurface(EGLSurface surface)
100
{
101
    // We're running on Wayland which means our EGLSurface may
102
    // have attached Wayland backend data which must be released.
103
    if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default())) {
104
        auto entry = sWaylandGLSurface.Lookup(surface);
105
        if (entry) {
106
            delete entry.Data();
107
            entry.Remove();
108
        }
109
    }
110
}
111
#endif
112
113
#define ADD_ATTR_2(_array, _k, _v) do {         \
114
    (_array).AppendElement(_k);                 \
115
    (_array).AppendElement(_v);                 \
116
} while (0)
117
118
#define ADD_ATTR_1(_array, _k) do {             \
119
    (_array).AppendElement(_k);                 \
120
} while (0)
121
122
static bool
123
CreateConfig(EGLConfig* aConfig, bool aEnableDepthBuffer);
124
125
// append three zeros at the end of attribs list to work around
126
// EGL implementation bugs that iterate until they find 0, instead of
127
// EGL_NONE. See bug 948406.
128
#define EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS \
129
     LOCAL_EGL_NONE, 0, 0, 0
130
131
static EGLint kTerminationAttribs[] = {
132
    EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
133
};
134
135
static int
136
next_power_of_two(int v)
137
0
{
138
0
    v--;
139
0
    v |= v >> 1;
140
0
    v |= v >> 2;
141
0
    v |= v >> 4;
142
0
    v |= v >> 8;
143
0
    v |= v >> 16;
144
0
    v++;
145
0
146
0
    return v;
147
0
}
148
149
static bool
150
is_power_of_two(int v)
151
0
{
152
0
    NS_ASSERTION(v >= 0, "bad value");
153
0
154
0
    if (v == 0)
155
0
        return true;
156
0
157
0
    return (v & (v-1)) == 0;
158
0
}
159
160
static void
161
0
DestroySurface(EGLSurface oldSurface) {
162
0
    auto* egl = gl::GLLibraryEGL::Get();
163
0
164
0
    if (oldSurface != EGL_NO_SURFACE) {
165
0
        // TODO: This breaks TLS MakeCurrent caching.
166
0
        egl->fMakeCurrent(EGL_DISPLAY(),
167
0
                          EGL_NO_SURFACE, EGL_NO_SURFACE,
168
0
                          EGL_NO_CONTEXT);
169
0
        egl->fDestroySurface(EGL_DISPLAY(), oldSurface);
170
#if defined(MOZ_WAYLAND)
171
        DeleteWaylandGLSurface(oldSurface);
172
#endif
173
    }
174
0
}
175
176
static EGLSurface
177
CreateFallbackSurface(const EGLConfig& config)
178
0
{
179
0
    nsCString discardFailureId;
180
0
    if (!GLLibraryEGL::EnsureInitialized(false, &discardFailureId)) {
181
0
        gfxCriticalNote << "Failed to load EGL library 3!";
182
0
        return EGL_NO_SURFACE;
183
0
    }
184
0
185
0
    auto* egl = gl::GLLibraryEGL::Get();
186
0
187
0
    if (egl->IsExtensionSupported(GLLibraryEGL::KHR_surfaceless_context)) {
188
0
        // We don't need a PBuffer surface in this case
189
0
        return EGL_NO_SURFACE;
190
0
    }
191
0
192
0
    std::vector<EGLint> pbattrs;
193
0
    pbattrs.push_back(LOCAL_EGL_WIDTH); pbattrs.push_back(1);
194
0
    pbattrs.push_back(LOCAL_EGL_HEIGHT); pbattrs.push_back(1);
195
0
196
0
    for (const auto& cur : kTerminationAttribs) {
197
0
        pbattrs.push_back(cur);
198
0
    }
199
0
200
0
    EGLSurface surface = egl->fCreatePbufferSurface(EGL_DISPLAY(), config, pbattrs.data());
201
0
    if (!surface) {
202
0
        MOZ_CRASH("Failed to create fallback EGLSurface");
203
0
    }
204
0
205
0
    return surface;
206
0
}
207
208
static EGLSurface
209
CreateSurfaceFromNativeWindow(EGLNativeWindowType window, const EGLConfig& config)
210
0
{
211
0
    MOZ_ASSERT(window);
212
0
    auto* egl = gl::GLLibraryEGL::Get();
213
0
    EGLSurface newSurface = EGL_NO_SURFACE;
214
0
215
#ifdef MOZ_WIDGET_ANDROID
216
    JNIEnv* const env = jni::GetEnvForThread();
217
    ANativeWindow* const nativeWindow = ANativeWindow_fromSurface(
218
            env, reinterpret_cast<jobject>(window));
219
    newSurface = egl->fCreateWindowSurface(
220
            egl->fGetDisplay(EGL_DEFAULT_DISPLAY),
221
            config, nativeWindow, 0);
222
    ANativeWindow_release(nativeWindow);
223
#else
224
0
    newSurface = egl->fCreateWindowSurface(EGL_DISPLAY(), config,
225
0
                                           window, 0);
226
0
#endif
227
0
    return newSurface;
228
0
}
229
230
/* GLContextEGLFactory class was added as a friend of GLContextEGL
231
 * so that it could access  GLContextEGL::CreateGLContext. This was
232
 * done so that a new function would not need to be added to the shared
233
 * GLContextProvider interface.
234
 */
235
class GLContextEGLFactory {
236
public:
237
    static already_AddRefed<GLContext> Create(EGLNativeWindowType aWindow,
238
                                              bool aWebRender);
239
private:
240
0
    GLContextEGLFactory(){}
241
0
    ~GLContextEGLFactory(){}
242
};
243
244
already_AddRefed<GLContext>
245
GLContextEGLFactory::Create(EGLNativeWindowType aWindow,
246
                            bool aWebRender)
247
0
{
248
0
    nsCString discardFailureId;
249
0
    if (!GLLibraryEGL::EnsureInitialized(false, &discardFailureId)) {
250
0
        gfxCriticalNote << "Failed to load EGL library 3!";
251
0
        return nullptr;
252
0
    }
253
0
254
0
    auto* egl = gl::GLLibraryEGL::Get();
255
0
    bool doubleBuffered = true;
256
0
257
0
    EGLConfig config;
258
0
    if (aWebRender && egl->IsANGLE()) {
259
0
        // Force enable alpha channel to make sure ANGLE use correct framebuffer formart
260
0
        const int bpp = 32;
261
0
        const bool withDepth = true;
262
0
        if (!CreateConfig(&config, bpp, withDepth)) {
263
0
            gfxCriticalNote << "Failed to create EGLConfig for WebRender ANGLE!";
264
0
            return nullptr;
265
0
        }
266
0
    } else {
267
0
        if (!CreateConfig(&config, aWebRender)) {
268
0
            gfxCriticalNote << "Failed to create EGLConfig!";
269
0
            return nullptr;
270
0
        }
271
0
    }
272
0
273
0
    EGLSurface surface = EGL_NO_SURFACE;
274
0
    if (aWindow) {
275
0
        surface = mozilla::gl::CreateSurfaceFromNativeWindow(aWindow, config);
276
0
    }
277
0
278
0
    CreateContextFlags flags = CreateContextFlags::NONE;
279
0
    if (aWebRender) {
280
0
        flags |= CreateContextFlags::PREFER_ES3;
281
0
    }
282
0
    SurfaceCaps caps = SurfaceCaps::Any();
283
0
    RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(flags, caps, false, config,
284
0
                                                            surface, &discardFailureId);
285
0
    if (!gl) {
286
0
        gfxCriticalNote << "Failed to create EGLContext!";
287
0
        mozilla::gl::DestroySurface(surface);
288
0
        return nullptr;
289
0
    }
290
0
291
0
    gl->MakeCurrent();
292
0
    gl->SetIsDoubleBuffered(doubleBuffered);
293
0
    if (aWebRender && egl->IsANGLE()) {
294
0
        MOZ_ASSERT(doubleBuffered);
295
0
        egl->fSwapInterval(EGL_DISPLAY(), 0);
296
0
    }
297
0
    return gl.forget();
298
0
}
299
300
GLContextEGL::GLContextEGL(CreateContextFlags flags, const SurfaceCaps& caps,
301
                           bool isOffscreen, EGLConfig config, EGLSurface surface,
302
                           EGLContext context)
303
    : GLContext(flags, caps, nullptr, isOffscreen, false)
304
    , mConfig(config)
305
    , mEgl(gl::GLLibraryEGL::Get())
306
    , mSurface(surface)
307
    , mFallbackSurface(CreateFallbackSurface(config))
308
    , mContext(context)
309
0
{
310
#ifdef DEBUG
311
    printf_stderr("Initializing context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
312
#endif
313
}
314
315
GLContextEGL::~GLContextEGL()
316
0
{
317
0
    MarkDestroyed();
318
0
319
0
    // Wrapped context should not destroy eglContext/Surface
320
0
    if (!mOwnsContext) {
321
0
        return;
322
0
    }
323
0
324
#ifdef DEBUG
325
    printf_stderr("Destroying context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
326
#endif
327
328
0
    mEgl->fDestroyContext(EGL_DISPLAY(), mContext);
329
0
330
0
    mozilla::gl::DestroySurface(mSurface);
331
0
    mozilla::gl::DestroySurface(mFallbackSurface);
332
0
}
333
334
bool
335
GLContextEGL::Init()
336
0
{
337
#if defined(ANDROID)
338
    // We can't use LoadApitraceLibrary here because the GLContext
339
    // expects its own handle to the GL library
340
    if (!OpenLibrary(APITRACE_LIB))
341
#endif
342
0
        if (!OpenLibrary(GLES2_LIB)) {
343
0
#if defined(XP_UNIX)
344
0
            if (!OpenLibrary(GLES2_LIB2)) {
345
0
                NS_WARNING("Couldn't load GLES2 LIB.");
346
0
                return false;
347
0
            }
348
0
#endif
349
0
        }
350
0
351
0
    SetupLookupFunction();
352
0
    if (!InitWithPrefix("gl", true))
353
0
        return false;
354
0
355
0
    bool current = MakeCurrent();
356
0
    if (!current) {
357
0
        gfx::LogFailure(NS_LITERAL_CSTRING(
358
0
            "Couldn't get device attachments for device."));
359
0
        return false;
360
0
    }
361
0
362
0
    static_assert(sizeof(GLint) >= sizeof(int32_t), "GLint is smaller than int32_t");
363
0
    mMaxTextureImageSize = INT32_MAX;
364
0
365
0
    mShareWithEGLImage = mEgl->HasKHRImageBase() &&
366
0
                         mEgl->HasKHRImageTexture2D() &&
367
0
                         IsExtensionSupported(OES_EGL_image);
368
0
369
0
    return true;
370
0
}
371
372
bool
373
GLContextEGL::BindTexImage()
374
0
{
375
0
    if (!mSurface)
376
0
        return false;
377
0
378
0
    if (mBound && !ReleaseTexImage())
379
0
        return false;
380
0
381
0
    EGLBoolean success = mEgl->fBindTexImage(EGL_DISPLAY(),
382
0
        (EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER);
383
0
    if (success == LOCAL_EGL_FALSE)
384
0
        return false;
385
0
386
0
    mBound = true;
387
0
    return true;
388
0
}
389
390
bool
391
GLContextEGL::ReleaseTexImage()
392
0
{
393
0
    if (!mBound)
394
0
        return true;
395
0
396
0
    if (!mSurface)
397
0
        return false;
398
0
399
0
    EGLBoolean success;
400
0
    success = mEgl->fReleaseTexImage(EGL_DISPLAY(),
401
0
                                     (EGLSurface)mSurface,
402
0
                                     LOCAL_EGL_BACK_BUFFER);
403
0
    if (success == LOCAL_EGL_FALSE)
404
0
        return false;
405
0
406
0
    mBound = false;
407
0
    return true;
408
0
}
409
410
void
411
0
GLContextEGL::SetEGLSurfaceOverride(EGLSurface surf) {
412
0
    if (Screen()) {
413
0
        /* Blit `draw` to `read` if we need to, before we potentially juggle
414
0
          * `read` around. If we don't, we might attach a different `read`,
415
0
          * and *then* hit AssureBlitted, which will blit a dirty `draw` onto
416
0
          * the wrong `read`!
417
0
          */
418
0
        Screen()->AssureBlitted();
419
0
    }
420
0
421
0
    mSurfaceOverride = surf;
422
0
    DebugOnly<bool> ok = MakeCurrent(true);
423
0
    MOZ_ASSERT(ok);
424
0
}
425
426
bool
427
GLContextEGL::MakeCurrentImpl() const
428
0
{
429
0
    EGLSurface surface = (mSurfaceOverride != EGL_NO_SURFACE) ? mSurfaceOverride
430
0
                                                              : mSurface;
431
0
    if (!surface) {
432
0
        surface = mFallbackSurface;
433
0
    }
434
0
435
0
    const bool succeeded = mEgl->fMakeCurrent(EGL_DISPLAY(), surface, surface,
436
0
                                              mContext);
437
0
    if (!succeeded) {
438
0
        const auto eglError = mEgl->fGetError();
439
0
        if (eglError == LOCAL_EGL_CONTEXT_LOST) {
440
0
            mContextLost = true;
441
0
            NS_WARNING("EGL context has been lost.");
442
0
        } else {
443
0
            NS_WARNING("Failed to make GL context current!");
444
#ifdef DEBUG
445
            printf_stderr("EGL Error: 0x%04x\n", eglError);
446
#endif
447
        }
448
0
    }
449
0
450
0
    return succeeded;
451
0
}
452
453
bool
454
GLContextEGL::IsCurrentImpl() const
455
0
{
456
0
    return mEgl->fGetCurrentContext() == mContext;
457
0
}
458
459
bool
460
0
GLContextEGL::RenewSurface(CompositorWidget* aWidget) {
461
0
    if (!mOwnsContext) {
462
0
        return false;
463
0
    }
464
0
    // unconditionally release the surface and create a new one. Don't try to optimize this away.
465
0
    // If we get here, then by definition we know that we want to get a new surface.
466
0
    ReleaseSurface();
467
0
    MOZ_ASSERT(aWidget);
468
0
469
0
    EGLNativeWindowType nativeWindow = GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget);
470
0
    if (nativeWindow) {
471
0
        mSurface = mozilla::gl::CreateSurfaceFromNativeWindow(nativeWindow, mConfig);
472
0
        if (!mSurface) {
473
0
            NS_WARNING("Failed to create EGLSurface from native window");
474
0
            return false;
475
0
        }
476
0
    }
477
0
478
0
    return MakeCurrent(true);
479
0
}
480
481
void
482
0
GLContextEGL::ReleaseSurface() {
483
0
    if (mOwnsContext) {
484
0
        mozilla::gl::DestroySurface(mSurface);
485
0
    }
486
0
    if (mSurface == mSurfaceOverride) {
487
0
        mSurfaceOverride = EGL_NO_SURFACE;
488
0
    }
489
0
    mSurface = EGL_NO_SURFACE;
490
0
}
491
492
bool
493
GLContextEGL::SetupLookupFunction()
494
0
{
495
0
    mLookupFunc = mEgl->GetLookupFunction();
496
0
    return true;
497
0
}
498
499
bool
500
GLContextEGL::SwapBuffers()
501
0
{
502
0
    EGLSurface surface = mSurfaceOverride != EGL_NO_SURFACE
503
0
                          ? mSurfaceOverride
504
0
                          : mSurface;
505
0
    if (surface) {
506
0
        return mEgl->fSwapBuffers(EGL_DISPLAY(), surface);
507
0
    } else {
508
0
        return false;
509
0
    }
510
0
}
511
512
void
513
GLContextEGL::GetWSIInfo(nsCString* const out) const
514
0
{
515
0
    out->AppendLiteral("EGL_VENDOR: ");
516
0
    out->Append((const char*)mEgl->fQueryString(EGL_DISPLAY(), LOCAL_EGL_VENDOR));
517
0
518
0
    out->AppendLiteral("\nEGL_VERSION: ");
519
0
    out->Append((const char*)mEgl->fQueryString(EGL_DISPLAY(), LOCAL_EGL_VERSION));
520
0
521
0
    out->AppendLiteral("\nEGL_EXTENSIONS: ");
522
0
    out->Append((const char*)mEgl->fQueryString(EGL_DISPLAY(), LOCAL_EGL_EXTENSIONS));
523
0
524
0
#ifndef ANDROID // This query will crash some old android.
525
0
    out->AppendLiteral("\nEGL_EXTENSIONS(nullptr): ");
526
0
    out->Append((const char*)mEgl->fQueryString(nullptr, LOCAL_EGL_EXTENSIONS));
527
0
#endif
528
0
}
529
530
// hold a reference to the given surface
531
// for the lifetime of this context.
532
void
533
0
GLContextEGL::HoldSurface(gfxASurface* aSurf) {
534
0
    mThebesSurface = aSurf;
535
0
}
536
537
already_AddRefed<GLContextEGL>
538
GLContextEGL::CreateGLContext(CreateContextFlags flags,
539
                const SurfaceCaps& caps,
540
                bool isOffscreen,
541
                EGLConfig config,
542
                EGLSurface surface,
543
                nsACString* const out_failureId)
544
0
{
545
0
    auto* egl = gl::GLLibraryEGL::Get();
546
0
547
0
    if (egl->fBindAPI(LOCAL_EGL_OPENGL_ES_API) == LOCAL_EGL_FALSE) {
548
0
        *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_ES");
549
0
        NS_WARNING("Failed to bind API to GLES!");
550
0
        return nullptr;
551
0
    }
552
0
553
0
    std::vector<EGLint> required_attribs;
554
0
    required_attribs.push_back(LOCAL_EGL_CONTEXT_CLIENT_VERSION);
555
0
    if (flags & CreateContextFlags::PREFER_ES3) {
556
0
        required_attribs.push_back(3);
557
0
    } else {
558
0
        required_attribs.push_back(2);
559
0
    }
560
0
561
0
    const auto debugFlags = GLContext::ChooseDebugFlags(flags);
562
0
    if (!debugFlags &&
563
0
        flags & CreateContextFlags::NO_VALIDATION &&
564
0
        egl->IsExtensionSupported(GLLibraryEGL::KHR_create_context_no_error))
565
0
    {
566
0
        required_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_NO_ERROR_KHR);
567
0
        required_attribs.push_back(LOCAL_EGL_TRUE);
568
0
    }
569
0
570
0
    std::vector<EGLint> robustness_attribs;
571
0
    std::vector<EGLint> rbab_attribs; // RBAB: Robust Buffer Access Behavior
572
0
    if (flags & CreateContextFlags::PREFER_ROBUSTNESS) {
573
0
        if (egl->IsExtensionSupported(GLLibraryEGL::EXT_create_context_robustness)) {
574
0
            robustness_attribs = required_attribs;
575
0
            robustness_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT);
576
0
            robustness_attribs.push_back(LOCAL_EGL_LOSE_CONTEXT_ON_RESET_EXT);
577
0
578
0
            rbab_attribs = robustness_attribs;
579
0
            rbab_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT);
580
0
            rbab_attribs.push_back(LOCAL_EGL_TRUE);
581
0
        } else if (egl->IsExtensionSupported(GLLibraryEGL::KHR_create_context)) {
582
0
            robustness_attribs = required_attribs;
583
0
            robustness_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR);
584
0
            robustness_attribs.push_back(LOCAL_EGL_LOSE_CONTEXT_ON_RESET_KHR);
585
0
586
0
            rbab_attribs = robustness_attribs;
587
0
            rbab_attribs.push_back(LOCAL_EGL_CONTEXT_FLAGS_KHR);
588
0
            rbab_attribs.push_back(LOCAL_EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR);
589
0
        }
590
0
    }
591
0
592
0
    const auto fnCreate = [&](const std::vector<EGLint>& attribs) {
593
0
        auto terminated_attribs = attribs;
594
0
595
0
        for (const auto& cur : kTerminationAttribs) {
596
0
            terminated_attribs.push_back(cur);
597
0
        }
598
0
599
0
        return egl->fCreateContext(EGL_DISPLAY(), config, EGL_NO_CONTEXT,
600
0
                                   terminated_attribs.data());
601
0
    };
602
0
603
0
    EGLContext context;
604
0
    do {
605
0
        if (!rbab_attribs.empty()) {
606
0
            context = fnCreate(rbab_attribs);
607
0
            if (context)
608
0
                break;
609
0
            NS_WARNING("Failed to create EGLContext with rbab_attribs");
610
0
        }
611
0
612
0
        if (!robustness_attribs.empty()) {
613
0
            context = fnCreate(robustness_attribs);
614
0
            if (context)
615
0
                break;
616
0
            NS_WARNING("Failed to create EGLContext with robustness_attribs");
617
0
        }
618
0
619
0
        context = fnCreate(required_attribs);
620
0
        if (context)
621
0
            break;
622
0
        NS_WARNING("Failed to create EGLContext with required_attribs");
623
0
624
0
        *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_CREATE");
625
0
        return nullptr;
626
0
    } while (false);
627
0
    MOZ_ASSERT(context);
628
0
629
0
    RefPtr<GLContextEGL> glContext = new GLContextEGL(flags, caps, isOffscreen, config,
630
0
                                                      surface, context);
631
0
    if (!glContext->Init()) {
632
0
        *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_INIT");
633
0
        return nullptr;
634
0
    }
635
0
636
0
    return glContext.forget();
637
0
}
638
639
EGLSurface
640
GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(EGLConfig config,
641
                                                   EGLenum bindToTextureFormat,
642
                                                   mozilla::gfx::IntSize& pbsize)
643
0
{
644
0
    nsTArray<EGLint> pbattrs(16);
645
0
    EGLSurface surface = nullptr;
646
0
647
0
TRY_AGAIN_POWER_OF_TWO:
648
0
    pbattrs.Clear();
649
0
    pbattrs.AppendElement(LOCAL_EGL_WIDTH); pbattrs.AppendElement(pbsize.width);
650
0
    pbattrs.AppendElement(LOCAL_EGL_HEIGHT); pbattrs.AppendElement(pbsize.height);
651
0
652
0
    if (bindToTextureFormat != LOCAL_EGL_NONE) {
653
0
        pbattrs.AppendElement(LOCAL_EGL_TEXTURE_TARGET);
654
0
        pbattrs.AppendElement(LOCAL_EGL_TEXTURE_2D);
655
0
656
0
        pbattrs.AppendElement(LOCAL_EGL_TEXTURE_FORMAT);
657
0
        pbattrs.AppendElement(bindToTextureFormat);
658
0
    }
659
0
660
0
    for (const auto& cur : kTerminationAttribs) {
661
0
        pbattrs.AppendElement(cur);
662
0
    }
663
0
664
0
    auto* egl = gl::GLLibraryEGL::Get();
665
0
666
0
    surface = egl->fCreatePbufferSurface(EGL_DISPLAY(), config, &pbattrs[0]);
667
0
    if (!surface) {
668
0
        if (!is_power_of_two(pbsize.width) ||
669
0
            !is_power_of_two(pbsize.height))
670
0
        {
671
0
            if (!is_power_of_two(pbsize.width))
672
0
                pbsize.width = next_power_of_two(pbsize.width);
673
0
            if (!is_power_of_two(pbsize.height))
674
0
                pbsize.height = next_power_of_two(pbsize.height);
675
0
676
0
            NS_WARNING("Failed to create pbuffer, trying power of two dims");
677
0
            goto TRY_AGAIN_POWER_OF_TWO;
678
0
        }
679
0
680
0
        NS_WARNING("Failed to create pbuffer surface");
681
0
        return nullptr;
682
0
    }
683
0
684
0
    return surface;
685
0
}
686
687
#if defined(MOZ_WAYLAND)
688
WaylandGLSurface::WaylandGLSurface(struct wl_surface *aWaylandSurface,
689
                                           struct wl_egl_window *aEGLWindow)
690
    : mWaylandSurface(aWaylandSurface)
691
    , mEGLWindow(aEGLWindow)
692
{
693
}
694
695
WaylandGLSurface::~WaylandGLSurface()
696
{
697
    wl_egl_window_destroy(mEGLWindow);
698
    wl_surface_destroy(mWaylandSurface);
699
}
700
701
EGLSurface
702
GLContextEGL::CreateWaylandBufferSurface(EGLConfig config,
703
                                         mozilla::gfx::IntSize& pbsize)
704
{
705
    // Available as of GTK 3.8+
706
    static auto sGdkWaylandDisplayGetWlCompositor =
707
        (wl_compositor *(*)(GdkDisplay *))
708
        dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_compositor");
709
710
    if (!sGdkWaylandDisplayGetWlCompositor)
711
        return nullptr;
712
713
    struct wl_compositor *compositor =
714
        sGdkWaylandDisplayGetWlCompositor(gdk_display_get_default());
715
    struct wl_surface *wlsurface = wl_compositor_create_surface(compositor);
716
    struct wl_egl_window *eglwindow =
717
        wl_egl_window_create(wlsurface, pbsize.width, pbsize.height);
718
719
    auto* egl = gl::GLLibraryEGL::Get();
720
    EGLSurface surface =
721
        egl->fCreateWindowSurface(EGL_DISPLAY(), config, eglwindow, 0);
722
723
    if (surface) {
724
        WaylandGLSurface* waylandData =
725
            new WaylandGLSurface(wlsurface, eglwindow);
726
        auto entry = sWaylandGLSurface.LookupForAdd(surface);
727
        entry.OrInsert([&waylandData](){ return waylandData; });
728
    }
729
730
    return surface;
731
}
732
#endif
733
734
static const EGLint kEGLConfigAttribsOffscreenPBuffer[] = {
735
    LOCAL_EGL_SURFACE_TYPE,    LOCAL_EGL_PBUFFER_BIT,
736
    LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
737
    // Old versions of llvmpipe seem to need this to properly create the pbuffer (bug 981856)
738
    LOCAL_EGL_RED_SIZE,        8,
739
    LOCAL_EGL_GREEN_SIZE,      8,
740
    LOCAL_EGL_BLUE_SIZE,       8,
741
    LOCAL_EGL_ALPHA_SIZE,      0,
742
    EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
743
};
744
745
static const EGLint kEGLConfigAttribsRGB16[] = {
746
    LOCAL_EGL_SURFACE_TYPE,    LOCAL_EGL_WINDOW_BIT,
747
    LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
748
    LOCAL_EGL_RED_SIZE,        5,
749
    LOCAL_EGL_GREEN_SIZE,      6,
750
    LOCAL_EGL_BLUE_SIZE,       5,
751
    LOCAL_EGL_ALPHA_SIZE,      0,
752
    EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
753
};
754
755
static const EGLint kEGLConfigAttribsRGB24[] = {
756
    LOCAL_EGL_SURFACE_TYPE,    LOCAL_EGL_WINDOW_BIT,
757
    LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
758
    LOCAL_EGL_RED_SIZE,        8,
759
    LOCAL_EGL_GREEN_SIZE,      8,
760
    LOCAL_EGL_BLUE_SIZE,       8,
761
    LOCAL_EGL_ALPHA_SIZE,      0,
762
    EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
763
};
764
765
static const EGLint kEGLConfigAttribsRGBA32[] = {
766
    LOCAL_EGL_SURFACE_TYPE,    LOCAL_EGL_WINDOW_BIT,
767
    LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
768
    LOCAL_EGL_RED_SIZE,        8,
769
    LOCAL_EGL_GREEN_SIZE,      8,
770
    LOCAL_EGL_BLUE_SIZE,       8,
771
    LOCAL_EGL_ALPHA_SIZE,      8,
772
    EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
773
};
774
775
bool
776
CreateConfig(EGLConfig* aConfig, int32_t depth, bool aEnableDepthBuffer)
777
0
{
778
0
    EGLConfig configs[64];
779
0
    const EGLint* attribs;
780
0
    EGLint ncfg = ArrayLength(configs);
781
0
782
0
    switch (depth) {
783
0
        case 16:
784
0
            attribs = kEGLConfigAttribsRGB16;
785
0
            break;
786
0
        case 24:
787
0
            attribs = kEGLConfigAttribsRGB24;
788
0
            break;
789
0
        case 32:
790
0
            attribs = kEGLConfigAttribsRGBA32;
791
0
            break;
792
0
        default:
793
0
            NS_ERROR("Unknown pixel depth");
794
0
            return false;
795
0
    }
796
0
797
0
    auto* egl = gl::GLLibraryEGL::Get();
798
0
799
0
    if (!egl->fChooseConfig(EGL_DISPLAY(), attribs,
800
0
                            configs, ncfg, &ncfg) ||
801
0
        ncfg < 1) {
802
0
        return false;
803
0
    }
804
0
805
0
    for (int j = 0; j < ncfg; ++j) {
806
0
        EGLConfig config = configs[j];
807
0
        EGLint r, g, b, a;
808
0
        if (egl->fGetConfigAttrib(EGL_DISPLAY(), config,
809
0
                                  LOCAL_EGL_RED_SIZE, &r) &&
810
0
            egl->fGetConfigAttrib(EGL_DISPLAY(), config,
811
0
                                  LOCAL_EGL_GREEN_SIZE, &g) &&
812
0
            egl->fGetConfigAttrib(EGL_DISPLAY(), config,
813
0
                                  LOCAL_EGL_BLUE_SIZE, &b) &&
814
0
            egl->fGetConfigAttrib(EGL_DISPLAY(), config,
815
0
                                  LOCAL_EGL_ALPHA_SIZE, &a) &&
816
0
            ((depth == 16 && r == 5 && g == 6 && b == 5) ||
817
0
             (depth == 24 && r == 8 && g == 8 && b == 8) ||
818
0
             (depth == 32 && r == 8 && g == 8 && b == 8 && a == 8)))
819
0
        {
820
0
            EGLint z;
821
0
            if (aEnableDepthBuffer) {
822
0
                if (!egl->fGetConfigAttrib(EGL_DISPLAY(), config, LOCAL_EGL_DEPTH_SIZE, &z) ||
823
0
                    z != 24) {
824
0
                    continue;
825
0
                }
826
0
            }
827
0
            *aConfig = config;
828
0
            return true;
829
0
        }
830
0
    }
831
0
    return false;
832
0
}
833
834
// Return true if a suitable EGLConfig was found and pass it out
835
// through aConfig.  Return false otherwise.
836
//
837
// NB: It's entirely legal for the returned EGLConfig to be valid yet
838
// have the value null.
839
static bool
840
CreateConfig(EGLConfig* aConfig, bool aEnableDepthBuffer)
841
0
{
842
0
    int32_t depth = gfxVars::ScreenDepth();
843
0
    if (!CreateConfig(aConfig, depth, aEnableDepthBuffer)) {
844
#ifdef MOZ_WIDGET_ANDROID
845
        // Bug 736005
846
        // Android doesn't always support 16 bit so also try 24 bit
847
        if (depth == 16) {
848
            return CreateConfig(aConfig, 24, aEnableDepthBuffer);
849
        }
850
        // Bug 970096
851
        // Some devices that have 24 bit screens only support 16 bit OpenGL?
852
        if (depth == 24) {
853
            return CreateConfig(aConfig, 16, aEnableDepthBuffer);
854
        }
855
#endif
856
        return false;
857
0
    } else {
858
0
        return true;
859
0
    }
860
0
}
861
862
already_AddRefed<GLContext>
863
GLContextProviderEGL::CreateWrappingExisting(void* aContext, void* aSurface)
864
0
{
865
0
    nsCString discardFailureId;
866
0
    if (!GLLibraryEGL::EnsureInitialized(false, &discardFailureId)) {
867
0
        MOZ_CRASH("GFX: Failed to load EGL library 2!");
868
0
        return nullptr;
869
0
    }
870
0
871
0
    if (!aContext || !aSurface)
872
0
        return nullptr;
873
0
874
0
    SurfaceCaps caps = SurfaceCaps::Any();
875
0
    EGLConfig config = EGL_NO_CONFIG;
876
0
    RefPtr<GLContextEGL> gl = new GLContextEGL(CreateContextFlags::NONE, caps, false,
877
0
                                               config, (EGLSurface)aSurface,
878
0
                                               (EGLContext)aContext);
879
0
    gl->SetIsDoubleBuffered(true);
880
0
    gl->mOwnsContext = false;
881
0
882
0
    return gl.forget();
883
0
}
884
885
already_AddRefed<GLContext>
886
GLContextProviderEGL::CreateForCompositorWidget(CompositorWidget* aCompositorWidget, bool aForceAccelerated)
887
0
{
888
0
    MOZ_ASSERT(aCompositorWidget);
889
0
    return GLContextEGLFactory::Create(GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aCompositorWidget),
890
0
                                       aCompositorWidget->GetCompositorOptions().UseWebRender());
891
0
}
892
893
already_AddRefed<GLContext>
894
GLContextProviderEGL::CreateForWindow(nsIWidget* aWidget,
895
                                      bool aWebRender,
896
                                      bool aForceAccelerated)
897
0
{
898
0
    MOZ_ASSERT(aWidget);
899
0
    return GLContextEGLFactory::Create(GET_NATIVE_WINDOW_FROM_REAL_WIDGET(aWidget),
900
0
                                       aWebRender);
901
0
}
902
903
#if defined(MOZ_WIDGET_ANDROID)
904
EGLSurface
905
GLContextEGL::CreateCompatibleSurface(void* aWindow)
906
{
907
    if (mConfig == EGL_NO_CONFIG) {
908
        MOZ_CRASH("GFX: Failed with invalid EGLConfig 2!");
909
    }
910
911
    return GLContextProviderEGL::CreateEGLSurface(aWindow, mConfig);
912
}
913
914
/* static */ EGLSurface
915
GLContextProviderEGL::CreateEGLSurface(void* aWindow, EGLConfig aConfig)
916
{
917
    // NOTE: aWindow is an ANativeWindow
918
    nsCString discardFailureId;
919
    if (!GLLibraryEGL::EnsureInitialized(false, &discardFailureId)) {
920
        MOZ_CRASH("GFX: Failed to load EGL library 4!");
921
    }
922
    auto* egl = gl::GLLibraryEGL::Get();
923
    EGLConfig config = aConfig;
924
    if (!config && !CreateConfig(&config, /* aEnableDepthBuffer */ false)) {
925
        MOZ_CRASH("GFX: Failed to create EGLConfig 2!");
926
    }
927
928
    MOZ_ASSERT(aWindow);
929
930
    EGLSurface surface = egl->fCreateWindowSurface(EGL_DISPLAY(), config, aWindow,
931
                                                   0);
932
    if (surface == EGL_NO_SURFACE) {
933
        MOZ_CRASH("GFX: Failed to create EGLSurface 2!");
934
    }
935
936
    return surface;
937
}
938
939
/* static */ void
940
GLContextProviderEGL::DestroyEGLSurface(EGLSurface surface)
941
{
942
    nsCString discardFailureId;
943
    if (!GLLibraryEGL::EnsureInitialized(false, &discardFailureId)) {
944
        MOZ_CRASH("GFX: Failed to load EGL library 5!");
945
    }
946
    auto* egl = gl::GLLibraryEGL::Get();
947
    egl->fDestroySurface(EGL_DISPLAY(), surface);
948
}
949
#endif // defined(ANDROID)
950
951
static void
952
FillContextAttribs(bool alpha, bool depth, bool stencil, bool bpp16,
953
                   bool es3, nsTArray<EGLint>* out)
954
0
{
955
0
    out->AppendElement(LOCAL_EGL_SURFACE_TYPE);
956
#if defined(MOZ_WAYLAND)
957
    if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default())) {
958
        // Wayland on desktop does not support PBuffer or FBO.
959
        // We create a dummy wl_egl_window instead.
960
        out->AppendElement(LOCAL_EGL_WINDOW_BIT);
961
    } else {
962
        out->AppendElement(LOCAL_EGL_PBUFFER_BIT);
963
    }
964
#else
965
0
    out->AppendElement(LOCAL_EGL_PBUFFER_BIT);
966
0
#endif
967
0
968
0
    out->AppendElement(LOCAL_EGL_RENDERABLE_TYPE);
969
0
    if (es3) {
970
0
        out->AppendElement(LOCAL_EGL_OPENGL_ES3_BIT_KHR);
971
0
    } else {
972
0
        out->AppendElement(LOCAL_EGL_OPENGL_ES2_BIT);
973
0
    }
974
0
975
0
    out->AppendElement(LOCAL_EGL_RED_SIZE);
976
0
    if (bpp16) {
977
0
        out->AppendElement(alpha ? 4 : 5);
978
0
    } else {
979
0
        out->AppendElement(8);
980
0
    }
981
0
982
0
    out->AppendElement(LOCAL_EGL_GREEN_SIZE);
983
0
    if (bpp16) {
984
0
        out->AppendElement(alpha ? 4 : 6);
985
0
    } else {
986
0
        out->AppendElement(8);
987
0
    }
988
0
989
0
    out->AppendElement(LOCAL_EGL_BLUE_SIZE);
990
0
    if (bpp16) {
991
0
        out->AppendElement(alpha ? 4 : 5);
992
0
    } else {
993
0
        out->AppendElement(8);
994
0
    }
995
0
996
0
    out->AppendElement(LOCAL_EGL_ALPHA_SIZE);
997
0
    if (alpha) {
998
0
        out->AppendElement(bpp16 ? 4 : 8);
999
0
    } else {
1000
0
        out->AppendElement(0);
1001
0
    }
1002
0
1003
0
    out->AppendElement(LOCAL_EGL_DEPTH_SIZE);
1004
0
    out->AppendElement(depth ? 16 : 0);
1005
0
1006
0
    out->AppendElement(LOCAL_EGL_STENCIL_SIZE);
1007
0
    out->AppendElement(stencil ? 8 : 0);
1008
0
1009
0
    // EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
1010
0
    out->AppendElement(LOCAL_EGL_NONE);
1011
0
    out->AppendElement(0);
1012
0
1013
0
    out->AppendElement(0);
1014
0
    out->AppendElement(0);
1015
0
}
1016
1017
static GLint
1018
GetAttrib(GLLibraryEGL* egl, EGLConfig config, EGLint attrib)
1019
0
{
1020
0
    EGLint bits = 0;
1021
0
    egl->fGetConfigAttrib(egl->Display(), config, attrib, &bits);
1022
0
    MOZ_ASSERT(egl->fGetError() == LOCAL_EGL_SUCCESS);
1023
0
1024
0
    return bits;
1025
0
}
1026
1027
static EGLConfig
1028
ChooseConfig(GLLibraryEGL* egl, CreateContextFlags flags, const SurfaceCaps& minCaps,
1029
             SurfaceCaps* const out_configCaps)
1030
0
{
1031
0
    nsTArray<EGLint> configAttribList;
1032
0
    FillContextAttribs(minCaps.alpha, minCaps.depth, minCaps.stencil, minCaps.bpp16,
1033
0
                       bool(flags & CreateContextFlags::PREFER_ES3), &configAttribList);
1034
0
1035
0
    const EGLint* configAttribs = configAttribList.Elements();
1036
0
1037
0
    // We're guaranteed to get at least minCaps, and the sorting dictated by the spec for
1038
0
    // eglChooseConfig reasonably assures that a reasonable 'best' config is on top.
1039
0
    const EGLint kMaxConfigs = 1;
1040
0
    EGLConfig configs[kMaxConfigs];
1041
0
    EGLint foundConfigs = 0;
1042
0
    if (!egl->fChooseConfig(egl->Display(), configAttribs, configs, kMaxConfigs,
1043
0
                            &foundConfigs)
1044
0
        || foundConfigs == 0)
1045
0
    {
1046
0
        return EGL_NO_CONFIG;
1047
0
    }
1048
0
1049
0
    EGLConfig config = configs[0];
1050
0
1051
0
    *out_configCaps = minCaps; // Pick up any preserve, etc.
1052
0
    out_configCaps->color = true;
1053
0
    out_configCaps->alpha   = bool(GetAttrib(egl, config, LOCAL_EGL_ALPHA_SIZE));
1054
0
    out_configCaps->depth   = bool(GetAttrib(egl, config, LOCAL_EGL_DEPTH_SIZE));
1055
0
    out_configCaps->stencil = bool(GetAttrib(egl, config, LOCAL_EGL_STENCIL_SIZE));
1056
0
    out_configCaps->bpp16 = (GetAttrib(egl, config, LOCAL_EGL_RED_SIZE) < 8);
1057
0
1058
0
    return config;
1059
0
}
1060
1061
/*static*/ already_AddRefed<GLContextEGL>
1062
GLContextEGL::CreateEGLPBufferOffscreenContext(CreateContextFlags flags,
1063
                                               const mozilla::gfx::IntSize& size,
1064
                                               const SurfaceCaps& minCaps,
1065
                                               nsACString* const out_failureId)
1066
0
{
1067
0
    bool forceEnableHardware = bool(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE);
1068
0
    if (!GLLibraryEGL::EnsureInitialized(forceEnableHardware, out_failureId)) {
1069
0
        return nullptr;
1070
0
    }
1071
0
1072
0
    auto* egl = gl::GLLibraryEGL::Get();
1073
0
    SurfaceCaps configCaps;
1074
0
    EGLConfig config = ChooseConfig(egl, flags, minCaps, &configCaps);
1075
0
    if (config == EGL_NO_CONFIG) {
1076
0
        *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_NO_CONFIG");
1077
0
        NS_WARNING("Failed to find a compatible config.");
1078
0
        return nullptr;
1079
0
    }
1080
0
1081
0
    if (GLContext::ShouldSpew()) {
1082
0
        egl->DumpEGLConfig(config);
1083
0
    }
1084
0
1085
0
    mozilla::gfx::IntSize pbSize(size);
1086
0
    EGLSurface surface = nullptr;
1087
#if defined(MOZ_WAYLAND)
1088
    if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default())) {
1089
        surface = GLContextEGL::CreateWaylandBufferSurface(config, pbSize);
1090
    } else
1091
#endif
1092
    {
1093
0
        surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(config,
1094
0
                                                                     LOCAL_EGL_NONE,
1095
0
                                                                     pbSize);
1096
0
    }
1097
0
    if (!surface) {
1098
0
        *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_POT");
1099
0
        NS_WARNING("Failed to create PBuffer for context!");
1100
0
        return nullptr;
1101
0
    }
1102
0
1103
0
    RefPtr<GLContextEGL> gl = GLContextEGL::CreateGLContext(flags, configCaps, true,
1104
0
                                                            config, surface,
1105
0
                                                            out_failureId);
1106
0
    if (!gl) {
1107
0
        NS_WARNING("Failed to create GLContext from PBuffer");
1108
0
        egl->fDestroySurface(egl->Display(), surface);
1109
#if defined(MOZ_WAYLAND)
1110
        DeleteWaylandGLSurface(surface);
1111
#endif
1112
        return nullptr;
1113
0
    }
1114
0
1115
0
    return gl.forget();
1116
0
}
1117
1118
/*static*/ already_AddRefed<GLContext>
1119
GLContextProviderEGL::CreateHeadless(CreateContextFlags flags,
1120
                                     nsACString* const out_failureId)
1121
0
{
1122
0
    mozilla::gfx::IntSize dummySize = mozilla::gfx::IntSize(16, 16);
1123
0
    SurfaceCaps dummyCaps = SurfaceCaps::Any();
1124
0
    return GLContextEGL::CreateEGLPBufferOffscreenContext(flags, dummySize, dummyCaps,
1125
0
                                                          out_failureId);
1126
0
}
1127
1128
// Under EGL, on Android, pbuffers are supported fine, though
1129
// often without the ability to texture from them directly.
1130
/*static*/ already_AddRefed<GLContext>
1131
GLContextProviderEGL::CreateOffscreen(const mozilla::gfx::IntSize& size,
1132
                                      const SurfaceCaps& minCaps,
1133
                                      CreateContextFlags flags,
1134
                                      nsACString* const out_failureId)
1135
0
{
1136
0
    bool forceEnableHardware = bool(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE);
1137
0
    if (!GLLibraryEGL::EnsureInitialized(forceEnableHardware, out_failureId)) { // Needed for IsANGLE().
1138
0
        return nullptr;
1139
0
    }
1140
0
1141
0
    auto* egl = gl::GLLibraryEGL::Get();
1142
0
    bool canOffscreenUseHeadless = true;
1143
0
    if (egl->IsANGLE()) {
1144
0
        // ANGLE needs to use PBuffers.
1145
0
        canOffscreenUseHeadless = false;
1146
0
    }
1147
0
1148
#if defined(MOZ_WIDGET_ANDROID)
1149
    // Using a headless context loses the SurfaceCaps
1150
    // which can cause a loss of depth and/or stencil
1151
    canOffscreenUseHeadless = false;
1152
#endif //  defined(MOZ_WIDGET_ANDROID)
1153
1154
0
    RefPtr<GLContext> gl;
1155
0
    SurfaceCaps minOffscreenCaps = minCaps;
1156
0
1157
0
    if (canOffscreenUseHeadless) {
1158
0
        gl = CreateHeadless(flags, out_failureId);
1159
0
        if (!gl) {
1160
0
            return nullptr;
1161
0
        }
1162
0
    } else {
1163
0
        SurfaceCaps minBackbufferCaps = minOffscreenCaps;
1164
0
        if (minOffscreenCaps.antialias) {
1165
0
            minBackbufferCaps.antialias = false;
1166
0
            minBackbufferCaps.depth = false;
1167
0
            minBackbufferCaps.stencil = false;
1168
0
        }
1169
0
1170
0
        gl = GLContextEGL::CreateEGLPBufferOffscreenContext(flags, size,
1171
0
                                                            minBackbufferCaps,
1172
0
                                                            out_failureId);
1173
0
        if (!gl)
1174
0
            return nullptr;
1175
0
1176
0
        // Pull the actual resulting caps to ensure that our offscreen matches our
1177
0
        // backbuffer.
1178
0
        minOffscreenCaps.alpha = gl->Caps().alpha;
1179
0
        if (!minOffscreenCaps.antialias) {
1180
0
            // Only update these if we don't have AA. If we do have AA, we ignore
1181
0
            // backbuffer depth/stencil.
1182
0
            minOffscreenCaps.depth = gl->Caps().depth;
1183
0
            minOffscreenCaps.stencil = gl->Caps().stencil;
1184
0
        }
1185
0
    }
1186
0
1187
0
    // Init the offscreen with the updated offscreen caps.
1188
0
    if (!gl->InitOffscreen(size, minOffscreenCaps)) {
1189
0
        *out_failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_EGL_OFFSCREEN");
1190
0
        return nullptr;
1191
0
    }
1192
0
1193
0
    return gl.forget();
1194
0
}
1195
1196
// Don't want a global context on Android as 1) share groups across 2 threads fail on many Tegra drivers (bug 759225)
1197
// and 2) some mobile devices have a very strict limit on global number of GL contexts (bug 754257)
1198
// and 3) each EGL context eats 750k on B2G (bug 813783)
1199
/*static*/ GLContext*
1200
GLContextProviderEGL::GetGlobalContext()
1201
0
{
1202
0
    return nullptr;
1203
0
}
1204
1205
/*static*/ void
1206
GLContextProviderEGL::Shutdown()
1207
0
{
1208
0
    const RefPtr<GLLibraryEGL> egl = GLLibraryEGL::Get();
1209
0
    if (egl) {
1210
0
        egl->Shutdown();
1211
0
    }
1212
0
}
1213
1214
} /* namespace gl */
1215
} /* namespace mozilla */
1216
1217
#undef EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS