From cb632c310910db456fbc3083fcad1fce0e1a2197 Mon Sep 17 00:00:00 2001 From: "piman@chromium.org" <piman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> Date: Thu, 5 Aug 2010 02:54:42 +0000 Subject: [PATCH] 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 --- chrome/plugin/webplugin_proxy.cc | 49 ++++++++ chrome/plugin/webplugin_proxy.h | 7 ++ webkit/glue/plugins/webplugin_delegate_impl.h | 11 ++ .../plugins/webplugin_delegate_impl_gtk.cc | 109 +++++++++++++----- 4 files changed, 148 insertions(+), 28 deletions(-) diff --git a/chrome/plugin/webplugin_proxy.cc b/chrome/plugin/webplugin_proxy.cc index 66f65fc074557..5441dc8494e5a 100644 --- a/chrome/plugin/webplugin_proxy.cc +++ b/chrome/plugin/webplugin_proxy.cc @@ -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 diff --git a/chrome/plugin/webplugin_proxy.h b/chrome/plugin/webplugin_proxy.h index 1fb72c498f908..b39026171b9db 100644 --- a/chrome/plugin/webplugin_proxy.h +++ b/chrome/plugin/webplugin_proxy.h @@ -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 diff --git a/webkit/glue/plugins/webplugin_delegate_impl.h b/webkit/glue/plugins/webplugin_delegate_impl.h index ebf5d3e069598..1c7ccb2ba5327 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl.h +++ b/webkit/glue/plugins/webplugin_delegate_impl.h @@ -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_; diff --git a/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc b/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc index 18b150474926c..d4a98a849e633 100644 --- a/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc +++ b/webkit/glue/plugins/webplugin_delegate_impl_gtk.cc @@ -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() { -- GitLab