widget/shared/nsShmImage.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/widget/shared/nsShmImage.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,212 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     1.5 + *
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#if defined(MOZ_WIDGET_GTK)
    1.11 +#include <gtk/gtk.h>
    1.12 +#include <gdk/gdkx.h>
    1.13 +#elif defined(MOZ_WIDGET_QT)
    1.14 +#include <QWindow>
    1.15 +#endif
    1.16 +
    1.17 +#include "nsShmImage.h"
    1.18 +#include "gfxPlatform.h"
    1.19 +#include "gfxImageSurface.h"
    1.20 +
    1.21 +#ifdef MOZ_HAVE_SHMIMAGE
    1.22 +
    1.23 +using namespace mozilla::ipc;
    1.24 +
    1.25 +// If XShm isn't available to our client, we'll try XShm once, fail,
    1.26 +// set this to false and then never try again.
    1.27 +static bool gShmAvailable = true;
    1.28 +bool nsShmImage::UseShm()
    1.29 +{
    1.30 +    return gfxPlatform::GetPlatform()->
    1.31 +        ScreenReferenceSurface()->GetType() == gfxSurfaceType::Image
    1.32 +        && gShmAvailable;
    1.33 +}
    1.34 +
    1.35 +already_AddRefed<nsShmImage>
    1.36 +nsShmImage::Create(const gfxIntSize& aSize,
    1.37 +                   Visual* aVisual, unsigned int aDepth)
    1.38 +{
    1.39 +    Display* dpy = DISPLAY();
    1.40 +
    1.41 +    nsRefPtr<nsShmImage> shm = new nsShmImage();
    1.42 +    shm->mImage = XShmCreateImage(dpy, aVisual, aDepth,
    1.43 +                                  ZPixmap, nullptr,
    1.44 +                                  &(shm->mInfo),
    1.45 +                                  aSize.width, aSize.height);
    1.46 +    if (!shm->mImage) {
    1.47 +        return nullptr;
    1.48 +    }
    1.49 +
    1.50 +    size_t size = SharedMemory::PageAlignedSize(
    1.51 +        shm->mImage->bytes_per_line * shm->mImage->height);
    1.52 +    shm->mSegment = new SharedMemorySysV();
    1.53 +    if (!shm->mSegment->Create(size) || !shm->mSegment->Map(size)) {
    1.54 +        return nullptr;
    1.55 +    }
    1.56 +
    1.57 +    shm->mInfo.shmid = shm->mSegment->GetHandle();
    1.58 +    shm->mInfo.shmaddr =
    1.59 +        shm->mImage->data = static_cast<char*>(shm->mSegment->memory());
    1.60 +    shm->mInfo.readOnly = False;
    1.61 +
    1.62 +    int xerror = 0;
    1.63 +#if defined(MOZ_WIDGET_GTK)
    1.64 +    gdk_error_trap_push();
    1.65 +    Status attachOk = XShmAttach(dpy, &shm->mInfo);
    1.66 +    XSync(dpy, False);
    1.67 +    xerror = gdk_error_trap_pop();
    1.68 +#elif defined(MOZ_WIDGET_QT)
    1.69 +    Status attachOk = XShmAttach(dpy, &shm->mInfo);
    1.70 +#endif
    1.71 +
    1.72 +    if (!attachOk || xerror) {
    1.73 +        // Assume XShm isn't available, and don't attempt to use it
    1.74 +        // again.
    1.75 +        gShmAvailable = false;
    1.76 +        return nullptr;
    1.77 +    }
    1.78 +
    1.79 +    shm->mXAttached = true;
    1.80 +    shm->mSize = aSize;
    1.81 +    switch (shm->mImage->depth) {
    1.82 +    case 32:
    1.83 +        if ((shm->mImage->red_mask == 0xff0000) &&
    1.84 +            (shm->mImage->green_mask == 0xff00) &&
    1.85 +            (shm->mImage->blue_mask == 0xff)) {
    1.86 +            shm->mFormat = gfxImageFormat::ARGB32;
    1.87 +            break;
    1.88 +        }
    1.89 +        goto unsupported;
    1.90 +    case 24:
    1.91 +        // Only xRGB is supported.
    1.92 +        if ((shm->mImage->red_mask == 0xff0000) &&
    1.93 +            (shm->mImage->green_mask == 0xff00) &&
    1.94 +            (shm->mImage->blue_mask == 0xff)) {
    1.95 +            shm->mFormat = gfxImageFormat::RGB24;
    1.96 +            break;
    1.97 +        }
    1.98 +        goto unsupported;
    1.99 +    case 16:
   1.100 +        shm->mFormat = gfxImageFormat::RGB16_565; break;
   1.101 +    unsupported:
   1.102 +    default:
   1.103 +        NS_WARNING("Unsupported XShm Image format!");
   1.104 +        gShmAvailable = false;
   1.105 +        return nullptr;
   1.106 +    }
   1.107 +    return shm.forget();
   1.108 +}
   1.109 +
   1.110 +already_AddRefed<gfxASurface>
   1.111 +nsShmImage::AsSurface()
   1.112 +{
   1.113 +    return nsRefPtr<gfxASurface>(
   1.114 +        new gfxImageSurface(static_cast<unsigned char*>(mSegment->memory()),
   1.115 +                            mSize,
   1.116 +                            mImage->bytes_per_line,
   1.117 +                            mFormat)
   1.118 +        ).forget();
   1.119 +}
   1.120 +
   1.121 +#if (MOZ_WIDGET_GTK == 2)
   1.122 +void
   1.123 +nsShmImage::Put(GdkWindow* aWindow, GdkRectangle* aRects, GdkRectangle* aEnd)
   1.124 +{
   1.125 +    GdkDrawable* gd;
   1.126 +    gint dx, dy;
   1.127 +    gdk_window_get_internal_paint_info(aWindow, &gd, &dx, &dy);
   1.128 +
   1.129 +    Display* dpy = gdk_x11_get_default_xdisplay();
   1.130 +    Drawable d = GDK_DRAWABLE_XID(gd);
   1.131 +
   1.132 +    GC gc = XCreateGC(dpy, d, 0, nullptr);
   1.133 +    for (GdkRectangle* r = aRects; r < aEnd; r++) {
   1.134 +        XShmPutImage(dpy, d, gc, mImage,
   1.135 +                     r->x, r->y,
   1.136 +                     r->x - dx, r->y - dy,
   1.137 +                     r->width, r->height,
   1.138 +                     False);
   1.139 +    }
   1.140 +    XFreeGC(dpy, gc);
   1.141 +
   1.142 +    // FIXME/bug 597336: we need to ensure that the shm image isn't
   1.143 +    // scribbled over before all its pending XShmPutImage()s complete.
   1.144 +    // However, XSync() is an unnecessarily heavyweight
   1.145 +    // synchronization mechanism; other options are possible.  If this
   1.146 +    // XSync is shown to hurt responsiveness, we need to explore the
   1.147 +    // other options.
   1.148 +    XSync(dpy, False);
   1.149 +}
   1.150 +
   1.151 +#elif (MOZ_WIDGET_GTK == 3)
   1.152 +void
   1.153 +nsShmImage::Put(GdkWindow* aWindow, cairo_rectangle_list_t* aRects)
   1.154 +{
   1.155 +    Display* dpy = gdk_x11_get_default_xdisplay();
   1.156 +    Drawable d = GDK_WINDOW_XID(aWindow);
   1.157 +    int dx = 0, dy = 0;
   1.158 +
   1.159 +    GC gc = XCreateGC(dpy, d, 0, nullptr);
   1.160 +    cairo_rectangle_t r;
   1.161 +    for (int i = 0; i < aRects->num_rectangles; i++) {
   1.162 +        r = aRects->rectangles[i];
   1.163 +        XShmPutImage(dpy, d, gc, mImage,
   1.164 +                     r.x, r.y,
   1.165 +                     r.x - dx, r.y - dy,
   1.166 +                     r.width, r.height,
   1.167 +                     False);
   1.168 +    }
   1.169 +
   1.170 +    XFreeGC(dpy, gc);
   1.171 +
   1.172 +    // FIXME/bug 597336: we need to ensure that the shm image isn't
   1.173 +    // scribbled over before all its pending XShmPutImage()s complete.
   1.174 +    // However, XSync() is an unnecessarily heavyweight
   1.175 +    // synchronization mechanism; other options are possible.  If this
   1.176 +    // XSync is shown to hurt responsiveness, we need to explore the
   1.177 +    // other options.
   1.178 +    XSync(dpy, False);
   1.179 +}
   1.180 +
   1.181 +#elif defined(MOZ_WIDGET_QT)
   1.182 +void
   1.183 +nsShmImage::Put(QWindow* aWindow, QRect& aRect)
   1.184 +{
   1.185 +    Display* dpy = gfxQtPlatform::GetXDisplay(aWindow);
   1.186 +    Drawable d = aWindow->winId();
   1.187 +
   1.188 +    GC gc = XCreateGC(dpy, d, 0, nullptr);
   1.189 +    // Avoid out of bounds painting
   1.190 +    QRect inter = aRect.intersected(aWindow->geometry());
   1.191 +    XShmPutImage(dpy, d, gc, mImage,
   1.192 +                 inter.x(), inter.y(),
   1.193 +                 inter.x(), inter.y(),
   1.194 +                 inter.width(), inter.height(),
   1.195 +                 False);
   1.196 +    XFreeGC(dpy, gc);
   1.197 +}
   1.198 +#endif
   1.199 +
   1.200 +already_AddRefed<gfxASurface>
   1.201 +nsShmImage::EnsureShmImage(const gfxIntSize& aSize, Visual* aVisual, unsigned int aDepth,
   1.202 +               nsRefPtr<nsShmImage>& aImage)
   1.203 +{
   1.204 +    if (!aImage || aImage->Size() != aSize) {
   1.205 +        // Because we XSync() after XShmAttach() to trap errors, we
   1.206 +        // know that the X server has the old image's memory mapped
   1.207 +        // into its address space, so it's OK to destroy the old image
   1.208 +        // here even if there are outstanding Puts.  The Detach is
   1.209 +        // ordered after the Puts.
   1.210 +        aImage = nsShmImage::Create(aSize, aVisual, aDepth);
   1.211 +    }
   1.212 +    return !aImage ? nullptr : aImage->AsSurface();
   1.213 +}
   1.214 +
   1.215 +#endif  // defined(MOZ_X11) && defined(MOZ_HAVE_SHAREDMEMORYSYSV)

mercurial