зеркало из https://github.com/mozilla/gecko-dev.git
Bug 597336, part 4: If UseClientSideRendering(), render to a gfxImageSurface backed by memory shared with X and then XShmPutImage to copy it to our window's drawable. r=karl a=blocking-fennec
This commit is contained in:
Родитель
61c93dad95
Коммит
27603d255c
|
@ -53,6 +53,7 @@
|
|||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
|
|
|
@ -142,6 +142,8 @@ CPPSRCS += nsNativeThemeGTK.cpp
|
|||
DEFINES += -DNATIVE_THEME_SUPPORT
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
CFLAGS += $(MOZ_GTK2_CFLAGS) $(MOZ_STARTUP_NOTIFICATION_CFLAGS)
|
||||
|
|
|
@ -43,6 +43,10 @@
|
|||
#define MAEMO_CHANGES
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_IPC
|
||||
# include "mozilla/ipc/SharedMemorySysV.h"
|
||||
#endif
|
||||
|
||||
#include "prlink.h"
|
||||
|
||||
#include "nsWindow.h"
|
||||
|
@ -64,6 +68,7 @@
|
|||
#ifdef MOZ_X11
|
||||
#include <gdk/gdkx.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <X11/extensions/XShm.h>
|
||||
|
||||
#ifdef AIX
|
||||
#include <X11/keysym.h>
|
||||
|
@ -149,6 +154,7 @@ D_DEBUG_DOMAIN( ns_Window, "nsWindow", "nsWindow" );
|
|||
#define GDK_WINDOW_XWINDOW(_win) _win
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
using mozilla::gl::GLContext;
|
||||
using mozilla::layers::LayerManagerOGL;
|
||||
|
||||
|
@ -285,6 +291,14 @@ UpdateLastInputEventTime()
|
|||
}
|
||||
}
|
||||
|
||||
// If XShm isn't available to our client, we'll try XShm once, fail,
|
||||
// set this to false and then never try again.
|
||||
static PRBool gShmAvailable = PR_TRUE;
|
||||
static PRBool UseShm()
|
||||
{
|
||||
return gfxPlatformGtk::UseClientSideRendering() && gShmAvailable;
|
||||
}
|
||||
|
||||
// this is the last window that had a drag event happen on it.
|
||||
nsWindow *nsWindow::mLastDragMotionWindow = NULL;
|
||||
PRBool nsWindow::sIsDraggingOutOf = PR_FALSE;
|
||||
|
@ -378,6 +392,160 @@ protected:
|
|||
pixman_region32& get() { return *this; }
|
||||
};
|
||||
|
||||
|
||||
#if defined(MOZ_X11) && defined(MOZ_HAVE_SHAREDMEMORYSYSV)
|
||||
# define MOZ_HAVE_SHMIMAGE
|
||||
|
||||
using mozilla::ipc::SharedMemorySysV;
|
||||
|
||||
class nsShmImage {
|
||||
NS_INLINE_DECL_REFCOUNTING(nsShmImage)
|
||||
|
||||
public:
|
||||
typedef gfxASurface::gfxImageFormat Format;
|
||||
|
||||
static already_AddRefed<nsShmImage>
|
||||
Create(const gfxIntSize& aSize, Visual* aVisual, unsigned int aDepth);
|
||||
|
||||
~nsShmImage() {
|
||||
if (mImage) {
|
||||
if (mXAttached) {
|
||||
XShmDetach(gdk_x11_get_default_xdisplay(), &mInfo);
|
||||
}
|
||||
XDestroyImage(mImage);
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface> AsSurface();
|
||||
|
||||
void Put(GdkWindow* aWindow, GdkRectangle* aRects, GdkRectangle* aEnd);
|
||||
|
||||
gfxIntSize Size() const { return mSize; }
|
||||
|
||||
private:
|
||||
nsShmImage()
|
||||
: mImage(nsnull)
|
||||
, mXAttached(PR_FALSE)
|
||||
{ mInfo.shmid = SharedMemorySysV::NULLHandle(); }
|
||||
|
||||
nsRefPtr<SharedMemorySysV> mSegment;
|
||||
XImage* mImage;
|
||||
XShmSegmentInfo mInfo;
|
||||
gfxIntSize mSize;
|
||||
Format mFormat;
|
||||
PRPackedBool mXAttached;
|
||||
};
|
||||
|
||||
already_AddRefed<nsShmImage>
|
||||
nsShmImage::Create(const gfxIntSize& aSize,
|
||||
Visual* aVisual, unsigned int aDepth)
|
||||
{
|
||||
Display* dpy = gdk_x11_get_default_xdisplay();
|
||||
|
||||
nsRefPtr<nsShmImage> shm = new nsShmImage();
|
||||
shm->mImage = XShmCreateImage(dpy, aVisual, aDepth,
|
||||
ZPixmap, nsnull,
|
||||
&(shm->mInfo),
|
||||
aSize.width, aSize.height);
|
||||
if (!shm->mImage) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
size_t size = shm->mImage->bytes_per_line * shm->mImage->height;
|
||||
shm->mSegment = new SharedMemorySysV();
|
||||
if (!shm->mSegment->Create(size) || !shm->mSegment->Map(size)) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
shm->mInfo.shmid = shm->mSegment->GetHandle();
|
||||
shm->mInfo.shmaddr =
|
||||
shm->mImage->data = static_cast<char*>(shm->mSegment->memory());
|
||||
shm->mInfo.readOnly = False;
|
||||
|
||||
gdk_error_trap_push();
|
||||
Status attachOk = XShmAttach(dpy, &shm->mInfo);
|
||||
gint xerror = gdk_error_trap_pop();
|
||||
|
||||
if (!attachOk || xerror) {
|
||||
// Assume XShm isn't available, and don't attempt to use it
|
||||
// again.
|
||||
gShmAvailable = PR_FALSE;
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
shm->mXAttached = PR_TRUE;
|
||||
shm->mSize = aSize;
|
||||
switch (shm->mImage->depth) {
|
||||
case 24:
|
||||
shm->mFormat = gfxASurface::ImageFormatRGB24; break;
|
||||
case 16:
|
||||
shm->mFormat = gfxASurface::ImageFormatRGB16_565; break;
|
||||
default:
|
||||
NS_WARNING("Unsupported XShm Image depth!");
|
||||
gShmAvailable = PR_FALSE;
|
||||
return nsnull;
|
||||
}
|
||||
return shm.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<gfxASurface>
|
||||
nsShmImage::AsSurface()
|
||||
{
|
||||
return nsRefPtr<gfxASurface>(
|
||||
new gfxImageSurface(static_cast<unsigned char*>(mSegment->memory()),
|
||||
mSize,
|
||||
mImage->bytes_per_line,
|
||||
mFormat)
|
||||
).forget();
|
||||
}
|
||||
|
||||
void
|
||||
nsShmImage::Put(GdkWindow* aWindow, GdkRectangle* aRects, GdkRectangle* aEnd)
|
||||
{
|
||||
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, nsnull);
|
||||
for (GdkRectangle* r = aRects; r < aEnd; r++) {
|
||||
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);
|
||||
}
|
||||
|
||||
static already_AddRefed<gfxASurface>
|
||||
EnsureShmImage(const gfxIntSize& aSize, Visual* aVisual, unsigned int aDepth,
|
||||
nsRefPtr<nsShmImage>& aImage)
|
||||
{
|
||||
if (!aImage || aImage->Size() != aSize) {
|
||||
// Because we XSync() after XShmAttach() to trap errors, we
|
||||
// know that the X server has the old image's memory mapped
|
||||
// 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);
|
||||
}
|
||||
return !aImage ? nsnull : aImage->AsSurface();
|
||||
}
|
||||
|
||||
#endif // defined(MOZ_X11) && defined(MOZ_HAVE_SHAREDMEMORYSYSV)
|
||||
|
||||
|
||||
nsWindow::nsWindow()
|
||||
{
|
||||
mIsTopLevel = PR_FALSE;
|
||||
|
@ -2141,10 +2309,6 @@ nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent)
|
|||
}
|
||||
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(GetThebesSurface());
|
||||
if (NS_UNLIKELY(!ctx)) {
|
||||
g_free(rects);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#ifdef MOZ_DFB
|
||||
gfxPlatformGtk::SetGdkDrawable(ctx->OriginalSurface(),
|
||||
|
@ -2187,6 +2351,11 @@ nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent)
|
|||
// channel is used on compositing window managers.)
|
||||
layerBuffering = BasicLayerManager::BUFFER_NONE;
|
||||
ctx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
|
||||
#ifdef MOZ_HAVE_SHMIMAGE
|
||||
} else if (UseShm()) {
|
||||
// We're using an xshm mapping as a back buffer.
|
||||
layerBuffering = BasicLayerManager::BUFFER_NONE;
|
||||
#endif // MOZ_HAVE_SHMIMAGE
|
||||
} else {
|
||||
// Get the layer manager to do double buffering (if necessary).
|
||||
layerBuffering = BasicLayerManager::BUFFER_BUFFERED;
|
||||
|
@ -2241,6 +2410,11 @@ nsWindow::OnExposeEvent(GtkWidget *aWidget, GdkEventExpose *aEvent)
|
|||
}
|
||||
}
|
||||
}
|
||||
# ifdef MOZ_HAVE_SHMIMAGE
|
||||
if (UseShm() && NS_LIKELY(!mIsDestroyed)) {
|
||||
mShmImage->Put(mGdkWindow, rects, r_end);
|
||||
}
|
||||
# endif // MOZ_HAVE_SHMIMAGE
|
||||
#endif // MOZ_X11
|
||||
|
||||
g_free(rects);
|
||||
|
@ -6544,12 +6718,28 @@ nsWindow::GetThebesSurface()
|
|||
// Owen Taylor says this is the right thing to do!
|
||||
width = PR_MIN(32767, width);
|
||||
height = PR_MIN(32767, height);
|
||||
gfxIntSize size(width, height);
|
||||
Visual* visual = GDK_VISUAL_XVISUAL(gdk_drawable_get_visual(d));
|
||||
|
||||
# ifdef MOZ_HAVE_SHMIMAGE
|
||||
PRBool usingShm = PR_FALSE;
|
||||
if (UseShm()) {
|
||||
// EnsureShmImage() is a dangerous interface, but we guarantee
|
||||
// that the thebes surface and the shmimage have the same
|
||||
// lifetime
|
||||
mThebesSurface = EnsureShmImage(size,
|
||||
visual, gdk_drawable_get_depth(d),
|
||||
mShmImage);
|
||||
usingShm = mThebesSurface != nsnull;
|
||||
}
|
||||
if (!usingShm)
|
||||
# endif // MOZ_HAVE_SHMIMAGE
|
||||
|
||||
mThebesSurface = new gfxXlibSurface
|
||||
(GDK_WINDOW_XDISPLAY(d),
|
||||
GDK_WINDOW_XWINDOW(d),
|
||||
GDK_VISUAL_XVISUAL(gdk_drawable_get_visual(d)),
|
||||
gfxIntSize(width, height));
|
||||
visual,
|
||||
size);
|
||||
#endif
|
||||
#ifdef MOZ_DFB
|
||||
mThebesSurface = new gfxDirectFBSurface(gdk_directfb_surface_lookup(d));
|
||||
|
|
|
@ -97,6 +97,7 @@ extern PRLogModuleInfo *gWidgetDrawLog;
|
|||
|
||||
#endif /* MOZ_LOGGING */
|
||||
|
||||
class nsShmImage;
|
||||
|
||||
class nsWindow : public nsBaseWidget, public nsSupportsWeakReference
|
||||
{
|
||||
|
@ -402,6 +403,10 @@ private:
|
|||
PRInt32 mTransparencyBitmapWidth;
|
||||
PRInt32 mTransparencyBitmapHeight;
|
||||
|
||||
#ifdef MOZ_X11
|
||||
// If we're using xshm rendering, mThebesSurface wraps mShmImage
|
||||
nsRefPtr<nsShmImage> mShmImage;
|
||||
#endif
|
||||
nsRefPtr<gfxASurface> mThebesSurface;
|
||||
|
||||
#ifdef MOZ_DFB
|
||||
|
|
Загрузка…
Ссылка в новой задаче