diff --git a/config/autoconf.mk.in b/config/autoconf.mk.in index e8c563c8c7b7..890242d5f357 100644 --- a/config/autoconf.mk.in +++ b/config/autoconf.mk.in @@ -330,6 +330,7 @@ XCOMPOSITE_LIBS = @XCOMPOSITE_LIBS@ XSS_LIBS = @XSS_LIBS@ MOZ_THUMB2 = @MOZ_THUMB2@ +MOZ_EGL_XRENDER_COMPOSITE = @MOZ_EGL_XRENDER_COMPOSITE@ WIN_TOP_SRC = @WIN_TOP_SRC@ AR = @AR@ diff --git a/configure.in b/configure.in index f0f75f3e1475..1bd32aa7070a 100644 --- a/configure.in +++ b/configure.in @@ -7178,6 +7178,20 @@ fi # CPU_ARCH = arm AC_SUBST(HAVE_ARM_SIMD) AC_SUBST(HAVE_ARM_NEON) +dnl ======================================================== +dnl = XRender Composite +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(egl-xrender-composite, +[ --enable-egl-xrender-composite + Enable EGL xrender composite optimizations], + MOZ_EGL_XRENDER_COMPOSITE=1) + +if test -n "$MOZ_EGL_XRENDER_COMPOSITE"; then + AC_DEFINE(MOZ_EGL_XRENDER_COMPOSITE) +fi + +AC_SUBST(MOZ_EGL_XRENDER_COMPOSITE) + dnl ======================================================== dnl = faststripe theme dnl ======================================================== diff --git a/gfx/cairo/cairo/src/cairo-xlib-display.c b/gfx/cairo/cairo/src/cairo-xlib-display.c index 139e63149614..7a382911fb0a 100644 --- a/gfx/cairo/cairo/src/cairo-xlib-display.c +++ b/gfx/cairo/cairo/src/cairo-xlib-display.c @@ -422,9 +422,11 @@ _cairo_xlib_device_create (Display *dpy) if (VendorRelease (dpy) < 10400000) display->buggy_repeat = TRUE; +#ifndef MOZ_EGL_XRENDER_COMPOSITE /* Too many bugs in the early drivers */ if (VendorRelease (dpy) < 10699000) display->buggy_pad_reflect = TRUE; +#endif } } else if (strstr (ServerVendor (dpy), "XFree86") != NULL) { if (VendorRelease (dpy) <= 40500000) diff --git a/gfx/layers/basic/BasicLayers.cpp b/gfx/layers/basic/BasicLayers.cpp index 6488861cecc8..b5e5fb05b793 100644 --- a/gfx/layers/basic/BasicLayers.cpp +++ b/gfx/layers/basic/BasicLayers.cpp @@ -1082,6 +1082,22 @@ BasicCanvasLayer::UpdateSurface(gfxASurface* aDestSurface) return; } + // We need to read from the GLContext + mGLContext->MakeCurrent(); + +#if defined (MOZ_X11) && defined (MOZ_EGL_XRENDER_COMPOSITE) + mGLContext->fFinish(); + gfxASurface* offscreenSurface = mGLContext->GetOffscreenPixmapSurface(); + + // XRender can only blend premuliplied alpha, so only allow xrender + // path if we have premultiplied alpha or opaque content. + if (offscreenSurface && (mGLBufferIsPremultiplied || (GetContentFlags() & CONTENT_OPAQUE))) { + mSurface = offscreenSurface; + mNeedsYFlip = false; + } + else +#endif + { nsRefPtr isurf = aDestSurface ? static_cast(aDestSurface) : new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height), @@ -1095,9 +1111,6 @@ BasicCanvasLayer::UpdateSurface(gfxASurface* aDestSurface) NS_ASSERTION(isurf->Stride() == mBounds.width * 4, "gfxImageSurface stride isn't what we expect!"); - // We need to read from the GLContext - mGLContext->MakeCurrent(); - // We have to flush to ensure that any buffered GL operations are // in the framebuffer before we read. mGLContext->fFlush(); @@ -1132,6 +1145,7 @@ BasicCanvasLayer::UpdateSurface(gfxASurface* aDestSurface) } } } +} void BasicCanvasLayer::Paint(gfxContext* aContext) @@ -1162,6 +1176,15 @@ BasicCanvasLayer::PaintWithOpacity(gfxContext* aContext, aContext->Scale(1.0, -1.0); } + // If content opaque, then save off current operator and set to source. + // This ensures that alpha is not applied even if the source surface + // has an alpha channel + gfxContext::GraphicsOperator savedOp; + if (GetContentFlags() & CONTENT_OPAQUE) { + savedOp = aContext->CurrentOperator(); + aContext->SetOperator(gfxContext::OPERATOR_SOURCE); + } + AutoSetOperator setOperator(aContext, GetOperator()); aContext->NewPath(); // No need to snap here; our transform is already set up to snap our rect @@ -1169,6 +1192,19 @@ BasicCanvasLayer::PaintWithOpacity(gfxContext* aContext, aContext->SetPattern(pat); aContext->FillWithOpacity(aOpacity); +#if defined (MOZ_X11) && defined (MOZ_EGL_XRENDER_COMPOSITE) + if (mGLContext) { + // Wait for X to complete all operations before continuing + // Otherwise gl context could get cleared before X is done. + mGLContext->WaitNative(); + } +#endif + + // Restore surface operator + if (GetContentFlags() & CONTENT_OPAQUE) { + aContext->SetOperator(savedOp); + } + if (mNeedsYFlip) { aContext->SetMatrix(m); } diff --git a/gfx/thebes/GLContext.h b/gfx/thebes/GLContext.h index 679f3354734c..5bb6f850be62 100644 --- a/gfx/thebes/GLContext.h +++ b/gfx/thebes/GLContext.h @@ -66,7 +66,7 @@ #include "nsAutoPtr.h" #include "nsThreadUtils.h" -#if defined(MOZ_PLATFORM_MAEMO) || defined(ANDROID) +#if defined(MOZ_PLATFORM_MAEMO) || defined(ANDROID) || defined(MOZ_EGL_XRENDER_COMPOSITE) #define USE_GLES2 1 #endif @@ -737,6 +737,15 @@ public: return mOffscreenTexture; } +#if defined(MOZ_X11) && defined(MOZ_EGL_XRENDER_COMPOSITE) + virtual gfxASurface* GetOffscreenPixmapSurface() + { + return 0; + }; + + virtual PRBool WaitNative() { return PR_FALSE; } +#endif + virtual PRBool TextureImageSupportsGetBackingSurface() { return PR_FALSE; } diff --git a/gfx/thebes/GLContextProvider.h b/gfx/thebes/GLContextProvider.h index e86c9ca66526..8fa4db452841 100644 --- a/gfx/thebes/GLContextProvider.h +++ b/gfx/thebes/GLContextProvider.h @@ -84,6 +84,14 @@ namespace gl { #endif #endif +// X11, with XRender optimizations and no GL layer support +#if defined(MOZ_X11) && defined(MOZ_EGL_XRENDER_COMPOSITE) && !defined(GL_CONTEXT_PROVIDER_DEFAULT) +#define GL_CONTEXT_PROVIDER_NAME GLContextProviderEGL +#include "GLContextProviderImpl.h" +#undef GL_CONTEXT_PROVIDER_NAME +#define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderEGL +#endif + // X11, but only if we didn't use EGL above #if defined(MOZ_X11) && !defined(GL_CONTEXT_PROVIDER_DEFAULT) #define GL_CONTEXT_PROVIDER_NAME GLContextProviderGLX diff --git a/gfx/thebes/GLContextProviderEGL.cpp b/gfx/thebes/GLContextProviderEGL.cpp index c40323637b96..4cb4620cc580 100644 --- a/gfx/thebes/GLContextProviderEGL.cpp +++ b/gfx/thebes/GLContextProviderEGL.cpp @@ -192,6 +192,12 @@ CreateSurfaceForWindow(nsIWidget *aWidget, EGLConfig config); EGLConfig CreateConfig(); #ifdef MOZ_X11 + +#ifdef MOZ_EGL_XRENDER_COMPOSITE +static EGLSurface +CreateBasicEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig); +#endif + static EGLConfig CreateEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig = nsnull, EGLenum aDepth = 0); #endif @@ -391,7 +397,11 @@ public: return PR_FALSE; } +#if defined(MOZ_X11) && defined(MOZ_EGL_XRENDER_COMPOSITE) + mEGLDisplay = fGetDisplay((EGLNativeDisplayType) gdk_x11_get_default_xdisplay()); +#else mEGLDisplay = fGetDisplay(EGL_DEFAULT_DISPLAY); +#endif if (!fInitialize(mEGLDisplay, NULL, NULL)) return PR_FALSE; @@ -720,6 +730,17 @@ public: mIsDoubleBuffered = aIsDB; } +#if defined(MOZ_X11) && defined(MOZ_EGL_XRENDER_COMPOSITE) + gfxASurface* GetOffscreenPixmapSurface() + { + return mThebesSurface; + } + + virtual PRBool WaitNative() { + return sEGLLibrary.fWaitNative(LOCAL_EGL_CORE_NATIVE_ENGINE); + } +#endif + PRBool BindTexImage() { if (!mSurface) @@ -857,6 +878,14 @@ public: const ContextFormat& aFormat, PRBool aShare); +#if defined(MOZ_X11) && defined(MOZ_EGL_XRENDER_COMPOSITE) + static already_AddRefed + CreateBasicEGLPixmapOffscreenContext(const gfxIntSize& aSize, + const ContextFormat& aFormat); + + PRBool ResizeOffscreenPixmapSurface(const gfxIntSize& aNewSize); +#endif + static already_AddRefed CreateEGLPBufferOffscreenContext(const gfxIntSize& aSize, const ContextFormat& aFormat); @@ -1060,6 +1089,10 @@ GLContextEGL::ResizeOffscreen(const gfxIntSize& aNewSize) } #endif +#if defined(MOZ_X11) && defined(MOZ_EGL_XRENDER_COMPOSITE) + return ResizeOffscreenPixmapSurface(aNewSize); +#endif + return ResizeOffscreenFBO(aNewSize); } @@ -2139,6 +2172,8 @@ GLContextProviderEGL::CreateOffscreen(const gfxIntSize& aSize, #if defined(ANDROID) || defined(XP_WIN) return GLContextEGL::CreateEGLPBufferOffscreenContext(aSize, aFormat); +#elif defined(MOZ_X11) && defined(MOZ_EGL_XRENDER_COMPOSITE) + return GLContextEGL::CreateBasicEGLPixmapOffscreenContext(aSize, aFormat); #elif defined(MOZ_X11) nsRefPtr glContext = GLContextEGL::CreateEGLPixmapOffscreenContext(aSize, aFormat, PR_TRUE); @@ -2241,6 +2276,181 @@ GLContextProviderEGL::Shutdown() gGlobalContext = nsnull; } +//------------------------------------------------------------------------------ +// The following methods exist to support an accelerated WebGL XRender composite +// path for BasicLayers. This is a potentially temporary change that can be +// removed when performance of GL layers is superior on mobile linux platforms. +//------------------------------------------------------------------------------ +#if defined(MOZ_X11) && defined(MOZ_EGL_XRENDER_COMPOSITE) + +EGLSurface +CreateBasicEGLSurfaceForXSurface(gfxASurface* aSurface, EGLConfig* aConfig) +{ + gfxXlibSurface* xsurface = static_cast(aSurface); + + PRBool opaque = + aSurface->GetContentType() == gfxASurface::CONTENT_COLOR; + + EGLSurface surface = nsnull; + if (aConfig && *aConfig) { + surface = sEGLLibrary.fCreatePixmapSurface(EGL_DISPLAY(), *aConfig, + xsurface->XDrawable(), + 0); + + if (surface != EGL_NO_SURFACE) + return surface; + } + + EGLConfig configs[32]; + int numConfigs = 32; + + static EGLint pixmap_config[] = { + LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PIXMAP_BIT, + LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT, + 0x30E2, 0x30E3, + LOCAL_EGL_DEPTH_SIZE, 16, + LOCAL_EGL_NONE + }; + + if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(), + pixmap_config, + configs, numConfigs, &numConfigs)) + return nsnull; + + if (numConfigs == 0) + return nsnull; + + int i = 0; + for (i = 0; i < numConfigs; ++i) { + surface = sEGLLibrary.fCreatePixmapSurface(EGL_DISPLAY(), configs[i], + xsurface->XDrawable(), + 0); + + if (surface != EGL_NO_SURFACE) + break; + } + + if (!surface) { + return nsnull; + } + + if (aConfig) + { + *aConfig = configs[i]; + } + + return surface; +} + +already_AddRefed +GLContextEGL::CreateBasicEGLPixmapOffscreenContext(const gfxIntSize& aSize, + const ContextFormat& aFormat) +{ + gfxASurface *thebesSurface = nsnull; + EGLNativePixmapType pixmap = 0; + + XRenderPictFormat* format = gfxXlibSurface::FindRenderFormat(DefaultXDisplay(), gfxASurface::ImageFormatARGB32); + + nsRefPtr xsurface = + gfxXlibSurface::Create(DefaultScreenOfDisplay(DefaultXDisplay()), format, aSize); + + // XSync required after gfxXlibSurface::Create, otherwise EGL will fail with BadDrawable error + XSync(DefaultXDisplay(), False); + if (xsurface->CairoStatus() != 0) + { + return nsnull; + } + + thebesSurface = xsurface; + + pixmap = xsurface->XDrawable(); + + if (!pixmap) { + return nsnull; + } + + EGLSurface surface = 0; + EGLConfig config = 0; + + surface = CreateBasicEGLSurfaceForXSurface(xsurface, &config); + + if (!config) { + return nsnull; + } + + EGLint cxattribs[] = { + LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2, + LOCAL_EGL_NONE + }; + + EGLContext context = sEGLLibrary.fCreateContext(EGL_DISPLAY(), + config, + EGL_NO_CONTEXT, + cxattribs); + if (!context) { + sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface); + return nsnull; + } + + nsRefPtr glContext = new GLContextEGL(aFormat, nsnull, + config, surface, context, + PR_TRUE); + + if (!glContext->Init()) + { + return nsnull; + } + + glContext->HoldSurface(thebesSurface); + + return glContext.forget(); +} + +PRBool GLContextEGL::ResizeOffscreenPixmapSurface(const gfxIntSize& aNewSize) +{ + gfxASurface *thebesSurface = nsnull; + EGLNativePixmapType pixmap = 0; + + XRenderPictFormat* format = gfxXlibSurface::FindRenderFormat(DefaultXDisplay(), gfxASurface::ImageFormatARGB32); + + nsRefPtr xsurface = + gfxXlibSurface::Create(DefaultScreenOfDisplay(DefaultXDisplay()), + format, + aNewSize); + + // XSync required after gfxXlibSurface::Create, otherwise EGL will fail with BadDrawable error + XSync(DefaultXDisplay(), False); + if (xsurface->CairoStatus() != 0) + return nsnull; + + thebesSurface = xsurface; + + pixmap = xsurface->XDrawable(); + + if (!pixmap) { + return nsnull; + } + + EGLSurface surface = 0; + EGLConfig config = 0; + surface = CreateBasicEGLSurfaceForXSurface(xsurface, &config); + if (!surface) { + NS_WARNING("Failed to resize pbuffer"); + return nsnull; + } + + sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface); + + mSurface = surface; + HoldSurface(thebesSurface); + SetOffscreenSize(aNewSize, aNewSize); + MakeCurrent(PR_TRUE); + + return PR_TRUE; +} + +#endif + } /* namespace gl */ } /* namespace mozilla */ diff --git a/gfx/thebes/GLDefs.h b/gfx/thebes/GLDefs.h index 6acd34aff64e..0ef43e1f7aa0 100644 --- a/gfx/thebes/GLDefs.h +++ b/gfx/thebes/GLDefs.h @@ -3197,5 +3197,6 @@ typedef ptrdiff_t GLintptr; #define LOCAL_EGL_READ_SURFACE_BIT_KHR 0x0001 #define LOCAL_EGL_WRITE_SURFACE_BIT_KHR 0x0002 #define LOCAL_EGL_LOCK_SURFACE_BIT_KHR 0x0080 +#define LOCAL_EGL_CORE_NATIVE_ENGINE 0x305B #endif diff --git a/gfx/thebes/Makefile.in b/gfx/thebes/Makefile.in index 629c2a27fdaa..c6e824967b31 100644 --- a/gfx/thebes/Makefile.in +++ b/gfx/thebes/Makefile.in @@ -338,9 +338,13 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2) ifdef MOZ_PLATFORM_MAEMO GL_PROVIDER = EGL else +ifdef MOZ_EGL_XRENDER_COMPOSITE +GL_PROVIDER = EGL +else GL_PROVIDER = GLX endif endif +endif ifeq ($(MOZ_WIDGET_TOOLKIT),qt) ifdef MOZ_PLATFORM_MAEMO