gfx/gl/GLContextProviderEGL.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:3ce91848e111
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 #include "mozilla/ArrayUtils.h"
7
8 #include "GLContextEGL.h"
9
10 #if defined(XP_UNIX)
11
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
23
24 #if defined(ANDROID)
25 /* from widget */
26 #if defined(MOZ_WIDGET_ANDROID)
27 #include "AndroidBridge.h"
28 #include "nsSurfaceTexture.h"
29 #endif
30
31 #include <android/log.h>
32 #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
33
34 # if defined(MOZ_WIDGET_GONK)
35 # include "cutils/properties.h"
36 # include <ui/GraphicBuffer.h>
37
38 using namespace android;
39 # endif
40
41 #endif
42
43 #define GLES2_LIB "libGLESv2.so"
44 #define GLES2_LIB2 "libGLESv2.so.2"
45
46 #elif defined(XP_WIN)
47
48 #include "nsIFile.h"
49
50 #define GLES2_LIB "libGLESv2.dll"
51
52 #ifndef WIN32_LEAN_AND_MEAN
53 #define WIN32_LEAN_AND_MEAN 1
54 #endif
55
56 #include <windows.h>
57
58 // a little helper
59 class AutoDestroyHWND {
60 public:
61 AutoDestroyHWND(HWND aWnd = nullptr)
62 : mWnd(aWnd)
63 {
64 }
65
66 ~AutoDestroyHWND() {
67 if (mWnd) {
68 ::DestroyWindow(mWnd);
69 }
70 }
71
72 operator HWND() {
73 return mWnd;
74 }
75
76 HWND forget() {
77 HWND w = mWnd;
78 mWnd = nullptr;
79 return w;
80 }
81
82 HWND operator=(HWND aWnd) {
83 if (mWnd && mWnd != aWnd) {
84 ::DestroyWindow(mWnd);
85 }
86 mWnd = aWnd;
87 return mWnd;
88 }
89
90 HWND mWnd;
91 };
92
93 #else
94
95 #error "Platform not recognized"
96
97 #endif
98
99 #include "mozilla/Preferences.h"
100 #include "gfxUtils.h"
101 #include "gfxFailure.h"
102 #include "gfxASurface.h"
103 #include "gfxPlatform.h"
104 #include "GLContextProvider.h"
105 #include "GLLibraryEGL.h"
106 #include "TextureImageEGL.h"
107 #include "nsDebug.h"
108 #include "nsThreadUtils.h"
109
110 #include "nsIWidget.h"
111
112 #include "gfxCrashReporterUtils.h"
113
114 #include "ScopedGLHelpers.h"
115 #include "GLBlitHelper.h"
116
117 using namespace mozilla::gfx;
118
119 #ifdef MOZ_WIDGET_GONK
120 extern nsIntRect gScreenBounds;
121 #endif
122
123 namespace mozilla {
124 namespace gl {
125
126 #define ADD_ATTR_2(_array, _k, _v) do { \
127 (_array).AppendElement(_k); \
128 (_array).AppendElement(_v); \
129 } while (0)
130
131 #define ADD_ATTR_1(_array, _k) do { \
132 (_array).AppendElement(_k); \
133 } while (0)
134
135 static bool
136 CreateConfig(EGLConfig* aConfig);
137
138 // append three zeros at the end of attribs list to work around
139 // EGL implementation bugs that iterate until they find 0, instead of
140 // EGL_NONE. See bug 948406.
141 #define EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS \
142 LOCAL_EGL_NONE, 0, 0, 0
143
144 static EGLint gTerminationAttribs[] = {
145 EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
146 };
147
148 static EGLint gContextAttribs[] = {
149 LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2,
150 EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
151 };
152
153 static EGLint gContextAttribsRobustness[] = {
154 LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2,
155 //LOCAL_EGL_CONTEXT_ROBUST_ACCESS_EXT, LOCAL_EGL_TRUE,
156 LOCAL_EGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_EXT, LOCAL_EGL_LOSE_CONTEXT_ON_RESET_EXT,
157 EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
158 };
159
160 static int
161 next_power_of_two(int v)
162 {
163 v--;
164 v |= v >> 1;
165 v |= v >> 2;
166 v |= v >> 4;
167 v |= v >> 8;
168 v |= v >> 16;
169 v++;
170
171 return v;
172 }
173
174 static bool
175 is_power_of_two(int v)
176 {
177 NS_ASSERTION(v >= 0, "bad value");
178
179 if (v == 0)
180 return true;
181
182 return (v & (v-1)) == 0;
183 }
184
185 static void
186 DestroySurface(EGLSurface oldSurface) {
187 if (oldSurface != EGL_NO_SURFACE) {
188 sEGLLibrary.fMakeCurrent(EGL_DISPLAY(),
189 EGL_NO_SURFACE, EGL_NO_SURFACE,
190 EGL_NO_CONTEXT);
191 sEGLLibrary.fDestroySurface(EGL_DISPLAY(), oldSurface);
192 }
193 }
194
195 static EGLSurface
196 CreateSurfaceForWindow(nsIWidget* widget, const EGLConfig& config) {
197 EGLSurface newSurface = EGL_NO_SURFACE;
198
199 #ifdef MOZ_ANDROID_OMTC
200 mozilla::AndroidBridge::Bridge()->RegisterCompositor();
201 newSurface = mozilla::AndroidBridge::Bridge()->CreateEGLSurfaceForCompositor();
202 if (newSurface == EGL_NO_SURFACE) {
203 return EGL_NO_SURFACE;
204 }
205 #else
206 MOZ_ASSERT(widget != nullptr);
207 newSurface = sEGLLibrary.fCreateWindowSurface(EGL_DISPLAY(), config, GET_NATIVE_WINDOW(widget), 0);
208 #ifdef MOZ_WIDGET_GONK
209 gScreenBounds.x = 0;
210 gScreenBounds.y = 0;
211 sEGLLibrary.fQuerySurface(EGL_DISPLAY(), newSurface, LOCAL_EGL_WIDTH, &gScreenBounds.width);
212 sEGLLibrary.fQuerySurface(EGL_DISPLAY(), newSurface, LOCAL_EGL_HEIGHT, &gScreenBounds.height);
213 #endif
214 #endif
215 return newSurface;
216 }
217
218 GLContextEGL::GLContextEGL(
219 const SurfaceCaps& caps,
220 GLContext* shareContext,
221 bool isOffscreen,
222 EGLConfig config,
223 EGLSurface surface,
224 EGLContext context)
225 : GLContext(caps, shareContext, isOffscreen)
226 , mConfig(config)
227 , mSurface(surface)
228 , mSurfaceOverride(EGL_NO_SURFACE)
229 , mContext(context)
230 , mThebesSurface(nullptr)
231 , mBound(false)
232 , mIsPBuffer(false)
233 , mIsDoubleBuffered(false)
234 , mCanBindToTexture(false)
235 , mShareWithEGLImage(false)
236 , mOwnsContext(true)
237 {
238 // any EGL contexts will always be GLESv2
239 SetProfileVersion(ContextProfile::OpenGLES, 200);
240
241 #ifdef DEBUG
242 printf_stderr("Initializing context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
243 #endif
244 #if defined(MOZ_WIDGET_GONK)
245 if (!mIsOffscreen) {
246 mHwc = HwcComposer2D::GetInstance();
247 MOZ_ASSERT(!mHwc->Initialized());
248
249 if (mHwc->Init(EGL_DISPLAY(), mSurface)) {
250 NS_WARNING("HWComposer initialization failed!");
251 mHwc = nullptr;
252 }
253 }
254 #endif
255 }
256
257 GLContextEGL::~GLContextEGL()
258 {
259 MarkDestroyed();
260
261 // Wrapped context should not destroy eglContext/Surface
262 if (!mOwnsContext) {
263 return;
264 }
265
266 #ifdef DEBUG
267 printf_stderr("Destroying context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
268 #endif
269
270 sEGLLibrary.fDestroyContext(EGL_DISPLAY(), mContext);
271
272 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION < 17
273 if (!mIsOffscreen) {
274 // In ICS, SurfaceFlinger's DisplayHardware::fini() does not destroy the EGLSurface associated with the
275 // native framebuffer. Destroying it causes crashes in the ICS emulator
276 // EGL implementation, specifically because the egl_window_surface_t dtor
277 // calls nativeWindow->cancelBuffer and FramebufferNativeWindow does not initialize
278 // the cancelBuffer function pointer, see bug 986836
279 return;
280 }
281 #endif
282
283 mozilla::gl::DestroySurface(mSurface);
284 }
285
286 bool
287 GLContextEGL::Init()
288 {
289 #if defined(ANDROID)
290 // We can't use LoadApitraceLibrary here because the GLContext
291 // expects its own handle to the GL library
292 if (!OpenLibrary(APITRACE_LIB))
293 #endif
294 if (!OpenLibrary(GLES2_LIB)) {
295 #if defined(XP_UNIX)
296 if (!OpenLibrary(GLES2_LIB2)) {
297 NS_WARNING("Couldn't load GLES2 LIB.");
298 return false;
299 }
300 #endif
301 }
302
303 SetupLookupFunction();
304 if (!InitWithPrefix("gl", true))
305 return false;
306
307 bool current = MakeCurrent();
308 if (!current) {
309 gfx::LogFailure(NS_LITERAL_CSTRING(
310 "Couldn't get device attachments for device."));
311 return false;
312 }
313
314 PR_STATIC_ASSERT(sizeof(GLint) >= sizeof(int32_t));
315 mMaxTextureImageSize = INT32_MAX;
316
317 mShareWithEGLImage = sEGLLibrary.HasKHRImageBase() &&
318 sEGLLibrary.HasKHRImageTexture2D() &&
319 IsExtensionSupported(OES_EGL_image);
320
321 return true;
322 }
323
324 bool
325 GLContextEGL::BindTexImage()
326 {
327 if (!mSurface)
328 return false;
329
330 if (mBound && !ReleaseTexImage())
331 return false;
332
333 EGLBoolean success = sEGLLibrary.fBindTexImage(EGL_DISPLAY(),
334 (EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER);
335 if (success == LOCAL_EGL_FALSE)
336 return false;
337
338 mBound = true;
339 return true;
340 }
341
342 bool
343 GLContextEGL::ReleaseTexImage()
344 {
345 if (!mBound)
346 return true;
347
348 if (!mSurface)
349 return false;
350
351 EGLBoolean success;
352 success = sEGLLibrary.fReleaseTexImage(EGL_DISPLAY(),
353 (EGLSurface)mSurface,
354 LOCAL_EGL_BACK_BUFFER);
355 if (success == LOCAL_EGL_FALSE)
356 return false;
357
358 mBound = false;
359 return true;
360 }
361
362 void
363 GLContextEGL::SetEGLSurfaceOverride(EGLSurface surf) {
364 if (Screen()) {
365 /* Blit `draw` to `read` if we need to, before we potentially juggle
366 * `read` around. If we don't, we might attach a different `read`,
367 * and *then* hit AssureBlitted, which will blit a dirty `draw` onto
368 * the wrong `read`!
369 */
370 Screen()->AssureBlitted();
371 }
372
373 mSurfaceOverride = surf ? (EGLSurface) surf : mSurface;
374 MakeCurrent(true);
375 }
376
377 bool
378 GLContextEGL::MakeCurrentImpl(bool aForce) {
379 bool succeeded = true;
380
381 // Assume that EGL has the same problem as WGL does,
382 // where MakeCurrent with an already-current context is
383 // still expensive.
384 if (aForce || sEGLLibrary.fGetCurrentContext() != mContext) {
385 EGLSurface surface = mSurfaceOverride != EGL_NO_SURFACE
386 ? mSurfaceOverride
387 : mSurface;
388 if (surface == EGL_NO_SURFACE) {
389 return false;
390 }
391 succeeded = sEGLLibrary.fMakeCurrent(EGL_DISPLAY(),
392 surface, surface,
393 mContext);
394 if (!succeeded) {
395 int eglError = sEGLLibrary.fGetError();
396 if (eglError == LOCAL_EGL_CONTEXT_LOST) {
397 mContextLost = true;
398 NS_WARNING("EGL context has been lost.");
399 } else {
400 NS_WARNING("Failed to make GL context current!");
401 #ifdef DEBUG
402 printf_stderr("EGL Error: 0x%04x\n", eglError);
403 #endif
404 }
405 }
406 }
407
408 return succeeded;
409 }
410
411 bool
412 GLContextEGL::IsCurrent() {
413 return sEGLLibrary.fGetCurrentContext() == mContext;
414 }
415
416 bool
417 GLContextEGL::RenewSurface() {
418 if (!mOwnsContext) {
419 return false;
420 }
421 #ifndef MOZ_WIDGET_ANDROID
422 MOZ_CRASH("unimplemented");
423 // to support this on non-Android platforms, need to keep track of the nsIWidget that
424 // this GLContext was created for (with CreateForWindow) so that we know what to
425 // pass again to CreateSurfaceForWindow below.
426 // The reason why Android doesn't need this is that it delegates EGLSurface creation to
427 // Java code which is the only thing that knows about our actual widget.
428 #endif
429 // unconditionally release the surface and create a new one. Don't try to optimize this away.
430 // If we get here, then by definition we know that we want to get a new surface.
431 ReleaseSurface();
432 mSurface = mozilla::gl::CreateSurfaceForWindow(nullptr, mConfig); // the nullptr here is where we assume Android.
433 if (mSurface == EGL_NO_SURFACE) {
434 return false;
435 }
436 return MakeCurrent(true);
437 }
438
439 void
440 GLContextEGL::ReleaseSurface() {
441 if (mOwnsContext) {
442 DestroySurface(mSurface);
443 }
444 mSurface = EGL_NO_SURFACE;
445 }
446
447 bool
448 GLContextEGL::SetupLookupFunction()
449 {
450 mLookupFunc = (PlatformLookupFunction)sEGLLibrary.mSymbols.fGetProcAddress;
451 return true;
452 }
453
454 bool
455 GLContextEGL::SwapBuffers()
456 {
457 if (mSurface) {
458 #ifdef MOZ_WIDGET_GONK
459 if (!mIsOffscreen) {
460 if (mHwc) {
461 return mHwc->Render(EGL_DISPLAY(), mSurface);
462 } else {
463 return GetGonkDisplay()->SwapBuffers(EGL_DISPLAY(), mSurface);
464 }
465 } else
466 #endif
467 return sEGLLibrary.fSwapBuffers(EGL_DISPLAY(), mSurface);
468 } else {
469 return false;
470 }
471 }
472
473 // hold a reference to the given surface
474 // for the lifetime of this context.
475 void
476 GLContextEGL::HoldSurface(gfxASurface *aSurf) {
477 mThebesSurface = aSurf;
478 }
479
480 already_AddRefed<GLContextEGL>
481 GLContextEGL::CreateGLContext(const SurfaceCaps& caps,
482 GLContextEGL *shareContext,
483 bool isOffscreen,
484 EGLConfig config,
485 EGLSurface surface)
486 {
487 if (sEGLLibrary.fBindAPI(LOCAL_EGL_OPENGL_ES_API) == LOCAL_EGL_FALSE) {
488 NS_WARNING("Failed to bind API to GLES!");
489 return nullptr;
490 }
491
492 EGLContext eglShareContext = shareContext ? shareContext->mContext
493 : EGL_NO_CONTEXT;
494 EGLint* attribs = sEGLLibrary.HasRobustness() ? gContextAttribsRobustness
495 : gContextAttribs;
496
497 EGLContext context = sEGLLibrary.fCreateContext(EGL_DISPLAY(),
498 config,
499 eglShareContext,
500 attribs);
501 if (!context && shareContext) {
502 shareContext = nullptr;
503 context = sEGLLibrary.fCreateContext(EGL_DISPLAY(),
504 config,
505 EGL_NO_CONTEXT,
506 attribs);
507 }
508 if (!context) {
509 NS_WARNING("Failed to create EGLContext!");
510 return nullptr;
511 }
512
513 nsRefPtr<GLContextEGL> glContext = new GLContextEGL(caps,
514 shareContext,
515 isOffscreen,
516 config,
517 surface,
518 context);
519
520 if (!glContext->Init())
521 return nullptr;
522
523 return glContext.forget();
524 }
525
526 EGLSurface
527 GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(EGLConfig config,
528 EGLenum bindToTextureFormat,
529 gfxIntSize& pbsize)
530 {
531 nsTArray<EGLint> pbattrs(16);
532 EGLSurface surface = nullptr;
533
534 TRY_AGAIN_POWER_OF_TWO:
535 pbattrs.Clear();
536 pbattrs.AppendElement(LOCAL_EGL_WIDTH); pbattrs.AppendElement(pbsize.width);
537 pbattrs.AppendElement(LOCAL_EGL_HEIGHT); pbattrs.AppendElement(pbsize.height);
538
539 if (bindToTextureFormat != LOCAL_EGL_NONE) {
540 pbattrs.AppendElement(LOCAL_EGL_TEXTURE_TARGET);
541 pbattrs.AppendElement(LOCAL_EGL_TEXTURE_2D);
542
543 pbattrs.AppendElement(LOCAL_EGL_TEXTURE_FORMAT);
544 pbattrs.AppendElement(bindToTextureFormat);
545 }
546
547 for (size_t i = 0; i < MOZ_ARRAY_LENGTH(gTerminationAttribs); i++) {
548 pbattrs.AppendElement(gTerminationAttribs[i]);
549 }
550
551 surface = sEGLLibrary.fCreatePbufferSurface(EGL_DISPLAY(), config, &pbattrs[0]);
552 if (!surface) {
553 if (!is_power_of_two(pbsize.width) ||
554 !is_power_of_two(pbsize.height))
555 {
556 if (!is_power_of_two(pbsize.width))
557 pbsize.width = next_power_of_two(pbsize.width);
558 if (!is_power_of_two(pbsize.height))
559 pbsize.height = next_power_of_two(pbsize.height);
560
561 NS_WARNING("Failed to create pbuffer, trying power of two dims");
562 goto TRY_AGAIN_POWER_OF_TWO;
563 }
564
565 NS_WARNING("Failed to create pbuffer surface");
566 return nullptr;
567 }
568
569 return surface;
570 }
571
572 static const EGLint kEGLConfigAttribsOffscreenPBuffer[] = {
573 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT,
574 LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
575 // Old versions of llvmpipe seem to need this to properly create the pbuffer (bug 981856)
576 LOCAL_EGL_RED_SIZE, 8,
577 LOCAL_EGL_GREEN_SIZE, 8,
578 LOCAL_EGL_BLUE_SIZE, 8,
579 LOCAL_EGL_ALPHA_SIZE, 0,
580 EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
581 };
582
583 static const EGLint kEGLConfigAttribsRGB16[] = {
584 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
585 LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
586 LOCAL_EGL_RED_SIZE, 5,
587 LOCAL_EGL_GREEN_SIZE, 6,
588 LOCAL_EGL_BLUE_SIZE, 5,
589 LOCAL_EGL_ALPHA_SIZE, 0,
590 EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
591 };
592
593 static const EGLint kEGLConfigAttribsRGB24[] = {
594 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
595 LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
596 LOCAL_EGL_RED_SIZE, 8,
597 LOCAL_EGL_GREEN_SIZE, 8,
598 LOCAL_EGL_BLUE_SIZE, 8,
599 LOCAL_EGL_ALPHA_SIZE, 0,
600 EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
601 };
602
603 static const EGLint kEGLConfigAttribsRGBA32[] = {
604 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
605 LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
606 LOCAL_EGL_RED_SIZE, 8,
607 LOCAL_EGL_GREEN_SIZE, 8,
608 LOCAL_EGL_BLUE_SIZE, 8,
609 LOCAL_EGL_ALPHA_SIZE, 8,
610 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
611 LOCAL_EGL_FRAMEBUFFER_TARGET_ANDROID, LOCAL_EGL_TRUE,
612 #endif
613 EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
614 };
615
616 static bool
617 CreateConfig(EGLConfig* aConfig, int32_t depth)
618 {
619 EGLConfig configs[64];
620 const EGLint* attribs;
621 EGLint ncfg = ArrayLength(configs);
622
623 switch (depth) {
624 case 16:
625 attribs = kEGLConfigAttribsRGB16;
626 break;
627 case 24:
628 attribs = kEGLConfigAttribsRGB24;
629 break;
630 case 32:
631 attribs = kEGLConfigAttribsRGBA32;
632 break;
633 default:
634 NS_ERROR("Unknown pixel depth");
635 return false;
636 }
637
638 if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(), attribs,
639 configs, ncfg, &ncfg) ||
640 ncfg < 1) {
641 return false;
642 }
643
644 for (int j = 0; j < ncfg; ++j) {
645 EGLConfig config = configs[j];
646 EGLint r, g, b, a;
647
648 if (sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
649 LOCAL_EGL_RED_SIZE, &r) &&
650 sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
651 LOCAL_EGL_GREEN_SIZE, &g) &&
652 sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
653 LOCAL_EGL_BLUE_SIZE, &b) &&
654 sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
655 LOCAL_EGL_ALPHA_SIZE, &a) &&
656 ((depth == 16 && r == 5 && g == 6 && b == 5) ||
657 (depth == 24 && r == 8 && g == 8 && b == 8) ||
658 (depth == 32 && r == 8 && g == 8 && b == 8 && a == 8)))
659 {
660 *aConfig = config;
661 return true;
662 }
663 }
664 return false;
665 }
666
667 // Return true if a suitable EGLConfig was found and pass it out
668 // through aConfig. Return false otherwise.
669 //
670 // NB: It's entirely legal for the returned EGLConfig to be valid yet
671 // have the value null.
672 static bool
673 CreateConfig(EGLConfig* aConfig)
674 {
675 int32_t depth = gfxPlatform::GetPlatform()->GetScreenDepth();
676 if (!CreateConfig(aConfig, depth)) {
677 #ifdef MOZ_WIDGET_ANDROID
678 // Bug 736005
679 // Android doesn't always support 16 bit so also try 24 bit
680 if (depth == 16) {
681 return CreateConfig(aConfig, 24);
682 }
683 // Bug 970096
684 // Some devices that have 24 bit screens only support 16 bit OpenGL?
685 if (depth == 24) {
686 return CreateConfig(aConfig, 16);
687 }
688 #endif
689 return false;
690 } else {
691 return true;
692 }
693 }
694
695 already_AddRefed<GLContext>
696 GLContextProviderEGL::CreateWrappingExisting(void* aContext, void* aSurface)
697 {
698 if (!sEGLLibrary.EnsureInitialized()) {
699 MOZ_CRASH("Failed to load EGL library!\n");
700 return nullptr;
701 }
702
703 if (aContext && aSurface) {
704 SurfaceCaps caps = SurfaceCaps::Any();
705 EGLConfig config = EGL_NO_CONFIG;
706 nsRefPtr<GLContextEGL> glContext =
707 new GLContextEGL(caps,
708 nullptr, false,
709 config, (EGLSurface)aSurface, (EGLContext)aContext);
710
711 glContext->SetIsDoubleBuffered(true);
712 glContext->mOwnsContext = false;
713
714 return glContext.forget();
715 }
716
717 return nullptr;
718 }
719
720 already_AddRefed<GLContext>
721 GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget)
722 {
723 if (!sEGLLibrary.EnsureInitialized()) {
724 MOZ_CRASH("Failed to load EGL library!\n");
725 return nullptr;
726 }
727
728 bool doubleBuffered = true;
729
730 EGLConfig config;
731 if (!CreateConfig(&config)) {
732 MOZ_CRASH("Failed to create EGLConfig!\n");
733 return nullptr;
734 }
735
736 EGLSurface surface = mozilla::gl::CreateSurfaceForWindow(aWidget, config);
737
738 if (surface == EGL_NO_SURFACE) {
739 MOZ_CRASH("Failed to create EGLSurface!\n");
740 return nullptr;
741 }
742
743 SurfaceCaps caps = SurfaceCaps::Any();
744 nsRefPtr<GLContextEGL> glContext =
745 GLContextEGL::CreateGLContext(caps,
746 nullptr, false,
747 config, surface);
748
749 if (!glContext) {
750 MOZ_CRASH("Failed to create EGLContext!\n");
751 DestroySurface(surface);
752 return nullptr;
753 }
754
755 glContext->MakeCurrent();
756 glContext->SetIsDoubleBuffered(doubleBuffered);
757
758 return glContext.forget();
759 }
760
761 already_AddRefed<GLContextEGL>
762 GLContextEGL::CreateEGLPBufferOffscreenContext(const gfxIntSize& size)
763 {
764 EGLConfig config;
765 EGLSurface surface;
766
767 const EGLint numConfigs = 1; // We only need one.
768 EGLConfig configs[numConfigs];
769 EGLint foundConfigs = 0;
770 if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(),
771 kEGLConfigAttribsOffscreenPBuffer,
772 configs, numConfigs,
773 &foundConfigs)
774 || foundConfigs == 0)
775 {
776 NS_WARNING("No EGL Config for minimal PBuffer!");
777 return nullptr;
778 }
779
780 // We absolutely don't care, so just pick the first one.
781 config = configs[0];
782 if (GLContext::DebugMode())
783 sEGLLibrary.DumpEGLConfig(config);
784
785 gfxIntSize pbSize(size);
786 surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(config,
787 LOCAL_EGL_NONE,
788 pbSize);
789 if (!surface) {
790 NS_WARNING("Failed to create PBuffer for context!");
791 return nullptr;
792 }
793
794 SurfaceCaps dummyCaps = SurfaceCaps::Any();
795 nsRefPtr<GLContextEGL> glContext =
796 GLContextEGL::CreateGLContext(dummyCaps,
797 nullptr, true,
798 config, surface);
799 if (!glContext) {
800 NS_WARNING("Failed to create GLContext from PBuffer");
801 sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
802 return nullptr;
803 }
804
805 if (!glContext->Init()) {
806 NS_WARNING("Failed to initialize GLContext!");
807 // GLContextEGL::dtor will destroy |surface| for us.
808 return nullptr;
809 }
810
811 return glContext.forget();
812 }
813
814 already_AddRefed<GLContextEGL>
815 GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& size)
816 {
817 gfxASurface *thebesSurface = nullptr;
818 EGLNativePixmapType pixmap = 0;
819
820 if (!pixmap) {
821 return nullptr;
822 }
823
824 EGLSurface surface = 0;
825 EGLConfig config = 0;
826
827 if (!config) {
828 return nullptr;
829 }
830 MOZ_ASSERT(surface);
831
832 SurfaceCaps dummyCaps = SurfaceCaps::Any();
833 nsRefPtr<GLContextEGL> glContext =
834 GLContextEGL::CreateGLContext(dummyCaps,
835 nullptr, true,
836 config, surface);
837 if (!glContext) {
838 NS_WARNING("Failed to create GLContext from XSurface");
839 sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
840 return nullptr;
841 }
842
843 if (!glContext->Init()) {
844 NS_WARNING("Failed to initialize GLContext!");
845 // GLContextEGL::dtor will destroy |surface| for us.
846 return nullptr;
847 }
848
849 glContext->HoldSurface(thebesSurface);
850
851 return glContext.forget();
852 }
853
854 // Under EGL, on Android, pbuffers are supported fine, though
855 // often without the ability to texture from them directly.
856 already_AddRefed<GLContext>
857 GLContextProviderEGL::CreateOffscreen(const gfxIntSize& size,
858 const SurfaceCaps& caps)
859 {
860 if (!sEGLLibrary.EnsureInitialized()) {
861 return nullptr;
862 }
863
864 gfxIntSize dummySize = gfxIntSize(16, 16);
865 nsRefPtr<GLContextEGL> glContext;
866 glContext = GLContextEGL::CreateEGLPBufferOffscreenContext(dummySize);
867
868 if (!glContext)
869 return nullptr;
870
871 if (!glContext->InitOffscreen(ToIntSize(size), caps))
872 return nullptr;
873
874 return glContext.forget();
875 }
876
877 // Don't want a global context on Android as 1) share groups across 2 threads fail on many Tegra drivers (bug 759225)
878 // and 2) some mobile devices have a very strict limit on global number of GL contexts (bug 754257)
879 // and 3) each EGL context eats 750k on B2G (bug 813783)
880 GLContext *
881 GLContextProviderEGL::GetGlobalContext()
882 {
883 return nullptr;
884 }
885
886 void
887 GLContextProviderEGL::Shutdown()
888 {
889 }
890
891 } /* namespace gl */
892 } /* namespace mozilla */
893
894 #undef EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS

mercurial