Bug 1205045 - remove GTK calls from compositor thread. r=jmuizelaar

This commit is contained in:
Lee Salzman 2015-09-15 16:46:39 -04:00
parent 352bdbd5e4
commit d240e9c991
6 changed files with 125 additions and 186 deletions

View File

@ -527,11 +527,11 @@ BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion,
}
if (mTarget) {
// If we have a copy target, then we don't have a widget-provided mDrawTarget (currently). Create a dummy
// If we have a copy target, then we don't have a widget-provided mDrawTarget (currently). Use a dummy
// placeholder so that CreateRenderTarget() works.
mDrawTarget = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(1,1), SurfaceFormat::B8G8R8A8);
mDrawTarget = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
} else {
mDrawTarget = mWidget->StartRemoteDrawing();
mDrawTarget = mWidget->StartRemoteDrawingInRegion(mInvalidRegion);
}
if (!mDrawTarget) {
return;

View File

@ -423,6 +423,11 @@ nsWindow::nsWindow()
#ifdef MOZ_X11
mOldFocusWindow = 0;
mXDisplay = nullptr;
mXWindow = None;
mXVisual = nullptr;
mXDepth = 0;
#endif /* MOZ_X11 */
mPluginType = PluginType_NONE;
@ -721,10 +726,6 @@ nsWindow::Destroy(void)
gPluginFocusWindow->LoseNonXEmbedPluginFocus();
}
#endif /* MOZ_X11 && MOZ_WIDGET_GTK2 */
// Destroy thebes surface now. Badness can happen if we destroy
// the surface after its X Window.
mThebesSurface = nullptr;
GtkWidget *owningWidget = GetMozContainerWidget();
if (mShell) {
@ -2171,7 +2172,7 @@ nsWindow::OnExposeEvent(cairo_t *cr)
return TRUE;
}
RefPtr<DrawTarget> dt = StartRemoteDrawing();
RefPtr<DrawTarget> dt = GetDrawTarget(region);
if(!dt) {
return FALSE;
}
@ -2250,7 +2251,7 @@ nsWindow::OnExposeEvent(cairo_t *cr)
}
# ifdef MOZ_HAVE_SHMIMAGE
if (mShmImage && MOZ_LIKELY(!mIsDestroyed)) {
mShmImage->Put(mGdkWindow, region);
mShmImage->Put(mXDisplay, mXWindow, region);
}
# endif // MOZ_HAVE_SHMIMAGE
#endif // MOZ_X11
@ -3828,9 +3829,12 @@ nsWindow::Create(nsIWidget *aParent,
#ifdef MOZ_X11
if (mGdkWindow) {
// force creation of native window via internal call to gdk_window_ensure_native
// in case it was not created already
gdk_x11_window_get_xid(mGdkWindow);
mXDisplay = GDK_WINDOW_XDISPLAY(mGdkWindow);
mXWindow = gdk_x11_window_get_xid(mGdkWindow);
GdkVisual* gdkVisual = gdk_window_get_visual(mGdkWindow);
mXVisual = gdk_x11_visual_get_xvisual(gdkVisual);
mXDepth = gdk_visual_get_depth(gdkVisual);
}
#endif
@ -6309,31 +6313,43 @@ nsWindow::GetSurfaceForGdkDrawable(GdkDrawable* aDrawable,
#endif
already_AddRefed<DrawTarget>
nsWindow::StartRemoteDrawing()
nsWindow::GetDrawTarget(const nsIntRegion& aRegion)
{
gfxASurface *surf = GetThebesSurface();
if (!surf) {
if (!mGdkWindow) {
return nullptr;
}
nsIntSize size = surf->GetSize();
nsIntRect bounds = aRegion.GetBounds();
IntSize size(bounds.XMost(), bounds.YMost());
if (size.width <= 0 || size.height <= 0) {
return nullptr;
}
gfxPlatform *platform = gfxPlatform::GetPlatform();
if (platform->SupportsAzureContentForType(BackendType::CAIRO) ||
surf->GetType() == gfxSurfaceType::Xlib) {
return platform->CreateDrawTargetForSurface(surf, size);
} else if (platform->SupportsAzureContentForType(BackendType::SKIA) &&
surf->GetType() == gfxSurfaceType::Image) {
gfxImageSurface* imgSurf = static_cast<gfxImageSurface*>(surf);
SurfaceFormat format = ImageFormatToSurfaceFormat(imgSurf->Format());
return platform->CreateDrawTargetForData(
imgSurf->Data(), size, imgSurf->Stride(), format);
} else {
return nullptr;
RefPtr<DrawTarget> dt;
#ifdef MOZ_X11
# ifdef MOZ_HAVE_SHMIMAGE
if (nsShmImage::UseShm()) {
dt = nsShmImage::EnsureShmImage(size,
mXDisplay, mXVisual, mXDepth,
mShmImage);
}
# endif // MOZ_HAVE_SHMIMAGE
if (!dt) {
RefPtr<gfxXlibSurface> surf = new gfxXlibSurface(mXDisplay, mXWindow, mXVisual, size);
if (!surf->CairoStatus()) {
dt = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surf.get(), surf->GetSize());
}
}
#endif // MOZ_X11
return dt.forget();
}
already_AddRefed<DrawTarget>
nsWindow::StartRemoteDrawingInRegion(nsIntRegion& aInvalidRegion)
{
return GetDrawTarget(aInvalidRegion);
}
void
@ -6345,73 +6361,11 @@ nsWindow::EndRemoteDrawingInRegion(DrawTarget* aDrawTarget, nsIntRegion& aInvali
return;
}
if (mThebesSurface) {
aInvalidRegion.AndWith(nsIntRect(nsIntPoint(0, 0), mThebesSurface->GetSize()));
}
mShmImage->Put(mGdkWindow, aInvalidRegion);
mShmImage->Put(mXDisplay, mXWindow, aInvalidRegion);
# endif // MOZ_HAVE_SHMIMAGE
#endif // MOZ_X11
}
// return the gfxASurface for rendering to this widget
gfxASurface*
nsWindow::GetThebesSurface()
{
if (!mGdkWindow)
return nullptr;
#ifdef MOZ_X11
gint width, height;
#if (MOZ_WIDGET_GTK == 2)
gdk_drawable_get_size(GDK_DRAWABLE(mGdkWindow), &width, &height);
#else
width = GdkCoordToDevicePixels(gdk_window_get_width(mGdkWindow));
height = GdkCoordToDevicePixels(gdk_window_get_height(mGdkWindow));
#endif
// Owen Taylor says this is the right thing to do!
width = std::min(32767, width);
height = std::min(32767, height);
gfxIntSize size(width, height);
GdkVisual *gdkVisual = gdk_window_get_visual(mGdkWindow);
Visual* visual = gdk_x11_visual_get_xvisual(gdkVisual);
# ifdef MOZ_HAVE_SHMIMAGE
bool usingShm = false;
if (nsShmImage::UseShm()) {
// EnsureShmImage() is a dangerous interface, but we guarantee
// that the thebes surface and the shmimage have the same
// lifetime
mThebesSurface =
nsShmImage::EnsureShmImage(size,
visual, gdk_visual_get_depth(gdkVisual),
mShmImage);
usingShm = mThebesSurface != nullptr;
}
if (!usingShm)
# endif // MOZ_HAVE_SHMIMAGE
{
mThebesSurface = new gfxXlibSurface
(GDK_WINDOW_XDISPLAY(mGdkWindow),
gdk_x11_window_get_xid(mGdkWindow),
visual,
size);
}
#endif // MOZ_X11
// if the surface creation is reporting an error, then
// we don't have a surface to give back
if (mThebesSurface && mThebesSurface->CairoStatus() != 0) {
mThebesSurface = nullptr;
}
return mThebesSurface;
}
// Code shared begin BeginMoveDrag and BeginResizeDrag
bool
nsWindow::GetDragInfo(WidgetMouseEvent* aMouseEvent,

View File

@ -207,7 +207,7 @@ public:
gpointer aData);
virtual already_AddRefed<mozilla::gfx::DrawTarget>
StartRemoteDrawing() override;
StartRemoteDrawingInRegion(nsIntRegion& aInvalidRegion) override;
virtual void EndRemoteDrawingInRegion(mozilla::gfx::DrawTarget* aDrawTarget,
nsIntRegion& aInvalidRegion) override;
@ -300,7 +300,7 @@ public:
virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations) override;
nsresult UpdateTranslucentWindowAlphaInternal(const nsIntRect& aRect,
uint8_t* aAlphas, int32_t aStride);
virtual gfxASurface *GetThebesSurface();
virtual already_AddRefed<mozilla::gfx::DrawTarget> GetDrawTarget(const nsIntRegion& aRegion);
#if (MOZ_WIDGET_GTK == 2)
static already_AddRefed<gfxASurface> GetSurfaceForGdkDrawable(GdkDrawable* aDrawable,
@ -395,11 +395,17 @@ private:
guint32 mLastScrollEventTime;
#endif
#ifdef MOZ_X11
Display* mXDisplay;
Drawable mXWindow;
Visual* mXVisual;
int mXDepth;
#endif
#ifdef MOZ_HAVE_SHMIMAGE
// If we're using xshm rendering, mThebesSurface wraps mShmImage
// If we're using xshm rendering
nsRefPtr<nsShmImage> mShmImage;
#endif
nsRefPtr<gfxASurface> mThebesSurface;
#ifdef ACCESSIBILITY
nsRefPtr<mozilla::a11y::Accessible> mRootAccessible;

View File

@ -1228,6 +1228,9 @@ class nsIWidget : public nsISupports {
* before each composition.
*/
virtual already_AddRefed<mozilla::gfx::DrawTarget> StartRemoteDrawing() = 0;
virtual already_AddRefed<mozilla::gfx::DrawTarget> StartRemoteDrawingInRegion(nsIntRegion& aInvalidRegion) {
return StartRemoteDrawing();
}
/**
* Ensure that what was painted into the DrawTarget returned from

View File

@ -15,11 +15,11 @@
#ifdef MOZ_WIDGET_GTK
#include "gfxPlatformGtk.h"
#endif
#include "gfxImageSurface.h"
#ifdef MOZ_HAVE_SHMIMAGE
using namespace mozilla::ipc;
using namespace mozilla::gfx;
// If XShm isn't available to our client, we'll try XShm once, fail,
// set this to false and then never try again.
@ -33,14 +33,25 @@ bool nsShmImage::UseShm()
#endif
}
#ifdef MOZ_WIDGET_GTK
static int gShmError = 0;
static int
TrapShmError(Display* aDisplay, XErrorEvent* aEvent)
{
// store the error code and ignore the error
gShmError = aEvent->error_code;
return 0;
}
#endif
already_AddRefed<nsShmImage>
nsShmImage::Create(const gfxIntSize& aSize,
Visual* aVisual, unsigned int aDepth)
Display* aDisplay, Visual* aVisual, unsigned int aDepth)
{
Display* dpy = DISPLAY();
nsRefPtr<nsShmImage> shm = new nsShmImage();
shm->mImage = XShmCreateImage(dpy, aVisual, aDepth,
shm->mDisplay = aDisplay;
shm->mImage = XShmCreateImage(aDisplay, aVisual, aDepth,
ZPixmap, nullptr,
&(shm->mInfo),
aSize.width, aSize.height);
@ -60,17 +71,20 @@ nsShmImage::Create(const gfxIntSize& aSize,
shm->mImage->data = static_cast<char*>(shm->mSegment->memory());
shm->mInfo.readOnly = False;
int xerror = 0;
#if defined(MOZ_WIDGET_GTK)
gdk_error_trap_push();
Status attachOk = XShmAttach(dpy, &shm->mInfo);
XSync(dpy, False);
xerror = gdk_error_trap_pop();
gShmError = 0;
XErrorHandler previousHandler = XSetErrorHandler(TrapShmError);
Status attachOk = XShmAttach(aDisplay, &shm->mInfo);
XSync(aDisplay, False);
XSetErrorHandler(previousHandler);
if (gShmError) {
attachOk = 0;
}
#elif defined(MOZ_WIDGET_QT)
Status attachOk = XShmAttach(dpy, &shm->mInfo);
Status attachOk = XShmAttach(aDisplay, &shm->mInfo);
#endif
if (!attachOk || xerror) {
if (!attachOk) {
// Assume XShm isn't available, and don't attempt to use it
// again.
gShmAvailable = false;
@ -84,7 +98,7 @@ nsShmImage::Create(const gfxIntSize& aSize,
if ((shm->mImage->red_mask == 0xff0000) &&
(shm->mImage->green_mask == 0xff00) &&
(shm->mImage->blue_mask == 0xff)) {
shm->mFormat = gfxImageFormat::ARGB32;
shm->mFormat = SurfaceFormat::B8G8R8A8;
break;
}
goto unsupported;
@ -93,12 +107,13 @@ nsShmImage::Create(const gfxIntSize& aSize,
if ((shm->mImage->red_mask == 0xff0000) &&
(shm->mImage->green_mask == 0xff00) &&
(shm->mImage->blue_mask == 0xff)) {
shm->mFormat = gfxImageFormat::RGB24;
shm->mFormat = SurfaceFormat::B8G8R8X8;
break;
}
goto unsupported;
case 16:
shm->mFormat = gfxImageFormat::RGB16_565; break;
shm->mFormat = SurfaceFormat::R5G6B5;
break;
unsupported:
default:
NS_WARNING("Unsupported XShm Image format!");
@ -108,40 +123,33 @@ nsShmImage::Create(const gfxIntSize& aSize,
return shm.forget();
}
already_AddRefed<gfxASurface>
nsShmImage::AsSurface()
already_AddRefed<DrawTarget>
nsShmImage::CreateDrawTarget()
{
return nsRefPtr<gfxASurface>(
new gfxImageSurface(static_cast<unsigned char*>(mSegment->memory()),
mSize,
mImage->bytes_per_line,
mFormat)
).forget();
return gfxPlatform::GetPlatform()->CreateDrawTargetForData(
static_cast<unsigned char*>(mSegment->memory()),
mSize,
mImage->bytes_per_line,
mFormat);
}
#if (MOZ_WIDGET_GTK == 2)
#ifdef MOZ_WIDGET_GTK
void
nsShmImage::Put(GdkWindow* aWindow, const nsIntRegion& aRegion)
nsShmImage::Put(Display* aDisplay, Drawable aWindow, const nsIntRegion& aRegion)
{
GdkDrawable* gd;
gint dx, dy;
gdk_window_get_internal_paint_info(aWindow, &gd, &dx, &dy);
Display* dpy = gdk_x11_get_default_xdisplay();
Drawable d = GDK_DRAWABLE_XID(gd);
GC gc = XCreateGC(dpy, d, 0, nullptr);
GC gc = XCreateGC(aDisplay, aWindow, 0, nullptr);
nsIntRegion bounded;
bounded.And(aRegion, nsIntRect(0, 0, mImage->width, mImage->height));
nsIntRegionRectIterator iter(bounded);
for (const nsIntRect *r = iter.Next(); r; r = iter.Next()) {
XShmPutImage(dpy, d, gc, mImage,
XShmPutImage(aDisplay, aWindow, gc, mImage,
r->x, r->y,
r->x, r->y,
r->x - dx, r->y - dy,
r->width, r->height,
False);
}
XFreeGC(dpy, gc);
XFreeGC(aDisplay, gc);
// FIXME/bug 597336: we need to ensure that the shm image isn't
// scribbled over before all its pending XShmPutImage()s complete.
@ -149,38 +157,7 @@ nsShmImage::Put(GdkWindow* aWindow, const nsIntRegion& aRegion)
// synchronization mechanism; other options are possible. If this
// XSync is shown to hurt responsiveness, we need to explore the
// other options.
XSync(dpy, False);
}
#elif (MOZ_WIDGET_GTK == 3)
void
nsShmImage::Put(GdkWindow* aWindow, const nsIntRegion& aRegion)
{
Display* dpy = gdk_x11_get_default_xdisplay();
Drawable d = GDK_WINDOW_XID(aWindow);
int dx = 0, dy = 0;
GC gc = XCreateGC(dpy, d, 0, nullptr);
nsIntRegion bounded;
bounded.And(aRegion, nsIntRect(0, 0, mImage->width, mImage->height));
nsIntRegionRectIterator iter(bounded);
for (const nsIntRect *r = iter.Next(); r; r = iter.Next()) {
XShmPutImage(dpy, d, gc, mImage,
r->x, r->y,
r->x - dx, r->y - dy,
r->width, r->height,
False);
}
XFreeGC(dpy, gc);
// FIXME/bug 597336: we need to ensure that the shm image isn't
// scribbled over before all its pending XShmPutImage()s complete.
// However, XSync() is an unnecessarily heavyweight
// synchronization mechanism; other options are possible. If this
// XSync is shown to hurt responsiveness, we need to explore the
// other options.
XSync(dpy, False);
XSync(aDisplay, False);
}
#elif defined(MOZ_WIDGET_QT)
@ -202,9 +179,10 @@ nsShmImage::Put(QWindow* aWindow, QRect& aRect)
}
#endif
already_AddRefed<gfxASurface>
nsShmImage::EnsureShmImage(const gfxIntSize& aSize, Visual* aVisual, unsigned int aDepth,
nsRefPtr<nsShmImage>& aImage)
already_AddRefed<DrawTarget>
nsShmImage::EnsureShmImage(const gfxIntSize& aSize,
Display* aDisplay, Visual* aVisual, unsigned int aDepth,
nsRefPtr<nsShmImage>& aImage)
{
if (!aImage || aImage->Size() != aSize) {
// Because we XSync() after XShmAttach() to trap errors, we
@ -212,9 +190,9 @@ nsShmImage::EnsureShmImage(const gfxIntSize& aSize, Visual* aVisual, unsigned in
// into its address space, so it's OK to destroy the old image
// here even if there are outstanding Puts. The Detach is
// ordered after the Puts.
aImage = nsShmImage::Create(aSize, aVisual, aDepth);
aImage = nsShmImage::Create(aSize, aDisplay, aVisual, aDepth);
}
return !aImage ? nullptr : aImage->AsSurface();
return !aImage ? nullptr : aImage->CreateDrawTarget();
}
#endif // defined(MOZ_X11) && defined(MOZ_HAVE_SHAREDMEMORYSYSV)

View File

@ -15,8 +15,8 @@
#ifdef MOZ_HAVE_SHMIMAGE
#include "mozilla/gfx/2D.h"
#include "nsIWidget.h"
#include "gfxTypes.h"
#include "nsAutoPtr.h"
#include "mozilla/X11Util.h"
@ -24,15 +24,10 @@
#include <X11/Xutil.h>
#include <X11/extensions/XShm.h>
#if defined(MOZ_WIDGET_GTK)
#define DISPLAY gdk_x11_get_default_xdisplay
#elif defined(MOZ_WIDGET_QT)
#define DISPLAY mozilla::DefaultXDisplay
#endif
#ifdef MOZ_WIDGET_QT
class QRect;
class QWindow;
class gfxASurface;
#endif
class nsShmImage {
// bug 1168843, compositor thread may create shared memory instances that are destroyed by main thread on shutdown, so this must use thread-safe RC to avoid hitting assertion
@ -41,31 +36,31 @@ class nsShmImage {
typedef mozilla::ipc::SharedMemorySysV SharedMemorySysV;
public:
typedef gfxImageFormat Format;
static bool UseShm();
static already_AddRefed<nsShmImage>
Create(const gfxIntSize& aSize, Visual* aVisual, unsigned int aDepth);
static already_AddRefed<gfxASurface>
EnsureShmImage(const gfxIntSize& aSize, Visual* aVisual, unsigned int aDepth,
Create(const gfxIntSize& aSize,
Display* aDisplay, Visual* aVisual, unsigned int aDepth);
static already_AddRefed<mozilla::gfx::DrawTarget>
EnsureShmImage(const gfxIntSize& aSize,
Display* aDisplay, Visual* aVisual, unsigned int aDepth,
nsRefPtr<nsShmImage>& aImage);
private:
~nsShmImage() {
if (mImage) {
mozilla::FinishX(DISPLAY());
mozilla::FinishX(mDisplay);
if (mXAttached) {
XShmDetach(DISPLAY(), &mInfo);
XShmDetach(mDisplay, &mInfo);
}
XDestroyImage(mImage);
}
}
public:
already_AddRefed<gfxASurface> AsSurface();
already_AddRefed<mozilla::gfx::DrawTarget> CreateDrawTarget();
#ifdef MOZ_WIDGET_GTK
void Put(GdkWindow* aWindow, const nsIntRegion& aRegion);
void Put(Display* aDisplay, Drawable aWindow, const nsIntRegion& aRegion);
#elif defined(MOZ_WIDGET_QT)
void Put(QWindow* aWindow, QRect& aRect);
#endif
@ -75,14 +70,17 @@ public:
private:
nsShmImage()
: mImage(nullptr)
, mDisplay(nullptr)
, mFormat(mozilla::gfx::SurfaceFormat::UNKNOWN)
, mXAttached(false)
{ mInfo.shmid = SharedMemorySysV::NULLHandle(); }
nsRefPtr<SharedMemorySysV> mSegment;
XImage* mImage;
Display* mDisplay;
XShmSegmentInfo mInfo;
gfxIntSize mSize;
Format mFormat;
mozilla::gfx::SurfaceFormat mFormat;
bool mXAttached;
};