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