Bumping manifests a=b2g-bump
[gecko.git] / gfx / gl / GLContextProviderEGL.cpp
blobdb6687f7fce3aac5ab7349c7bd5921f804379e5f
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/. */
6 #include "mozilla/ArrayUtils.h"
8 #include "GLContextEGL.h"
10 #if defined(XP_UNIX)
12 #ifdef MOZ_WIDGET_GTK
13 #include <gdk/gdkx.h>
14 // we're using default display for now
15 #define GET_NATIVE_WINDOW(aWidget) (EGLNativeWindowType)GDK_WINDOW_XID((GdkWindow *) aWidget->GetNativeData(NS_NATIVE_WINDOW))
16 #elif defined(MOZ_WIDGET_QT)
17 #define GET_NATIVE_WINDOW(aWidget) (EGLNativeWindowType)(aWidget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW))
18 #elif defined(MOZ_WIDGET_GONK)
19 #define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW))
20 #include "HwcComposer2D.h"
21 #include "libdisplay/GonkDisplay.h"
22 #endif
24 #if defined(ANDROID)
25 /* from widget */
26 #if defined(MOZ_WIDGET_ANDROID)
27 #include "AndroidBridge.h"
28 #endif
30 #include <android/log.h>
31 #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
33 # if defined(MOZ_WIDGET_GONK)
34 # include "cutils/properties.h"
35 # include <ui/GraphicBuffer.h>
37 using namespace android;
38 # endif
40 #endif
42 #define GLES2_LIB "libGLESv2.so"
43 #define GLES2_LIB2 "libGLESv2.so.2"
45 #elif defined(XP_WIN)
47 #include "nsIFile.h"
49 #define GLES2_LIB "libGLESv2.dll"
51 #ifndef WIN32_LEAN_AND_MEAN
52 #define WIN32_LEAN_AND_MEAN 1
53 #endif
55 #include <windows.h>
57 // a little helper
58 class AutoDestroyHWND {
59 public:
60 AutoDestroyHWND(HWND aWnd = nullptr)
61 : mWnd(aWnd)
65 ~AutoDestroyHWND() {
66 if (mWnd) {
67 ::DestroyWindow(mWnd);
71 operator HWND() {
72 return mWnd;
75 HWND forget() {
76 HWND w = mWnd;
77 mWnd = nullptr;
78 return w;
81 HWND operator=(HWND aWnd) {
82 if (mWnd && mWnd != aWnd) {
83 ::DestroyWindow(mWnd);
85 mWnd = aWnd;
86 return mWnd;
89 HWND mWnd;
92 #else
94 #error "Platform not recognized"
96 #endif
98 #include "mozilla/Preferences.h"
99 #include "gfxUtils.h"
100 #include "gfxFailure.h"
101 #include "gfxASurface.h"
102 #include "gfxPlatform.h"
103 #include "GLContextProvider.h"
104 #include "GLLibraryEGL.h"
105 #include "TextureImageEGL.h"
106 #include "nsDebug.h"
107 #include "nsThreadUtils.h"
109 #include "nsIWidget.h"
111 #include "gfxCrashReporterUtils.h"
113 #include "ScopedGLHelpers.h"
114 #include "GLBlitHelper.h"
116 using namespace mozilla::gfx;
118 namespace mozilla {
119 namespace gl {
121 #define ADD_ATTR_2(_array, _k, _v) do { \
122 (_array).AppendElement(_k); \
123 (_array).AppendElement(_v); \
124 } while (0)
126 #define ADD_ATTR_1(_array, _k) do { \
127 (_array).AppendElement(_k); \
128 } while (0)
130 static bool
131 CreateConfig(EGLConfig* aConfig);
133 // append three zeros at the end of attribs list to work around
134 // EGL implementation bugs that iterate until they find 0, instead of
135 // EGL_NONE. See bug 948406.
136 #define EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS \
137 LOCAL_EGL_NONE, 0, 0, 0
139 static EGLint gTerminationAttribs[] = {
140 EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
143 static EGLint gContextAttribs[] = {
144 LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2,
145 EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
148 static EGLint gContextAttribsRobustness[] = {
149 LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2,
150 //LOCAL_EGL_CONTEXT_ROBUST_ACCESS_EXT, LOCAL_EGL_TRUE,
151 LOCAL_EGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_EXT, LOCAL_EGL_LOSE_CONTEXT_ON_RESET_EXT,
152 EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
155 static int
156 next_power_of_two(int v)
158 v--;
159 v |= v >> 1;
160 v |= v >> 2;
161 v |= v >> 4;
162 v |= v >> 8;
163 v |= v >> 16;
164 v++;
166 return v;
169 static bool
170 is_power_of_two(int v)
172 NS_ASSERTION(v >= 0, "bad value");
174 if (v == 0)
175 return true;
177 return (v & (v-1)) == 0;
180 static void
181 DestroySurface(EGLSurface oldSurface) {
182 if (oldSurface != EGL_NO_SURFACE) {
183 sEGLLibrary.fMakeCurrent(EGL_DISPLAY(),
184 EGL_NO_SURFACE, EGL_NO_SURFACE,
185 EGL_NO_CONTEXT);
186 sEGLLibrary.fDestroySurface(EGL_DISPLAY(), oldSurface);
190 static EGLSurface
191 CreateSurfaceForWindow(nsIWidget* widget, const EGLConfig& config) {
192 EGLSurface newSurface = EGL_NO_SURFACE;
194 #ifdef MOZ_WIDGET_ANDROID
195 mozilla::AndroidBridge::Bridge()->RegisterCompositor();
196 newSurface = mozilla::AndroidBridge::Bridge()->CreateEGLSurfaceForCompositor();
197 if (newSurface == EGL_NO_SURFACE) {
198 return EGL_NO_SURFACE;
200 #else
201 MOZ_ASSERT(widget != nullptr);
202 newSurface = sEGLLibrary.fCreateWindowSurface(EGL_DISPLAY(), config, GET_NATIVE_WINDOW(widget), 0);
203 #endif
204 return newSurface;
207 GLContextEGL::GLContextEGL(
208 const SurfaceCaps& caps,
209 GLContext* shareContext,
210 bool isOffscreen,
211 EGLConfig config,
212 EGLSurface surface,
213 EGLContext context)
214 : GLContext(caps, shareContext, isOffscreen)
215 , mConfig(config)
216 , mSurface(surface)
217 , mSurfaceOverride(EGL_NO_SURFACE)
218 , mContext(context)
219 , mThebesSurface(nullptr)
220 , mBound(false)
221 , mIsPBuffer(false)
222 , mIsDoubleBuffered(false)
223 , mCanBindToTexture(false)
224 , mShareWithEGLImage(false)
225 , mOwnsContext(true)
227 // any EGL contexts will always be GLESv2
228 SetProfileVersion(ContextProfile::OpenGLES, 200);
230 #ifdef DEBUG
231 printf_stderr("Initializing context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
232 #endif
233 #if defined(MOZ_WIDGET_GONK)
234 if (!mIsOffscreen) {
235 mHwc = HwcComposer2D::GetInstance();
236 MOZ_ASSERT(!mHwc->Initialized());
238 if (mHwc->Init(EGL_DISPLAY(), mSurface, this)) {
239 NS_WARNING("HWComposer initialization failed!");
240 mHwc = nullptr;
243 #endif
246 GLContextEGL::~GLContextEGL()
248 MarkDestroyed();
250 // Wrapped context should not destroy eglContext/Surface
251 if (!mOwnsContext) {
252 return;
255 #ifdef DEBUG
256 printf_stderr("Destroying context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
257 #endif
259 sEGLLibrary.fDestroyContext(EGL_DISPLAY(), mContext);
260 sEGLLibrary.UnsetCachedCurrentContext();
262 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION < 17
263 if (!mIsOffscreen) {
264 // In ICS, SurfaceFlinger's DisplayHardware::fini() does not destroy the EGLSurface associated with the
265 // native framebuffer. Destroying it causes crashes in the ICS emulator
266 // EGL implementation, specifically because the egl_window_surface_t dtor
267 // calls nativeWindow->cancelBuffer and FramebufferNativeWindow does not initialize
268 // the cancelBuffer function pointer, see bug 986836
269 return;
271 #endif
273 mozilla::gl::DestroySurface(mSurface);
276 bool
277 GLContextEGL::Init()
279 #if defined(ANDROID)
280 // We can't use LoadApitraceLibrary here because the GLContext
281 // expects its own handle to the GL library
282 if (!OpenLibrary(APITRACE_LIB))
283 #endif
284 if (!OpenLibrary(GLES2_LIB)) {
285 #if defined(XP_UNIX)
286 if (!OpenLibrary(GLES2_LIB2)) {
287 NS_WARNING("Couldn't load GLES2 LIB.");
288 return false;
290 #endif
293 SetupLookupFunction();
294 if (!InitWithPrefix("gl", true))
295 return false;
297 bool current = MakeCurrent();
298 if (!current) {
299 gfx::LogFailure(NS_LITERAL_CSTRING(
300 "Couldn't get device attachments for device."));
301 return false;
304 PR_STATIC_ASSERT(sizeof(GLint) >= sizeof(int32_t));
305 mMaxTextureImageSize = INT32_MAX;
307 mShareWithEGLImage = sEGLLibrary.HasKHRImageBase() &&
308 sEGLLibrary.HasKHRImageTexture2D() &&
309 IsExtensionSupported(OES_EGL_image);
311 return true;
314 bool
315 GLContextEGL::BindTexImage()
317 if (!mSurface)
318 return false;
320 if (mBound && !ReleaseTexImage())
321 return false;
323 EGLBoolean success = sEGLLibrary.fBindTexImage(EGL_DISPLAY(),
324 (EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER);
325 if (success == LOCAL_EGL_FALSE)
326 return false;
328 mBound = true;
329 return true;
332 bool
333 GLContextEGL::ReleaseTexImage()
335 if (!mBound)
336 return true;
338 if (!mSurface)
339 return false;
341 EGLBoolean success;
342 success = sEGLLibrary.fReleaseTexImage(EGL_DISPLAY(),
343 (EGLSurface)mSurface,
344 LOCAL_EGL_BACK_BUFFER);
345 if (success == LOCAL_EGL_FALSE)
346 return false;
348 mBound = false;
349 return true;
352 void
353 GLContextEGL::SetEGLSurfaceOverride(EGLSurface surf) {
354 if (Screen()) {
355 /* Blit `draw` to `read` if we need to, before we potentially juggle
356 * `read` around. If we don't, we might attach a different `read`,
357 * and *then* hit AssureBlitted, which will blit a dirty `draw` onto
358 * the wrong `read`!
360 Screen()->AssureBlitted();
363 mSurfaceOverride = surf ? (EGLSurface) surf : mSurface;
364 MakeCurrent(true);
367 bool
368 GLContextEGL::MakeCurrentImpl(bool aForce) {
369 bool succeeded = true;
371 // Assume that EGL has the same problem as WGL does,
372 // where MakeCurrent with an already-current context is
373 // still expensive.
374 bool hasDifferentContext = false;
375 if (sEGLLibrary.CachedCurrentContext() != mContext) {
376 // even if the cached context doesn't match the current one
377 // might still
378 if (sEGLLibrary.fGetCurrentContext() != mContext) {
379 hasDifferentContext = true;
380 } else {
381 sEGLLibrary.SetCachedCurrentContext(mContext);
385 if (aForce || hasDifferentContext) {
386 EGLSurface surface = mSurfaceOverride != EGL_NO_SURFACE
387 ? mSurfaceOverride
388 : mSurface;
389 if (surface == EGL_NO_SURFACE) {
390 return false;
392 succeeded = sEGLLibrary.fMakeCurrent(EGL_DISPLAY(),
393 surface, surface,
394 mContext);
395 if (!succeeded) {
396 int eglError = sEGLLibrary.fGetError();
397 if (eglError == LOCAL_EGL_CONTEXT_LOST) {
398 mContextLost = true;
399 NS_WARNING("EGL context has been lost.");
400 } else {
401 NS_WARNING("Failed to make GL context current!");
402 #ifdef DEBUG
403 printf_stderr("EGL Error: 0x%04x\n", eglError);
404 #endif
406 } else {
407 sEGLLibrary.SetCachedCurrentContext(mContext);
409 } else {
410 MOZ_ASSERT(sEGLLibrary.CachedCurrentContextMatches());
413 return succeeded;
416 bool
417 GLContextEGL::IsCurrent() {
418 return sEGLLibrary.fGetCurrentContext() == mContext;
421 bool
422 GLContextEGL::RenewSurface() {
423 if (!mOwnsContext) {
424 return false;
426 #ifndef MOZ_WIDGET_ANDROID
427 MOZ_CRASH("unimplemented");
428 // to support this on non-Android platforms, need to keep track of the nsIWidget that
429 // this GLContext was created for (with CreateForWindow) so that we know what to
430 // pass again to CreateSurfaceForWindow below.
431 // The reason why Android doesn't need this is that it delegates EGLSurface creation to
432 // Java code which is the only thing that knows about our actual widget.
433 #endif
434 // unconditionally release the surface and create a new one. Don't try to optimize this away.
435 // If we get here, then by definition we know that we want to get a new surface.
436 ReleaseSurface();
437 mSurface = mozilla::gl::CreateSurfaceForWindow(nullptr, mConfig); // the nullptr here is where we assume Android.
438 if (mSurface == EGL_NO_SURFACE) {
439 return false;
441 return MakeCurrent(true);
444 void
445 GLContextEGL::ReleaseSurface() {
446 if (mOwnsContext) {
447 DestroySurface(mSurface);
449 mSurface = EGL_NO_SURFACE;
452 bool
453 GLContextEGL::SetupLookupFunction()
455 mLookupFunc = (PlatformLookupFunction)sEGLLibrary.mSymbols.fGetProcAddress;
456 return true;
459 bool
460 GLContextEGL::SwapBuffers()
462 if (mSurface) {
463 #ifdef MOZ_WIDGET_GONK
464 if (!mIsOffscreen) {
465 if (mHwc) {
466 return mHwc->Render(EGL_DISPLAY(), mSurface);
467 } else {
468 return GetGonkDisplay()->SwapBuffers(EGL_DISPLAY(), mSurface);
470 } else
471 #endif
472 return sEGLLibrary.fSwapBuffers(EGL_DISPLAY(), mSurface);
473 } else {
474 return false;
478 // hold a reference to the given surface
479 // for the lifetime of this context.
480 void
481 GLContextEGL::HoldSurface(gfxASurface *aSurf) {
482 mThebesSurface = aSurf;
485 already_AddRefed<GLContextEGL>
486 GLContextEGL::CreateGLContext(const SurfaceCaps& caps,
487 GLContextEGL *shareContext,
488 bool isOffscreen,
489 EGLConfig config,
490 EGLSurface surface)
492 if (sEGLLibrary.fBindAPI(LOCAL_EGL_OPENGL_ES_API) == LOCAL_EGL_FALSE) {
493 NS_WARNING("Failed to bind API to GLES!");
494 return nullptr;
497 EGLContext eglShareContext = shareContext ? shareContext->mContext
498 : EGL_NO_CONTEXT;
499 EGLint* attribs = sEGLLibrary.HasRobustness() ? gContextAttribsRobustness
500 : gContextAttribs;
502 EGLContext context = sEGLLibrary.fCreateContext(EGL_DISPLAY(),
503 config,
504 eglShareContext,
505 attribs);
506 if (!context && shareContext) {
507 shareContext = nullptr;
508 context = sEGLLibrary.fCreateContext(EGL_DISPLAY(),
509 config,
510 EGL_NO_CONTEXT,
511 attribs);
513 if (!context) {
514 NS_WARNING("Failed to create EGLContext!");
515 return nullptr;
518 nsRefPtr<GLContextEGL> glContext = new GLContextEGL(caps,
519 shareContext,
520 isOffscreen,
521 config,
522 surface,
523 context);
525 if (!glContext->Init())
526 return nullptr;
528 return glContext.forget();
531 EGLSurface
532 GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(EGLConfig config,
533 EGLenum bindToTextureFormat,
534 gfxIntSize& pbsize)
536 nsTArray<EGLint> pbattrs(16);
537 EGLSurface surface = nullptr;
539 TRY_AGAIN_POWER_OF_TWO:
540 pbattrs.Clear();
541 pbattrs.AppendElement(LOCAL_EGL_WIDTH); pbattrs.AppendElement(pbsize.width);
542 pbattrs.AppendElement(LOCAL_EGL_HEIGHT); pbattrs.AppendElement(pbsize.height);
544 if (bindToTextureFormat != LOCAL_EGL_NONE) {
545 pbattrs.AppendElement(LOCAL_EGL_TEXTURE_TARGET);
546 pbattrs.AppendElement(LOCAL_EGL_TEXTURE_2D);
548 pbattrs.AppendElement(LOCAL_EGL_TEXTURE_FORMAT);
549 pbattrs.AppendElement(bindToTextureFormat);
552 for (size_t i = 0; i < MOZ_ARRAY_LENGTH(gTerminationAttribs); i++) {
553 pbattrs.AppendElement(gTerminationAttribs[i]);
556 surface = sEGLLibrary.fCreatePbufferSurface(EGL_DISPLAY(), config, &pbattrs[0]);
557 if (!surface) {
558 if (!is_power_of_two(pbsize.width) ||
559 !is_power_of_two(pbsize.height))
561 if (!is_power_of_two(pbsize.width))
562 pbsize.width = next_power_of_two(pbsize.width);
563 if (!is_power_of_two(pbsize.height))
564 pbsize.height = next_power_of_two(pbsize.height);
566 NS_WARNING("Failed to create pbuffer, trying power of two dims");
567 goto TRY_AGAIN_POWER_OF_TWO;
570 NS_WARNING("Failed to create pbuffer surface");
571 return nullptr;
574 return surface;
577 static const EGLint kEGLConfigAttribsOffscreenPBuffer[] = {
578 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT,
579 LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
580 // Old versions of llvmpipe seem to need this to properly create the pbuffer (bug 981856)
581 LOCAL_EGL_RED_SIZE, 8,
582 LOCAL_EGL_GREEN_SIZE, 8,
583 LOCAL_EGL_BLUE_SIZE, 8,
584 LOCAL_EGL_ALPHA_SIZE, 0,
585 EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
588 static const EGLint kEGLConfigAttribsRGB16[] = {
589 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
590 LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
591 LOCAL_EGL_RED_SIZE, 5,
592 LOCAL_EGL_GREEN_SIZE, 6,
593 LOCAL_EGL_BLUE_SIZE, 5,
594 LOCAL_EGL_ALPHA_SIZE, 0,
595 EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
598 static const EGLint kEGLConfigAttribsRGB24[] = {
599 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
600 LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
601 LOCAL_EGL_RED_SIZE, 8,
602 LOCAL_EGL_GREEN_SIZE, 8,
603 LOCAL_EGL_BLUE_SIZE, 8,
604 LOCAL_EGL_ALPHA_SIZE, 0,
605 EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
608 static const EGLint kEGLConfigAttribsRGBA32[] = {
609 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
610 LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
611 LOCAL_EGL_RED_SIZE, 8,
612 LOCAL_EGL_GREEN_SIZE, 8,
613 LOCAL_EGL_BLUE_SIZE, 8,
614 LOCAL_EGL_ALPHA_SIZE, 8,
615 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
616 LOCAL_EGL_FRAMEBUFFER_TARGET_ANDROID, LOCAL_EGL_TRUE,
617 #endif
618 EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
621 static bool
622 CreateConfig(EGLConfig* aConfig, int32_t depth)
624 EGLConfig configs[64];
625 const EGLint* attribs;
626 EGLint ncfg = ArrayLength(configs);
628 switch (depth) {
629 case 16:
630 attribs = kEGLConfigAttribsRGB16;
631 break;
632 case 24:
633 attribs = kEGLConfigAttribsRGB24;
634 break;
635 case 32:
636 attribs = kEGLConfigAttribsRGBA32;
637 break;
638 default:
639 NS_ERROR("Unknown pixel depth");
640 return false;
643 if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(), attribs,
644 configs, ncfg, &ncfg) ||
645 ncfg < 1) {
646 return false;
649 #ifdef MOZ_WIDGET_GONK
650 // On gonk, it's important to select a configuration with the
651 // the correct order as well as bits per channel.
652 // EGL_NATIVE_VISUAL_ID gives us the Android pixel format which
653 // is an enum that tells us both order and bits per channel.
654 // For example -
655 // HAL_PIXEL_FORMAT_RGBX_8888
656 // HAL_PIXEL_FORMAT_BGRA_8888
657 // HAL_PIXEL_FORMAT_RGB_565
658 for (int j = 0; j < ncfg; ++j) {
659 EGLConfig config = configs[j];
660 EGLint format;
661 if (sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
662 LOCAL_EGL_NATIVE_VISUAL_ID, &format) &&
663 format == GetGonkDisplay()->surfaceformat)
665 *aConfig = config;
666 return true;
669 #endif
671 for (int j = 0; j < ncfg; ++j) {
672 EGLConfig config = configs[j];
673 EGLint r, g, b, a;
674 if (sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
675 LOCAL_EGL_RED_SIZE, &r) &&
676 sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
677 LOCAL_EGL_GREEN_SIZE, &g) &&
678 sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
679 LOCAL_EGL_BLUE_SIZE, &b) &&
680 sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
681 LOCAL_EGL_ALPHA_SIZE, &a) &&
682 ((depth == 16 && r == 5 && g == 6 && b == 5) ||
683 (depth == 24 && r == 8 && g == 8 && b == 8) ||
684 (depth == 32 && r == 8 && g == 8 && b == 8 && a == 8)))
686 *aConfig = config;
687 return true;
690 return false;
693 // Return true if a suitable EGLConfig was found and pass it out
694 // through aConfig. Return false otherwise.
696 // NB: It's entirely legal for the returned EGLConfig to be valid yet
697 // have the value null.
698 static bool
699 CreateConfig(EGLConfig* aConfig)
701 int32_t depth = gfxPlatform::GetPlatform()->GetScreenDepth();
702 if (!CreateConfig(aConfig, depth)) {
703 #ifdef MOZ_WIDGET_ANDROID
704 // Bug 736005
705 // Android doesn't always support 16 bit so also try 24 bit
706 if (depth == 16) {
707 return CreateConfig(aConfig, 24);
709 // Bug 970096
710 // Some devices that have 24 bit screens only support 16 bit OpenGL?
711 if (depth == 24) {
712 return CreateConfig(aConfig, 16);
714 #endif
715 return false;
716 } else {
717 return true;
721 already_AddRefed<GLContext>
722 GLContextProviderEGL::CreateWrappingExisting(void* aContext, void* aSurface)
724 if (!sEGLLibrary.EnsureInitialized()) {
725 MOZ_CRASH("Failed to load EGL library!\n");
726 return nullptr;
729 if (aContext && aSurface) {
730 SurfaceCaps caps = SurfaceCaps::Any();
731 EGLConfig config = EGL_NO_CONFIG;
732 nsRefPtr<GLContextEGL> glContext =
733 new GLContextEGL(caps,
734 nullptr, false,
735 config, (EGLSurface)aSurface, (EGLContext)aContext);
737 glContext->SetIsDoubleBuffered(true);
738 glContext->mOwnsContext = false;
740 return glContext.forget();
743 return nullptr;
746 already_AddRefed<GLContext>
747 GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget)
749 if (!sEGLLibrary.EnsureInitialized()) {
750 MOZ_CRASH("Failed to load EGL library!\n");
751 return nullptr;
754 bool doubleBuffered = true;
756 EGLConfig config;
757 if (!CreateConfig(&config)) {
758 MOZ_CRASH("Failed to create EGLConfig!\n");
759 return nullptr;
762 EGLSurface surface = mozilla::gl::CreateSurfaceForWindow(aWidget, config);
764 if (surface == EGL_NO_SURFACE) {
765 MOZ_CRASH("Failed to create EGLSurface!\n");
766 return nullptr;
769 SurfaceCaps caps = SurfaceCaps::Any();
770 nsRefPtr<GLContextEGL> glContext =
771 GLContextEGL::CreateGLContext(caps,
772 nullptr, false,
773 config, surface);
775 if (!glContext) {
776 MOZ_CRASH("Failed to create EGLContext!\n");
777 DestroySurface(surface);
778 return nullptr;
781 glContext->MakeCurrent();
782 glContext->SetIsDoubleBuffered(doubleBuffered);
784 return glContext.forget();
787 already_AddRefed<GLContextEGL>
788 GLContextEGL::CreateEGLPBufferOffscreenContext(const gfxIntSize& size)
790 EGLConfig config;
791 EGLSurface surface;
793 const EGLint numConfigs = 1; // We only need one.
794 EGLConfig configs[numConfigs];
795 EGLint foundConfigs = 0;
796 if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(),
797 kEGLConfigAttribsOffscreenPBuffer,
798 configs, numConfigs,
799 &foundConfigs)
800 || foundConfigs == 0)
802 NS_WARNING("No EGL Config for minimal PBuffer!");
803 return nullptr;
806 // We absolutely don't care, so just pick the first one.
807 config = configs[0];
808 if (GLContext::DebugMode())
809 sEGLLibrary.DumpEGLConfig(config);
811 gfxIntSize pbSize(size);
812 surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(config,
813 LOCAL_EGL_NONE,
814 pbSize);
815 if (!surface) {
816 NS_WARNING("Failed to create PBuffer for context!");
817 return nullptr;
820 SurfaceCaps dummyCaps = SurfaceCaps::Any();
821 nsRefPtr<GLContextEGL> glContext =
822 GLContextEGL::CreateGLContext(dummyCaps,
823 nullptr, true,
824 config, surface);
825 if (!glContext) {
826 NS_WARNING("Failed to create GLContext from PBuffer");
827 sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
828 return nullptr;
831 if (!glContext->Init()) {
832 NS_WARNING("Failed to initialize GLContext!");
833 // GLContextEGL::dtor will destroy |surface| for us.
834 return nullptr;
837 return glContext.forget();
840 already_AddRefed<GLContextEGL>
841 GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& size)
843 gfxASurface *thebesSurface = nullptr;
844 EGLNativePixmapType pixmap = 0;
846 if (!pixmap) {
847 return nullptr;
850 EGLSurface surface = 0;
851 EGLConfig config = 0;
853 if (!config) {
854 return nullptr;
856 MOZ_ASSERT(surface);
858 SurfaceCaps dummyCaps = SurfaceCaps::Any();
859 nsRefPtr<GLContextEGL> glContext =
860 GLContextEGL::CreateGLContext(dummyCaps,
861 nullptr, true,
862 config, surface);
863 if (!glContext) {
864 NS_WARNING("Failed to create GLContext from XSurface");
865 sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
866 return nullptr;
869 if (!glContext->Init()) {
870 NS_WARNING("Failed to initialize GLContext!");
871 // GLContextEGL::dtor will destroy |surface| for us.
872 return nullptr;
875 glContext->HoldSurface(thebesSurface);
877 return glContext.forget();
880 already_AddRefed<GLContext>
881 GLContextProviderEGL::CreateHeadless()
883 if (!sEGLLibrary.EnsureInitialized()) {
884 return nullptr;
887 gfxIntSize dummySize = gfxIntSize(16, 16);
888 nsRefPtr<GLContext> glContext;
889 glContext = GLContextEGL::CreateEGLPBufferOffscreenContext(dummySize);
890 if (!glContext)
891 return nullptr;
893 return glContext.forget();
896 // Under EGL, on Android, pbuffers are supported fine, though
897 // often without the ability to texture from them directly.
898 already_AddRefed<GLContext>
899 GLContextProviderEGL::CreateOffscreen(const gfxIntSize& size,
900 const SurfaceCaps& caps)
902 nsRefPtr<GLContext> glContext = CreateHeadless();
903 if (!glContext)
904 return nullptr;
906 if (!glContext->InitOffscreen(ToIntSize(size), caps))
907 return nullptr;
909 return glContext.forget();
912 // Don't want a global context on Android as 1) share groups across 2 threads fail on many Tegra drivers (bug 759225)
913 // and 2) some mobile devices have a very strict limit on global number of GL contexts (bug 754257)
914 // and 3) each EGL context eats 750k on B2G (bug 813783)
915 GLContext*
916 GLContextProviderEGL::GetGlobalContext()
918 return nullptr;
921 void
922 GLContextProviderEGL::Shutdown()
926 } /* namespace gl */
927 } /* namespace mozilla */
929 #undef EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS