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)