Bug 649525 - WebGL layer compositing through the BasicCanvasLayer is very slow (desktop version). r=jmuizelaar

This commit is contained in:
Scott Ruff 2011-07-27 13:00:17 +02:00
parent 5572ff62cb
commit 4e4c1347d5
9 changed files with 289 additions and 4 deletions

View File

@ -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@

View File

@ -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 ========================================================

View File

@ -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)

View File

@ -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<gfxImageSurface> isurf = aDestSurface ?
static_cast<gfxImageSurface*>(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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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<GLContextEGL>
CreateBasicEGLPixmapOffscreenContext(const gfxIntSize& aSize,
const ContextFormat& aFormat);
PRBool ResizeOffscreenPixmapSurface(const gfxIntSize& aNewSize);
#endif
static already_AddRefed<GLContextEGL>
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<GLContextEGL> 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<gfxXlibSurface*>(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>
GLContextEGL::CreateBasicEGLPixmapOffscreenContext(const gfxIntSize& aSize,
const ContextFormat& aFormat)
{
gfxASurface *thebesSurface = nsnull;
EGLNativePixmapType pixmap = 0;
XRenderPictFormat* format = gfxXlibSurface::FindRenderFormat(DefaultXDisplay(), gfxASurface::ImageFormatARGB32);
nsRefPtr<gfxXlibSurface> 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<GLContextEGL> 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<gfxXlibSurface> 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 */

View File

@ -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

View File

@ -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