Skip to content
Snippets Groups Projects
Commit cb632c31 authored by piman@chromium.org's avatar piman@chromium.org
Browse files

If SHM pixmaps support is available, for example, Intel drivers now support that

(http://cgit.freedesktop.org/xorg/driver/xf86-video-intel/commit/?id=4b7142baa0b3bf6f38843d06aadc579d8624cefc),
use SHM pixmaps support to accelerate windowless plugin painting.
Modify WindowlessPaint to directly use Xlib interfaces for SHM pixmaps support,
similarly to the way how backing_store_x handles different SHM support levels provided by X server.

BUG=50912
TEST=Open the page "http://disney.go.com/official-sites/demi-lovato/albums" using Chromium browser,
compare the CPU usage of browser and X server before and after the change, and confirm CPU usage
is reduced with this change (for example, on an Atom N450 Netbook with MeeGo 1.0 and Chromium browser
6.0.417.0 there's >30% CPU usage reduction, especially X server CPU usage is reduced by half).

Review URL: http://codereview.chromium.org/3052039
Patch from Yuqiang Xian <yuqiang.xian@intel.com>.

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@55020 0039d316-1c4b-4281-b951-d872f2087c98
parent 5d682cb2
No related branches found
No related tags found
No related merge requests found
......@@ -32,6 +32,10 @@
#include "third_party/WebKit/WebKit/chromium/public/WebBindings.h"
#include "webkit/glue/plugins/webplugin_delegate_impl.h"
#if defined(USE_X11)
#include "app/x11_util_internal.h"
#endif
using WebKit::WebBindings;
using webkit_glue::WebPluginResourceClient;
......@@ -58,11 +62,36 @@ WebPluginProxy::WebPluginProxy(
transparent_(false),
host_render_view_routing_id_(host_render_view_routing_id),
ALLOW_THIS_IN_INITIALIZER_LIST(runnable_method_factory_(this)) {
#if defined(USE_X11)
windowless_shm_pixmap_ = None;
use_shm_pixmap_ = false;
// If the X server supports SHM pixmaps
// and the color depth and masks match,
// then consider using SHM pixmaps for windowless plugin painting.
Display* display = x11_util::GetXDisplay();
if (x11_util::QuerySharedMemorySupport(display) ==
x11_util::SHARED_MEMORY_PIXMAP &&
x11_util::BitsPerPixelForPixmapDepth(
display, DefaultDepth(display, 0)) == 32) {
Visual* vis = DefaultVisual(display, 0);
if (vis->red_mask == 0xff0000 &&
vis->green_mask == 0xff00 &&
vis->blue_mask == 0xff)
use_shm_pixmap_ = true;
}
#endif
}
WebPluginProxy::~WebPluginProxy() {
if (cp_browsing_context_)
GetContextMap().erase(cp_browsing_context_);
#if defined(USE_X11)
if (windowless_shm_pixmap_ != None)
XFreePixmap(x11_util::GetXDisplay(), windowless_shm_pixmap_);
#endif
}
bool WebPluginProxy::Send(IPC::Message* msg) {
......@@ -567,6 +596,26 @@ void WebPluginProxy::SetWindowlessBuffer(
} else {
background_canvas_.reset();
}
// If SHM pixmaps support is available, create a SHM pixmap and
// pass it to the delegate for windowless plugin painting.
if (delegate_->IsWindowless() && use_shm_pixmap_ && windowless_dib_.get()) {
Display* display = x11_util::GetXDisplay();
XID root_window = x11_util::GetX11RootWindow();
XShmSegmentInfo shminfo = {0};
if (windowless_shm_pixmap_ != None)
XFreePixmap(display, windowless_shm_pixmap_);
shminfo.shmseg = windowless_dib_->MapToX(display);
// Create a shared memory pixmap based on the image buffer.
windowless_shm_pixmap_ = XShmCreatePixmap(display, root_window,
NULL, &shminfo,
width, height,
DefaultDepth(display, 0));
delegate_->SetWindowlessShmPixmap(windowless_shm_pixmap_);
}
}
#endif
......
......@@ -8,6 +8,9 @@
#include <string>
#if defined(USE_X11)
#include "app/x11_util.h"
#endif
#include "app/surface/transport_dib.h"
#include "base/hash_tables.h"
#include "base/ref_counted.h"
......@@ -185,6 +188,10 @@ class WebPluginProxy : public webkit_glue::WebPlugin {
#if defined(USE_X11)
scoped_ptr<TransportDIB> windowless_dib_;
scoped_ptr<TransportDIB> background_dib_;
// If we can use SHM pixmaps for windowless plugin painting or not.
bool use_shm_pixmap_;
// The SHM pixmap for windowless plugin painting.
XID windowless_shm_pixmap_;
#endif
#endif
......
......@@ -27,6 +27,8 @@
#endif
#if defined(USE_X11)
#include "app/x11_util.h"
typedef struct _GdkDrawable GdkPixmap;
#endif
......@@ -181,6 +183,12 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate {
void set_windowed_handle(gfx::PluginWindowHandle handle);
#endif
#if defined(USE_X11)
void SetWindowlessShmPixmap(XID shm_pixmap) {
windowless_shm_pixmap_ = shm_pixmap;
}
#endif
private:
friend class DeleteTask<WebPluginDelegateImpl>;
friend class webkit_glue::WebPluginDelegate;
......@@ -292,6 +300,9 @@ class WebPluginDelegateImpl : public webkit_glue::WebPluginDelegate {
#endif // OS_WIN
#if defined(USE_X11)
// The SHM pixmap for a windowless plugin.
XID windowless_shm_pixmap_;
// The pixmap we're drawing into, for a windowless plugin.
GdkPixmap* pixmap_;
double first_event_time_;
......
......@@ -44,6 +44,7 @@ WebPluginDelegateImpl::WebPluginDelegateImpl(
windowless_(false),
plugin_(NULL),
instance_(instance),
windowless_shm_pixmap_(None),
pixmap_(NULL),
first_event_time_(-1.0),
plug_(NULL),
......@@ -399,47 +400,99 @@ void WebPluginDelegateImpl::WindowlessPaint(cairo_t* context,
pixmap_draw_rect.right(),
pixmap_draw_rect.bottom());
EnsurePixmapAtLeastSize(pixmap_rect.width(), pixmap_rect.height());
// Copy the current image into the pixmap, so the plugin can draw over
// this background.
cairo_t* cairo = gdk_cairo_create(pixmap_);
BlitContextToContext(cairo, pixmap_draw_rect, context, draw_rect.origin());
cairo_destroy(cairo);
// Construct the paint message, targeting the pixmap.
NPEvent np_event = {0};
XGraphicsExposeEvent &event = np_event.xgraphicsexpose;
event.type = GraphicsExpose;
event.display = GDK_DISPLAY();
event.drawable = GDK_PIXMAP_XID(pixmap_);
event.x = pixmap_draw_rect.x();
event.y = pixmap_draw_rect.y();
event.width = pixmap_draw_rect.width();
event.height = pixmap_draw_rect.height();
event.display = GDK_DISPLAY();
if (windowless_shm_pixmap_ != None) {
Pixmap pixmap = None;
GC xgc = NULL;
Display* display = event.display;
gfx::Rect plugin_draw_rect = draw_rect;
// Make plugin_draw_rect relative to the plugin window.
plugin_draw_rect.Offset(-window_rect_.x(), -window_rect_.y());
// In case the drawing area does not start with the plugin window origin,
// we can not let the plugin directly draw over the shared memory pixmap.
if (plugin_draw_rect.x() != pixmap_draw_rect.x() ||
plugin_draw_rect.y() != pixmap_draw_rect.y()) {
pixmap = XCreatePixmap(display, windowless_shm_pixmap_,
std::max(1, pixmap_rect.width()),
std::max(1, pixmap_rect.height()),
DefaultDepth(display, 0));
xgc = XCreateGC(display, windowless_shm_pixmap_, 0, NULL);
// Copy the current image into the pixmap, so the plugin can draw over it.
XCopyArea(display, windowless_shm_pixmap_, pixmap, xgc,
plugin_draw_rect.x(), plugin_draw_rect.y(),
pixmap_draw_rect.width(), pixmap_draw_rect.height(),
pixmap_draw_rect.x(), pixmap_draw_rect.y());
event.drawable = pixmap;
} else {
event.drawable = windowless_shm_pixmap_;
}
// Tell the plugin to paint into the pixmap.
static StatsRate plugin_paint("Plugin.Paint");
StatsScope<StatsRate> scope(plugin_paint);
NPError err = instance()->NPP_HandleEvent(&np_event);
DCHECK_EQ(err, NPERR_NO_ERROR);
if (pixmap != None) {
// Copy the rendered image pixmap back into the shm pixmap
// and thus the drawing buffer.
XCopyArea(display, pixmap, windowless_shm_pixmap_, xgc,
pixmap_draw_rect.x(), pixmap_draw_rect.y(),
pixmap_draw_rect.width(), pixmap_draw_rect.height(),
plugin_draw_rect.x(), plugin_draw_rect.y());
XSync(display, FALSE);
if (xgc)
XFreeGC(display, xgc);
XFreePixmap(display, pixmap);
} else {
XSync(display, FALSE);
}
} else {
EnsurePixmapAtLeastSize(pixmap_rect.width(), pixmap_rect.height());
// Tell the plugin to paint into the pixmap.
static StatsRate plugin_paint("Plugin.Paint");
StatsScope<StatsRate> scope(plugin_paint);
NPError err = instance()->NPP_HandleEvent(&np_event);
DCHECK_EQ(err, NPERR_NO_ERROR);
// Copy the current image into the pixmap, so the plugin can draw over
// this background.
cairo_t* cairo = gdk_cairo_create(pixmap_);
BlitContextToContext(cairo, pixmap_draw_rect, context, draw_rect.origin());
cairo_destroy(cairo);
cairo_save(context);
// Now copy the rendered image pixmap back into the drawing buffer.
gdk_cairo_set_source_pixmap(context, pixmap_, -offset_x, -offset_y);
cairo_rectangle(context, draw_rect.x(), draw_rect.y(),
draw_rect.width(), draw_rect.height());
cairo_clip(context);
cairo_paint(context);
event.drawable = GDK_PIXMAP_XID(pixmap_);
// Tell the plugin to paint into the pixmap.
static StatsRate plugin_paint("Plugin.Paint");
StatsScope<StatsRate> scope(plugin_paint);
NPError err = instance()->NPP_HandleEvent(&np_event);
DCHECK_EQ(err, NPERR_NO_ERROR);
cairo_save(context);
// Now copy the rendered image pixmap back into the drawing buffer.
gdk_cairo_set_source_pixmap(context, pixmap_, -offset_x, -offset_y);
cairo_rectangle(context, draw_rect.x(), draw_rect.y(),
draw_rect.width(), draw_rect.height());
cairo_clip(context);
cairo_paint(context);
#ifdef DEBUG_RECTANGLES
// Draw some debugging rectangles.
// Pixmap rect = blue.
DrawDebugRectangle(context, pixmap_rect, 0, 0, 1);
// Drawing rect = red.
DrawDebugRectangle(context, draw_rect, 1, 0, 0);
// Draw some debugging rectangles.
// Pixmap rect = blue.
DrawDebugRectangle(context, pixmap_rect, 0, 0, 1);
// Drawing rect = red.
DrawDebugRectangle(context, draw_rect, 1, 0, 0);
#endif
cairo_restore(context);
cairo_restore(context);
}
}
void WebPluginDelegateImpl::WindowlessSetWindow() {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment