summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/tab_contents/thumbnail_generator.cc114
-rw-r--r--chrome/browser/tab_contents/thumbnail_generator.h20
-rw-r--r--content/browser/renderer_host/image_transport_factory.cc47
-rw-r--r--content/browser/renderer_host/render_widget_host_impl.cc34
-rw-r--r--content/browser/renderer_host/render_widget_host_impl.h5
-rw-r--r--content/browser/renderer_host/render_widget_host_view_aura.cc100
-rw-r--r--content/browser/renderer_host/render_widget_host_view_aura.h10
-rw-r--r--content/browser/renderer_host/render_widget_host_view_gtk.cc25
-rw-r--r--content/browser/renderer_host/render_widget_host_view_gtk.h10
-rw-r--r--content/browser/renderer_host/render_widget_host_view_mac.h10
-rw-r--r--content/browser/renderer_host/render_widget_host_view_mac.mm25
-rw-r--r--content/browser/renderer_host/render_widget_host_view_win.cc19
-rw-r--r--content/browser/renderer_host/render_widget_host_view_win.h10
-rw-r--r--content/browser/renderer_host/test_render_view_host.cc19
-rw-r--r--content/browser/renderer_host/test_render_view_host.h10
-rw-r--r--content/common/gpu/client/gl_helper.cc237
-rw-r--r--content/common/gpu/client/gl_helper.h17
-rw-r--r--content/port/browser/render_widget_host_view_port.h15
-rw-r--r--content/public/browser/render_widget_host.h23
-rw-r--r--ui/gfx/compositor/compositor.cc20
-rw-r--r--ui/gfx/compositor/compositor.h11
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);