Bug 754472 - Implement multiple plugin click-to-play UI. r=jaws r=margaret r=dietrich
[gecko.git] / gfx / gl / GLContextProviderEGL.cpp
blobc2ebe0402ac1f79f8e0ac18ccb35abb4cc2671bc
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/Util.h"
7 // please add new includes below Qt, otherwise it break Qt build due malloc wrapper conflicts
9 #if defined(XP_UNIX)
11 #ifdef MOZ_WIDGET_GTK
12 #include <gdk/gdkx.h>
13 // we're using default display for now
14 #define GET_NATIVE_WINDOW(aWidget) (EGLNativeWindowType)GDK_WINDOW_XID((GdkWindow *) aWidget->GetNativeData(NS_NATIVE_WINDOW))
15 #elif defined(MOZ_WIDGET_QT)
16 #include <QtOpenGL/QGLContext>
17 #define GLdouble_defined 1
18 // we're using default display for now
19 #define GET_NATIVE_WINDOW(aWidget) (EGLNativeWindowType)static_cast<QWidget*>(aWidget->GetNativeData(NS_NATIVE_SHELLWIDGET))->winId()
20 #elif defined(MOZ_WIDGET_GONK)
21 #define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW))
22 #include "HWComposer.h"
23 #endif
25 #if defined(MOZ_X11)
26 #include <X11/Xlib.h>
27 #include <X11/Xutil.h>
28 #include "mozilla/X11Util.h"
29 #include "gfxXlibSurface.h"
30 #endif
32 #if defined(ANDROID)
33 /* from widget */
34 #if defined(MOZ_WIDGET_ANDROID)
35 #include "AndroidBridge.h"
36 #include "nsSurfaceTexture.h"
37 #endif
38 #include <android/log.h>
39 #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
41 # if defined(MOZ_WIDGET_GONK)
42 # include "cutils/properties.h"
43 # include <ui/GraphicBuffer.h>
45 using namespace android;
47 # define EGL_NATIVE_BUFFER_ANDROID 0x3140
49 # endif
51 #endif
53 #define GLES2_LIB "libGLESv2.so"
54 #define GLES2_LIB2 "libGLESv2.so.2"
56 #elif defined(XP_WIN)
58 #include "nsIFile.h"
60 #define GLES2_LIB "libGLESv2.dll"
62 #ifndef WIN32_LEAN_AND_MEAN
63 #define WIN32_LEAN_AND_MEAN 1
64 #endif
66 #include <windows.h>
68 // a little helper
69 class AutoDestroyHWND {
70 public:
71 AutoDestroyHWND(HWND aWnd = NULL)
72 : mWnd(aWnd)
76 ~AutoDestroyHWND() {
77 if (mWnd) {
78 ::DestroyWindow(mWnd);
82 operator HWND() {
83 return mWnd;
86 HWND forget() {
87 HWND w = mWnd;
88 mWnd = NULL;
89 return w;
92 HWND operator=(HWND aWnd) {
93 if (mWnd && mWnd != aWnd) {
94 ::DestroyWindow(mWnd);
96 mWnd = aWnd;
97 return mWnd;
100 HWND mWnd;
103 #else
105 #error "Platform not recognized"
107 #endif
109 #include "mozilla/Preferences.h"
110 #include "gfxUtils.h"
111 #include "gfxFailure.h"
112 #include "gfxASurface.h"
113 #include "gfxImageSurface.h"
114 #include "gfxPlatform.h"
115 #include "GLContextProvider.h"
116 #include "GLLibraryEGL.h"
117 #include "nsDebug.h"
118 #include "nsThreadUtils.h"
120 #include "nsIWidget.h"
122 #include "gfxCrashReporterUtils.h"
125 #if defined(MOZ_PLATFORM_MAEMO) || defined(MOZ_WIDGET_GONK)
126 static bool gUseBackingSurface = true;
127 #else
128 static bool gUseBackingSurface = false;
129 #endif
131 #ifdef MOZ_WIDGET_GONK
132 extern nsIntRect gScreenBounds;
133 #endif
135 namespace mozilla {
136 namespace gl {
138 static GLLibraryEGL sEGLLibrary;
140 #define ADD_ATTR_2(_array, _k, _v) do { \
141 (_array).AppendElement(_k); \
142 (_array).AppendElement(_v); \
143 } while (0)
145 #define ADD_ATTR_1(_array, _k) do { \
146 (_array).AppendElement(_k); \
147 } while (0)
149 #ifndef MOZ_ANDROID_OMTC
150 static EGLSurface
151 CreateSurfaceForWindow(nsIWidget *aWidget, EGLConfig config);
152 #endif
154 static bool
155 CreateConfig(EGLConfig* aConfig);
156 #ifdef MOZ_X11
158 #ifdef MOZ_EGL_XRENDER_COMPOSITE
159 static EGLSurface
160 CreateBasicEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig);
161 #endif
163 static EGLConfig
164 CreateEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig = nullptr);
165 #endif
167 static EGLint gContextAttribs[] = {
168 LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2,
169 LOCAL_EGL_NONE
172 static EGLint gContextAttribsRobustness[] = {
173 LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2,
174 //LOCAL_EGL_CONTEXT_ROBUST_ACCESS_EXT, LOCAL_EGL_TRUE,
175 LOCAL_EGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_EXT, LOCAL_EGL_LOSE_CONTEXT_ON_RESET_EXT,
176 LOCAL_EGL_NONE
179 static int
180 next_power_of_two(int v)
182 v--;
183 v |= v >> 1;
184 v |= v >> 2;
185 v |= v >> 4;
186 v |= v >> 8;
187 v |= v >> 16;
188 v++;
190 return v;
193 static bool
194 is_power_of_two(int v)
196 NS_ASSERTION(v >= 0, "bad value");
198 if (v == 0)
199 return true;
201 return (v & (v-1)) == 0;
204 class GLContextEGL : public GLContext
206 friend class TextureImageEGL;
208 static already_AddRefed<GLContextEGL>
209 CreateGLContext(const ContextFormat& format,
210 EGLSurface surface,
211 EGLConfig config,
212 GLContextEGL *shareContext,
213 bool aIsOffscreen = false)
215 EGLContext context;
217 context = sEGLLibrary.fCreateContext(EGL_DISPLAY(),
218 config,
219 shareContext ? shareContext->mContext : EGL_NO_CONTEXT,
220 sEGLLibrary.HasRobustness() ? gContextAttribsRobustness
221 : gContextAttribs);
222 if (!context) {
223 if (shareContext) {
224 shareContext = nullptr;
225 context = sEGLLibrary.fCreateContext(EGL_DISPLAY(),
226 config,
227 EGL_NO_CONTEXT,
228 sEGLLibrary.HasRobustness() ? gContextAttribsRobustness
229 : gContextAttribs);
230 if (!context) {
231 NS_WARNING("Failed to create EGLContext!");
232 return nullptr;
237 nsRefPtr<GLContextEGL> glContext =
238 new GLContextEGL(format, shareContext, config,
239 surface, context, aIsOffscreen);
241 if (!glContext->Init())
242 return nullptr;
244 return glContext.forget();
247 public:
248 GLContextEGL(const ContextFormat& aFormat,
249 GLContext *aShareContext,
250 EGLConfig aConfig,
251 EGLSurface aSurface,
252 EGLContext aContext,
253 bool aIsOffscreen = false)
254 : GLContext(aFormat, aIsOffscreen, aShareContext)
255 , mConfig(aConfig)
256 , mSurface(aSurface), mContext(aContext)
257 , mPlatformContext(nullptr)
258 , mThebesSurface(nullptr)
259 , mBound(false)
260 , mIsPBuffer(false)
261 , mIsDoubleBuffered(false)
262 , mCanBindToTexture(false)
263 , mShareWithEGLImage(false)
264 , mTemporaryEGLImageTexture(0)
266 // any EGL contexts will always be GLESv2
267 SetIsGLES2(true);
269 #ifdef DEBUG
270 printf_stderr("Initializing context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
271 #endif
272 #ifdef MOZ_WIDGET_GONK
273 if (!aIsOffscreen)
274 mHwc = new HWComposer();
276 if (mHwc && mHwc->init()) {
277 NS_WARNING("HWComposer initialization failed!");
278 mHwc = nullptr;
280 #endif
283 ~GLContextEGL()
285 if (MakeCurrent()) {
286 if (mTemporaryEGLImageTexture != 0) {
287 fDeleteTextures(1, &mTemporaryEGLImageTexture);
288 mTemporaryEGLImageTexture = 0;
292 MarkDestroyed();
294 // If mGLWidget is non-null, then we've been given it by the GL context provider,
295 // and it's managed by the widget implementation. In this case, We can't destroy
296 // our contexts.
297 if (mPlatformContext)
298 return;
300 #ifdef DEBUG
301 printf_stderr("Destroying context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
302 #endif
304 sEGLLibrary.fDestroyContext(EGL_DISPLAY(), mContext);
305 if (mSurface && !mPlatformContext) {
306 sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface);
310 GLContextType GetContextType() {
311 return ContextTypeEGL;
314 bool Init()
316 #if defined(ANDROID)
317 // We can't use LoadApitraceLibrary here because the GLContext
318 // expects its own handle to the GL library
319 if (!OpenLibrary(APITRACE_LIB))
320 #endif
321 if (!OpenLibrary(GLES2_LIB)) {
322 #if defined(XP_UNIX)
323 if (!OpenLibrary(GLES2_LIB2)) {
324 NS_WARNING("Couldn't load GLES2 LIB.");
325 return false;
327 #endif
330 #ifdef MOZ_WIDGET_GONK
331 char propValue[PROPERTY_VALUE_MAX];
332 property_get("ro.build.version.sdk", propValue, "0");
333 if (atoi(propValue) < 15)
334 gUseBackingSurface = false;
335 #endif
337 bool current = MakeCurrent();
338 if (!current) {
339 gfx::LogFailure(NS_LITERAL_CSTRING(
340 "Couldn't get device attachments for device."));
341 return false;
344 SetupLookupFunction();
346 bool ok = InitWithPrefix("gl", true);
348 PR_STATIC_ASSERT(sizeof(GLint) >= sizeof(int32_t));
349 mMaxTextureImageSize = INT32_MAX;
351 mShareWithEGLImage = sEGLLibrary.HasKHRImageBase() &&
352 sEGLLibrary.HasKHRImageTexture2D() &&
353 IsExtensionSupported(OES_EGL_image);
355 if (ok)
356 InitFramebuffers();
358 return ok;
361 bool IsDoubleBuffered() {
362 return mIsDoubleBuffered;
365 void SetIsDoubleBuffered(bool aIsDB) {
366 mIsDoubleBuffered = aIsDB;
369 bool SupportsRobustness()
371 return sEGLLibrary.HasRobustness();
374 virtual bool IsANGLE()
376 return sEGLLibrary.IsANGLE();
379 #if defined(MOZ_X11) && defined(MOZ_EGL_XRENDER_COMPOSITE)
380 gfxASurface* GetOffscreenPixmapSurface()
382 return mThebesSurface;
385 virtual bool WaitNative() {
386 return sEGLLibrary.fWaitNative(LOCAL_EGL_CORE_NATIVE_ENGINE);
388 #endif
390 bool BindTexImage()
392 if (!mSurface)
393 return false;
395 if (mBound && !ReleaseTexImage())
396 return false;
398 EGLBoolean success = sEGLLibrary.fBindTexImage(EGL_DISPLAY(),
399 (EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER);
400 if (success == LOCAL_EGL_FALSE)
401 return false;
403 mBound = true;
404 return true;
407 bool ReleaseTexImage()
409 if (!mBound)
410 return true;
412 if (!mSurface)
413 return false;
415 EGLBoolean success;
416 success = sEGLLibrary.fReleaseTexImage(EGL_DISPLAY(),
417 (EGLSurface)mSurface,
418 LOCAL_EGL_BACK_BUFFER);
419 if (success == LOCAL_EGL_FALSE)
420 return false;
422 mBound = false;
423 return true;
426 bool BindExternalBuffer(GLuint texture, void* buffer)
428 #if defined(MOZ_WIDGET_GONK)
429 EGLint attrs[] = {
430 LOCAL_EGL_IMAGE_PRESERVED, LOCAL_EGL_TRUE,
431 LOCAL_EGL_NONE, LOCAL_EGL_NONE
433 EGLImage image = sEGLLibrary.fCreateImage(EGL_DISPLAY(),
434 EGL_NO_CONTEXT,
435 EGL_NATIVE_BUFFER_ANDROID,
436 buffer, attrs);
437 fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL, texture);
438 fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_EXTERNAL, image);
439 sEGLLibrary.fDestroyImage(EGL_DISPLAY(), image);
440 return true;
441 #else
442 return false;
443 #endif
446 bool UnbindExternalBuffer(GLuint texture)
448 #if defined(MOZ_WIDGET_GONK)
449 fActiveTexture(LOCAL_GL_TEXTURE0);
450 fBindTexture(LOCAL_GL_TEXTURE_2D, texture);
451 fTexImage2D(LOCAL_GL_TEXTURE_2D, 0,
452 LOCAL_GL_RGBA,
453 1, 1, 0,
454 LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE,
455 nullptr);
456 return true;
457 #else
458 return false;
459 #endif
462 #ifdef MOZ_WIDGET_GONK
463 virtual already_AddRefed<TextureImage>
464 CreateDirectTextureImage(GraphicBuffer* aBuffer, GLenum aWrapMode) MOZ_OVERRIDE;
465 #endif
467 bool MakeCurrentImpl(bool aForce = false) {
468 bool succeeded = true;
470 // Assume that EGL has the same problem as WGL does,
471 // where MakeCurrent with an already-current context is
472 // still expensive.
473 #ifndef MOZ_WIDGET_QT
474 if (!mSurface) {
475 // We need to be able to bind NO_SURFACE when we don't
476 // have access to a surface. We won't be drawing to the screen
477 // but we will be able to do things like resource releases.
478 succeeded = sEGLLibrary.fMakeCurrent(EGL_DISPLAY(),
479 EGL_NO_SURFACE, EGL_NO_SURFACE,
480 EGL_NO_CONTEXT);
481 if (!succeeded && sEGLLibrary.fGetError() == LOCAL_EGL_CONTEXT_LOST) {
482 mContextLost = true;
483 NS_WARNING("EGL context has been lost.");
485 NS_ASSERTION(succeeded, "Failed to make GL context current!");
486 return succeeded;
488 #endif
489 if (aForce || sEGLLibrary.fGetCurrentContext() != mContext) {
490 #ifdef MOZ_WIDGET_QT
491 // Shared Qt GL context need to be informed about context switch
492 if (mSharedContext) {
493 QGLContext* qglCtx = static_cast<QGLContext*>(static_cast<GLContextEGL*>(mSharedContext.get())->mPlatformContext);
494 if (qglCtx) {
495 qglCtx->doneCurrent();
498 #endif
499 succeeded = sEGLLibrary.fMakeCurrent(EGL_DISPLAY(),
500 mSurface, mSurface,
501 mContext);
503 int eglError = sEGLLibrary.fGetError();
504 if (!succeeded) {
505 if (eglError == LOCAL_EGL_CONTEXT_LOST) {
506 mContextLost = true;
507 NS_WARNING("EGL context has been lost.");
508 } else {
509 NS_WARNING("Failed to make GL context current!");
510 #ifdef DEBUG
511 printf_stderr("EGL Error: 0x%04x\n", eglError);
512 #endif
517 return succeeded;
520 virtual bool IsCurrent() {
521 return sEGLLibrary.fGetCurrentContext() == mContext;
524 #ifdef MOZ_WIDGET_QT
525 virtual bool
526 RenewSurface() {
527 /* We don't support renewing on QT because we don't create the surface ourselves */
528 return false;
530 #else
531 virtual bool
532 RenewSurface() {
533 sEGLLibrary.fMakeCurrent(EGL_DISPLAY(), EGL_NO_SURFACE, EGL_NO_SURFACE,
534 EGL_NO_CONTEXT);
535 if (!mSurface) {
536 #ifdef MOZ_ANDROID_OMTC
537 mSurface = mozilla::AndroidBridge::Bridge()->ProvideEGLSurface();
538 #else
539 EGLConfig config;
540 CreateConfig(&config);
541 mSurface = CreateSurfaceForWindow(NULL, config);
542 #endif
544 return sEGLLibrary.fMakeCurrent(EGL_DISPLAY(),
545 mSurface, mSurface,
546 mContext);
548 #endif
550 virtual void
551 ReleaseSurface() {
552 if (mSurface && !mPlatformContext) {
553 sEGLLibrary.fMakeCurrent(EGL_DISPLAY(), EGL_NO_SURFACE, EGL_NO_SURFACE,
554 EGL_NO_CONTEXT);
555 sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface);
556 mSurface = NULL;
560 bool SetupLookupFunction()
562 mLookupFunc = (PlatformLookupFunction)sEGLLibrary.mSymbols.fGetProcAddress;
563 return true;
566 void *GetNativeData(NativeDataType aType)
568 switch (aType) {
569 case NativeGLContext:
570 return mContext;
572 default:
573 return nullptr;
577 bool SwapBuffers()
579 if (mSurface && !mPlatformContext) {
580 #ifdef MOZ_WIDGET_GONK
581 if (mHwc)
582 return !mHwc->swapBuffers((hwc_display_t)EGL_DISPLAY(),
583 (hwc_surface_t)mSurface);
584 else
585 #endif
586 return sEGLLibrary.fSwapBuffers(EGL_DISPLAY(), mSurface);
587 } else {
588 return false;
591 // GLContext interface - returns Tiled Texture Image in our case
592 virtual already_AddRefed<TextureImage>
593 CreateTextureImage(const nsIntSize& aSize,
594 TextureImage::ContentType aContentType,
595 GLenum aWrapMode,
596 TextureImage::Flags aFlags = TextureImage::NoFlags);
598 // a function to generate Tiles for Tiled Texture Image
599 virtual already_AddRefed<TextureImage>
600 TileGenFunc(const nsIntSize& aSize,
601 TextureImage::ContentType aContentType,
602 TextureImage::Flags aFlags = TextureImage::NoFlags);
603 // hold a reference to the given surface
604 // for the lifetime of this context.
605 void HoldSurface(gfxASurface *aSurf) {
606 mThebesSurface = aSurf;
609 void SetPlatformContext(void *context) {
610 mPlatformContext = context;
613 EGLContext Context() {
614 return mContext;
617 bool BindTex2DOffscreen(GLContext *aOffscreen);
618 void UnbindTex2DOffscreen(GLContext *aOffscreen);
619 bool ResizeOffscreen(const gfxIntSize& aNewSize);
620 void BindOffscreenFramebuffer();
622 static already_AddRefed<GLContextEGL>
623 CreateEGLPixmapOffscreenContext(const gfxIntSize& aSize,
624 const ContextFormat& aFormat,
625 bool aShare);
627 #if defined(MOZ_X11) && defined(MOZ_EGL_XRENDER_COMPOSITE)
628 static already_AddRefed<GLContextEGL>
629 CreateBasicEGLPixmapOffscreenContext(const gfxIntSize& aSize,
630 const ContextFormat& aFormat);
632 bool ResizeOffscreenPixmapSurface(const gfxIntSize& aNewSize);
633 #endif
635 static already_AddRefed<GLContextEGL>
636 CreateEGLPBufferOffscreenContext(const gfxIntSize& aSize,
637 const ContextFormat& aFormat,
638 bool bufferUnused = false);
640 void SetOffscreenSize(const gfxIntSize &aRequestedSize,
641 const gfxIntSize &aActualSize)
643 mOffscreenSize = aRequestedSize;
644 mOffscreenActualSize = aActualSize;
647 void *GetD3DShareHandle() {
648 if (!sEGLLibrary.HasANGLESurfaceD3DTexture2DShareHandle()) {
649 return nullptr;
652 void *h = nullptr;
654 #ifndef EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE
655 #define EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200
656 #endif
658 if (!sEGLLibrary.fQuerySurfacePointerANGLE(EGL_DISPLAY(), mSurface,
659 EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, (void**) &h))
661 return nullptr;
664 return h;
667 virtual bool HasLockSurface() {
668 return sEGLLibrary.HasKHRLockSurface();
671 virtual SharedTextureHandle CreateSharedHandle(TextureImage::TextureShareType aType);
672 virtual SharedTextureHandle CreateSharedHandle(TextureImage::TextureShareType aType,
673 void* aBuffer,
674 SharedTextureBufferType aBufferType);
675 virtual void UpdateSharedHandle(TextureImage::TextureShareType aType,
676 SharedTextureHandle aSharedHandle);
677 virtual void ReleaseSharedHandle(TextureImage::TextureShareType aType,
678 SharedTextureHandle aSharedHandle);
679 virtual bool GetSharedHandleDetails(TextureImage::TextureShareType aType,
680 SharedTextureHandle aSharedHandle,
681 SharedHandleDetails& aDetails);
682 virtual bool AttachSharedHandle(TextureImage::TextureShareType aType,
683 SharedTextureHandle aSharedHandle);
684 protected:
685 friend class GLContextProviderEGL;
687 EGLConfig mConfig;
688 EGLSurface mSurface;
689 EGLContext mContext;
690 void *mPlatformContext;
691 nsRefPtr<gfxASurface> mThebesSurface;
692 bool mBound;
694 bool mIsPBuffer;
695 bool mIsDoubleBuffered;
696 bool mCanBindToTexture;
697 bool mShareWithEGLImage;
698 #ifdef MOZ_WIDGET_GONK
699 nsAutoPtr<HWComposer> mHwc;
700 #endif
702 // A dummy texture ID that can be used when we need a texture object whose
703 // images we're going to define with EGLImageTargetTexture2D.
704 GLuint mTemporaryEGLImageTexture;
706 static EGLSurface CreatePBufferSurfaceTryingPowerOfTwo(EGLConfig config,
707 EGLenum bindToTextureFormat,
708 gfxIntSize& pbsize)
710 nsTArray<EGLint> pbattrs(16);
711 EGLSurface surface = nullptr;
713 TRY_AGAIN_POWER_OF_TWO:
714 pbattrs.Clear();
715 pbattrs.AppendElement(LOCAL_EGL_WIDTH); pbattrs.AppendElement(pbsize.width);
716 pbattrs.AppendElement(LOCAL_EGL_HEIGHT); pbattrs.AppendElement(pbsize.height);
718 if (bindToTextureFormat != LOCAL_EGL_NONE) {
719 pbattrs.AppendElement(LOCAL_EGL_TEXTURE_TARGET);
720 pbattrs.AppendElement(LOCAL_EGL_TEXTURE_2D);
722 pbattrs.AppendElement(LOCAL_EGL_TEXTURE_FORMAT);
723 pbattrs.AppendElement(bindToTextureFormat);
726 pbattrs.AppendElement(LOCAL_EGL_NONE);
728 surface = sEGLLibrary.fCreatePbufferSurface(EGL_DISPLAY(), config, &pbattrs[0]);
729 if (!surface) {
730 if (!is_power_of_two(pbsize.width) ||
731 !is_power_of_two(pbsize.height))
733 if (!is_power_of_two(pbsize.width))
734 pbsize.width = next_power_of_two(pbsize.width);
735 if (!is_power_of_two(pbsize.height))
736 pbsize.height = next_power_of_two(pbsize.height);
738 NS_WARNING("Failed to create pbuffer, trying power of two dims");
739 goto TRY_AGAIN_POWER_OF_TWO;
742 NS_WARNING("Failed to create pbuffer surface");
743 return nullptr;
746 return surface;
750 typedef enum {
751 Image
752 #ifdef MOZ_WIDGET_ANDROID
753 , SurfaceTexture
754 #endif
755 } SharedHandleType;
757 class SharedTextureHandleWrapper
759 public:
760 SharedTextureHandleWrapper(SharedHandleType aHandleType) : mHandleType(aHandleType)
764 virtual ~SharedTextureHandleWrapper()
768 SharedHandleType Type() { return mHandleType; }
770 SharedHandleType mHandleType;
773 #ifdef MOZ_WIDGET_ANDROID
775 class SurfaceTextureWrapper: public SharedTextureHandleWrapper
777 public:
778 SurfaceTextureWrapper(nsSurfaceTexture* aSurfaceTexture) :
779 SharedTextureHandleWrapper(SharedHandleType::SurfaceTexture)
780 , mSurfaceTexture(aSurfaceTexture)
784 virtual ~SurfaceTextureWrapper() {
785 mSurfaceTexture = nullptr;
788 nsSurfaceTexture* SurfaceTexture() { return mSurfaceTexture; }
790 nsRefPtr<nsSurfaceTexture> mSurfaceTexture;
793 #endif // MOZ_WIDGET_ANDROID
795 class EGLTextureWrapper : public SharedTextureHandleWrapper
797 public:
798 EGLTextureWrapper() :
799 SharedTextureHandleWrapper(SharedHandleType::Image)
800 , mEGLImage(nullptr)
801 , mSyncObject(nullptr)
805 // Args are the active GL context, and a texture in that GL
806 // context for which to create an EGLImage. After the EGLImage
807 // is created, the texture is unused by EGLTextureWrapper.
808 bool CreateEGLImage(GLContextEGL *ctx, GLuint texture) {
809 MOZ_ASSERT(!mEGLImage && texture && sEGLLibrary.HasKHRImageBase());
810 static const EGLint eglAttributes[] = {
811 LOCAL_EGL_NONE
813 mEGLImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(), ctx->Context(), LOCAL_EGL_GL_TEXTURE_2D,
814 (EGLClientBuffer)texture, eglAttributes);
815 if (!mEGLImage) {
816 #ifdef DEBUG
817 printf_stderr("Could not create EGL images: ERROR (0x%04x)\n", sEGLLibrary.fGetError());
818 #endif
819 return false;
821 return true;
824 virtual ~EGLTextureWrapper() {
825 if (mEGLImage) {
826 sEGLLibrary.fDestroyImage(EGL_DISPLAY(), mEGLImage);
827 mEGLImage = nullptr;
831 const EGLImage GetEGLImage() {
832 return mEGLImage;
835 // Insert a sync point on the given context, which should be the current active
836 // context.
837 bool MakeSync(GLContext *ctx) {
838 MOZ_ASSERT(mSyncObject == nullptr);
840 if (sEGLLibrary.IsExtensionSupported(GLLibraryEGL::KHR_fence_sync)) {
841 mSyncObject = sEGLLibrary.fCreateSync(EGL_DISPLAY(), LOCAL_EGL_SYNC_FENCE, nullptr);
842 // We need to flush to make sure the sync object enters the command stream;
843 // we can't use EGL_SYNC_FLUSH_COMMANDS_BIT at wait time, because the wait
844 // happens on a different thread/context.
845 ctx->fFlush();
848 if (mSyncObject == EGL_NO_SYNC) {
849 // we failed to create one, so just do a finish
850 ctx->fFinish();
853 return true;
856 bool WaitSync() {
857 if (!mSyncObject) {
858 // if we have no sync object, then we did a Finish() earlier
859 return true;
862 // wait at most 1 second; this should really be never/rarely hit
863 const uint64_t ns_per_ms = 1000 * 1000;
864 EGLTime timeout = 1000 * ns_per_ms;
866 EGLint result = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), mSyncObject, 0, timeout);
867 sEGLLibrary.fDestroySync(EGL_DISPLAY(), mSyncObject);
868 mSyncObject = nullptr;
870 return result == LOCAL_EGL_CONDITION_SATISFIED;
873 private:
874 EGLImage mEGLImage;
875 EGLSync mSyncObject;
878 void
879 GLContextEGL::UpdateSharedHandle(TextureImage::TextureShareType aType,
880 SharedTextureHandle aSharedHandle)
882 if (aType != TextureImage::ThreadShared) {
883 NS_ERROR("Implementation not available for this sharing type");
884 return;
887 SharedTextureHandleWrapper* wrapper = reinterpret_cast<SharedTextureHandleWrapper*>(aSharedHandle);
889 NS_ASSERTION(wrapper->Type() == SharedHandleType::Image, "Expected EGLImage shared handle");
890 NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime");
892 EGLTextureWrapper* wrap = reinterpret_cast<EGLTextureWrapper*>(wrapper);
893 // We need to copy the current GLContext drawing buffer to the texture
894 // exported by the EGLImage. Need to save both the read FBO and the texture
895 // binding, because we're going to munge them to do this.
896 GLuint prevRead = GetUserBoundReadFBO();
897 GLint oldtex = -1;
898 BindUserReadFBO(0);
899 fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &oldtex);
900 MOZ_ASSERT(oldtex != -1);
901 fBindTexture(LOCAL_GL_TEXTURE_2D, mTemporaryEGLImageTexture);
902 fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, wrap->GetEGLImage());
904 // CopyTexSubImage2D, is ~2x slower than simple FBO render to texture with draw quads,
905 // but render with draw quads require complex and hard to maintain context save/restore code
906 fCopyTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, 0, 0,
907 0, 0, mOffscreenActualSize.width,
908 mOffscreenActualSize.height);
910 fBindTexture(LOCAL_GL_TEXTURE_2D, oldtex);
911 BindUserReadFBO(prevRead);
913 // Make sure our copy is finished, so that we can be ready to draw
914 // in different thread GLContext. If we have KHR_fence_sync, then
915 // we insert a sync object, otherwise we have to do a GuaranteeResolve.
916 wrap->MakeSync(this);
919 SharedTextureHandle
920 GLContextEGL::CreateSharedHandle(TextureImage::TextureShareType aType)
922 if (aType != TextureImage::ThreadShared)
923 return 0;
925 if (!mShareWithEGLImage)
926 return 0;
928 MakeCurrent();
929 ContextFormat fmt = ActualFormat();
931 CreateTextureForOffscreen(ChooseGLFormats(fmt, GLContext::ForceRGBA), mOffscreenActualSize,
932 mTemporaryEGLImageTexture);
934 EGLTextureWrapper* tex = new EGLTextureWrapper();
935 bool ok = tex->CreateEGLImage(this, mTemporaryEGLImageTexture);
937 if (!ok) {
938 NS_ERROR("EGLImage creation for EGLTextureWrapper failed");
939 ReleaseSharedHandle(aType, (SharedTextureHandle)tex);
940 return 0;
943 // Raw pointer shared across threads
944 return (SharedTextureHandle)tex;
947 SharedTextureHandle
948 GLContextEGL::CreateSharedHandle(TextureImage::TextureShareType aType,
949 void* aBuffer,
950 SharedTextureBufferType aBufferType)
952 // Both EGLImage and SurfaceTexture only support ThreadShared currently, but
953 // it's possible to make SurfaceTexture work across processes. We should do that.
954 if (aType != TextureImage::ThreadShared)
955 return 0;
957 switch (aBufferType) {
958 #ifdef MOZ_WIDGET_ANDROID
959 case SharedTextureBufferType::SurfaceTexture:
960 if (!IsExtensionSupported(GLContext::OES_EGL_image_external)) {
961 NS_WARNING("Missing GL_OES_EGL_image_external");
962 return 0;
965 return (SharedTextureHandle) new SurfaceTextureWrapper(reinterpret_cast<nsSurfaceTexture*>(aBuffer));
966 #endif
967 case SharedTextureBufferType::TextureID: {
968 if (!mShareWithEGLImage)
969 return 0;
971 GLuint texture = (uintptr_t)aBuffer;
972 EGLTextureWrapper* tex = new EGLTextureWrapper();
973 if (!tex->CreateEGLImage(this, texture)) {
974 NS_ERROR("EGLImage creation for EGLTextureWrapper failed");
975 delete tex;
976 return 0;
979 return (SharedTextureHandle)tex;
981 default:
982 NS_ERROR("Unknown shared texture buffer type");
983 return 0;
987 void GLContextEGL::ReleaseSharedHandle(TextureImage::TextureShareType aType,
988 SharedTextureHandle aSharedHandle)
990 if (aType != TextureImage::ThreadShared) {
991 NS_ERROR("Implementation not available for this sharing type");
992 return;
995 SharedTextureHandleWrapper* wrapper = reinterpret_cast<SharedTextureHandleWrapper*>(aSharedHandle);
997 switch (wrapper->Type()) {
998 #ifdef MOZ_WIDGET_ANDROID
999 case SharedHandleType::SurfaceTexture:
1000 delete wrapper;
1001 break;
1002 #endif
1004 case SharedHandleType::Image: {
1005 NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime");
1007 EGLTextureWrapper* wrap = (EGLTextureWrapper*)aSharedHandle;
1008 delete wrap;
1009 break;
1012 default:
1013 NS_ERROR("Unknown shared handle type");
1017 bool GLContextEGL::GetSharedHandleDetails(TextureImage::TextureShareType aType,
1018 SharedTextureHandle aSharedHandle,
1019 SharedHandleDetails& aDetails)
1021 if (aType != TextureImage::ThreadShared)
1022 return false;
1024 SharedTextureHandleWrapper* wrapper = reinterpret_cast<SharedTextureHandleWrapper*>(aSharedHandle);
1026 switch (wrapper->Type()) {
1027 #ifdef MOZ_WIDGET_ANDROID
1028 case SharedHandleType::SurfaceTexture: {
1029 SurfaceTextureWrapper* surfaceWrapper = reinterpret_cast<SurfaceTextureWrapper*>(wrapper);
1031 aDetails.mTarget = LOCAL_GL_TEXTURE_EXTERNAL;
1032 aDetails.mProgramType = RGBALayerExternalProgramType;
1033 surfaceWrapper->SurfaceTexture()->GetTransformMatrix(aDetails.mTextureTransform);
1034 break;
1036 #endif
1038 case SharedHandleType::Image:
1039 aDetails.mTarget = LOCAL_GL_TEXTURE_2D;
1040 aDetails.mProgramType = RGBALayerProgramType;
1041 break;
1043 default:
1044 NS_ERROR("Unknown shared handle type");
1045 return false;
1048 return true;
1051 bool GLContextEGL::AttachSharedHandle(TextureImage::TextureShareType aType,
1052 SharedTextureHandle aSharedHandle)
1054 if (aType != TextureImage::ThreadShared)
1055 return false;
1057 SharedTextureHandleWrapper* wrapper = reinterpret_cast<SharedTextureHandleWrapper*>(aSharedHandle);
1059 switch (wrapper->Type()) {
1060 #ifdef MOZ_WIDGET_ANDROID
1061 case SharedHandleType::SurfaceTexture: {
1062 #ifndef DEBUG
1064 * NOTE: SurfaceTexture spams us if there are any existing GL errors, so we'll clear
1065 * them here in order to avoid that.
1067 GetAndClearError();
1068 #endif
1069 SurfaceTextureWrapper* surfaceTextureWrapper = reinterpret_cast<SurfaceTextureWrapper*>(wrapper);
1071 // FIXME: SurfaceTexture provides a transform matrix which is supposed to
1072 // be applied to the texture coordinates. We should return that here
1073 // so we can render correctly. Bug 775083
1074 surfaceTextureWrapper->SurfaceTexture()->UpdateTexImage();
1075 break;
1077 #endif // MOZ_WIDGET_ANDROID
1079 case SharedHandleType::Image: {
1080 NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime");
1082 EGLTextureWrapper* wrap = (EGLTextureWrapper*)aSharedHandle;
1083 wrap->WaitSync();
1084 fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, wrap->GetEGLImage());
1085 break;
1088 default:
1089 NS_ERROR("Unknown shared handle type");
1090 return false;
1093 return true;
1096 bool
1097 GLContextEGL::BindTex2DOffscreen(GLContext *aOffscreen)
1099 if (aOffscreen->GetContextType() != ContextTypeEGL) {
1100 NS_WARNING("non-EGL context");
1101 return false;
1104 GLContextEGL *offs = static_cast<GLContextEGL*>(aOffscreen);
1106 if (offs->mCanBindToTexture) {
1107 bool ok = sEGLLibrary.fBindTexImage(EGL_DISPLAY(),
1108 offs->mSurface,
1109 LOCAL_EGL_BACK_BUFFER);
1110 return ok;
1113 if (offs->mOffscreenTexture) {
1114 if (offs->GetSharedContext() != GLContextProviderEGL::GetGlobalContext())
1116 NS_WARNING("offscreen FBO context can only be bound with context sharing!");
1117 return false;
1120 fBindTexture(LOCAL_GL_TEXTURE_2D, offs->mOffscreenTexture);
1121 return true;
1124 NS_WARNING("don't know how to bind this!");
1126 return false;
1129 void
1130 GLContextEGL::UnbindTex2DOffscreen(GLContext *aOffscreen)
1132 NS_ASSERTION(aOffscreen->GetContextType() == ContextTypeEGL, "wrong type");
1134 GLContextEGL *offs = static_cast<GLContextEGL*>(aOffscreen);
1136 if (offs->mCanBindToTexture) {
1137 sEGLLibrary.fReleaseTexImage(EGL_DISPLAY(),
1138 offs->mSurface,
1139 LOCAL_EGL_BACK_BUFFER);
1143 bool
1144 GLContextEGL::ResizeOffscreen(const gfxIntSize& aNewSize)
1146 if (!IsOffscreenSizeAllowed(aNewSize))
1147 return false;
1149 if (mIsPBuffer) {
1150 gfxIntSize pbsize(aNewSize);
1152 EGLSurface surface =
1153 CreatePBufferSurfaceTryingPowerOfTwo(mConfig,
1154 mCanBindToTexture
1155 ? (mCreationFormat.minAlpha
1156 ? LOCAL_EGL_TEXTURE_RGBA
1157 : LOCAL_EGL_TEXTURE_RGB)
1158 : LOCAL_EGL_NONE,
1159 pbsize);
1160 if (!surface) {
1161 NS_WARNING("Failed to resize pbuffer");
1162 return false;
1165 if (!ResizeOffscreenFBOs(pbsize, false))
1166 return false;
1168 SetOffscreenSize(aNewSize, pbsize);
1170 if (mSurface && !mPlatformContext) {
1171 sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface);
1174 mSurface = surface;
1176 MakeCurrent(true);
1177 ClearSafely();
1179 return true;
1182 #if defined(MOZ_X11) && defined(MOZ_EGL_XRENDER_COMPOSITE)
1183 if (ResizeOffscreenPixmapSurface(aNewSize)) {
1184 if (ResizeOffscreenFBOs(aNewSize, true))
1185 return true;
1187 #endif
1189 return ResizeOffscreenFBOs(aNewSize, true);
1193 static GLContextEGL *
1194 GetGlobalContextEGL()
1196 return static_cast<GLContextEGL*>(GLContextProviderEGL::GetGlobalContext());
1199 static GLenum
1200 GLFormatForImage(gfxASurface::gfxImageFormat aFormat)
1202 switch (aFormat) {
1203 case gfxASurface::ImageFormatARGB32:
1204 case gfxASurface::ImageFormatRGB24:
1205 // Thebes only supports RGBX, not packed RGB.
1206 return LOCAL_GL_RGBA;
1207 case gfxASurface::ImageFormatRGB16_565:
1208 return LOCAL_GL_RGB;
1209 case gfxASurface::ImageFormatA8:
1210 return LOCAL_GL_LUMINANCE;
1211 default:
1212 NS_WARNING("Unknown GL format for Image format");
1214 return 0;
1217 #ifdef MOZ_WIDGET_GONK
1218 static PixelFormat
1219 PixelFormatForImage(gfxASurface::gfxImageFormat aFormat)
1221 switch (aFormat) {
1222 case gfxASurface::ImageFormatARGB32:
1223 return PIXEL_FORMAT_RGBA_8888;
1224 case gfxASurface::ImageFormatRGB24:
1225 return PIXEL_FORMAT_RGBX_8888;
1226 case gfxASurface::ImageFormatRGB16_565:
1227 return PIXEL_FORMAT_RGB_565;
1228 case gfxASurface::ImageFormatA8:
1229 return PIXEL_FORMAT_L_8;
1230 default:
1231 MOZ_NOT_REACHED("Unknown gralloc pixel format for Image format");
1233 return 0;
1236 static gfxASurface::gfxContentType
1237 ContentTypeForPixelFormat(PixelFormat aFormat)
1239 switch (aFormat) {
1240 case PIXEL_FORMAT_L_8:
1241 return gfxASurface::CONTENT_ALPHA;
1242 case PIXEL_FORMAT_RGBA_8888:
1243 return gfxASurface::CONTENT_COLOR_ALPHA;
1244 case PIXEL_FORMAT_RGBX_8888:
1245 case PIXEL_FORMAT_RGB_565:
1246 return gfxASurface::CONTENT_COLOR;
1247 default:
1248 MOZ_NOT_REACHED("Unknown content type for gralloc pixel format");
1250 return gfxASurface::CONTENT_COLOR;
1252 #endif
1254 static GLenum
1255 GLTypeForImage(gfxASurface::gfxImageFormat aFormat)
1257 switch (aFormat) {
1258 case gfxASurface::ImageFormatARGB32:
1259 case gfxASurface::ImageFormatRGB24:
1260 case gfxASurface::ImageFormatA8:
1261 return LOCAL_GL_UNSIGNED_BYTE;
1262 case gfxASurface::ImageFormatRGB16_565:
1263 return LOCAL_GL_UNSIGNED_SHORT_5_6_5;
1264 default:
1265 NS_WARNING("Unknown GL format for Image format");
1267 return 0;
1270 class TextureImageEGL
1271 : public TextureImage
1273 public:
1274 TextureImageEGL(GLuint aTexture,
1275 const nsIntSize& aSize,
1276 GLenum aWrapMode,
1277 ContentType aContentType,
1278 GLContext* aContext,
1279 Flags aFlags = TextureImage::NoFlags,
1280 TextureState aTextureState = Created)
1281 : TextureImage(aSize, aWrapMode, aContentType, aFlags)
1282 , mGLContext(aContext)
1283 , mUpdateFormat(gfxASurface::ImageFormatUnknown)
1284 , mEGLImage(nullptr)
1285 , mTexture(aTexture)
1286 , mSurface(nullptr)
1287 , mConfig(nullptr)
1288 , mTextureState(aTextureState)
1289 , mBound(false)
1290 , mIsLocked(false)
1292 mUpdateFormat = gfxPlatform::GetPlatform()->OptimalFormatForContent(GetContentType());
1294 if (gUseBackingSurface) {
1295 #ifdef MOZ_WIDGET_GONK
1296 switch (mUpdateFormat) {
1297 case gfxASurface::ImageFormatARGB32:
1298 mShaderType = BGRALayerProgramType;
1299 break;
1300 case gfxASurface::ImageFormatRGB24:
1301 mUpdateFormat = gfxASurface::ImageFormatARGB32;
1302 mShaderType = BGRXLayerProgramType;
1303 break;
1304 case gfxASurface::ImageFormatRGB16_565:
1305 mShaderType = RGBXLayerProgramType;
1306 break;
1307 case gfxASurface::ImageFormatA8:
1308 mShaderType = RGBALayerProgramType;
1309 break;
1310 default:
1311 MOZ_NOT_REACHED("Unknown update format");
1313 #else
1314 if (mUpdateFormat != gfxASurface::ImageFormatARGB32) {
1315 mShaderType = RGBXLayerProgramType;
1316 } else {
1317 mShaderType = RGBALayerProgramType;
1319 #endif
1320 Resize(aSize);
1321 } else {
1322 if (mUpdateFormat == gfxASurface::ImageFormatRGB16_565) {
1323 mShaderType = RGBXLayerProgramType;
1324 } else if (mUpdateFormat == gfxASurface::ImageFormatRGB24) {
1325 // RGB24 means really RGBX for Thebes, which means we have to
1326 // use the right shader and ignore the uninitialized alpha
1327 // value.
1328 mShaderType = BGRXLayerProgramType;
1329 } else {
1330 mShaderType = BGRALayerProgramType;
1335 virtual ~TextureImageEGL()
1337 GLContext *ctx = mGLContext;
1338 if (ctx->IsDestroyed() || !ctx->IsOwningThreadCurrent()) {
1339 ctx = ctx->GetSharedContext();
1342 // If we have a context, then we need to delete the texture;
1343 // if we don't have a context (either real or shared),
1344 // then they went away when the contex was deleted, because it
1345 // was the only one that had access to it.
1346 if (ctx && !ctx->IsDestroyed()) {
1347 ctx->MakeCurrent();
1348 ctx->fDeleteTextures(1, &mTexture);
1349 ReleaseTexImage();
1350 DestroyEGLSurface();
1354 bool UsingDirectTexture()
1356 #ifdef MOZ_WIDGET_GONK
1357 if (mGraphicBuffer != nullptr)
1358 return true;
1359 #endif
1360 return !!mBackingSurface;
1363 virtual void GetUpdateRegion(nsIntRegion& aForRegion)
1365 if (mTextureState != Valid) {
1366 // if the texture hasn't been initialized yet, force the
1367 // client to paint everything
1368 aForRegion = nsIntRect(nsIntPoint(0, 0), mSize);
1371 if (UsingDirectTexture()) {
1372 return;
1375 // We can only draw a rectangle, not subregions due to
1376 // the way that our texture upload functions work. If
1377 // needed, we /could/ do multiple texture uploads if we have
1378 // non-overlapping rects, but that's a tradeoff.
1379 aForRegion = nsIntRegion(aForRegion.GetBounds());
1382 virtual gfxASurface* BeginUpdate(nsIntRegion& aRegion)
1384 NS_ASSERTION(!mUpdateSurface, "BeginUpdate() without EndUpdate()?");
1386 // determine the region the client will need to repaint
1387 GetUpdateRegion(aRegion);
1388 mUpdateRect = aRegion.GetBounds();
1390 //printf_stderr("BeginUpdate with updateRect [%d %d %d %d]\n", mUpdateRect.x, mUpdateRect.y, mUpdateRect.width, mUpdateRect.height);
1391 if (!nsIntRect(nsIntPoint(0, 0), mSize).Contains(mUpdateRect)) {
1392 NS_ERROR("update outside of image");
1393 return NULL;
1396 #ifdef MOZ_WIDGET_GONK
1397 if (mGraphicBuffer != nullptr) {
1398 mUpdateSurface = GetLockSurface();
1400 return mUpdateSurface;
1402 #endif
1404 if (mBackingSurface) {
1405 if (sEGLLibrary.HasKHRLockSurface()) {
1406 mUpdateSurface = GetLockSurface();
1407 } else {
1408 mUpdateSurface = mBackingSurface;
1411 return mUpdateSurface;
1414 //printf_stderr("creating image surface %dx%d format %d\n", mUpdateRect.width, mUpdateRect.height, mUpdateFormat);
1416 mUpdateSurface =
1417 new gfxImageSurface(gfxIntSize(mUpdateRect.width, mUpdateRect.height),
1418 mUpdateFormat);
1420 mUpdateSurface->SetDeviceOffset(gfxPoint(-mUpdateRect.x, -mUpdateRect.y));
1422 return mUpdateSurface;
1425 virtual void EndUpdate()
1427 NS_ASSERTION(!!mUpdateSurface, "EndUpdate() without BeginUpdate()?");
1429 if (mIsLocked) {
1430 UnlockSurface();
1431 mTextureState = Valid;
1432 mUpdateSurface = nullptr;
1433 return;
1436 if (mBackingSurface && mUpdateSurface == mBackingSurface) {
1437 #ifdef MOZ_X11
1438 if (mBackingSurface->GetType() == gfxASurface::SurfaceTypeXlib) {
1439 FinishX(DefaultXDisplay());
1441 #endif
1443 mBackingSurface->SetDeviceOffset(gfxPoint(0, 0));
1444 mTextureState = Valid;
1445 mUpdateSurface = nullptr;
1446 return;
1449 //printf_stderr("EndUpdate: slow path");
1451 // This is the slower path -- we didn't have any way to set up
1452 // a fast mapping between our cairo target surface and the GL
1453 // texture, so we have to upload data.
1455 // Undo the device offset that BeginUpdate set; doesn't much
1456 // matter for us here, but important if we ever do anything
1457 // directly with the surface.
1458 mUpdateSurface->SetDeviceOffset(gfxPoint(0, 0));
1460 nsRefPtr<gfxImageSurface> uploadImage = nullptr;
1461 gfxIntSize updateSize(mUpdateRect.width, mUpdateRect.height);
1463 NS_ASSERTION(mUpdateSurface->GetType() == gfxASurface::SurfaceTypeImage &&
1464 mUpdateSurface->GetSize() == updateSize,
1465 "Upload image isn't an image surface when one is expected, or is wrong size!");
1467 uploadImage = static_cast<gfxImageSurface*>(mUpdateSurface.get());
1469 if (!uploadImage) {
1470 return;
1473 mGLContext->MakeCurrent();
1474 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
1476 if (mTextureState != Valid) {
1477 NS_ASSERTION(mUpdateRect.x == 0 && mUpdateRect.y == 0 &&
1478 mUpdateRect.Size() == mSize,
1479 "Bad initial update on non-created texture!");
1481 mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
1483 GLFormatForImage(mUpdateFormat),
1484 mUpdateRect.width,
1485 mUpdateRect.height,
1487 GLFormatForImage(uploadImage->Format()),
1488 GLTypeForImage(uploadImage->Format()),
1489 uploadImage->Data());
1490 } else {
1491 mGLContext->fTexSubImage2D(LOCAL_GL_TEXTURE_2D,
1493 mUpdateRect.x,
1494 mUpdateRect.y,
1495 mUpdateRect.width,
1496 mUpdateRect.height,
1497 GLFormatForImage(uploadImage->Format()),
1498 GLTypeForImage(uploadImage->Format()),
1499 uploadImage->Data());
1502 mUpdateSurface = nullptr;
1503 mTextureState = Valid;
1504 return; // mTexture is bound
1507 virtual bool DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom /* = nsIntPoint(0, 0) */)
1509 nsIntRect bounds = aRegion.GetBounds();
1511 nsIntRegion region;
1512 if (mTextureState != Valid) {
1513 bounds = nsIntRect(0, 0, mSize.width, mSize.height);
1514 region = nsIntRegion(bounds);
1515 } else {
1516 region = aRegion;
1519 if ((mBackingSurface && sEGLLibrary.HasKHRLockSurface())
1520 #ifdef MOZ_WIDGET_GONK
1521 || (mGraphicBuffer != nullptr)
1522 #endif
1524 mUpdateSurface = GetLockSurface();
1525 if (mUpdateSurface) {
1526 nsRefPtr<gfxContext> ctx = new gfxContext(mUpdateSurface);
1527 gfxUtils::ClipToRegion(ctx, aRegion);
1528 ctx->SetSource(aSurf, gfxPoint(-aFrom.x, -aFrom.y));
1529 ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
1530 ctx->Paint();
1531 mUpdateSurface = nullptr;
1532 UnlockSurface();
1534 } else {
1535 mShaderType =
1536 mGLContext->UploadSurfaceToTexture(aSurf,
1537 region,
1538 mTexture,
1539 mTextureState == Created,
1540 bounds.TopLeft() + aFrom,
1541 false);
1544 mTextureState = Valid;
1545 return true;
1548 virtual void BindTexture(GLenum aTextureUnit)
1550 // Ensure the texture is allocated before it is used.
1551 if (mTextureState == Created) {
1552 Resize(mSize);
1555 #ifdef MOZ_WIDGET_GONK
1556 if (UsingDirectTexture()) {
1557 mGLContext->fActiveTexture(aTextureUnit);
1558 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
1559 mGLContext->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, mEGLImage);
1560 if (sEGLLibrary.fGetError() != LOCAL_EGL_SUCCESS) {
1561 LOG("Could not set image target texture. ERROR (0x%04x)", sEGLLibrary.fGetError());
1563 } else
1564 #endif
1566 mGLContext->fActiveTexture(aTextureUnit);
1567 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
1568 mGLContext->fActiveTexture(LOCAL_GL_TEXTURE0);
1572 virtual GLuint GetTextureID()
1574 // Ensure the texture is allocated before it is used.
1575 if (mTextureState == Created) {
1576 Resize(mSize);
1578 return mTexture;
1581 virtual bool InUpdate() const { return !!mUpdateSurface; }
1583 virtual void Resize(const nsIntSize& aSize)
1585 NS_ASSERTION(!mUpdateSurface, "Resize() while in update?");
1587 if (mSize == aSize && mTextureState != Created)
1588 return;
1590 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
1592 // Try to generate a backin surface first if we have the ability
1593 if (gUseBackingSurface) {
1594 CreateBackingSurface(gfxIntSize(aSize.width, aSize.height));
1597 if (!UsingDirectTexture()) {
1598 // If we don't have a backing surface or failed to obtain one,
1599 // use the GL Texture failsafe
1600 mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D,
1602 GLFormatForImage(mUpdateFormat),
1603 aSize.width,
1604 aSize.height,
1606 GLFormatForImage(mUpdateFormat),
1607 GLTypeForImage(mUpdateFormat),
1608 NULL);
1611 mTextureState = Allocated;
1612 mSize = aSize;
1615 bool BindTexImage()
1617 if (mBound && !ReleaseTexImage())
1618 return false;
1620 EGLBoolean success =
1621 sEGLLibrary.fBindTexImage(EGL_DISPLAY(),
1622 (EGLSurface)mSurface,
1623 LOCAL_EGL_BACK_BUFFER);
1625 if (success == LOCAL_EGL_FALSE)
1626 return false;
1628 mBound = true;
1629 return true;
1632 bool ReleaseTexImage()
1634 if (!mBound)
1635 return true;
1637 EGLBoolean success =
1638 sEGLLibrary.fReleaseTexImage(EGL_DISPLAY(),
1639 (EGLSurface)mSurface,
1640 LOCAL_EGL_BACK_BUFFER);
1642 if (success == LOCAL_EGL_FALSE)
1643 return false;
1645 mBound = false;
1646 return true;
1649 virtual already_AddRefed<gfxImageSurface> GetLockSurface()
1651 if (mIsLocked) {
1652 NS_WARNING("Can't lock surface twice");
1653 return nullptr;
1656 #ifdef MOZ_WIDGET_GONK
1657 if (mGraphicBuffer != nullptr) {
1658 // Unset the EGLImage target so that we don't get clashing locks
1659 mGLContext->MakeCurrent(true);
1660 mGLContext->UnbindExternalBuffer(mTexture);
1662 void *vaddr;
1663 if (mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN |
1664 GraphicBuffer::USAGE_SW_WRITE_OFTEN,
1665 &vaddr) != OK) {
1666 LOG("Could not lock GraphicBuffer");
1667 return nullptr;
1670 nsRefPtr<gfxImageSurface> surface =
1671 new gfxImageSurface(reinterpret_cast<unsigned char *>(vaddr),
1672 gfxIntSize(mSize.width, mSize.height),
1673 mGraphicBuffer->getStride() * gfxUtils::ImageFormatToDepth(mUpdateFormat) / 8,
1674 mUpdateFormat);
1676 mIsLocked = true;
1678 return surface.forget();
1680 #endif
1682 if (!sEGLLibrary.HasKHRLockSurface()) {
1683 NS_WARNING("GetLockSurface called, but no EGL_KHR_lock_surface extension!");
1684 return nullptr;
1687 if (!CreateEGLSurface(mBackingSurface)) {
1688 NS_WARNING("Failed to create EGL surface");
1689 return nullptr;
1692 static EGLint lock_attribs[] = {
1693 LOCAL_EGL_MAP_PRESERVE_PIXELS_KHR, LOCAL_EGL_TRUE,
1694 LOCAL_EGL_LOCK_USAGE_HINT_KHR, LOCAL_EGL_READ_SURFACE_BIT_KHR | LOCAL_EGL_WRITE_SURFACE_BIT_KHR,
1695 LOCAL_EGL_NONE
1698 sEGLLibrary.fLockSurface(EGL_DISPLAY(), mSurface, lock_attribs);
1700 mIsLocked = true;
1702 unsigned char *data = nullptr;
1703 int pitch = 0;
1704 int pixsize = 0;
1706 sEGLLibrary.fQuerySurface(EGL_DISPLAY(), mSurface, LOCAL_EGL_BITMAP_POINTER_KHR, (EGLint*)&data);
1707 sEGLLibrary.fQuerySurface(EGL_DISPLAY(), mSurface, LOCAL_EGL_BITMAP_PITCH_KHR, &pitch);
1708 sEGLLibrary.fQuerySurface(EGL_DISPLAY(), mSurface, LOCAL_EGL_BITMAP_PIXEL_SIZE_KHR, &pixsize);
1710 nsRefPtr<gfxImageSurface> sharedImage =
1711 new gfxImageSurface(data,
1712 mBackingSurface->GetSize(),
1713 pitch,
1714 mUpdateFormat);
1716 return sharedImage.forget();
1719 virtual void UnlockSurface()
1721 if (!mIsLocked) {
1722 NS_WARNING("UnlockSurface called, surface not locked!");
1723 return;
1726 mIsLocked = false;
1728 #ifdef MOZ_WIDGET_GONK
1729 if (mGraphicBuffer != nullptr) {
1730 mGraphicBuffer->unlock();
1732 return;
1734 #endif
1736 sEGLLibrary.fUnlockSurface(EGL_DISPLAY(), mSurface);
1739 virtual already_AddRefed<gfxASurface> GetBackingSurface()
1741 nsRefPtr<gfxASurface> copy = mBackingSurface;
1742 return copy.forget();
1745 virtual bool CreateEGLSurface(gfxASurface* aSurface)
1747 #ifdef MOZ_X11
1748 if (!aSurface) {
1749 NS_WARNING("no surface");
1750 return false;
1753 if (aSurface->GetType() != gfxASurface::SurfaceTypeXlib) {
1754 NS_WARNING("wrong surface type, must be xlib");
1755 return false;
1758 if (mSurface) {
1759 return true;
1762 EGLSurface surface = CreateEGLSurfaceForXSurface(aSurface, &mConfig);
1764 if (!surface) {
1765 NS_WARNING("couldn't find X config for surface");
1766 return false;
1769 mSurface = surface;
1770 return true;
1771 #else
1772 return false;
1773 #endif
1776 virtual void DestroyEGLSurface(void)
1778 #ifdef MOZ_WIDGET_GONK
1779 mGraphicBuffer.clear();
1781 if (mEGLImage) {
1782 sEGLLibrary.fDestroyImage(EGL_DISPLAY(), mEGLImage);
1783 mEGLImage = nullptr;
1785 #endif
1787 if (!mSurface)
1788 return;
1790 sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface);
1791 mSurface = nullptr;
1794 virtual bool CreateBackingSurface(const gfxIntSize& aSize)
1796 ReleaseTexImage();
1797 DestroyEGLSurface();
1798 mBackingSurface = nullptr;
1800 #ifdef MOZ_X11
1801 Display* dpy = DefaultXDisplay();
1802 XRenderPictFormat* renderFMT =
1803 gfxXlibSurface::FindRenderFormat(dpy, mUpdateFormat);
1805 nsRefPtr<gfxXlibSurface> xsurface =
1806 gfxXlibSurface::Create(DefaultScreenOfDisplay(dpy),
1807 renderFMT,
1808 gfxIntSize(aSize.width, aSize.height));
1810 XSync(dpy, False);
1811 mConfig = nullptr;
1813 if (sEGLLibrary.HasKHRImagePixmap() &&
1814 mGLContext->IsExtensionSupported(GLContext::OES_EGL_image))
1816 mEGLImage =
1817 sEGLLibrary.fCreateImage(EGL_DISPLAY(),
1818 EGL_NO_CONTEXT,
1819 LOCAL_EGL_NATIVE_PIXMAP,
1820 (EGLClientBuffer)xsurface->XDrawable(),
1821 nullptr);
1823 if (!mEGLImage) {
1824 printf_stderr("couldn't create EGL image: ERROR (0x%04x)\n", sEGLLibrary.fGetError());
1825 return false;
1827 mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture);
1828 mGLContext->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, mEGLImage);
1829 sEGLLibrary.fDestroyImage(EGL_DISPLAY(), mEGLImage);
1830 mEGLImage = nullptr;
1831 } else {
1832 if (!CreateEGLSurface(xsurface)) {
1833 printf_stderr("ProviderEGL Failed create EGL surface: ERROR (0x%04x)\n", sEGLLibrary.fGetError());
1834 return false;
1837 if (!BindTexImage()) {
1838 printf_stderr("ProviderEGL Failed to bind teximage: ERROR (0x%04x)\n", sEGLLibrary.fGetError());
1839 return false;
1843 mBackingSurface = xsurface;
1845 return mBackingSurface != nullptr;
1846 #endif
1848 #ifdef MOZ_WIDGET_GONK
1849 if (gUseBackingSurface) {
1850 mGLContext->MakeCurrent(true);
1851 PixelFormat format = PixelFormatForImage(mUpdateFormat);
1852 uint32_t usage = GraphicBuffer::USAGE_HW_TEXTURE |
1853 GraphicBuffer::USAGE_SW_READ_OFTEN |
1854 GraphicBuffer::USAGE_SW_WRITE_OFTEN;
1855 mGraphicBuffer = new GraphicBuffer(aSize.width, aSize.height, format, usage);
1856 if (mGraphicBuffer->initCheck() == OK) {
1857 const int eglImageAttributes[] = { LOCAL_EGL_IMAGE_PRESERVED, LOCAL_EGL_TRUE,
1858 LOCAL_EGL_NONE, LOCAL_EGL_NONE };
1859 mEGLImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(),
1860 EGL_NO_CONTEXT,
1861 EGL_NATIVE_BUFFER_ANDROID,
1862 (EGLClientBuffer) mGraphicBuffer->getNativeBuffer(),
1863 eglImageAttributes);
1864 if (!mEGLImage) {
1865 mGraphicBuffer = nullptr;
1866 LOG("Could not create EGL images: ERROR (0x%04x)", sEGLLibrary.fGetError());
1867 return false;
1870 return true;
1873 mGraphicBuffer = nullptr;
1874 LOG("GraphicBufferAllocator::alloc failed");
1875 return false;
1877 #endif
1878 return mBackingSurface != nullptr;
1881 protected:
1882 typedef gfxASurface::gfxImageFormat ImageFormat;
1884 GLContext* mGLContext;
1886 nsIntRect mUpdateRect;
1887 ImageFormat mUpdateFormat;
1888 bool mUsingDirectTexture;
1889 nsRefPtr<gfxASurface> mBackingSurface;
1890 nsRefPtr<gfxASurface> mUpdateSurface;
1891 #ifdef MOZ_WIDGET_GONK
1892 sp<GraphicBuffer> mGraphicBuffer;
1893 #endif
1894 EGLImage mEGLImage;
1895 GLuint mTexture;
1896 EGLSurface mSurface;
1897 EGLConfig mConfig;
1898 TextureState mTextureState;
1900 bool mBound;
1901 bool mIsLocked;
1903 virtual void ApplyFilter()
1905 mGLContext->ApplyFilterToBoundTexture(mFilter);
1909 #ifdef MOZ_WIDGET_GONK
1911 class DirectTextureImageEGL
1912 : public TextureImageEGL
1914 public:
1915 DirectTextureImageEGL(GLuint aTexture,
1916 sp<GraphicBuffer> aGraphicBuffer,
1917 GLenum aWrapMode,
1918 GLContext* aContext)
1919 : TextureImageEGL(aTexture,
1920 nsIntSize(aGraphicBuffer->getWidth(), aGraphicBuffer->getHeight()),
1921 aWrapMode,
1922 ContentTypeForPixelFormat(aGraphicBuffer->getPixelFormat()),
1923 aContext,
1924 ForceSingleTile,
1925 Valid)
1927 mGraphicBuffer = aGraphicBuffer;
1929 const int eglImageAttributes[] =
1930 { LOCAL_EGL_IMAGE_PRESERVED, LOCAL_EGL_TRUE,
1931 LOCAL_EGL_NONE, LOCAL_EGL_NONE };
1933 mEGLImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(),
1934 EGL_NO_CONTEXT,
1935 EGL_NATIVE_BUFFER_ANDROID,
1936 mGraphicBuffer->getNativeBuffer(),
1937 eglImageAttributes);
1938 if (!mEGLImage) {
1939 LOG("Could not create EGL images: ERROR (0x%04x)", sEGLLibrary.fGetError());
1944 #endif // MOZ_WIDGET_GONK
1946 already_AddRefed<TextureImage>
1947 GLContextEGL::CreateTextureImage(const nsIntSize& aSize,
1948 TextureImage::ContentType aContentType,
1949 GLenum aWrapMode,
1950 TextureImage::Flags aFlags)
1952 nsRefPtr<TextureImage> t = new gl::TiledTextureImage(this, aSize, aContentType, aFlags);
1953 return t.forget();
1956 #ifdef MOZ_WIDGET_GONK
1957 already_AddRefed<TextureImage>
1958 GLContextEGL::CreateDirectTextureImage(GraphicBuffer* aBuffer,
1959 GLenum aWrapMode)
1961 MakeCurrent();
1963 GLuint texture;
1964 fGenTextures(1, &texture);
1966 nsRefPtr<TextureImage> texImage(
1967 new DirectTextureImageEGL(texture, aBuffer, aWrapMode, this));
1968 texImage->BindTexture(LOCAL_GL_TEXTURE0);
1970 GLint texfilter = LOCAL_GL_LINEAR;
1971 fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter);
1972 fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter);
1973 fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, aWrapMode);
1974 fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, aWrapMode);
1976 return texImage.forget();
1978 #endif // MOZ_WIDGET_GONK
1980 already_AddRefed<TextureImage>
1981 GLContextEGL::TileGenFunc(const nsIntSize& aSize,
1982 TextureImage::ContentType aContentType,
1983 TextureImage::Flags aFlags)
1985 MakeCurrent();
1987 GLuint texture;
1988 fGenTextures(1, &texture);
1990 nsRefPtr<TextureImageEGL> teximage =
1991 new TextureImageEGL(texture, aSize, LOCAL_GL_CLAMP_TO_EDGE, aContentType, this, aFlags);
1993 teximage->BindTexture(LOCAL_GL_TEXTURE0);
1995 GLint texfilter = aFlags & TextureImage::UseNearestFilter ? LOCAL_GL_NEAREST : LOCAL_GL_LINEAR;
1996 fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, texfilter);
1997 fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, texfilter);
1998 fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
1999 fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
2001 return teximage.forget();
2004 inline static ContextFormat
2005 DepthToGLFormat(int aDepth)
2007 switch (aDepth) {
2008 case 32:
2009 return ContextFormat::BasicRGBA32;
2010 case 24:
2011 return ContextFormat::BasicRGB24;
2012 case 16:
2013 return ContextFormat::BasicRGB16_565;
2014 default:
2015 break;
2017 return ContextFormat::BasicRGBA32;
2020 static nsRefPtr<GLContext> gGlobalContext;
2022 static const EGLint kEGLConfigAttribsRGB16[] = {
2023 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
2024 LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
2025 LOCAL_EGL_RED_SIZE, 5,
2026 LOCAL_EGL_GREEN_SIZE, 6,
2027 LOCAL_EGL_BLUE_SIZE, 5,
2028 LOCAL_EGL_ALPHA_SIZE, 0,
2029 LOCAL_EGL_NONE
2032 static const EGLint kEGLConfigAttribsRGB24[] = {
2033 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
2034 LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
2035 LOCAL_EGL_RED_SIZE, 8,
2036 LOCAL_EGL_GREEN_SIZE, 8,
2037 LOCAL_EGL_BLUE_SIZE, 8,
2038 LOCAL_EGL_NONE
2041 static const EGLint kEGLConfigAttribsRGBA32[] = {
2042 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
2043 LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
2044 LOCAL_EGL_RED_SIZE, 8,
2045 LOCAL_EGL_GREEN_SIZE, 8,
2046 LOCAL_EGL_BLUE_SIZE, 8,
2047 LOCAL_EGL_ALPHA_SIZE, 8,
2048 LOCAL_EGL_NONE
2051 static bool
2052 CreateConfig(EGLConfig* aConfig, int32_t depth)
2054 EGLConfig configs[64];
2055 const EGLint* attribs;
2056 EGLint ncfg = ArrayLength(configs);
2058 switch (depth) {
2059 case 16:
2060 attribs = kEGLConfigAttribsRGB16;
2061 break;
2062 case 24:
2063 attribs = kEGLConfigAttribsRGB24;
2064 break;
2065 case 32:
2066 attribs = kEGLConfigAttribsRGBA32;
2067 break;
2068 default:
2069 NS_ERROR("Unknown pixel depth");
2070 return false;
2073 if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(), attribs,
2074 configs, ncfg, &ncfg) ||
2075 ncfg < 1) {
2076 return false;
2079 for (int j = 0; j < ncfg; ++j) {
2080 EGLConfig config = configs[j];
2081 EGLint r, g, b, a;
2083 if (sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
2084 LOCAL_EGL_RED_SIZE, &r) &&
2085 sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
2086 LOCAL_EGL_GREEN_SIZE, &g) &&
2087 sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
2088 LOCAL_EGL_BLUE_SIZE, &b) &&
2089 sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
2090 LOCAL_EGL_ALPHA_SIZE, &a) &&
2091 ((depth == 16 && r == 5 && g == 6 && b == 5) ||
2092 (depth == 24 && r == 8 && g == 8 && b == 8) ||
2093 (depth == 32 && r == 8 && g == 8 && b == 8 && a == 8)))
2095 *aConfig = config;
2096 return true;
2099 return false;
2102 // Return true if a suitable EGLConfig was found and pass it out
2103 // through aConfig. Return false otherwise.
2105 // NB: It's entirely legal for the returned EGLConfig to be valid yet
2106 // have the value null.
2107 static bool
2108 CreateConfig(EGLConfig* aConfig)
2110 int32_t depth = gfxPlatform::GetPlatform()->GetScreenDepth();
2111 if (!CreateConfig(aConfig, depth)) {
2112 #ifdef MOZ_WIDGET_ANDROID
2113 // Bug 736005
2114 // Android doesn't always support 16 bit so also try 24 bit
2115 if (depth == 16) {
2116 return CreateConfig(aConfig, 24);
2118 #endif
2119 return false;
2120 } else {
2121 return true;
2125 // When MOZ_ANDROID_OMTC is defined,
2126 // use mozilla::AndroidBridge::Bridge()->ProvideEGLSurface() instead.
2127 #ifndef MOZ_ANDROID_OMTC
2128 static EGLSurface
2129 CreateSurfaceForWindow(nsIWidget *aWidget, EGLConfig config)
2131 EGLSurface surface;
2133 #ifdef DEBUG
2134 sEGLLibrary.DumpEGLConfig(config);
2135 #endif
2137 #if defined(MOZ_WIDGET_ANDROID)
2139 // On Android, we have to ask Java to make the eglCreateWindowSurface
2140 // call for us. See GLHelpers.java for a description of why.
2142 // We also only have one true "window", so we just use it directly and ignore
2143 // what was passed in.
2144 AndroidGeckoSurfaceView& sview = mozilla::AndroidBridge::Bridge()->SurfaceView();
2145 if (sview.isNull()) {
2146 printf_stderr("got null surface\n");
2147 return NULL;
2150 surface = mozilla::AndroidBridge::Bridge()->
2151 CallEglCreateWindowSurface(EGL_DISPLAY(), config, sview);
2152 #else
2153 surface = sEGLLibrary.fCreateWindowSurface(EGL_DISPLAY(), config, GET_NATIVE_WINDOW(aWidget), 0);
2154 #endif
2156 #ifdef MOZ_WIDGET_GONK
2157 gScreenBounds.x = 0;
2158 gScreenBounds.y = 0;
2159 sEGLLibrary.fQuerySurface(EGL_DISPLAY(), surface, LOCAL_EGL_WIDTH, &gScreenBounds.width);
2160 sEGLLibrary.fQuerySurface(EGL_DISPLAY(), surface, LOCAL_EGL_HEIGHT, &gScreenBounds.height);
2161 #endif
2163 return surface;
2165 #endif
2167 already_AddRefed<GLContext>
2168 GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget)
2170 EGLConfig config;
2172 if (!sEGLLibrary.EnsureInitialized()) {
2173 return nullptr;
2176 bool doubleBuffered = true;
2178 void* currentContext = sEGLLibrary.fGetCurrentContext();
2179 if (aWidget->HasGLContext() && currentContext) {
2180 int32_t depth = gfxPlatform::GetPlatform()->GetScreenDepth();
2181 void* platformContext = currentContext;
2182 #ifdef MOZ_WIDGET_QT
2183 QGLContext* context = const_cast<QGLContext*>(QGLContext::currentContext());
2184 if (context && context->device()) {
2185 depth = context->device()->depth();
2187 doubleBuffered = context->format().doubleBuffer();
2188 platformContext = context;
2189 #endif
2190 nsRefPtr<GLContextEGL> glContext =
2191 new GLContextEGL(ContextFormat(DepthToGLFormat(depth)),
2192 gGlobalContext,
2193 NULL,
2194 sEGLLibrary.fGetCurrentSurface(LOCAL_EGL_DRAW), // just use same surface for read and draw
2195 currentContext,
2196 false);
2198 if (!glContext->Init())
2199 return nullptr;
2201 glContext->MakeCurrent();
2202 sEGLLibrary.LoadConfigSensitiveSymbols();
2204 glContext->SetIsDoubleBuffered(doubleBuffered);
2206 glContext->SetPlatformContext(platformContext);
2207 if (!gGlobalContext) {
2208 gGlobalContext = glContext;
2211 return glContext.forget();
2214 if (!CreateConfig(&config)) {
2215 printf_stderr("Failed to create EGL config!\n");
2216 return nullptr;
2219 #ifdef MOZ_ANDROID_OMTC
2220 mozilla::AndroidBridge::Bridge()->RegisterCompositor();
2221 EGLSurface surface = mozilla::AndroidBridge::Bridge()->ProvideEGLSurface();
2222 #else
2223 EGLSurface surface = CreateSurfaceForWindow(aWidget, config);
2224 #endif
2226 if (!surface) {
2227 return nullptr;
2230 if (!sEGLLibrary.fBindAPI(LOCAL_EGL_OPENGL_ES_API)) {
2231 sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
2232 return nullptr;
2235 GLContextEGL *shareContext = GetGlobalContextEGL();
2237 nsRefPtr<GLContextEGL> glContext =
2238 GLContextEGL::CreateGLContext(ContextFormat(ContextFormat::BasicRGB24),
2239 surface,
2240 config,
2241 shareContext,
2242 false);
2244 if (!glContext) {
2245 return nullptr;
2248 glContext->MakeCurrent();
2249 sEGLLibrary.LoadConfigSensitiveSymbols();
2250 glContext->SetIsDoubleBuffered(doubleBuffered);
2252 return glContext.forget();
2255 static void
2256 FillPBufferAttribs_Minimal(nsTArray<EGLint>& aAttrs)
2258 aAttrs.Clear();
2260 #define A1(_x) do { aAttrs.AppendElement(_x); } while (0)
2261 #define A2(_x,_y) do { A1(_x); A1(_y); } while (0)
2263 A2(LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT);
2265 A2(LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT);
2267 A1(LOCAL_EGL_NONE);
2268 #undef A1
2269 #undef A2
2272 static void
2273 FillPBufferAttribs(nsTArray<EGLint>& aAttrs,
2274 const ContextFormat& aFormat,
2275 bool aCanBindToTexture,
2276 int aColorBitsOverride,
2277 int aDepthBitsOverride)
2279 aAttrs.Clear();
2281 #define A1(_x) do { aAttrs.AppendElement(_x); } while (0)
2282 #define A2(_x,_y) do { A1(_x); A1(_y); } while (0)
2284 A2(LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT);
2286 A2(LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT);
2288 if (aColorBitsOverride == -1) {
2289 A2(LOCAL_EGL_RED_SIZE, aFormat.red);
2290 A2(LOCAL_EGL_GREEN_SIZE, aFormat.green);
2291 A2(LOCAL_EGL_BLUE_SIZE, aFormat.blue);
2292 } else {
2293 A2(LOCAL_EGL_RED_SIZE, aColorBitsOverride);
2294 A2(LOCAL_EGL_GREEN_SIZE, aColorBitsOverride);
2295 A2(LOCAL_EGL_BLUE_SIZE, aColorBitsOverride);
2298 A2(LOCAL_EGL_ALPHA_SIZE, aFormat.alpha);
2300 if (aDepthBitsOverride == -1) {
2301 A2(LOCAL_EGL_DEPTH_SIZE, aFormat.minDepth);
2302 } else {
2303 A2(LOCAL_EGL_DEPTH_SIZE, aDepthBitsOverride);
2306 A2(LOCAL_EGL_STENCIL_SIZE, aFormat.minStencil);
2308 if (aCanBindToTexture) {
2309 A2(aFormat.minAlpha ? LOCAL_EGL_BIND_TO_TEXTURE_RGBA : LOCAL_EGL_BIND_TO_TEXTURE_RGB,
2310 LOCAL_EGL_TRUE);
2313 A1(LOCAL_EGL_NONE);
2314 #undef A1
2315 #undef A2
2318 already_AddRefed<GLContextEGL>
2319 GLContextEGL::CreateEGLPBufferOffscreenContext(const gfxIntSize& aSize,
2320 const ContextFormat& aFormat,
2321 bool bufferUnused)
2323 EGLConfig config;
2324 EGLSurface surface;
2325 EGLContext context;
2327 bool configCanBindToTexture = true;
2329 EGLConfig configs[64];
2330 int numConfigs = sizeof(configs)/sizeof(EGLConfig);
2331 int foundConfigs = 0;
2333 // if we're running under ANGLE, we can't set BIND_TO_TEXTURE --
2334 // it's not supported, and we have dx interop pbuffers anyway
2335 if (sEGLLibrary.IsANGLE() || bufferUnused)
2336 configCanBindToTexture = false;
2338 nsTArray<EGLint> attribs(32);
2339 int attribAttempt = 0;
2341 int tryDepthSize = (aFormat.depth > 0) ? 24 : 0;
2343 TRY_ATTRIBS_AGAIN:
2344 if (bufferUnused) {
2345 FillPBufferAttribs_Minimal(attribs);
2346 } else {
2347 switch (attribAttempt) {
2348 case 0:
2349 FillPBufferAttribs(attribs, aFormat, configCanBindToTexture, 8, tryDepthSize);
2350 break;
2351 case 1:
2352 FillPBufferAttribs(attribs, aFormat, configCanBindToTexture, -1, tryDepthSize);
2353 break;
2354 case 2:
2355 FillPBufferAttribs(attribs, aFormat, configCanBindToTexture, -1, -1);
2356 break;
2360 if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(),
2361 &attribs[0],
2362 configs, numConfigs,
2363 &foundConfigs)
2364 || foundConfigs == 0)
2366 if (bufferUnused) {
2367 NS_WARNING("No EGL Config for minimal PBuffer!");
2368 return nullptr;
2371 if (attribAttempt < 3) {
2372 attribAttempt++;
2373 goto TRY_ATTRIBS_AGAIN;
2376 if (configCanBindToTexture) {
2377 NS_WARNING("No pbuffer EGL configs that can bind to texture, trying without");
2378 configCanBindToTexture = false;
2379 attribAttempt = 0;
2380 goto TRY_ATTRIBS_AGAIN;
2383 // no configs? no pbuffers!
2384 NS_WARNING("Failed to select acceptable config for PBuffer creation!");
2385 return nullptr;
2388 // XXX do some smarter matching here, perhaps instead of the more complex
2389 // minimum overrides above
2390 config = configs[0];
2391 #ifdef DEBUG
2392 sEGLLibrary.DumpEGLConfig(config);
2393 #endif
2395 gfxIntSize pbsize(aSize);
2396 surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(config,
2397 configCanBindToTexture
2398 ? (aFormat.minAlpha
2399 ? LOCAL_EGL_TEXTURE_RGBA
2400 : LOCAL_EGL_TEXTURE_RGB)
2401 : LOCAL_EGL_NONE,
2402 pbsize);
2403 if (!surface) {
2404 NS_WARNING("Failed to create PBuffer for context!");
2405 return nullptr;
2408 sEGLLibrary.fBindAPI(LOCAL_EGL_OPENGL_ES_API);
2410 GLContextEGL* shareContext = GetGlobalContextEGL();
2411 context = sEGLLibrary.fCreateContext(EGL_DISPLAY(),
2412 config,
2413 shareContext ? shareContext->mContext
2414 : EGL_NO_CONTEXT,
2415 sEGLLibrary.HasRobustness() ? gContextAttribsRobustness
2416 : gContextAttribs);
2417 if (!context) {
2418 NS_WARNING("Failed to create GLContext from PBuffer");
2419 sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
2420 return nullptr;
2423 nsRefPtr<GLContextEGL> glContext = new GLContextEGL(aFormat, shareContext,
2424 config, surface, context,
2425 true);
2427 if (!glContext->Init()) {
2428 NS_WARNING("Failed to initialize GLContext!");
2429 return nullptr;
2432 glContext->mCanBindToTexture = configCanBindToTexture;
2434 if (!bufferUnused) { // We *are* using the buffer
2435 glContext->SetOffscreenSize(aSize, pbsize);
2436 glContext->mIsPBuffer = true;
2439 return glContext.forget();
2442 #ifdef MOZ_X11
2443 EGLSurface
2444 CreateEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig)
2446 gfxXlibSurface* xsurface = static_cast<gfxXlibSurface*>(aSurface);
2447 bool opaque =
2448 aSurface->GetContentType() == gfxASurface::CONTENT_COLOR;
2450 static EGLint pixmap_config_rgb[] = {
2451 LOCAL_EGL_TEXTURE_TARGET, LOCAL_EGL_TEXTURE_2D,
2452 LOCAL_EGL_TEXTURE_FORMAT, LOCAL_EGL_TEXTURE_RGB,
2453 LOCAL_EGL_NONE
2456 static EGLint pixmap_config_rgba[] = {
2457 LOCAL_EGL_TEXTURE_TARGET, LOCAL_EGL_TEXTURE_2D,
2458 LOCAL_EGL_TEXTURE_FORMAT, LOCAL_EGL_TEXTURE_RGBA,
2459 LOCAL_EGL_NONE
2462 EGLSurface surface = nullptr;
2463 if (aConfig && *aConfig) {
2464 if (opaque)
2465 surface = sEGLLibrary.fCreatePixmapSurface(EGL_DISPLAY(), *aConfig,
2466 (EGLNativePixmapType)xsurface->XDrawable(),
2467 pixmap_config_rgb);
2468 else
2469 surface = sEGLLibrary.fCreatePixmapSurface(EGL_DISPLAY(), *aConfig,
2470 (EGLNativePixmapType)xsurface->XDrawable(),
2471 pixmap_config_rgba);
2473 if (surface != EGL_NO_SURFACE)
2474 return surface;
2477 EGLConfig configs[32];
2478 int numConfigs = 32;
2480 static EGLint pixmap_config[] = {
2481 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PIXMAP_BIT,
2482 LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
2483 LOCAL_EGL_DEPTH_SIZE, 0,
2484 LOCAL_EGL_BIND_TO_TEXTURE_RGB, LOCAL_EGL_TRUE,
2485 LOCAL_EGL_NONE
2488 static EGLint pixmap_lock_config[] = {
2489 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PIXMAP_BIT | LOCAL_EGL_LOCK_SURFACE_BIT_KHR,
2490 LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
2491 LOCAL_EGL_DEPTH_SIZE, 0,
2492 LOCAL_EGL_BIND_TO_TEXTURE_RGB, LOCAL_EGL_TRUE,
2493 LOCAL_EGL_NONE
2496 if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(),
2497 sEGLLibrary.HasKHRLockSurface() ?
2498 pixmap_lock_config : pixmap_config,
2499 configs, numConfigs, &numConfigs))
2500 return nullptr;
2502 if (numConfigs == 0)
2503 return nullptr;
2505 int i = 0;
2506 for (i = 0; i < numConfigs; ++i) {
2507 if (opaque)
2508 surface = sEGLLibrary.fCreatePixmapSurface(EGL_DISPLAY(), configs[i],
2509 (EGLNativePixmapType)xsurface->XDrawable(),
2510 pixmap_config_rgb);
2511 else
2512 surface = sEGLLibrary.fCreatePixmapSurface(EGL_DISPLAY(), configs[i],
2513 (EGLNativePixmapType)xsurface->XDrawable(),
2514 pixmap_config_rgba);
2516 if (surface != EGL_NO_SURFACE)
2517 break;
2520 if (!surface) {
2521 return nullptr;
2524 if (aConfig)
2525 *aConfig = configs[i];
2527 return surface;
2529 #endif
2531 already_AddRefed<GLContextEGL>
2532 GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& aSize,
2533 const ContextFormat& aFormat,
2534 bool aShare)
2536 gfxASurface *thebesSurface = nullptr;
2537 EGLNativePixmapType pixmap = 0;
2539 #ifdef MOZ_X11
2540 nsRefPtr<gfxXlibSurface> xsurface =
2541 gfxXlibSurface::Create(DefaultScreenOfDisplay(DefaultXDisplay()),
2542 gfxXlibSurface::FindRenderFormat(DefaultXDisplay(),
2543 gfxASurface::ImageFormatRGB24),
2544 aSize);
2546 // XSync required after gfxXlibSurface::Create, otherwise EGL will fail with BadDrawable error
2547 XSync(DefaultXDisplay(), False);
2548 if (xsurface->CairoStatus() != 0)
2549 return nullptr;
2551 thebesSurface = xsurface;
2552 pixmap = (EGLNativePixmapType)xsurface->XDrawable();
2553 #endif
2555 if (!pixmap) {
2556 return nullptr;
2559 EGLSurface surface = 0;
2560 EGLConfig config = 0;
2562 #ifdef MOZ_X11
2563 surface = CreateEGLSurfaceForXSurface(thebesSurface, &config);
2564 #endif
2565 if (!config) {
2566 return nullptr;
2569 GLContextEGL *shareContext = aShare ? GetGlobalContextEGL() : nullptr;
2571 nsRefPtr<GLContextEGL> glContext =
2572 GLContextEGL::CreateGLContext(aFormat,
2573 surface,
2574 config,
2575 shareContext,
2576 true);
2578 glContext->HoldSurface(thebesSurface);
2580 return glContext.forget();
2583 // Under EGL, if we're under X11, then we have to create a Pixmap
2584 // because Maemo's EGL implementation doesn't support pbuffers at all
2585 // for some reason. On Android, pbuffers are supported fine, though
2586 // often without the ability to texture from them directly.
2587 already_AddRefed<GLContext>
2588 GLContextProviderEGL::CreateOffscreen(const gfxIntSize& aSize,
2589 const ContextFormat& aFormat,
2590 const ContextFlags aFlags)
2592 if (!sEGLLibrary.EnsureInitialized()) {
2593 return nullptr;
2596 #if !defined(MOZ_X11)
2597 bool usePBuffers = false; // Generally, prefer FBOs to PBuffers
2599 if (sEGLLibrary.IsANGLE())
2600 usePBuffers = true; // For d3d share handle, we need an EGL surface
2602 gfxIntSize pbufferSize = usePBuffers ? aSize : gfxIntSize(16, 16);
2603 nsRefPtr<GLContextEGL> glContext =
2604 GLContextEGL::CreateEGLPBufferOffscreenContext(pbufferSize, aFormat, !usePBuffers);
2606 if (!glContext)
2607 return nullptr;
2609 gfxIntSize fboSize = usePBuffers ? glContext->OffscreenActualSize() : aSize;
2610 if (!(aFlags & GLContext::ContextFlagsGlobal) && !glContext->ResizeOffscreenFBOs(fboSize, !usePBuffers))
2611 return nullptr;
2613 return glContext.forget();
2614 #elif defined(MOZ_X11) && defined(MOZ_EGL_XRENDER_COMPOSITE)
2615 nsRefPtr<GLContextEGL> glContext =
2616 GLContextEGL::CreateBasicEGLPixmapOffscreenContext(aSize, aFormat);
2618 if (!glContext)
2619 return nullptr;
2621 if (!(aFlags & GLContext::ContextFlagsGlobal) && !glContext->ResizeOffscreenFBOs(glContext->OffscreenActualSize(), true))
2622 return nullptr;
2624 return glContext.forget();
2625 #elif defined(MOZ_X11)
2626 nsRefPtr<GLContextEGL> glContext =
2627 GLContextEGL::CreateEGLPixmapOffscreenContext(gfxIntSize(16, 16), aFormat, true);
2629 if (!glContext) {
2630 return nullptr;
2633 if (!(aFlags & GLContext::ContextFlagsGlobal) && !glContext->ResizeOffscreenFBOs(aSize, true)) {
2634 // we weren't able to create the initial
2635 // offscreen FBO, so this is dead
2636 return nullptr;
2638 return glContext.forget();
2639 #else
2640 return nullptr;
2641 #endif
2644 GLContext *
2645 GLContextProviderEGL::GetGlobalContext(const ContextFlags)
2647 // Don't want a global context on Android as 1) share groups across 2 threads fail on many Tegra drivers (bug 759225)
2648 // and 2) some mobile devices have a very strict limit on global number of GL contexts (bug 754257)
2649 #ifdef MOZ_ANDROID_OMTC
2650 return nullptr;
2651 #endif
2653 // Don't want a global context on Windows as we don't use it for WebGL surface sharing and it makes
2654 // context creation fail after a context loss (bug 764578)
2655 #ifdef XP_WIN
2656 return nullptr;
2657 #endif
2660 static bool triedToCreateContext = false;
2661 if (!triedToCreateContext && !gGlobalContext) {
2662 triedToCreateContext = true;
2663 // Don't assign directly to gGlobalContext here, because
2664 // CreateOffscreen can call us re-entrantly.
2665 nsRefPtr<GLContext> ctx =
2666 GLContextProviderEGL::CreateOffscreen(gfxIntSize(16, 16),
2667 ContextFormat(ContextFormat::BasicRGB24),
2668 GLContext::ContextFlagsGlobal);
2669 gGlobalContext = ctx;
2670 if (gGlobalContext)
2671 gGlobalContext->SetIsGlobalSharedContext(true);
2674 return gGlobalContext;
2677 void
2678 GLContextProviderEGL::Shutdown()
2680 gGlobalContext = nullptr;
2683 //------------------------------------------------------------------------------
2684 // The following methods exist to support an accelerated WebGL XRender composite
2685 // path for BasicLayers. This is a potentially temporary change that can be
2686 // removed when performance of GL layers is superior on mobile linux platforms.
2687 //------------------------------------------------------------------------------
2688 #if defined(MOZ_X11) && defined(MOZ_EGL_XRENDER_COMPOSITE)
2690 EGLSurface
2691 CreateBasicEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig)
2693 gfxXlibSurface* xsurface = static_cast<gfxXlibSurface*>(aSurface);
2695 bool opaque =
2696 aSurface->GetContentType() == gfxASurface::CONTENT_COLOR;
2698 EGLSurface surface = nullptr;
2699 if (aConfig && *aConfig) {
2700 surface = sEGLLibrary.fCreatePixmapSurface(EGL_DISPLAY(), *aConfig,
2701 xsurface->XDrawable(),
2704 if (surface != EGL_NO_SURFACE)
2705 return surface;
2708 EGLConfig configs[32];
2709 int numConfigs = 32;
2711 static EGLint pixmap_config[] = {
2712 LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PIXMAP_BIT,
2713 LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
2714 0x30E2, 0x30E3,
2715 LOCAL_EGL_DEPTH_SIZE, 16,
2716 LOCAL_EGL_NONE
2719 if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(),
2720 pixmap_config,
2721 configs, numConfigs, &numConfigs))
2722 return nullptr;
2724 if (numConfigs == 0)
2725 return nullptr;
2727 int i = 0;
2728 for (i = 0; i < numConfigs; ++i) {
2729 surface = sEGLLibrary.fCreatePixmapSurface(EGL_DISPLAY(), configs[i],
2730 xsurface->XDrawable(),
2733 if (surface != EGL_NO_SURFACE)
2734 break;
2737 if (!surface) {
2738 return nullptr;
2741 if (aConfig)
2743 *aConfig = configs[i];
2746 return surface;
2749 already_AddRefed<GLContextEGL>
2750 GLContextEGL::CreateBasicEGLPixmapOffscreenContext(const gfxIntSize& aSize,
2751 const ContextFormat& aFormat)
2753 gfxASurface *thebesSurface = nullptr;
2754 EGLNativePixmapType pixmap = 0;
2756 XRenderPictFormat* format = gfxXlibSurface::FindRenderFormat(DefaultXDisplay(), gfxASurface::ImageFormatARGB32);
2758 nsRefPtr<gfxXlibSurface> xsurface =
2759 gfxXlibSurface::Create(DefaultScreenOfDisplay(DefaultXDisplay()), format, aSize);
2761 // XSync required after gfxXlibSurface::Create, otherwise EGL will fail with BadDrawable error
2762 XSync(DefaultXDisplay(), False);
2763 if (xsurface->CairoStatus() != 0)
2765 return nullptr;
2768 thebesSurface = xsurface;
2770 pixmap = xsurface->XDrawable();
2772 if (!pixmap) {
2773 return nullptr;
2776 EGLSurface surface = 0;
2777 EGLConfig config = 0;
2779 surface = CreateBasicEGLSurfaceForXSurface(xsurface, &config);
2781 if (!config) {
2782 return nullptr;
2785 EGLContext context = sEGLLibrary.fCreateContext(EGL_DISPLAY(),
2786 config,
2787 EGL_NO_CONTEXT,
2788 sEGLLibrary.HasRobustness() ? gContextAttribsRobustness
2789 : gContextAttribs);
2790 if (!context) {
2791 sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
2792 return nullptr;
2795 nsRefPtr<GLContextEGL> glContext = new GLContextEGL(aFormat, nullptr,
2796 config, surface, context,
2797 true);
2799 if (!glContext->Init())
2801 return nullptr;
2804 glContext->HoldSurface(thebesSurface);
2806 return glContext.forget();
2809 bool GLContextEGL::ResizeOffscreenPixmapSurface(const gfxIntSize& aNewSize)
2811 gfxASurface *thebesSurface = nullptr;
2812 EGLNativePixmapType pixmap = 0;
2814 XRenderPictFormat* format = gfxXlibSurface::FindRenderFormat(DefaultXDisplay(), gfxASurface::ImageFormatARGB32);
2816 nsRefPtr<gfxXlibSurface> xsurface =
2817 gfxXlibSurface::Create(DefaultScreenOfDisplay(DefaultXDisplay()),
2818 format,
2819 aNewSize);
2821 // XSync required after gfxXlibSurface::Create, otherwise EGL will fail with BadDrawable error
2822 XSync(DefaultXDisplay(), False);
2823 if (xsurface->CairoStatus() != 0)
2824 return nullptr;
2826 thebesSurface = xsurface;
2828 pixmap = xsurface->XDrawable();
2830 if (!pixmap) {
2831 return nullptr;
2834 EGLSurface surface = 0;
2835 EGLConfig config = 0;
2836 surface = CreateBasicEGLSurfaceForXSurface(xsurface, &config);
2837 if (!surface) {
2838 NS_WARNING("Failed to resize pbuffer");
2839 return nullptr;
2842 sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface);
2844 mSurface = surface;
2845 HoldSurface(thebesSurface);
2846 SetOffscreenSize(aNewSize, aNewSize);
2847 MakeCurrent(true);
2849 return true;
2852 #endif
2854 } /* namespace gl */
2855 } /* namespace mozilla */