diff options
21 files changed, 624 insertions, 157 deletions
diff --git a/chrome/browser/tab_contents/thumbnail_generator.cc b/chrome/browser/tab_contents/thumbnail_generator.cc index eeb2bfb..ba85037 100644 --- a/chrome/browser/tab_contents/thumbnail_generator.cc +++ b/chrome/browser/tab_contents/thumbnail_generator.cc @@ -16,6 +16,7 @@ #include "chrome/browser/history/top_sites.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/thumbnail_score.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_details.h" #include "content/public/browser/notification_source.h" #include "content/public/browser/notification_types.h" @@ -86,33 +87,16 @@ gfx::Size GetCopySizeForThumbnail(const gfx::Size& view_size, static_cast<int>(scale * view_size.height())); } -// Creates a downsampled thumbnail for the given RenderWidgetHost's backing +// Creates a downsampled thumbnail from the given bitmap. // store. The returned bitmap will be isNull if there was an error creating it. -SkBitmap GetBitmapForRenderWidgetHost( - RenderWidgetHost* render_widget_host, +SkBitmap CreateThumbnail( + const SkBitmap& bmp_with_scrollbars, int desired_width, int desired_height, int options, ThumbnailGenerator::ClipResult* clip_result) { base::TimeTicks begin_compute_thumbnail = base::TimeTicks::Now(); - SkBitmap result; - - // Get the bitmap as a Skia object so we can resample it. This is a large - // allocation and we can tolerate failure here, so give up if the allocation - // fails. - skia::PlatformCanvas temp_canvas; - content::RenderWidgetHostView* view = render_widget_host->GetView(); - if (!view) - return result; - const gfx::Size copy_size = - GetCopySizeForThumbnail(view->GetViewBounds().size(), - gfx::Size(desired_width, desired_height)); - if (!render_widget_host->CopyFromBackingStore( - gfx::Rect(), copy_size, &temp_canvas)) - return result; - const SkBitmap& bmp_with_scrollbars = - skia::GetTopDevice(temp_canvas)->accessBitmap(false); // Clip the edgemost 15 pixels as that will commonly hold a scrollbar, which // looks bad in thumbnails. SkIRect scrollbarless_rect = @@ -121,7 +105,7 @@ SkBitmap GetBitmapForRenderWidgetHost( std::max(1, bmp_with_scrollbars.height() - 15) }; SkBitmap bmp; bmp_with_scrollbars.extractSubset(&bmp, scrollbarless_rect); - + SkBitmap result; // Check if a clipped thumbnail is requested. if (options & ThumbnailGenerator::kClippedThumbnail) { SkBitmap clipped_bitmap = ThumbnailGenerator::GetClippedBitmap( @@ -167,6 +151,37 @@ SkBitmap GetBitmapForRenderWidgetHost( return result; } +// Creates a downsampled thumbnail for the given RenderWidgetHost's backing +// store. The returned bitmap will be isNull if there was an error creating it. +SkBitmap GetBitmapForRenderWidgetHost( + RenderWidgetHost* render_widget_host, + int desired_width, + int desired_height, + int options, + ThumbnailGenerator::ClipResult* clip_result) { + // base::TimeTicks begin_compute_thumbnail = base::TimeTicks::Now(); + + // Get the bitmap as a Skia object so we can resample it. This is a large + // allocation and we can tolerate failure here, so give up if the allocation + // fails. + skia::PlatformCanvas temp_canvas; + content::RenderWidgetHostView* view = render_widget_host->GetView(); + if (!view) + return SkBitmap(); + const gfx::Size copy_size = + GetCopySizeForThumbnail(view->GetViewBounds().size(), + gfx::Size(desired_width, desired_height)); + if (!render_widget_host->CopyFromBackingStore( + gfx::Rect(), copy_size, &temp_canvas)) + return SkBitmap(); + + return CreateThumbnail(skia::GetTopDevice(temp_canvas)->accessBitmap(false), + desired_width, + desired_height, + options, + clip_result); +} + } // namespace struct ThumbnailGenerator::AsyncRequestInfo { @@ -176,7 +191,8 @@ struct ThumbnailGenerator::AsyncRequestInfo { }; ThumbnailGenerator::ThumbnailGenerator() - : load_interrupted_(false) { + : load_interrupted_(false), + weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { // The BrowserProcessImpl creates this non-lazily. If you add nontrivial // stuff here, be sure to convert it to being lazily created. // @@ -411,6 +427,9 @@ void ThumbnailGenerator::WebContentsDisconnected(WebContents* contents) { } ++iterator; } + + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + web_contents_weak_factory_.reset(NULL); } double ThumbnailGenerator::CalculateBoringScore(const SkBitmap& bitmap) { @@ -486,15 +505,7 @@ void ThumbnailGenerator::UpdateThumbnailIfNecessary( if (!ShouldUpdateThumbnail(profile, top_sites, url)) return; - const int options = ThumbnailGenerator::kClippedThumbnail; - ThumbnailGenerator::ClipResult clip_result = ThumbnailGenerator::kNotClipped; - SkBitmap thumbnail = GetThumbnailForRendererWithOptions( - web_contents->GetRenderViewHost(), options, &clip_result); - // Failed to generate a thumbnail. Maybe the tab is in the background? - if (thumbnail.isNull()) - return; - - UpdateThumbnail(web_contents, thumbnail, clip_result); + AsyncUpdateThumbnail(web_contents); } void ThumbnailGenerator::UpdateThumbnail( @@ -524,6 +535,47 @@ void ThumbnailGenerator::UpdateThumbnail( VLOG(1) << "Thumbnail taken for " << url << ": " << score.ToString(); } +void ThumbnailGenerator::AsyncUpdateThumbnail( + WebContents* web_contents) { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + RenderWidgetHost* render_widget_host = web_contents->GetRenderViewHost(); + content::RenderWidgetHostView* view = render_widget_host->GetView(); + if (!view) + return; + + const gfx::Size copy_size = + GetCopySizeForThumbnail(view->GetViewBounds().size(), + gfx::Size(kThumbnailWidth, kThumbnailHeight)); + skia::PlatformCanvas* temp_canvas = new skia::PlatformCanvas; + web_contents_weak_factory_.reset( + new base::WeakPtrFactory<WebContents>(web_contents)); + render_widget_host->AsyncCopyFromBackingStore( + gfx::Rect(), copy_size, temp_canvas, + base::Bind(&ThumbnailGenerator::AsyncUpdateThumbnailFinish, + weak_factory_.GetWeakPtr(), + web_contents_weak_factory_->GetWeakPtr(), + base::Owned(temp_canvas))); +} + +void ThumbnailGenerator::AsyncUpdateThumbnailFinish( + base::WeakPtr<WebContents> web_contents, + skia::PlatformCanvas* temp_canvas, + bool succeeded) { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (!succeeded) + return; + + SkBitmap bmp_with_scrollbars = + skia::GetTopDevice(*temp_canvas)->accessBitmap(false); + ClipResult clip_result; + SkBitmap thumbnail = CreateThumbnail(bmp_with_scrollbars, + kThumbnailWidth, + kThumbnailHeight, + ThumbnailGenerator::kClippedThumbnail, + &clip_result); + UpdateThumbnail(web_contents.get(), thumbnail, clip_result); +} + bool ThumbnailGenerator::ShouldUpdateThumbnail(Profile* profile, history::TopSites* top_sites, const GURL& url) { diff --git a/chrome/browser/tab_contents/thumbnail_generator.h b/chrome/browser/tab_contents/thumbnail_generator.h index 481e5da..0ea0be4 100644 --- a/chrome/browser/tab_contents/thumbnail_generator.h +++ b/chrome/browser/tab_contents/thumbnail_generator.h @@ -13,6 +13,7 @@ #include "base/basictypes.h" #include "base/callback_forward.h" #include "base/memory/linked_ptr.h" +#include "base/memory/weak_ptr.h" #include "base/timer.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" @@ -34,6 +35,10 @@ namespace history { class TopSites; } +namespace skia { +class PlatformCanvas; +} + class ThumbnailGenerator : public content::NotificationObserver, public content::WebContentsObserver { public: @@ -146,6 +151,17 @@ class ThumbnailGenerator : public content::NotificationObserver, int tag, const gfx::Size& size); + // Asynchronously updates the thumbnail of the given tab. This must be called + // on the UI thread. + void AsyncUpdateThumbnail(content::WebContents* web_contents); + + // Called when the bitmap for generating a thumbnail is ready after the + // AsyncUpdateThumbnail invocation. This runs on the UI thread. + void AsyncUpdateThumbnailFinish( + base::WeakPtr<content::WebContents> web_contents, + skia::PlatformCanvas* temp_canvas, + bool result); + // content::NotificationObserver interface. virtual void Observe(int type, const content::NotificationSource& source, @@ -168,6 +184,10 @@ class ThumbnailGenerator : public content::NotificationObserver, bool load_interrupted_; + base::WeakPtrFactory<ThumbnailGenerator> weak_factory_; + scoped_ptr<base::WeakPtrFactory<content::WebContents> > + web_contents_weak_factory_; + DISALLOW_COPY_AND_ASSIGN(ThumbnailGenerator); }; diff --git a/content/browser/renderer_host/image_transport_factory.cc b/content/browser/renderer_host/image_transport_factory.cc index d000c7d..a25ca60 100644 --- a/content/browser/renderer_host/image_transport_factory.cc +++ b/content/browser/renderer_host/image_transport_factory.cc @@ -243,25 +243,12 @@ class GpuProcessTransportFactory : public ui::ContextFactory, virtual WebKit::WebGraphicsContext3D* CreateContext( ui::Compositor* compositor) OVERRIDE { - PerCompositorData* data = per_compositor_data_[compositor]; - if (!data) - data = CreatePerCompositorData(compositor); + return CreateContextCommon(compositor, false); + } - WebKit::WebGraphicsContext3D::Attributes attrs; - attrs.shareResources = true; - GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance(); - scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context( - new WebGraphicsContext3DCommandBufferImpl( - data->surface_id, - GURL(), - factory, - data->swap_client->AsWeakPtr())); - if (!context->Initialize( - attrs, - false, - content::CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE)) - return NULL; - return context.release(); + virtual WebKit::WebGraphicsContext3D* CreateOffscreenContext( + ui::Compositor* compositor) OVERRIDE { + return CreateContextCommon(compositor, true); } virtual void RemoveCompositor(ui::Compositor* compositor) OVERRIDE { @@ -386,6 +373,30 @@ class GpuProcessTransportFactory : public ui::ContextFactory, return data; } + WebKit::WebGraphicsContext3D* CreateContextCommon( + ui::Compositor* compositor, + bool offscreen) OVERRIDE { + PerCompositorData* data = per_compositor_data_[compositor]; + if (!data) + data = CreatePerCompositorData(compositor); + + WebKit::WebGraphicsContext3D::Attributes attrs; + attrs.shareResources = true; + GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance(); + scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context( + new WebGraphicsContext3DCommandBufferImpl( + offscreen ? 0 : data->surface_id, + GURL(), + factory, + data->swap_client->AsWeakPtr())); + if (!context->Initialize( + attrs, + false, + content::CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE)) + return NULL; + return context.release(); + } + void CreateSharedContext(ui::Compositor* compositor) { PerCompositorData* data = per_compositor_data_[compositor]; DCHECK(data); diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index 7476989..fd5e142 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc @@ -514,6 +514,40 @@ bool RenderWidgetHostImpl::CopyFromBackingStore( return backing_store->CopyFromBackingStore(copy_rect, output); } +void RenderWidgetHostImpl::AsyncCopyFromBackingStore( + const gfx::Rect& src_rect, + const gfx::Size& accelerated_dest_size, + skia::PlatformCanvas* output, + base::Callback<void(bool)> callback) { + if (view_ && is_accelerated_compositing_active_) { + TRACE_EVENT0("browser", + "RenderWidgetHostImpl::CopyFromBackingStore::FromCompositingSurface"); + // TODO(mazda): Support partial copy with |src_rect| + // (http://crbug.com/118571). + view_->AsyncCopyFromCompositingSurface(accelerated_dest_size, + output, + callback); + return; + } + + BackingStore* backing_store = GetBackingStore(false); + if (!backing_store) { + callback.Run(false); + return; + } + + TRACE_EVENT0("browser", + "RenderWidgetHostImpl::CopyFromBackingStore::FromBackingStore"); + const gfx::Size backing_store_size = backing_store->size(); + gfx::Rect copy_rect = src_rect.IsEmpty() ? + gfx::Rect(0, 0, backing_store_size.width(), backing_store_size.height()) : + src_rect; + // When the result size is equal to the backing store size, copy from the + // backing store directly to the output canvas. + bool result = backing_store->CopyFromBackingStore(copy_rect, output); + callback.Run(result); +} + #if defined(TOOLKIT_GTK) bool RenderWidgetHostImpl::CopyFromBackingStoreToGtkWindow( const gfx::Rect& dest_rect, GdkWindow* target) { diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index ca16dbc5..b66a6cd 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h @@ -81,6 +81,11 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost, virtual bool CopyFromBackingStore(const gfx::Rect& src_rect, const gfx::Size& accelerated_dest_size, skia::PlatformCanvas* output) OVERRIDE; + virtual void AsyncCopyFromBackingStore( + const gfx::Rect& src_rect, + const gfx::Size& accelerated_dest_size, + skia::PlatformCanvas* output, + base::Callback<void(bool)> callback) OVERRIDE; #if defined(TOOLKIT_GTK) virtual bool CopyFromBackingStoreToGtkWindow(const gfx::Rect& dest_rect, GdkWindow* target) OVERRIDE; diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index 0b7665a..89c1d03 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc @@ -5,6 +5,7 @@ #include "content/browser/renderer_host/render_widget_host_view_aura.h" #include "base/bind.h" +#include "base/bind_helpers.h" #include "base/logging.h" #include "base/memory/weak_ptr.h" #include "content/browser/renderer_host/backing_store_skia.h" @@ -100,6 +101,18 @@ bool CanRendererHandleEvent(const aura::MouseEvent* event) { return true; } +// Creates a content::GLHelper for the given compositor. +content::GLHelper* CreateGLHelper(ui::Compositor* compositor) { + ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); + WebKit::WebGraphicsContext3D* context = + factory->GetSharedContext(compositor); + DCHECK(context); + WebKit::WebGraphicsContext3D* context_for_thread = + factory->AsContextFactory()->CreateOffscreenContext(compositor); + DCHECK(context_for_thread); + return new content::GLHelper(context, context_for_thread); +} + } // namespace // We have to implement the WindowObserver interface on a separate object @@ -403,6 +416,60 @@ BackingStore* RenderWidgetHostViewAura::AllocBackingStore( return new BackingStoreSkia(host_, size); } +bool RenderWidgetHostViewAura::CopyFromCompositingSurface( + const gfx::Size& size, + skia::PlatformCanvas* output) { + ui::Compositor* compositor = GetCompositor(); + if (!compositor) + return false; + + ImageTransportClient* container = image_transport_clients_[current_surface_]; + if (!container) + return false; + + if (!output->initialize(size.width(), size.height(), true)) + return false; + + if (!gl_helper_.get()) + gl_helper_.reset(CreateGLHelper(compositor)); + + unsigned char* addr = static_cast<unsigned char*>( + output->getTopDevice()->accessBitmap(true).getPixels()); + return gl_helper_->CopyTextureTo(container->texture_id(), + container->size(), + size, + addr); +} + +void RenderWidgetHostViewAura::AsyncCopyFromCompositingSurface( + const gfx::Size& size, + skia::PlatformCanvas* output, + base::Callback<void(bool)> callback) { + base::ScopedClosureRunner scoped_callback_runner(base::Bind(callback, false)); + ui::Compositor* compositor = GetCompositor(); + if (!compositor) + return; + + ImageTransportClient* container = image_transport_clients_[current_surface_]; + if (!container) + return; + + if (!output->initialize(size.width(), size.height(), true)) + return; + + if (!gl_helper_.get()) + gl_helper_.reset(CreateGLHelper(compositor)); + + scoped_callback_runner.Release(); + unsigned char* addr = static_cast<unsigned char*>( + output->getTopDevice()->accessBitmap(true).getPixels()); + gl_helper_->AsyncCopyTextureTo(container->texture_id(), + container->size(), + size, + addr, + callback); +} + void RenderWidgetHostViewAura::OnAcceleratedCompositingStateChange() { // Delay UpdateExternalTexture until we actually got a software frame. // Sometimes (e.g. on a page load) the renderer will spuriously disable then @@ -572,36 +639,6 @@ void RenderWidgetHostViewAura::SetBackground(const SkBitmap& background) { window_->layer()->SetFillsBoundsOpaquely(background.isOpaque()); } -bool RenderWidgetHostViewAura::CopyFromCompositingSurface( - const gfx::Size& size, - skia::PlatformCanvas* output) { - ui::Compositor* compositor = GetCompositor(); - if (!compositor) - return false; - - ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); - WebKit::WebGraphicsContext3D* context = factory->GetSharedContext(compositor); - if (!context) - return false; - - ImageTransportClient* container = image_transport_clients_[current_surface_]; - if (!container) - return false; - - if (!output->initialize(size.width(), size.height(), true)) - return false; - - if (!gl_helper_.get()) - gl_helper_.reset(new content::GLHelper(context)); - - unsigned char* addr = static_cast<unsigned char*>( - output->getTopDevice()->accessBitmap(true).getPixels()); - return gl_helper_->CopyTextureTo(container->texture_id(), - container->size(), - size, - addr); -} - void RenderWidgetHostViewAura::GetScreenInfo(WebKit::WebScreenInfo* results) { GetDefaultScreenInfo(results); } @@ -1112,8 +1149,7 @@ void RenderWidgetHostViewAura::OnLostResources(ui::Compositor* compositor) { // Detach the resources to avoid deleting them using the invalid context. // They've been released anyway when the GPU process died. gl_helper_->Detach(); - gl_helper_.reset( - new content::GLHelper(factory->GetSharedContext(compositor))); + gl_helper_.reset(CreateGLHelper(compositor)); } } diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h index 49479b0..0127f1e 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.h +++ b/content/browser/renderer_host/render_widget_host_view_aura.h @@ -66,9 +66,6 @@ class RenderWidgetHostViewAura virtual bool IsShowing() OVERRIDE; virtual gfx::Rect GetViewBounds() const OVERRIDE; virtual void SetBackground(const SkBitmap& background) OVERRIDE; - virtual bool CopyFromCompositingSurface( - const gfx::Size& size, - skia::PlatformCanvas* output) OVERRIDE; // Overridden from RenderWidgetHostViewPort: virtual void InitAsPopup(content::RenderWidgetHostView* parent_host_view, @@ -96,6 +93,13 @@ class RenderWidgetHostViewAura virtual void SelectionBoundsChanged(const gfx::Rect& start_rect, const gfx::Rect& end_rect) OVERRIDE; virtual BackingStore* AllocBackingStore(const gfx::Size& size) OVERRIDE; + virtual bool CopyFromCompositingSurface( + const gfx::Size& size, + skia::PlatformCanvas* output) OVERRIDE; + virtual void AsyncCopyFromCompositingSurface( + const gfx::Size& size, + skia::PlatformCanvas* output, + base::Callback<void(bool)> callback) OVERRIDE; virtual void OnAcceleratedCompositingStateChange() OVERRIDE; virtual void AcceleratedSurfaceBuffersSwapped( const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params, diff --git a/content/browser/renderer_host/render_widget_host_view_gtk.cc b/content/browser/renderer_host/render_widget_host_view_gtk.cc index b49e8d6..7c5fcdf 100644 --- a/content/browser/renderer_host/render_widget_host_view_gtk.cc +++ b/content/browser/renderer_host/render_widget_host_view_gtk.cc @@ -969,6 +969,23 @@ BackingStore* RenderWidgetHostViewGtk::AllocBackingStore( depth); } +bool RenderWidgetHostViewGtk::CopyFromCompositingSurface( + const gfx::Size& size, + skia::PlatformCanvas* output) { + // TODO(mazda): Implement this. + NOTIMPLEMENTED(); + return false; +} + +void RenderWidgetHostViewGtk::AsyncCopyFromCompositingSurface( + const gfx::Size& size, + skia::PlatformCanvas* output, + base::Callback<void(bool)> callback) { + // TODO(mazda): Implement this. + NOTIMPLEMENTED(); + callback.Run(false); +} + void RenderWidgetHostViewGtk::AcceleratedSurfaceBuffersSwapped( const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params, int gpu_host_id) { @@ -990,14 +1007,6 @@ void RenderWidgetHostViewGtk::SetBackground(const SkBitmap& background) { host_->Send(new ViewMsg_SetBackground(host_->GetRoutingID(), background)); } -bool RenderWidgetHostViewGtk::CopyFromCompositingSurface( - const gfx::Size& size, - skia::PlatformCanvas* output) { - // TODO(mazda): Implement this. - NOTIMPLEMENTED(); - return false; -} - void RenderWidgetHostViewGtk::ModifyEventForEdgeDragging( GtkWidget* widget, GdkEventMotion* event) { // If the widget is aligned with an edge of the monitor its on and the user diff --git a/content/browser/renderer_host/render_widget_host_view_gtk.h b/content/browser/renderer_host/render_widget_host_view_gtk.h index b943a8d..71c080d 100644 --- a/content/browser/renderer_host/render_widget_host_view_gtk.h +++ b/content/browser/renderer_host/render_widget_host_view_gtk.h @@ -62,9 +62,6 @@ class RenderWidgetHostViewGtk : public content::RenderWidgetHostViewBase { virtual GdkEventButton* GetLastMouseDown() OVERRIDE; virtual gfx::NativeView BuildInputMethodsGtkMenu() OVERRIDE; virtual void SetBackground(const SkBitmap& background) OVERRIDE; - virtual bool CopyFromCompositingSurface( - const gfx::Size& size, - skia::PlatformCanvas* output) OVERRIDE; // RenderWidgetHostViewPort implementation. virtual void InitAsPopup(content::RenderWidgetHostView* parent_host_view, @@ -96,6 +93,13 @@ class RenderWidgetHostViewGtk : public content::RenderWidgetHostViewBase { virtual void SelectionBoundsChanged(const gfx::Rect& start_rect, const gfx::Rect& end_rect) OVERRIDE; virtual BackingStore* AllocBackingStore(const gfx::Size& size) OVERRIDE; + virtual bool CopyFromCompositingSurface( + const gfx::Size& size, + skia::PlatformCanvas* output) OVERRIDE; + virtual void AsyncCopyFromCompositingSurface( + const gfx::Size& size, + skia::PlatformCanvas* output, + base::Callback<void(bool)> callback) OVERRIDE; virtual void OnAcceleratedCompositingStateChange() OVERRIDE; virtual void AcceleratedSurfaceBuffersSwapped( const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params, diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h index 2cb053e..4df271b 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.h +++ b/content/browser/renderer_host/render_widget_host_view_mac.h @@ -206,9 +206,6 @@ class RenderWidgetHostViewMac : public content::RenderWidgetHostViewBase { virtual void SetWindowVisibility(bool visible) OVERRIDE; virtual void WindowFrameChanged() OVERRIDE; virtual void SetBackground(const SkBitmap& background) OVERRIDE; - virtual bool CopyFromCompositingSurface( - const gfx::Size& size, - skia::PlatformCanvas* output) OVERRIDE; // Implementation of RenderWidgetHostViewPort. virtual void InitAsPopup(content::RenderWidgetHostView* parent_host_view, @@ -240,6 +237,13 @@ class RenderWidgetHostViewMac : public content::RenderWidgetHostViewBase { size_t offset, const ui::Range& range) OVERRIDE; virtual BackingStore* AllocBackingStore(const gfx::Size& size) OVERRIDE; + virtual bool CopyFromCompositingSurface( + const gfx::Size& size, + skia::PlatformCanvas* output) OVERRIDE; + virtual void AsyncCopyFromCompositingSurface( + const gfx::Size& size, + skia::PlatformCanvas* output, + base::Callback<void(bool)> callback) OVERRIDE; virtual void OnAcceleratedCompositingStateChange() OVERRIDE; // See comment in RenderWidgetHostView! virtual gfx::Rect GetViewCocoaBounds() const OVERRIDE; diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm index 2138fa7..6ba515f 100644 --- a/content/browser/renderer_host/render_widget_host_view_mac.mm +++ b/content/browser/renderer_host/render_widget_host_view_mac.mm @@ -793,6 +793,23 @@ BackingStore* RenderWidgetHostViewMac::AllocBackingStore( return new BackingStoreMac(render_widget_host_, size); } +bool RenderWidgetHostViewMac::CopyFromCompositingSurface( + const gfx::Size& size, + skia::PlatformCanvas* output) { + // TODO(mazda): Implement this. + NOTIMPLEMENTED(); + return false; +} + +void RenderWidgetHostViewMac::AsyncCopyFromCompositingSurface( + const gfx::Size& size, + skia::PlatformCanvas* output, + base::Callback<void(bool)> callback) { + // TODO(mazda): Implement this. + NOTIMPLEMENTED(); + callback.Run(false); +} + // Sets whether or not to accept first responder status. void RenderWidgetHostViewMac::SetTakesFocusOnlyOnMouseDown(bool flag) { [cocoa_view_ setTakesFocusOnlyOnMouseDown:flag]; @@ -1163,14 +1180,6 @@ void RenderWidgetHostViewMac::SetBackground(const SkBitmap& background) { render_widget_host_->GetRoutingID(), background)); } -bool RenderWidgetHostViewMac::CopyFromCompositingSurface( - const gfx::Size& size, - skia::PlatformCanvas* output) { - // TODO(mazda): Implement this. - NOTIMPLEMENTED(); - return false; -} - void RenderWidgetHostViewMac::OnAccessibilityNotifications( const std::vector<AccessibilityHostMsg_NotificationParams>& params) { if (!GetBrowserAccessibilityManager()) { diff --git a/content/browser/renderer_host/render_widget_host_view_win.cc b/content/browser/renderer_host/render_widget_host_view_win.cc index 530e5c3..8ee1da2 100644 --- a/content/browser/renderer_host/render_widget_host_view_win.cc +++ b/content/browser/renderer_host/render_widget_host_view_win.cc @@ -903,11 +903,6 @@ BackingStore* RenderWidgetHostViewWin::AllocBackingStore( return new BackingStoreWin(render_widget_host_, size); } -void RenderWidgetHostViewWin::SetBackground(const SkBitmap& background) { - content::RenderWidgetHostViewBase::SetBackground(background); - render_widget_host_->SetBackground(background); -} - bool RenderWidgetHostViewWin::CopyFromCompositingSurface( const gfx::Size& size, skia::PlatformCanvas* output) { @@ -924,6 +919,20 @@ bool RenderWidgetHostViewWin::CopyFromCompositingSurface( size, output->getTopDevice()->accessBitmap(true).getPixels()); } +void RenderWidgetHostViewWin::AsyncCopyFromCompositingSurface( + const gfx::Size& size, + skia::PlatformCanvas* output, + base::Callback<void(bool)> callback) { + // TODO(mazda): Implement this. + NOTIMPLEMENTED(); + callback.Run(false); +} + +void RenderWidgetHostViewWin::SetBackground(const SkBitmap& background) { + content::RenderWidgetHostViewBase::SetBackground(background); + render_widget_host_->SetBackground(background); +} + void RenderWidgetHostViewWin::ProcessTouchAck( WebKit::WebInputEvent::Type type, bool processed) { if (type == WebKit::WebInputEvent::TouchStart) diff --git a/content/browser/renderer_host/render_widget_host_view_win.h b/content/browser/renderer_host/render_widget_host_view_win.h index 08829ad..44dbfcb 100644 --- a/content/browser/renderer_host/render_widget_host_view_win.h +++ b/content/browser/renderer_host/render_widget_host_view_win.h @@ -169,9 +169,6 @@ class RenderWidgetHostViewWin virtual bool IsShowing() OVERRIDE; virtual gfx::Rect GetViewBounds() const OVERRIDE; virtual void SetBackground(const SkBitmap& background) OVERRIDE; - virtual bool CopyFromCompositingSurface( - const gfx::Size& size, - skia::PlatformCanvas* output) OVERRIDE; // Implementation of RenderWidgetHostViewPort. virtual void InitAsPopup(content::RenderWidgetHostView* parent_host_view, @@ -202,6 +199,13 @@ class RenderWidgetHostViewWin virtual void Destroy() OVERRIDE; virtual void SetTooltipText(const string16& tooltip_text) OVERRIDE; virtual BackingStore* AllocBackingStore(const gfx::Size& size) OVERRIDE; + virtual bool CopyFromCompositingSurface( + const gfx::Size& size, + skia::PlatformCanvas* output) OVERRIDE; + virtual void AsyncCopyFromCompositingSurface( + const gfx::Size& size, + skia::PlatformCanvas* output, + base::Callback<void(bool)> callback) OVERRIDE; virtual void OnAcceleratedCompositingStateChange() OVERRIDE; virtual void ProcessTouchAck(WebKit::WebInputEvent::Type type, bool processed) OVERRIDE; diff --git a/content/browser/renderer_host/test_render_view_host.cc b/content/browser/renderer_host/test_render_view_host.cc index 791fa17..03d9656 100644 --- a/content/browser/renderer_host/test_render_view_host.cc +++ b/content/browser/renderer_host/test_render_view_host.cc @@ -94,6 +94,19 @@ BackingStore* TestRenderWidgetHostView::AllocBackingStore( return new TestBackingStore(rwh_, size); } +bool TestRenderWidgetHostView::CopyFromCompositingSurface( + const gfx::Size& size, + skia::PlatformCanvas* output) { + return false; +} + +void TestRenderWidgetHostView::AsyncCopyFromCompositingSurface( + const gfx::Size& size, + skia::PlatformCanvas* output, + base::Callback<void(bool)> callback) { + callback.Run(false); +} + void TestRenderWidgetHostView::OnAcceleratedCompositingStateChange() { } @@ -179,12 +192,6 @@ gfx::NativeView TestRenderWidgetHostView::BuildInputMethodsGtkMenu() { } #endif // defined(TOOLKIT_GTK) -bool TestRenderWidgetHostView::CopyFromCompositingSurface( - const gfx::Size& size, - skia::PlatformCanvas* output) { - return false; -} - gfx::GLSurfaceHandle TestRenderWidgetHostView::GetCompositingSurface() { return gfx::GLSurfaceHandle(); } diff --git a/content/browser/renderer_host/test_render_view_host.h b/content/browser/renderer_host/test_render_view_host.h index 365a05b..b3837e5 100644 --- a/content/browser/renderer_host/test_render_view_host.h +++ b/content/browser/renderer_host/test_render_view_host.h @@ -71,9 +71,6 @@ class TestRenderWidgetHostView : public RenderWidgetHostViewBase { virtual GdkEventButton* GetLastMouseDown() OVERRIDE; virtual gfx::NativeView BuildInputMethodsGtkMenu() OVERRIDE; #endif // defined(TOOLKIT_GTK) - virtual bool CopyFromCompositingSurface( - const gfx::Size& size, - skia::PlatformCanvas* output) OVERRIDE; // RenderWidgetHostViewPort implementation. virtual void InitAsPopup(RenderWidgetHostView* parent_host_view, @@ -100,6 +97,13 @@ class TestRenderWidgetHostView : public RenderWidgetHostViewBase { virtual void Destroy() OVERRIDE {} virtual void SetTooltipText(const string16& tooltip_text) OVERRIDE {} virtual BackingStore* AllocBackingStore(const gfx::Size& size) OVERRIDE; + virtual bool CopyFromCompositingSurface( + const gfx::Size& size, + skia::PlatformCanvas* output) OVERRIDE; + virtual void AsyncCopyFromCompositingSurface( + const gfx::Size& size, + skia::PlatformCanvas* output, + base::Callback<void(bool)> callback) OVERRIDE; virtual void OnAcceleratedCompositingStateChange() OVERRIDE; virtual void AcceleratedSurfaceBuffersSwapped( const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params, diff --git a/content/common/gpu/client/gl_helper.cc b/content/common/gpu/client/gl_helper.cc index 5b88e4f..ca91b84 100644 --- a/content/common/gpu/client/gl_helper.cc +++ b/content/common/gpu/client/gl_helper.cc @@ -4,7 +4,12 @@ #include "content/common/gpu/client/gl_helper.h" +#include "base/bind.h" +#include "base/lazy_instance.h" #include "base/logging.h" +#include "base/message_loop.h" +#include "base/synchronization/waitable_event.h" +#include "base/threading/thread.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebCString.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" #include "ui/gfx/gl/gl_bindings.h" @@ -12,6 +17,21 @@ namespace { +const char kGLHelperThreadName[] = "GLHelperThread"; + +class GLHelperThread : public base::Thread { + public: + GLHelperThread() : base::Thread(kGLHelperThreadName) { + Start(); + } + virtual ~GLHelperThread() {} + + DISALLOW_COPY_AND_ASSIGN(GLHelperThread); +}; + +base::LazyInstance<GLHelperThread> g_gl_helper_thread = + LAZY_INSTANCE_INITIALIZER; + class ScopedWebGLId { public: typedef void (WebKit::WebGraphicsContext3D::*DeleteFunc)(WebKit::WebGLId); @@ -171,6 +191,57 @@ class ScopedTextureBinder : ScopedBinder<target> { &WebKit::WebGraphicsContext3D::bindTexture) {} }; +void ReadBackFramebuffer( + WebKit::WebGraphicsContext3D* context, + unsigned char* pixels, + gfx::Size size, + WebKit::WebGLId dst_texture, + bool* result) { + *result = false; + if (!context->makeContextCurrent()) + return; + if (context->isContextLost()) + return; + ScopedFramebuffer dst_framebuffer(context, context->createFramebuffer()); + { + ScopedFramebufferBinder<GL_DRAW_FRAMEBUFFER> framebuffer_binder( + context, dst_framebuffer); + ScopedTextureBinder<GL_TEXTURE_2D> texture_binder( + context, dst_texture); + context->framebufferTexture2D(GL_DRAW_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + dst_texture, + 0); + } + *result = context->readBackFramebuffer( + pixels, + 4 * size.GetArea(), + static_cast<WebKit::WebGLId>(dst_framebuffer), + size.width(), + size.height()); + context->flush(); +} + +void ReadBackFramebufferComplete(WebKit::WebGraphicsContext3D* context, + WebKit::WebGLId* dst_texture, + base::Callback<void(bool)> callback, + bool* result) { + callback.Run(*result); + if (*dst_texture != 0) { + context->deleteTexture(*dst_texture); + *dst_texture = 0; + } +} + +void DeleteContext(WebKit::WebGraphicsContext3D* context) { + delete context; +} + +void SignalWaitableEvent(base::WaitableEvent* event) { + event->Signal(); +} + } // namespace namespace content { @@ -179,15 +250,20 @@ namespace content { class GLHelper::CopyTextureToImpl { public: CopyTextureToImpl(WebKit::WebGraphicsContext3D* context, + WebKit::WebGraphicsContext3D* context_for_thread, GLHelper* helper) : context_(context), + context_for_thread_(context_for_thread), helper_(helper), program_(context, context->createProgram()), - vertex_attributes_buffer_(context_, context_->createBuffer()) { + vertex_attributes_buffer_(context_, context_->createBuffer()), + dst_texture_(0) { InitBuffer(); InitProgram(); } - ~CopyTextureToImpl() {} + ~CopyTextureToImpl() { + DeleteContextForThread(); + } void InitBuffer(); void InitProgram(); @@ -197,7 +273,21 @@ class GLHelper::CopyTextureToImpl { const gfx::Size& src_size, const gfx::Size& dst_size, unsigned char* out); + + void AsyncCopyTextureTo(WebKit::WebGLId src_texture, + const gfx::Size& src_size, + const gfx::Size& dst_size, + unsigned char* out, + base::Callback<void(bool)> callback); private: + // Returns the id of a framebuffer that + WebKit::WebGLId ScaleTexture(WebKit::WebGLId src_texture, + const gfx::Size& src_size, + const gfx::Size& dst_size); + + // Deletes the context for GLHelperThread. + void DeleteContextForThread(); + // Interleaved array of 2-dimentional vertex positions (x, y) and // 2-dimentional texture coordinates (s, t). static const WebKit::WGC3Dfloat kVertexAttributes[]; @@ -206,6 +296,7 @@ class GLHelper::CopyTextureToImpl { static const WebKit::WGC3Dchar kCopyFragmentShader[]; WebKit::WebGraphicsContext3D* context_; + WebKit::WebGraphicsContext3D* context_for_thread_; GLHelper* helper_; // A program for copying a source texture into a destination texture. @@ -219,6 +310,8 @@ class GLHelper::CopyTextureToImpl { WebKit::WGC3Dint texcoord_location_; // The location of the source texture in the program. WebKit::WGC3Dint texture_location_; + // The destination texture id. This is used only for the asynchronous version. + WebKit::WebGLId dst_texture_; }; const WebKit::WGC3Dfloat GLHelper::CopyTextureToImpl::kVertexAttributes[] = { @@ -281,19 +374,21 @@ void GLHelper::CopyTextureToImpl::InitProgram() { void GLHelper::CopyTextureToImpl::Detach() { program_.Detach(); vertex_attributes_buffer_.Detach(); + dst_texture_ = 0; } -bool GLHelper::CopyTextureToImpl::CopyTextureTo(WebKit::WebGLId src_texture, - const gfx::Size& src_size, - const gfx::Size& dst_size, - unsigned char* out) { - ScopedFramebuffer dst_framebuffer(context_, context_->createFramebuffer()); - ScopedTexture dst_texture(context_, context_->createTexture()); +WebKit::WebGLId GLHelper::CopyTextureToImpl::ScaleTexture( + WebKit::WebGLId src_texture, + const gfx::Size& src_size, + const gfx::Size& dst_size) { + WebKit::WebGLId dst_texture = context_->createTexture(); { + ScopedFramebuffer dst_framebuffer(context_, context_->createFramebuffer()); ScopedFramebufferBinder<GL_DRAW_FRAMEBUFFER> framebuffer_binder( context_, dst_framebuffer); { - ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(context_, dst_texture); + ScopedTextureBinder<GL_TEXTURE_2D> texture_binder( + context_, dst_texture); context_->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, @@ -340,22 +435,102 @@ bool GLHelper::CopyTextureToImpl::CopyTextureTo(WebKit::WebGLId src_texture, // Conduct texture mapping by drawing a quad composed of two triangles. context_->drawArrays(GL_TRIANGLE_STRIP, 0, 4); } + return dst_texture; +} + +void GLHelper::CopyTextureToImpl::DeleteContextForThread() { + if (!context_for_thread_) + return; + + g_gl_helper_thread.Pointer()->message_loop_proxy()->PostTask( + FROM_HERE, + base::Bind(&DeleteContext, + context_for_thread_)); + context_for_thread_ = NULL; +} - // TODO(mazda): Do this on another thread because this can block the UI - // thread for possibly a long time (http://crbug.com/118547). +bool GLHelper::CopyTextureToImpl::CopyTextureTo( + WebKit::WebGLId src_texture, + const gfx::Size& src_size, + const gfx::Size& dst_size, + unsigned char* out) { + ScopedTexture dst_texture(context_, + ScaleTexture(src_texture, src_size, dst_size)); + ScopedFramebuffer dst_framebuffer(context_, context_->createFramebuffer()); + { + ScopedFramebufferBinder<GL_DRAW_FRAMEBUFFER> framebuffer_binder( + context_, dst_framebuffer); + ScopedTextureBinder<GL_TEXTURE_2D> texture_binder( + context_, dst_framebuffer); + context_->framebufferTexture2D(GL_DRAW_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + dst_texture, + 0); + } return context_->readBackFramebuffer( out, - 4 * dst_size.width() * dst_size.height(), - dst_framebuffer, + 4 * dst_size.GetArea(), + static_cast<WebKit::WebGLId>(dst_framebuffer), dst_size.width(), dst_size.height()); } -GLHelper::GLHelper(WebKit::WebGraphicsContext3D* context) - : context_(context) { +void GLHelper::CopyTextureToImpl::AsyncCopyTextureTo( + WebKit::WebGLId src_texture, + const gfx::Size& src_size, + const gfx::Size& dst_size, + unsigned char* out, + base::Callback<void(bool)> callback) { + if (!context_for_thread_) { + callback.Run(false); + return; + } + + dst_texture_ = ScaleTexture(src_texture, src_size, dst_size); + context_->flush(); + bool* result = new bool(false); + g_gl_helper_thread.Pointer()->message_loop_proxy()->PostTaskAndReply( + FROM_HERE, + base::Bind(&ReadBackFramebuffer, + context_for_thread_, + out, + dst_size, + dst_texture_, + result), + base::Bind(&ReadBackFramebufferComplete, + context_, + &dst_texture_, + callback, + base::Owned(result))); +} + +base::subtle::Atomic32 GLHelper::count_ = 0; + +GLHelper::GLHelper(WebKit::WebGraphicsContext3D* context, + WebKit::WebGraphicsContext3D* context_for_thread) + : context_(context), + context_for_thread_(context_for_thread) { + base::subtle::NoBarrier_AtomicIncrement(&count_, 1); } GLHelper::~GLHelper() { + DCHECK_NE(MessageLoop::current(), + g_gl_helper_thread.Pointer()->message_loop()); + base::subtle::Atomic32 decremented_count = + base::subtle::NoBarrier_AtomicIncrement(&count_, -1); + if (decremented_count == 0) { + // When this is the last instance, we synchronize with the pending + // operations on GLHelperThread. Otherwise on shutdown we may kill the GPU + // process infrastructure (BrowserGpuChannelHostFactory) before they have + // a chance to complete, likely leading to a crash. + base::WaitableEvent event(false, false); + g_gl_helper_thread.Pointer()->message_loop_proxy()->PostTask( + FROM_HERE, + base::Bind(&SignalWaitableEvent, + &event)); + event.Wait(); + } } WebKit::WebGraphicsContext3D* GLHelper::context() const { @@ -373,13 +548,33 @@ bool GLHelper::CopyTextureTo(WebKit::WebGLId src_texture, unsigned char* out) { // Lazily initialize |copy_texture_to_impl_| if (!copy_texture_to_impl_.get()) - copy_texture_to_impl_.reset(new CopyTextureToImpl(context_, this)); - - return copy_texture_to_impl_->CopyTextureTo(src_texture, - src_size, - dst_size, - out); + copy_texture_to_impl_.reset(new CopyTextureToImpl(context_, + context_for_thread_, + this)); + + return copy_texture_to_impl_->CopyTextureTo( + src_texture, + src_size, + dst_size, + out); +} +void GLHelper::AsyncCopyTextureTo(WebKit::WebGLId src_texture, + const gfx::Size& src_size, + const gfx::Size& dst_size, + unsigned char* out, + const base::Callback<void(bool)>& callback) { + // Lazily initialize |copy_texture_to_impl_| + if (!copy_texture_to_impl_.get()) + copy_texture_to_impl_.reset(new CopyTextureToImpl(context_, + context_for_thread_, + this)); + + copy_texture_to_impl_->AsyncCopyTextureTo(src_texture, + src_size, + dst_size, + out, + callback); } WebKit::WebGLId GLHelper::CompileShaderFromSource( diff --git a/content/common/gpu/client/gl_helper.h b/content/common/gpu/client/gl_helper.h index 73e7949..771cad3 100644 --- a/content/common/gpu/client/gl_helper.h +++ b/content/common/gpu/client/gl_helper.h @@ -6,7 +6,9 @@ #define CONTENT_COMMON_GPU_CLIENT_GL_HELPER_H_ #pragma once +#include "base/atomicops.h" #include "base/basictypes.h" +#include "base/callback.h" #include "base/memory/scoped_ptr.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebGraphicsContext3D.h" @@ -20,7 +22,8 @@ namespace content { // interfaces. class GLHelper { public: - GLHelper(WebKit::WebGraphicsContext3D* context); + GLHelper(WebKit::WebGraphicsContext3D* context, + WebKit::WebGraphicsContext3D* context_for_thread); virtual ~GLHelper(); WebKit::WebGraphicsContext3D* context() const; @@ -35,6 +38,14 @@ class GLHelper { const gfx::Size& dst_size, unsigned char* out); + // Asynchronous version of CopyTextureTo. |callback| is invoked with the copy + // result when the copy operation has completed. + void AsyncCopyTextureTo(WebKit::WebGLId src_texture, + const gfx::Size& src_size, + const gfx::Size& dst_size, + unsigned char* out, + const base::Callback<void(bool)>& callback); + // Returns the shader compiled from the source. WebKit::WebGLId CompileShaderFromSource(const WebKit::WGC3Dchar* source, WebKit::WGC3Denum type); @@ -43,8 +54,12 @@ class GLHelper { class CopyTextureToImpl; WebKit::WebGraphicsContext3D* context_; + WebKit::WebGraphicsContext3D* context_for_thread_; scoped_ptr<CopyTextureToImpl> copy_texture_to_impl_; + // The number of all GLHelper instances. + static base::subtle::Atomic32 count_; + DISALLOW_COPY_AND_ASSIGN(GLHelper); }; diff --git a/content/port/browser/render_widget_host_view_port.h b/content/port/browser/render_widget_host_view_port.h index a45a214..55e06be 100644 --- a/content/port/browser/render_widget_host_view_port.h +++ b/content/port/browser/render_widget_host_view_port.h @@ -6,6 +6,7 @@ #define CONTENT_PORT_BROWSER_RENDER_WIDGET_HOST_VIEW_PORT_H_ #pragma once +#include "base/callback.h" #include "base/process_util.h" #include "base/string16.h" #include "content/common/content_export.h" @@ -138,12 +139,20 @@ class CONTENT_EXPORT RenderWidgetHostViewPort : public RenderWidgetHostView { // Allocate a backing store for this view. virtual BackingStore* AllocBackingStore(const gfx::Size& size) = 0; - // Copies the contents of the compositing surface into the given - // (uninitialized) PlatformCanvas if any. Returns true on success, false - // otherwise. + // DEPRECATED: Synchronous version of AsyncCopyFromCompositingSurface. + // This will be removed once all the caller have been chagned to use the + // asynchronous version. virtual bool CopyFromCompositingSurface(const gfx::Size& size, skia::PlatformCanvas* output) = 0; + // Asynchrnously copies the contents of the compositing surface into the given + // (uninitialized) PlatformCanvas if any. Returns true on success, false + // otherwise. + virtual void AsyncCopyFromCompositingSurface( + const gfx::Size& size, + skia::PlatformCanvas* output, + base::Callback<void(bool)> callback) = 0; + // Called when accelerated compositing state changes. virtual void OnAcceleratedCompositingStateChange() = 0; // |params.window| and |params.surface_id| indicate which accelerated diff --git a/content/public/browser/render_widget_host.h b/content/public/browser/render_widget_host.h index 2a5bf15..1529069 100644 --- a/content/public/browser/render_widget_host.h +++ b/content/public/browser/render_widget_host.h @@ -6,6 +6,7 @@ #define CONTENT_PUBLIC_BROWSER_RENDER_WIDGET_HOST_H_ #pragma once +#include "base/callback.h" #include "content/common/content_export.h" #include "content/public/browser/keyboard_listener.h" #include "content/public/browser/native_web_keyboard_event.h" @@ -170,10 +171,19 @@ class CONTENT_EXPORT RenderWidgetHost : public IPC::Channel::Sender { virtual void Blur() = 0; + // DEPRECATED: Synchronous version of AsyncCopyFromBackingSurface. + // This will be removed once all the caller have been changed to use the + // asynchronous version. + virtual bool CopyFromBackingStore(const gfx::Rect& src_rect, + const gfx::Size& accelerated_dest_size, + skia::PlatformCanvas* output) = 0; + // Copies the given subset of the backing store into the given (uninitialized) // PlatformCanvas. If |src_rect| is empty, the whole contents is copied. - // Returns true on success, false otherwise. When accelerated compositing is - // active, the contents is copied from the compositing surface. + // |callback| is invoked with true on success, false otherwise. + // When accelerated compositing is active, the contents is copied + // asynchronously from the compositing surface, but when the backing store is + // available, the contents is copied synchronously because it's fast enough. // If non empty |accelerated_dest_size| is given and accelerated compositing // is active, the content is shrinked so that it fits in // |accelerated_dest_size|. If |accelerated_dest_size| is larger than the @@ -182,10 +192,11 @@ class CONTENT_EXPORT RenderWidgetHost : public IPC::Channel::Sender { // NOTE: |src_rect| is not supported yet when accelerated compositing is // active (http://crbug.com/118571) and the whole content is always copied // regardless of |src_rect|. - virtual bool CopyFromBackingStore(const gfx::Rect& src_rect, - const gfx::Size& accelerated_dest_size, - skia::PlatformCanvas* output) = 0; - + virtual void AsyncCopyFromBackingStore( + const gfx::Rect& src_rect, + const gfx::Size& accelerated_dest_size, + skia::PlatformCanvas* output, + base::Callback<void(bool)> callback) = 0; #if defined(TOOLKIT_GTK) // Paint the backing store into the target's |dest_rect|. virtual bool CopyFromBackingStoreToGtkWindow(const gfx::Rect& dest_rect, diff --git a/ui/gfx/compositor/compositor.cc b/ui/gfx/compositor/compositor.cc index 965d1cb..0a94054 100644 --- a/ui/gfx/compositor/compositor.cc +++ b/ui/gfx/compositor/compositor.cc @@ -77,9 +77,26 @@ bool DefaultContextFactory::Initialize() { WebKit::WebGraphicsContext3D* DefaultContextFactory::CreateContext( Compositor* compositor) { + return CreateContextCommon(compositor, false); +} + +WebKit::WebGraphicsContext3D* DefaultContextFactory::CreateOffscreenContext( + Compositor* compositor) { + return CreateContextCommon(compositor, true); +} + +void DefaultContextFactory::RemoveCompositor(Compositor* compositor) { +} + +WebKit::WebGraphicsContext3D* DefaultContextFactory::CreateContextCommon( + Compositor* compositor, + bool offscreen) { WebKit::WebGraphicsContext3D::Attributes attrs; attrs.shareResources = true; WebKit::WebGraphicsContext3D* context = + offscreen ? + webkit::gpu::WebGraphicsContext3DInProcessImpl::CreateForWebView( + attrs, false) : webkit::gpu::WebGraphicsContext3DInProcessImpl::CreateForWindow( attrs, compositor->widget(), share_group_.get()); CommandLine* command_line = CommandLine::ForCurrentProcess(); @@ -92,9 +109,6 @@ WebKit::WebGraphicsContext3D* DefaultContextFactory::CreateContext( return context; } -void DefaultContextFactory::RemoveCompositor(Compositor* compositor) { -} - Texture::Texture(bool flipped, const gfx::Size& size) : texture_id_(0), flipped_(flipped), diff --git a/ui/gfx/compositor/compositor.h b/ui/gfx/compositor/compositor.h index 1a2422a..d8d75dc 100644 --- a/ui/gfx/compositor/compositor.h +++ b/ui/gfx/compositor/compositor.h @@ -54,6 +54,11 @@ class COMPOSITOR_EXPORT ContextFactory { virtual WebKit::WebGraphicsContext3D* CreateContext( Compositor* compositor) = 0; + // Creates a context for given compositor used for offscreen rendering. See + // the comments of CreateContext to know how per-compositor data is handled. + virtual WebKit::WebGraphicsContext3D* CreateOffscreenContext( + Compositor* compositor) = 0; + // Destroys per-compositor data. virtual void RemoveCompositor(Compositor* compositor) = 0; }; @@ -67,6 +72,8 @@ class COMPOSITOR_EXPORT DefaultContextFactory : public ContextFactory { // ContextFactory implementation virtual WebKit::WebGraphicsContext3D* CreateContext( Compositor* compositor) OVERRIDE; + virtual WebKit::WebGraphicsContext3D* CreateOffscreenContext( + Compositor* compositor) OVERRIDE; virtual void RemoveCompositor(Compositor* compositor) OVERRIDE; bool Initialize(); @@ -76,6 +83,10 @@ class COMPOSITOR_EXPORT DefaultContextFactory : public ContextFactory { } private: + WebKit::WebGraphicsContext3D* CreateContextCommon( + Compositor* compositor, + bool offscreen); + scoped_refptr<gfx::GLShareGroup> share_group_; DISALLOW_COPY_AND_ASSIGN(DefaultContextFactory); |