summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cc/cc.gyp1
-rw-r--r--cc/cc_tests.gyp2
-rw-r--r--cc/context_provider.h42
-rw-r--r--cc/gl_renderer.cc103
-rw-r--r--cc/layer.cc15
-rw-r--r--cc/layer_tree_host.cc6
-rw-r--r--cc/layer_tree_host.h9
-rw-r--r--cc/layer_tree_host_client.h9
-rw-r--r--cc/layer_tree_host_unittest_context.cc234
-rw-r--r--cc/occlusion_tracker_unittest.cc1
-rw-r--r--cc/render_surface_filters.cc7
-rw-r--r--cc/render_surface_filters.h3
-rw-r--r--cc/resource_provider.cc7
-rw-r--r--cc/resource_provider.h6
-rw-r--r--cc/resource_update_controller.cc38
-rw-r--r--cc/resource_update_controller.h7
-rw-r--r--cc/resource_update_controller_unittest.cc5
-rw-r--r--cc/single_thread_proxy.cc31
-rw-r--r--cc/single_thread_proxy.h4
-rw-r--r--cc/test/fake_context_provider.cc61
-rw-r--r--cc/test/fake_context_provider.h45
-rw-r--r--cc/test/fake_layer_tree_host_client.cc23
-rw-r--r--cc/test/fake_layer_tree_host_client.h14
-rw-r--r--cc/test/layer_tree_test_common.cc37
-rw-r--r--cc/test/layer_tree_test_common.h15
-rw-r--r--cc/test/test_web_graphics_context_3d.cc4
-rw-r--r--cc/test/test_web_graphics_context_3d.h6
-rw-r--r--cc/thread_proxy.cc40
-rw-r--r--cc/thread_proxy.h6
-rw-r--r--cc/tiled_layer_unittest.cc3
-rw-r--r--content/browser/renderer_host/compositor_impl_android.cc33
-rw-r--r--content/browser/renderer_host/compositor_impl_android.h6
-rw-r--r--content/browser/renderer_host/image_transport_factory.cc141
-rw-r--r--content/common/gpu/client/context_provider_command_buffer.cc107
-rw-r--r--content/common/gpu/client/context_provider_command_buffer.h62
-rw-r--r--content/content_common.gypi2
-rw-r--r--content/renderer/gpu/render_widget_compositor.cc75
-rw-r--r--content/renderer/gpu/render_widget_compositor.h9
-rw-r--r--ui/compositor/compositor.cc123
-rw-r--r--ui/compositor/compositor.h18
-rw-r--r--webkit/compositor_bindings/web_layer_tree_view_impl_for_testing.cc76
-rw-r--r--webkit/compositor_bindings/web_layer_tree_view_impl_for_testing.h9
-rw-r--r--webkit/gpu/grcontext_for_webgraphicscontext3d.cc70
-rw-r--r--webkit/gpu/grcontext_for_webgraphicscontext3d.h37
-rw-r--r--webkit/gpu/webkit_gpu.gypi2
45 files changed, 1376 insertions, 178 deletions
diff --git a/cc/cc.gyp b/cc/cc.gyp
index 3e013b5..5a8d084 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -35,6 +35,7 @@
'content_layer_updater.h',
'contents_scaling_layer.cc',
'contents_scaling_layer.h',
+ 'context_provider.h',
'damage_tracker.cc',
'damage_tracker.h',
'debug_border_draw_quad.cc',
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index ccfdf3f..1361914 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -79,6 +79,8 @@
'test/fake_content_layer_client.h',
'test/fake_content_layer_impl.cc',
'test/fake_content_layer_impl.h',
+ 'test/fake_context_provider.cc',
+ 'test/fake_context_provider.h',
'test/fake_impl_proxy.h',
'test/fake_output_surface.h',
'test/fake_layer_tree_host_client.cc',
diff --git a/cc/context_provider.h b/cc/context_provider.h
new file mode 100644
index 0000000..ffb4822f
--- /dev/null
+++ b/cc/context_provider.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_CONTEXT_PROVIDER_H_
+#define CC_CONTEXT_PROVIDER_H_
+
+#include "base/memory/ref_counted.h"
+
+class GrContext;
+namespace WebKit { class WebGraphicsContext3D; }
+
+namespace cc {
+
+class ContextProvider : public base::RefCountedThreadSafe<ContextProvider> {
+ public:
+ // Initialize and create a 3d context. This must be called from the main
+ // thread. Calling it more than once should have no effect.
+ virtual bool InitializeOnMainThread() = 0;
+
+ // Bind the 3d context to the current thread. This should be called before
+ // accessing the contexts. Calling it more than once should have no effect.
+ // Once this function has been called, the class should only be accessed
+ // from the same thread.
+ virtual bool BindToCurrentThread() = 0;
+
+ virtual WebKit::WebGraphicsContext3D* Context3d() = 0;
+ virtual class GrContext* GrContext() = 0;
+
+ // Ask the provider to check if the contexts are valid or lost. If they are,
+ // this should invalidate the provider so that it can be replaced with a new
+ // one.
+ virtual void VerifyContexts() = 0;
+
+ protected:
+ friend class base::RefCountedThreadSafe<ContextProvider>;
+ virtual ~ContextProvider() {}
+};
+
+} // namespace cc
+
+#endif // CC_CONTEXT_PROVIDER_H_
diff --git a/cc/gl_renderer.cc b/cc/gl_renderer.cc
index 7189960..6a4413d 100644
--- a/cc/gl_renderer.cc
+++ b/cc/gl_renderer.cc
@@ -15,6 +15,7 @@
#include "build/build_config.h"
#include "cc/compositor_frame.h"
#include "cc/compositor_frame_metadata.h"
+#include "cc/context_provider.h"
#include "cc/damage_tracker.h"
#include "cc/geometry_binding.h"
#include "cc/gl_frame_data.h"
@@ -31,7 +32,6 @@
#include "cc/video_layer_impl.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3D.h"
-#include "third_party/WebKit/Source/Platform/chromium/public/WebSharedGraphicsContext3D.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -45,7 +45,6 @@
using WebKit::WebGraphicsContext3D;
using WebKit::WebGraphicsMemoryAllocation;
-using WebKit::WebSharedGraphicsContext3D;
namespace cc {
@@ -155,6 +154,8 @@ bool GLRenderer::initialize()
// so we only need to avoid POT textures if we have an NPOT fast-path.
m_capabilities.avoidPow2Textures = extensions.count("GL_CHROMIUM_fast_NPOT_MO8_textures");
+ m_capabilities.usingOffscreenContext3d = true;
+
m_isUsingBindUniform = extensions.count("GL_CHROMIUM_bind_uniform_location");
// Make sure scissoring starts as disabled.
@@ -372,67 +373,71 @@ void GLRenderer::drawDebugBorderQuad(const DrawingFrame& frame, const DebugBorde
GLC(context(), context()->drawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, 0));
}
-static WebGraphicsContext3D* getFilterContext(bool hasImplThread)
-{
- if (hasImplThread)
- return WebSharedGraphicsContext3D::compositorThreadContext();
- else
- return WebSharedGraphicsContext3D::mainThreadContext();
-}
-
-static GrContext* getFilterGrContext(bool hasImplThread)
-{
- if (hasImplThread)
- return WebSharedGraphicsContext3D::compositorThreadGrContext();
- else
- return WebSharedGraphicsContext3D::mainThreadGrContext();
-}
-
-static inline SkBitmap applyFilters(GLRenderer* renderer, const WebKit::WebFilterOperations& filters, ScopedResource* sourceTexture, bool hasImplThread)
+static inline SkBitmap applyFilters(GLRenderer* renderer, const WebKit::WebFilterOperations& filters, ScopedResource* sourceTextureResource)
{
if (filters.isEmpty())
return SkBitmap();
- WebGraphicsContext3D* filterContext = getFilterContext(hasImplThread);
- GrContext* filterGrContext = getFilterGrContext(hasImplThread);
-
- if (!filterContext || !filterGrContext)
+ cc::ContextProvider* offscreenContexts = renderer->resourceProvider()->offscreenContextProvider();
+ if (!offscreenContexts || !offscreenContexts->Context3d() || !offscreenContexts->GrContext())
return SkBitmap();
- renderer->context()->flush();
+ ResourceProvider::ScopedWriteLockGL lock(renderer->resourceProvider(), sourceTextureResource->id());
+
+ // Flush the compositor context to ensure that textures there are available
+ // in the shared context. Do this after locking/creating the compositor
+ // texture.
+ renderer->resourceProvider()->flush();
- ResourceProvider::ScopedWriteLockGL lock(renderer->resourceProvider(), sourceTexture->id());
- SkBitmap source = RenderSurfaceFilters::apply(filters, lock.textureId(), sourceTexture->size(), filterContext, filterGrContext);
+ // Make sure skia uses the correct GL context.
+ offscreenContexts->Context3d()->makeContextCurrent();
+
+ SkBitmap source = RenderSurfaceFilters::apply(filters, lock.textureId(), sourceTextureResource->size(), offscreenContexts->GrContext());
+
+ // Flush skia context so that all the rendered stuff appears on the
+ // texture.
+ offscreenContexts->GrContext()->flush();
+
+ // Flush the GL context so rendering results from this context are
+ // visible in the compositor's context.
+ offscreenContexts->Context3d()->flush();
+
+ // Use the compositor's GL context again.
+ renderer->resourceProvider()->graphicsContext3D()->makeContextCurrent();
return source;
}
-static SkBitmap applyImageFilter(GLRenderer* renderer, SkImageFilter* filter, ScopedResource* sourceTexture, bool hasImplThread)
+static SkBitmap applyImageFilter(GLRenderer* renderer, SkImageFilter* filter, ScopedResource* sourceTextureResource)
{
if (!filter)
return SkBitmap();
- WebGraphicsContext3D* context3d = getFilterContext(hasImplThread);
- GrContext* grContext = getFilterGrContext(hasImplThread);
-
- if (!context3d || !grContext)
+ cc::ContextProvider* offscreenContexts = renderer->resourceProvider()->offscreenContextProvider();
+ if (!offscreenContexts || !offscreenContexts->Context3d() || !offscreenContexts->GrContext())
return SkBitmap();
- renderer->context()->flush();
+ ResourceProvider::ScopedWriteLockGL lock(renderer->resourceProvider(), sourceTextureResource->id());
- ResourceProvider::ScopedWriteLockGL lock(renderer->resourceProvider(), sourceTexture->id());
+ // Flush the compositor context to ensure that textures there are available
+ // in the shared context. Do this after locking/creating the compositor
+ // texture.
+ renderer->resourceProvider()->flush();
+
+ // Make sure skia uses the correct GL context.
+ offscreenContexts->Context3d()->makeContextCurrent();
// Wrap the source texture in a Ganesh platform texture.
GrBackendTextureDesc backendTextureDescription;
- backendTextureDescription.fWidth = sourceTexture->size().width();
- backendTextureDescription.fHeight = sourceTexture->size().height();
+ backendTextureDescription.fWidth = sourceTextureResource->size().width();
+ backendTextureDescription.fHeight = sourceTextureResource->size().height();
backendTextureDescription.fConfig = kSkia8888_GrPixelConfig;
backendTextureDescription.fTextureHandle = lock.textureId();
backendTextureDescription.fOrigin = kTopLeft_GrSurfaceOrigin;
- skia::RefPtr<GrTexture> texture = skia::AdoptRef(grContext->wrapBackendTexture(backendTextureDescription));
+ skia::RefPtr<GrTexture> texture = skia::AdoptRef(offscreenContexts->GrContext()->wrapBackendTexture(backendTextureDescription));
// Place the platform texture inside an SkBitmap.
SkBitmap source;
- source.setConfig(SkBitmap::kARGB_8888_Config, sourceTexture->size().width(), sourceTexture->size().height());
+ source.setConfig(SkBitmap::kARGB_8888_Config, sourceTextureResource->size().width(), sourceTextureResource->size().height());
skia::RefPtr<SkGrPixelRef> pixelRef = skia::AdoptRef(new SkGrPixelRef(texture.get()));
source.setPixelRef(pixelRef.get());
@@ -444,11 +449,11 @@ static SkBitmap applyImageFilter(GLRenderer* renderer, SkImageFilter* filter, Sc
desc.fHeight = source.height();
desc.fConfig = kSkia8888_GrPixelConfig;
desc.fOrigin = kTopLeft_GrSurfaceOrigin;
- GrAutoScratchTexture scratchTexture(grContext, desc, GrContext::kExact_ScratchTexMatch);
+ GrAutoScratchTexture scratchTexture(offscreenContexts->GrContext(), desc, GrContext::kExact_ScratchTexMatch);
skia::RefPtr<GrTexture> backingStore = skia::AdoptRef(scratchTexture.detach());
// Create a device and canvas using that backing store.
- SkGpuDevice device(grContext, backingStore.get());
+ SkGpuDevice device(offscreenContexts->GrContext(), backingStore.get());
SkCanvas canvas(&device);
// Draw the source bitmap through the filter to the canvas.
@@ -456,8 +461,18 @@ static SkBitmap applyImageFilter(GLRenderer* renderer, SkImageFilter* filter, Sc
paint.setImageFilter(filter);
canvas.clear(0x0);
canvas.drawSprite(source, 0, 0, &paint);
- canvas.flush();
- context3d->flush();
+
+ // Flush skia context so that all the rendered stuff appears on the
+ // texture.
+ offscreenContexts->GrContext()->flush();
+
+ // Flush the GL context so rendering results from this context are
+ // visible in the compositor's context.
+ offscreenContexts->Context3d()->flush();
+
+ // Use the compositor's GL context again.
+ renderer->resourceProvider()->graphicsContext3D()->makeContextCurrent();
+
return device.accessBitmap(false);
}
@@ -505,7 +520,7 @@ scoped_ptr<ScopedResource> GLRenderer::drawBackgroundFilters(
if (!getFramebufferTexture(deviceBackgroundTexture.get(), deviceRect))
return scoped_ptr<ScopedResource>();
- SkBitmap filteredDeviceBackground = applyFilters(this, filters, deviceBackgroundTexture.get(), m_client->hasImplThread());
+ SkBitmap filteredDeviceBackground = applyFilters(this, filters, deviceBackgroundTexture.get());
if (!filteredDeviceBackground.getTexture())
return scoped_ptr<ScopedResource>();
@@ -558,9 +573,9 @@ void GLRenderer::drawRenderPassQuad(DrawingFrame& frame, const RenderPassDrawQua
// Apply filters to the contents texture.
SkBitmap filterBitmap;
if (quad->filter) {
- filterBitmap = applyImageFilter(this, quad->filter.get(), contentsTexture, m_client->hasImplThread());
+ filterBitmap = applyImageFilter(this, quad->filter.get(), contentsTexture);
} else {
- filterBitmap = applyFilters(this, quad->filters, contentsTexture, m_client->hasImplThread());
+ filterBitmap = applyFilters(this, quad->filters, contentsTexture);
}
// Draw the background texture if there is one.
diff --git a/cc/layer.cc b/cc/layer.cc
index 1f22bad..d78afaf 100644
--- a/cc/layer.cc
+++ b/cc/layer.cc
@@ -97,6 +97,9 @@ void Layer::setLayerTreeHost(LayerTreeHost* host)
if (host && m_layerAnimationController->hasAnyAnimation())
host->setNeedsCommit();
+ if (host && (!m_filters.isEmpty() || !m_backgroundFilters.isEmpty() || m_filter))
+ m_layerTreeHost->setNeedsFilterContext();
+
}
void Layer::setNeedsCommit()
@@ -365,8 +368,8 @@ void Layer::setFilters(const WebKit::WebFilterOperations& filters)
DCHECK(!m_filter);
m_filters = filters;
setNeedsCommit();
- if (!filters.isEmpty())
- LayerTreeHost::setNeedsFilterContext(true);
+ if (!filters.isEmpty() && m_layerTreeHost)
+ m_layerTreeHost->setNeedsFilterContext();
}
void Layer::setFilter(const skia::RefPtr<SkImageFilter>& filter)
@@ -376,8 +379,8 @@ void Layer::setFilter(const skia::RefPtr<SkImageFilter>& filter)
DCHECK(m_filters.isEmpty());
m_filter = filter;
setNeedsCommit();
- if (filter)
- LayerTreeHost::setNeedsFilterContext(true);
+ if (filter && m_layerTreeHost)
+ m_layerTreeHost->setNeedsFilterContext();
}
void Layer::setBackgroundFilters(const WebKit::WebFilterOperations& backgroundFilters)
@@ -386,8 +389,8 @@ void Layer::setBackgroundFilters(const WebKit::WebFilterOperations& backgroundFi
return;
m_backgroundFilters = backgroundFilters;
setNeedsCommit();
- if (!backgroundFilters.isEmpty())
- LayerTreeHost::setNeedsFilterContext(true);
+ if (!backgroundFilters.isEmpty() && m_layerTreeHost)
+ m_layerTreeHost->setNeedsFilterContext();
}
void Layer::setOpacity(float opacity)
diff --git a/cc/layer_tree_host.cc b/cc/layer_tree_host.cc
index 3d97269..eff03f6 100644
--- a/cc/layer_tree_host.cc
+++ b/cc/layer_tree_host.cc
@@ -36,8 +36,6 @@ static int numLayerTreeInstances;
namespace cc {
-bool LayerTreeHost::s_needsFilterContext = false;
-
RendererCapabilities::RendererCapabilities()
: bestTextureFormat(0)
, usingPartialSwap(false)
@@ -48,6 +46,7 @@ RendererCapabilities::RendererCapabilities()
, usingDiscardBackbuffer(false)
, usingEglImage(false)
, allowPartialTextureUpdates(false)
+ , usingOffscreenContext3d(false)
, maxTextureSize(0)
, avoidPow2Textures(false)
{
@@ -73,6 +72,7 @@ scoped_ptr<LayerTreeHost> LayerTreeHost::create(LayerTreeHostClient* client, con
LayerTreeHost::LayerTreeHost(LayerTreeHostClient* client, const LayerTreeSettings& settings)
: m_animating(false)
, m_needsFullTreeSync(true)
+ , m_needsFilterContext(false)
, m_client(client)
, m_commitNumber(0)
, m_renderingStats()
@@ -183,6 +183,8 @@ LayerTreeHost::RecreateResult LayerTreeHost::recreateOutputSurface()
return RecreateSucceeded;
}
+ m_client->willRetryRecreateOutputSurface();
+
// Tolerate a certain number of recreation failures to work around races
// in the output-surface-lost machinery.
m_numFailedRecreateAttempts++;
diff --git a/cc/layer_tree_host.h b/cc/layer_tree_host.h
index aae0400..40e5c25 100644
--- a/cc/layer_tree_host.h
+++ b/cc/layer_tree_host.h
@@ -69,6 +69,7 @@ struct CC_EXPORT RendererCapabilities {
bool usingDiscardBackbuffer;
bool usingEglImage;
bool allowPartialTextureUpdates;
+ bool usingOffscreenContext3d;
int maxTextureSize;
bool avoidPow2Textures;
};
@@ -83,9 +84,8 @@ public:
// Returns true if any LayerTreeHost is alive.
static bool anyLayerTreeHostInstanceExists();
- static bool needsFilterContext() { return s_needsFilterContext; }
- static void setNeedsFilterContext(bool needsFilterContext) { s_needsFilterContext = needsFilterContext; }
- bool needsSharedContext() const { return needsFilterContext() || settings().acceleratePainting; }
+ void setNeedsFilterContext() { m_needsFilterContext = true; }
+ bool needsOffscreenContext() const { return m_needsFilterContext || settings().acceleratePainting; }
// LayerTreeHost interface to Proxy.
void willBeginFrame() { m_client->willBeginFrame(); }
@@ -233,6 +233,7 @@ private:
bool m_animating;
bool m_needsFullTreeSync;
+ bool m_needsFilterContext;
base::CancelableClosure m_prepaintCallback;
@@ -277,8 +278,6 @@ private:
scoped_ptr<AnimationRegistrar> m_animationRegistrar;
- static bool s_needsFilterContext;
-
DISALLOW_COPY_AND_ASSIGN(LayerTreeHost);
};
diff --git a/cc/layer_tree_host_client.h b/cc/layer_tree_host_client.h
index 25d93aef..f2b9a14 100644
--- a/cc/layer_tree_host_client.h
+++ b/cc/layer_tree_host_client.h
@@ -5,6 +5,7 @@
#ifndef CC_LAYER_TREE_HOST_CLIENT_H_
#define CC_LAYER_TREE_HOST_CLIENT_H_
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
namespace gfx {
@@ -12,6 +13,7 @@ class Vector2d;
}
namespace cc {
+class ContextProvider;
class InputHandler;
class OutputSurface;
@@ -34,6 +36,13 @@ public:
// Used only in the single-threaded path.
virtual void scheduleComposite() = 0;
+ // These must always return a valid ContextProvider. But the provider does not need to be capable of creating contexts.
+ virtual scoped_refptr<cc::ContextProvider> OffscreenContextProviderForMainThread() = 0;
+ virtual scoped_refptr<cc::ContextProvider> OffscreenContextProviderForCompositorThread() = 0;
+
+ // This hook is for testing.
+ virtual void willRetryRecreateOutputSurface() {}
+
protected:
virtual ~LayerTreeHostClient() { }
};
diff --git a/cc/layer_tree_host_unittest_context.cc b/cc/layer_tree_host_unittest_context.cc
index 41ebbfd..0147ca9 100644
--- a/cc/layer_tree_host_unittest_context.cc
+++ b/cc/layer_tree_host_unittest_context.cc
@@ -19,6 +19,7 @@
#include "cc/test/fake_content_layer.h"
#include "cc/test/fake_content_layer_client.h"
#include "cc/test/fake_content_layer_impl.h"
+#include "cc/test/fake_context_provider.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/fake_scrollbar_layer.h"
#include "cc/test/fake_scrollbar_theme_painter.h"
@@ -33,6 +34,7 @@
#include "cc/video_layer_impl.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "media/base/media.h"
+#include "third_party/WebKit/Source/Platform/chromium/public/WebFilterOperations.h"
using media::VideoFrame;
using WebKit::WebGraphicsContext3D;
@@ -53,7 +55,13 @@ class LayerTreeHostContextTest : public ThreadedTest {
times_to_lose_during_draw_(0),
times_to_fail_recreate_(0),
times_to_fail_reinitialize_(0),
- times_to_lose_on_recreate_(0) {
+ times_to_lose_on_recreate_(0),
+ times_to_fail_create_offscreen_(0),
+ times_to_fail_recreate_offscreen_(0),
+ times_to_expect_recreate_retried_(0),
+ times_recreate_retried_(0),
+ times_offscreen_created_(0),
+ committed_at_least_once_(false) {
media::InitializeMediaLibraryForTesting();
}
@@ -70,6 +78,7 @@ class LayerTreeHostContextTest : public ThreadedTest {
virtual scoped_ptr<OutputSurface> createOutputSurface() OVERRIDE {
if (times_to_fail_create_) {
--times_to_fail_create_;
+ ExpectRecreateToRetry();
return scoped_ptr<OutputSurface>();
}
@@ -82,29 +91,88 @@ class LayerTreeHostContextTest : public ThreadedTest {
// The number of times MakeCurrent succeeds is not important, and
// can be changed if needed to make this pass with future changes.
context3d_->set_times_make_current_succeeds(2);
+ ExpectRecreateToRetry();
} else if (times_to_lose_on_create_) {
--times_to_lose_on_create_;
LoseContext();
+ ExpectRecreateToRetry();
}
return FakeOutputSurface::Create3d(
context3d.PassAs<WebGraphicsContext3D>()).PassAs<OutputSurface>();
}
- virtual bool prepareToDrawOnThread(
- LayerTreeHostImpl*, LayerTreeHostImpl::FrameData&, bool result)
- OVERRIDE {
- EXPECT_TRUE(result);
- if (!times_to_lose_during_draw_)
- return result;
+ scoped_ptr<TestWebGraphicsContext3D> CreateOffscreenContext3d() {
+ if (!context3d_)
+ return scoped_ptr<TestWebGraphicsContext3D>();
- --times_to_lose_during_draw_;
- if (context3d_)
- context3d_->set_times_make_current_succeeds(0);
- return result;
+ ++times_offscreen_created_;
+
+ if (times_to_fail_create_offscreen_) {
+ --times_to_fail_create_offscreen_;
+ ExpectRecreateToRetry();
+ return scoped_ptr<TestWebGraphicsContext3D>();
+ }
+
+ scoped_ptr<TestWebGraphicsContext3D> offscreen_context3d =
+ TestWebGraphicsContext3D::Create().Pass();
+ DCHECK(offscreen_context3d);
+ context3d_->add_share_group_context(offscreen_context3d.get());
+
+ return offscreen_context3d.Pass();
+ }
+
+ virtual scoped_refptr<cc::ContextProvider>
+ OffscreenContextProviderForMainThread() OVERRIDE {
+ DCHECK(!implThread());
+
+ if (!offscreen_contexts_main_thread_ ||
+ offscreen_contexts_main_thread_->DestroyedOnMainThread()) {
+ offscreen_contexts_main_thread_ = new FakeContextProvider(
+ base::Bind(&LayerTreeHostContextTest::CreateOffscreenContext3d,
+ base::Unretained(this)));
+ }
+ return offscreen_contexts_main_thread_;
+ }
+
+ virtual scoped_refptr<cc::ContextProvider>
+ OffscreenContextProviderForCompositorThread() OVERRIDE {
+ DCHECK(implThread());
+
+ if (!offscreen_contexts_compositor_thread_ ||
+ offscreen_contexts_compositor_thread_->DestroyedOnMainThread()) {
+ offscreen_contexts_compositor_thread_ = new FakeContextProvider(
+ base::Bind(&LayerTreeHostContextTest::CreateOffscreenContext3d,
+ base::Unretained(this)));
}
+ return offscreen_contexts_compositor_thread_;
+ }
+
+ virtual bool prepareToDrawOnThread(
+ LayerTreeHostImpl*, LayerTreeHostImpl::FrameData&, bool result)
+ OVERRIDE {
+ EXPECT_TRUE(result);
+ if (!times_to_lose_during_draw_)
+ return result;
+
+ --times_to_lose_during_draw_;
+ context3d_->set_times_make_current_succeeds(0);
+
+ times_to_fail_create_ = times_to_fail_recreate_;
+ times_to_fail_recreate_ = 0;
+ times_to_fail_initialize_ = times_to_fail_reinitialize_;
+ times_to_fail_reinitialize_ = 0;
+ times_to_lose_on_create_ = times_to_lose_on_recreate_;
+ times_to_lose_on_recreate_ = 0;
+ times_to_fail_create_offscreen_ = times_to_fail_recreate_offscreen_;
+ times_to_fail_recreate_offscreen_ = 0;
+
+ return result;
+ }
virtual void commitCompleteOnThread(LayerTreeHostImpl *host_impl) OVERRIDE {
+ committed_at_least_once_ = true;
+
if (!times_to_lose_during_commit_)
return;
--times_to_lose_during_commit_;
@@ -116,6 +184,22 @@ class LayerTreeHostContextTest : public ThreadedTest {
times_to_fail_reinitialize_ = 0;
times_to_lose_on_create_ = times_to_lose_on_recreate_;
times_to_lose_on_recreate_ = 0;
+ times_to_fail_create_offscreen_ = times_to_fail_recreate_offscreen_;
+ times_to_fail_recreate_offscreen_ = 0;
+ }
+
+ virtual void willRetryRecreateOutputSurface() OVERRIDE {
+ ++times_recreate_retried_;
+ }
+
+ virtual void TearDown() OVERRIDE {
+ ThreadedTest::TearDown();
+ EXPECT_EQ(times_to_expect_recreate_retried_, times_recreate_retried_);
+ }
+
+ void ExpectRecreateToRetry() {
+ if (committed_at_least_once_)
+ ++times_to_expect_recreate_retried_;
}
protected:
@@ -128,6 +212,15 @@ class LayerTreeHostContextTest : public ThreadedTest {
int times_to_fail_reinitialize_;
int times_to_fail_recreate_;
int times_to_lose_on_recreate_;
+ int times_to_fail_create_offscreen_;
+ int times_to_fail_recreate_offscreen_;
+ int times_to_expect_recreate_retried_;
+ int times_recreate_retried_;
+ int times_offscreen_created_;
+ bool committed_at_least_once_;
+
+ scoped_refptr<FakeContextProvider> offscreen_contexts_main_thread_;
+ scoped_refptr<FakeContextProvider> offscreen_contexts_compositor_thread_;
};
class LayerTreeHostContextTestLostContextSucceeds :
@@ -151,8 +244,8 @@ class LayerTreeHostContextTestLostContextSucceeds :
}
virtual void afterTest() OVERRIDE {
- EXPECT_EQ(8, test_case_);
- EXPECT_EQ(6 + 10 + 10, num_losses_);
+ EXPECT_EQ(10, test_case_);
+ EXPECT_EQ(8 + 10 + 10, num_losses_);
}
virtual void didCommitAndDrawFrame() OVERRIDE {
@@ -185,36 +278,56 @@ class LayerTreeHostContextTestLostContextSucceeds :
3, // times_to_fail_reinitialize
0, // times_to_fail_recreate
0, // times_to_lose_on_recreate
+ 0, // times_to_fail_recreate_offscreen
},
{ 0, // times_to_lose_during_commit
1, // times_to_lose_during_draw
3, // times_to_fail_reinitialize
0, // times_to_fail_recreate
0, // times_to_lose_on_recreate
+ 0, // times_to_fail_recreate_offscreen
},
{ 1, // times_to_lose_during_commit
0, // times_to_lose_during_draw
0, // times_to_fail_reinitialize
3, // times_to_fail_recreate
0, // times_to_lose_on_recreate
+ 0, // times_to_fail_recreate_offscreen
},
{ 0, // times_to_lose_during_commit
1, // times_to_lose_during_draw
0, // times_to_fail_reinitialize
3, // times_to_fail_recreate
0, // times_to_lose_on_recreate
+ 0, // times_to_fail_recreate_offscreen
},
{ 1, // times_to_lose_during_commit
0, // times_to_lose_during_draw
0, // times_to_fail_reinitialize
0, // times_to_fail_recreate
3, // times_to_lose_on_recreate
+ 0, // times_to_fail_recreate_offscreen
},
{ 0, // times_to_lose_during_commit
1, // times_to_lose_during_draw
0, // times_to_fail_reinitialize
0, // times_to_fail_recreate
3, // times_to_lose_on_recreate
+ 0, // times_to_fail_recreate_offscreen
+ },
+ { 1, // times_to_lose_during_commit
+ 0, // times_to_lose_during_draw
+ 0, // times_to_fail_reinitialize
+ 0, // times_to_fail_recreate
+ 0, // times_to_lose_on_recreate
+ 3, // times_to_fail_recreate_offscreen
+ },
+ { 0, // times_to_lose_during_commit
+ 1, // times_to_lose_during_draw
+ 0, // times_to_fail_reinitialize
+ 0, // times_to_fail_recreate
+ 0, // times_to_lose_on_recreate
+ 3, // times_to_fail_recreate_offscreen
},
// Losing the context and recreating it any number of times should
// succeed.
@@ -223,12 +336,14 @@ class LayerTreeHostContextTestLostContextSucceeds :
0, // times_to_fail_reinitialize
0, // times_to_fail_recreate
0, // times_to_lose_on_recreate
+ 0, // times_to_fail_recreate_offscreen
},
{ 0, // times_to_lose_during_commit
10, // times_to_lose_during_draw
0, // times_to_fail_reinitialize
0, // times_to_fail_recreate
0, // times_to_lose_on_recreate
+ 0, // times_to_fail_recreate_offscreen
},
};
@@ -242,6 +357,8 @@ class LayerTreeHostContextTestLostContextSucceeds :
times_to_fail_reinitialize_ = kTests[test_case_].times_to_fail_reinitialize;
times_to_fail_recreate_ = kTests[test_case_].times_to_fail_recreate;
times_to_lose_on_recreate_ = kTests[test_case_].times_to_lose_on_recreate;
+ times_to_fail_recreate_offscreen_ =
+ kTests[test_case_].times_to_fail_recreate_offscreen;
++test_case_;
return true;
}
@@ -252,9 +369,10 @@ class LayerTreeHostContextTestLostContextSucceeds :
int times_to_fail_reinitialize;
int times_to_fail_recreate;
int times_to_lose_on_recreate;
+ int times_to_fail_recreate_offscreen;
};
- private:
+ protected:
size_t test_case_;
int num_losses_;
bool recovered_context_;
@@ -281,9 +399,12 @@ class LayerTreeHostContextTestLostContextSucceedsWithContent :
content_->setAnchorPoint(gfx::PointF());
content_->setIsDrawable(true);
if (use_surface_) {
- // TODO(danakj): Give the surface a filter to test more code when we can
- // do so without crashing in the shared context creation.
content_->setForceRenderSurface(true);
+ // Filters require us to create an offscreen context.
+ WebKit::WebFilterOperations filters;
+ filters.append(WebKit::WebFilterOperation::createGrayscaleFilter(0.5f));
+ content_->setFilters(filters);
+ content_->setBackgroundFilters(filters);
}
root_->addChild(content_);
@@ -307,6 +428,31 @@ class LayerTreeHostContextTestLostContextSucceedsWithContent :
// TestWebGraphicsContext3D ensures that this resource is created with
// the active context.
EXPECT_TRUE(content_impl->HaveResourceForTileAt(0, 0));
+
+ cc::ContextProvider* contexts =
+ host_impl->resourceProvider()->offscreenContextProvider();
+ if (use_surface_) {
+ EXPECT_TRUE(contexts->Context3d());
+ // TODO(danakj): Make a fake GrContext.
+ //EXPECT_TRUE(contexts->GrContext());
+ } else {
+ EXPECT_FALSE(contexts);
+ }
+ }
+
+ virtual void afterTest() OVERRIDE {
+ LayerTreeHostContextTestLostContextSucceeds::afterTest();
+ if (use_surface_) {
+ // 1 create to start with +
+ // 6 from test cases that fail on initializing the renderer (after the
+ // offscreen context is created) +
+ // 6 from test cases that lose the offscreen context directly +
+ // All the test cases that recreate both contexts only once
+ // per time it is lost.
+ EXPECT_EQ(6 + 6 + 1 + num_losses_, times_offscreen_created_);
+ } else {
+ EXPECT_EQ(0, times_offscreen_created_);
+ }
}
protected:
@@ -340,6 +486,54 @@ TEST_F(LayerTreeHostContextTestLostContextSucceedsWithContent,
runTest(true);
}
+class LayerTreeHostContextTestOffscreenContextFails
+ : public LayerTreeHostContextTest {
+ public:
+ virtual void setupTree() OVERRIDE {
+ root_ = Layer::create();
+ root_->setBounds(gfx::Size(10, 10));
+ root_->setAnchorPoint(gfx::PointF());
+ root_->setIsDrawable(true);
+
+ content_ = FakeContentLayer::Create(&client_);
+ content_->setBounds(gfx::Size(10, 10));
+ content_->setAnchorPoint(gfx::PointF());
+ content_->setIsDrawable(true);
+ content_->setForceRenderSurface(true);
+ // Filters require us to create an offscreen context.
+ WebKit::WebFilterOperations filters;
+ filters.append(WebKit::WebFilterOperation::createGrayscaleFilter(0.5f));
+ content_->setFilters(filters);
+ content_->setBackgroundFilters(filters);
+
+ root_->addChild(content_);
+
+ m_layerTreeHost->setRootLayer(root_);
+ LayerTreeHostContextTest::setupTree();
+ }
+
+ virtual void beginTest() OVERRIDE {
+ times_to_fail_create_offscreen_ = 1;
+ postSetNeedsCommitToMainThread();
+ }
+
+ virtual void drawLayersOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ cc::ContextProvider* contexts =
+ host_impl->resourceProvider()->offscreenContextProvider();
+ EXPECT_FALSE(contexts);
+ endTest();
+ }
+
+ virtual void afterTest() OVERRIDE {}
+
+ protected:
+ FakeContentLayerClient client_;
+ scoped_refptr<Layer> root_;
+ scoped_refptr<ContentLayer> content_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostContextTestOffscreenContextFails)
+
class LayerTreeHostContextTestLostContextFails :
public LayerTreeHostContextTest {
public:
@@ -493,6 +687,7 @@ class LayerTreeHostContextTestLostContextAndEvictTextures :
}
virtual void commitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ LayerTreeHostContextTest::commitCompleteOnThread(impl);
if (num_commits_ > 1)
return;
++num_commits_;
@@ -579,6 +774,7 @@ class LayerTreeHostContextTestLostContextWhileUpdatingResources :
}
virtual void commitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ LayerTreeHostContextTest::commitCompleteOnThread(impl);
endTest();
}
@@ -625,6 +821,8 @@ class LayerTreeHostContextTestLayersNotified :
}
virtual void commitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ LayerTreeHostContextTest::commitCompleteOnThread(host_impl);
+
FakeContentLayerImpl* root = static_cast<FakeContentLayerImpl*>(
host_impl->rootLayer());
FakeContentLayerImpl* child = static_cast<FakeContentLayerImpl*>(
@@ -787,6 +985,8 @@ class LayerTreeHostContextTestDontUseLostResources :
}
virtual void commitCompleteOnThread(LayerTreeHostImpl* host_impl) OVERRIDE {
+ LayerTreeHostContextTest::commitCompleteOnThread(host_impl);
+
ResourceProvider* resource_provider = host_impl->resourceProvider();
if (host_impl->activeTree()->source_frame_number() == 0) {
@@ -995,6 +1195,8 @@ class ScrollbarLayerLostContext : public LayerTreeHostContextTest {
}
virtual void commitCompleteOnThread(LayerTreeHostImpl* impl) OVERRIDE {
+ LayerTreeHostContextTest::commitCompleteOnThread(impl);
+
++commits_;
size_t upload_count = scrollbar_layer_->last_update_full_upload_size() +
scrollbar_layer_->last_update_partial_upload_size();
diff --git a/cc/occlusion_tracker_unittest.cc b/cc/occlusion_tracker_unittest.cc
index 0065401..63cdeb6 100644
--- a/cc/occlusion_tracker_unittest.cc
+++ b/cc/occlusion_tracker_unittest.cc
@@ -189,7 +189,6 @@ protected:
m_renderSurfaceLayerListImpl.clear();
m_replicaLayers.clear();
m_maskLayers.clear();
- LayerTreeHost::setNeedsFilterContext(false);
}
typename Types::HostType* getHost();
diff --git a/cc/render_surface_filters.cc b/cc/render_surface_filters.cc
index 29c031c..f04fbb9 100644
--- a/cc/render_surface_filters.cc
+++ b/cc/render_surface_filters.cc
@@ -8,7 +8,6 @@
#include "skia/ext/refptr.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebFilterOperation.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebFilterOperations.h"
-#include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3D.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/effects/SkBlurImageFilter.h"
#include "third_party/skia/include/effects/SkColorMatrixFilter.h"
@@ -377,10 +376,9 @@ WebKit::WebFilterOperations RenderSurfaceFilters::optimize(const WebKit::WebFilt
return newList;
}
-SkBitmap RenderSurfaceFilters::apply(const WebKit::WebFilterOperations& filters, unsigned textureId, const gfx::SizeF& size, WebKit::WebGraphicsContext3D* context3D, GrContext* grContext)
+SkBitmap RenderSurfaceFilters::apply(const WebKit::WebFilterOperations& filters, unsigned textureId, gfx::SizeF size, GrContext* grContext)
{
- if (!context3D || !grContext)
- return SkBitmap();
+ DCHECK(grContext);
WebKit::WebFilterOperations optimizedFilters = optimize(filters);
FilterBufferState state(grContext, size, textureId);
@@ -448,7 +446,6 @@ SkBitmap RenderSurfaceFilters::apply(const WebKit::WebFilterOperations& filters,
}
state.swap();
}
- context3D->flush();
return state.source();
}
diff --git a/cc/render_surface_filters.h b/cc/render_surface_filters.h
index 0186613..86f366b 100644
--- a/cc/render_surface_filters.h
+++ b/cc/render_surface_filters.h
@@ -17,14 +17,13 @@ class SizeF;
namespace WebKit {
class WebFilterOperations;
-class WebGraphicsContext3D;
}
namespace cc {
class CC_EXPORT RenderSurfaceFilters {
public:
- static SkBitmap apply(const WebKit::WebFilterOperations& filters, unsigned textureId, const gfx::SizeF&, WebKit::WebGraphicsContext3D*, GrContext*);
+ static SkBitmap apply(const WebKit::WebFilterOperations& filters, unsigned textureId, gfx::SizeF, GrContext*);
static WebKit::WebFilterOperations optimize(const WebKit::WebFilterOperations& filters);
private:
diff --git a/cc/resource_provider.cc b/cc/resource_provider.cc
index 5de3149..104b0cc 100644
--- a/cc/resource_provider.cc
+++ b/cc/resource_provider.cc
@@ -11,6 +11,7 @@
#include "base/stl_util.h"
#include "base/string_split.h"
#include "base/string_util.h"
+#include "cc/context_provider.h"
#include "cc/gl_renderer.h" // For the GLC() macro.
#include "cc/platform_color.h"
#include "cc/texture_uploader.h"
@@ -1133,4 +1134,10 @@ void ResourceProvider::enableReadLockFences(ResourceProvider::ResourceId id, boo
resource->enableReadLockFences = enable;
}
+void ResourceProvider::setOffscreenContextProvider(scoped_refptr<cc::ContextProvider> offscreenContextProvider) {
+ if (offscreenContextProvider)
+ offscreenContextProvider->BindToCurrentThread();
+ m_offscreenContextProvider = offscreenContextProvider;
+}
+
} // namespace cc
diff --git a/cc/resource_provider.h b/cc/resource_provider.h
index 5b31139..e63093c 100644
--- a/cc/resource_provider.h
+++ b/cc/resource_provider.h
@@ -35,6 +35,7 @@ class Vector2d;
namespace cc {
+class ContextProvider;
class TextureUploader;
// This class is not thread-safe and can only be called from the thread it was
@@ -263,6 +264,9 @@ public:
// Indicates if we can currently lock this resource for write.
bool canLockForWrite(ResourceId);
+ cc::ContextProvider* offscreenContextProvider() { return m_offscreenContextProvider.get(); }
+ void setOffscreenContextProvider(scoped_refptr<cc::ContextProvider> offscreenContextProvider);
+
private:
struct Resource {
Resource();
@@ -334,6 +338,8 @@ private:
int m_maxTextureSize;
GLenum m_bestTextureFormat;
+ scoped_refptr<cc::ContextProvider> m_offscreenContextProvider;
+
base::ThreadChecker m_threadChecker;
scoped_refptr<Fence> m_currentReadLockFence;
diff --git a/cc/resource_update_controller.cc b/cc/resource_update_controller.cc
index d60b5bb..f305946 100644
--- a/cc/resource_update_controller.cc
+++ b/cc/resource_update_controller.cc
@@ -7,18 +7,17 @@
#include <limits>
#include "base/debug/trace_event.h"
+#include "cc/context_provider.h"
#include "cc/prioritized_resource.h"
#include "cc/resource_provider.h"
#include "cc/texture_copier.h"
#include "cc/thread.h"
#include "skia/ext/refptr.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3D.h"
-#include "third_party/WebKit/Source/Platform/chromium/public/WebSharedGraphicsContext3D.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/skia/include/gpu/SkGpuDevice.h"
using WebKit::WebGraphicsContext3D;
-using WebKit::WebSharedGraphicsContext3D;
namespace {
@@ -67,9 +66,8 @@ size_t ResourceUpdateController::maxFullUpdatesPerTick(
return texturesPerTick ? texturesPerTick : 1;
}
-ResourceUpdateController::ResourceUpdateController(ResourceUpdateControllerClient* client, Thread* thread, scoped_ptr<ResourceUpdateQueue> queue, ResourceProvider* resourceProvider, bool hasImplThread)
+ResourceUpdateController::ResourceUpdateController(ResourceUpdateControllerClient* client, Thread* thread, scoped_ptr<ResourceUpdateQueue> queue, ResourceProvider* resourceProvider)
: m_client(client)
- , m_hasImplThread(hasImplThread)
, m_queue(queue.Pass())
, m_resourceProvider(resourceProvider)
, m_textureUpdatesPerTick(maxFullUpdatesPerTick(resourceProvider))
@@ -130,27 +128,22 @@ void ResourceUpdateController::updateTexture(ResourceUpdate update)
DCHECK(m_resourceProvider->resourceType(texture->resourceId()) ==
ResourceProvider::GLTexture);
- WebGraphicsContext3D* paintContext = m_hasImplThread ?
- WebSharedGraphicsContext3D::compositorThreadContext() :
- WebSharedGraphicsContext3D::mainThreadContext();
- GrContext* paintGrContext = m_hasImplThread ?
- WebSharedGraphicsContext3D::compositorThreadGrContext() :
- WebSharedGraphicsContext3D::mainThreadGrContext();
-
- // Flush the context in which the backing texture is created so that it
- // is available in other shared contexts. It is important to do here
- // because the backing texture is created in one context while it is
- // being written to in another.
+ cc::ContextProvider* offscreenContexts = m_resourceProvider->offscreenContextProvider();
+
ResourceProvider::ScopedWriteLockGL lock(
m_resourceProvider, texture->resourceId());
+
+ // Flush the compositor context to ensure that textures there are available
+ // in the shared context. Do this after locking/creating the compositor
+ // texture.
m_resourceProvider->flush();
- // Make sure ganesh uses the correct GL context.
- paintContext->makeContextCurrent();
+ // Make sure skia uses the correct GL context.
+ offscreenContexts->Context3d()->makeContextCurrent();
// Create an accelerated canvas to draw on.
skia::RefPtr<SkCanvas> canvas = createAcceleratedCanvas(
- paintGrContext, texture->size(), lock.textureId());
+ offscreenContexts->GrContext(), texture->size(), lock.textureId());
// The compositor expects the textures to be upside-down so it can flip
// the final composited image. Ganesh renders the image upright so we
@@ -169,13 +162,16 @@ void ResourceUpdateController::updateTexture(ResourceUpdate update)
pictureRect.y() - sourceRect.y() + destOffset.y());
canvas->drawPicture(*update.picture);
- // Flush ganesh context so that all the rendered stuff appears on the
+ // Flush skia context so that all the rendered stuff appears on the
// texture.
- paintGrContext->flush();
+ offscreenContexts->GrContext()->flush();
// Flush the GL context so rendering results from this context are
// visible in the compositor's context.
- paintContext->flush();
+ offscreenContexts->Context3d()->flush();
+
+ // Use the compositor's GL context again.
+ m_resourceProvider->graphicsContext3D()->makeContextCurrent();
}
if (update.bitmap) {
diff --git a/cc/resource_update_controller.h b/cc/resource_update_controller.h
index bd3e2b8..fbec7c4 100644
--- a/cc/resource_update_controller.h
+++ b/cc/resource_update_controller.h
@@ -27,9 +27,9 @@ protected:
class CC_EXPORT ResourceUpdateController {
public:
- static scoped_ptr<ResourceUpdateController> create(ResourceUpdateControllerClient* client, Thread* thread, scoped_ptr<ResourceUpdateQueue> queue, ResourceProvider* resourceProvider, bool hasImplThread)
+ static scoped_ptr<ResourceUpdateController> create(ResourceUpdateControllerClient* client, Thread* thread, scoped_ptr<ResourceUpdateQueue> queue, ResourceProvider* resourceProvider)
{
- return make_scoped_ptr(new ResourceUpdateController(client, thread, queue.Pass(), resourceProvider, hasImplThread));
+ return make_scoped_ptr(new ResourceUpdateController(client, thread, queue.Pass(), resourceProvider));
}
static size_t maxPartialTextureUpdates();
@@ -48,7 +48,7 @@ public:
virtual size_t updateMoreTexturesSize() const;
protected:
- ResourceUpdateController(ResourceUpdateControllerClient*, Thread*, scoped_ptr<ResourceUpdateQueue>, ResourceProvider*, bool hasImplThread);
+ ResourceUpdateController(ResourceUpdateControllerClient*, Thread*, scoped_ptr<ResourceUpdateQueue>, ResourceProvider*);
private:
static size_t maxFullUpdatesPerTick(ResourceProvider*);
@@ -64,7 +64,6 @@ private:
void onTimerFired();
ResourceUpdateControllerClient* m_client;
- bool m_hasImplThread;
scoped_ptr<ResourceUpdateQueue> m_queue;
bool m_contentsTexturesPurged;
ResourceProvider* m_resourceProvider;
diff --git a/cc/resource_update_controller_unittest.cc b/cc/resource_update_controller_unittest.cc
index 9dfcb3e..b9c0f66 100644
--- a/cc/resource_update_controller_unittest.cc
+++ b/cc/resource_update_controller_unittest.cc
@@ -185,8 +185,7 @@ protected:
NULL,
m_proxy.implThread(),
m_queue.Pass(),
- m_resourceProvider.get(),
- m_proxy.hasImplThread());
+ m_resourceProvider.get());
updateController->finalize();
}
@@ -365,7 +364,7 @@ public:
protected:
FakeResourceUpdateController(cc::ResourceUpdateControllerClient* client, cc::Thread* thread, scoped_ptr<ResourceUpdateQueue> queue, ResourceProvider* resourceProvider)
- : cc::ResourceUpdateController(client, thread, queue.Pass(), resourceProvider, false)
+ : cc::ResourceUpdateController(client, thread, queue.Pass(), resourceProvider)
, m_updateMoreTexturesSize(0) { }
base::TimeTicks m_now;
diff --git a/cc/single_thread_proxy.cc b/cc/single_thread_proxy.cc
index 1301355..9c51d4ca3 100644
--- a/cc/single_thread_proxy.cc
+++ b/cc/single_thread_proxy.cc
@@ -6,6 +6,7 @@
#include "base/auto_reset.h"
#include "base/debug/trace_event.h"
+#include "cc/context_provider.h"
#include "cc/draw_quad.h"
#include "cc/layer_tree_host.h"
#include "cc/layer_tree_impl.h"
@@ -25,6 +26,7 @@ SingleThreadProxy::SingleThreadProxy(LayerTreeHost* layerTreeHost)
: Proxy(scoped_ptr<Thread>(NULL))
, m_layerTreeHost(layerTreeHost)
, m_outputSurfaceLost(false)
+ , m_createdOffscreenContextProvider(false)
, m_rendererInitialized(false)
, m_nextFrameIsNewlyCommittedFrame(false)
, m_insideDraw(false)
@@ -139,6 +141,12 @@ bool SingleThreadProxy::recreateOutputSurface()
scoped_ptr<OutputSurface> outputSurface = m_layerTreeHost->createOutputSurface();
if (!outputSurface.get())
return false;
+ scoped_refptr<cc::ContextProvider> offscreenContextProvider;
+ if (m_createdOffscreenContextProvider) {
+ offscreenContextProvider = m_layerTreeHost->client()->OffscreenContextProviderForMainThread();
+ if (!offscreenContextProvider->InitializeOnMainThread())
+ return false;
+ }
bool initialized;
{
@@ -148,6 +156,9 @@ bool SingleThreadProxy::recreateOutputSurface()
initialized = m_layerTreeHostImpl->initializeRenderer(outputSurface.Pass());
if (initialized) {
m_RendererCapabilitiesForMainThread = m_layerTreeHostImpl->rendererCapabilities();
+ m_layerTreeHostImpl->resourceProvider()->setOffscreenContextProvider(offscreenContextProvider);
+ } else if (offscreenContextProvider) {
+ offscreenContextProvider->VerifyContexts();
}
}
@@ -196,8 +207,7 @@ void SingleThreadProxy::doCommit(scoped_ptr<ResourceUpdateQueue> queue)
NULL,
Proxy::mainThread(),
queue.Pass(),
- m_layerTreeHostImpl->resourceProvider(),
- hasImplThread());
+ m_layerTreeHostImpl->resourceProvider());
updateController->finalize();
m_layerTreeHost->finishCommitOnImplThread(m_layerTreeHostImpl.get());
@@ -382,6 +392,15 @@ bool SingleThreadProxy::commitAndComposite()
if (!m_layerTreeHost->initializeRendererIfNeeded())
return false;
+ scoped_refptr<cc::ContextProvider> offscreenContextProvider;
+ if (m_RendererCapabilitiesForMainThread.usingOffscreenContext3d && m_layerTreeHost->needsOffscreenContext()) {
+ offscreenContextProvider = m_layerTreeHost->client()->OffscreenContextProviderForMainThread();
+ if (offscreenContextProvider->InitializeOnMainThread())
+ m_createdOffscreenContextProvider = true;
+ else
+ offscreenContextProvider = NULL;
+ }
+
m_layerTreeHost->contentsTextureManager()->unlinkAndClearEvictedBackings();
scoped_ptr<ResourceUpdateQueue> queue = make_scoped_ptr(new ResourceUpdateQueue);
@@ -389,18 +408,20 @@ bool SingleThreadProxy::commitAndComposite()
m_layerTreeHost->willCommit();
doCommit(queue.Pass());
- bool result = doComposite();
+ bool result = doComposite(offscreenContextProvider);
m_layerTreeHost->didBeginFrame();
return result;
}
-bool SingleThreadProxy::doComposite()
+bool SingleThreadProxy::doComposite(scoped_refptr<cc::ContextProvider> offscreenContextProvider)
{
DCHECK(!m_outputSurfaceLost);
{
DebugScopedSetImplThread impl(this);
base::AutoReset<bool> markInside(&m_insideDraw, true);
+ m_layerTreeHostImpl->resourceProvider()->setOffscreenContextProvider(offscreenContextProvider);
+
if (!m_layerTreeHostImpl->visible())
return false;
@@ -422,6 +443,8 @@ bool SingleThreadProxy::doComposite()
}
if (m_outputSurfaceLost) {
+ if (cc::ContextProvider* offscreenContexts = m_layerTreeHostImpl->resourceProvider()->offscreenContextProvider())
+ offscreenContexts->VerifyContexts();
m_layerTreeHost->didLoseOutputSurface();
return false;
}
diff --git a/cc/single_thread_proxy.h b/cc/single_thread_proxy.h
index a499501..a8be093 100644
--- a/cc/single_thread_proxy.h
+++ b/cc/single_thread_proxy.h
@@ -14,6 +14,7 @@
namespace cc {
+class ContextProvider;
class LayerTreeHost;
class SingleThreadProxy : public Proxy, LayerTreeHostImplClient {
@@ -73,12 +74,13 @@ private:
bool commitAndComposite();
void doCommit(scoped_ptr<ResourceUpdateQueue>);
- bool doComposite();
+ bool doComposite(scoped_refptr<cc::ContextProvider> offscreenContextProvider);
void didSwapFrame();
// Accessed on main thread only.
LayerTreeHost* m_layerTreeHost;
bool m_outputSurfaceLost;
+ bool m_createdOffscreenContextProvider;
// Holds on to the context between initializeContext() and initializeRenderer() calls. Shouldn't
// be used for anything else.
diff --git a/cc/test/fake_context_provider.cc b/cc/test/fake_context_provider.cc
new file mode 100644
index 0000000..ed777fc
--- /dev/null
+++ b/cc/test/fake_context_provider.cc
@@ -0,0 +1,61 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/test/fake_context_provider.h"
+
+#include "cc/test/test_web_graphics_context_3d.h"
+
+namespace cc {
+
+FakeContextProvider::FakeContextProvider()
+ : destroyed_(false) {
+}
+
+FakeContextProvider::FakeContextProvider(
+ const CreateCallback& create_callback)
+ : create_callback_(create_callback),
+ destroyed_(false) {
+}
+
+FakeContextProvider::~FakeContextProvider() {}
+
+bool FakeContextProvider::InitializeOnMainThread() {
+ if (destroyed_)
+ return false;
+ if (context3d_)
+ return true;
+
+ if (create_callback_.is_null())
+ context3d_ = TestWebGraphicsContext3D::Create().Pass();
+ else
+ context3d_ = create_callback_.Run();
+ destroyed_ = !context3d_;
+ return !!context3d_;
+}
+
+bool FakeContextProvider::BindToCurrentThread() {
+ return context3d_->makeContextCurrent();
+}
+
+WebKit::WebGraphicsContext3D* FakeContextProvider::Context3d() {
+ return context3d_.get();
+}
+class GrContext* FakeContextProvider::GrContext() {
+ // TODO(danakj): Make a fake GrContext.
+ return NULL;
+}
+
+void FakeContextProvider::VerifyContexts() {
+ if (!Context3d() || Context3d()->isContextLost()) {
+ base::AutoLock lock(destroyed_lock_);
+ destroyed_ = true;
+ }
+}
+
+bool FakeContextProvider::DestroyedOnMainThread() {
+ base::AutoLock lock(destroyed_lock_);
+ return destroyed_;
+}
+
+} // namespace cc
diff --git a/cc/test/fake_context_provider.h b/cc/test/fake_context_provider.h
new file mode 100644
index 0000000..f7c1839
--- /dev/null
+++ b/cc/test/fake_context_provider.h
@@ -0,0 +1,45 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_TEST_FAKE_CONTEXT_PROVIDER_H_
+#define CC_TEST_FAKE_CONTEXT_PROVIDER_H_
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/lock.h"
+#include "cc/context_provider.h"
+
+namespace cc {
+class TestWebGraphicsContext3D;
+
+class FakeContextProvider : public cc::ContextProvider {
+ public:
+ typedef base::Callback<scoped_ptr<TestWebGraphicsContext3D>(void)>
+ CreateCallback;
+
+ FakeContextProvider();
+ explicit FakeContextProvider(const CreateCallback& create_callback);
+
+ virtual bool InitializeOnMainThread() OVERRIDE;
+ virtual bool BindToCurrentThread() OVERRIDE;
+ virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE;
+ virtual class GrContext* GrContext() OVERRIDE;
+ virtual void VerifyContexts() OVERRIDE;
+
+ bool DestroyedOnMainThread();
+
+ protected:
+ virtual ~FakeContextProvider();
+
+ CreateCallback create_callback_;
+ scoped_ptr<WebKit::WebGraphicsContext3D> context3d_;
+
+ base::Lock destroyed_lock_;
+ bool destroyed_;
+};
+
+} // namespace cc
+
+#endif // CC_TEST_FAKE_CONTEXT_PROVIDER_H_
+
diff --git a/cc/test/fake_layer_tree_host_client.cc b/cc/test/fake_layer_tree_host_client.cc
index e3e7735..253f5fd 100644
--- a/cc/test/fake_layer_tree_host_client.cc
+++ b/cc/test/fake_layer_tree_host_client.cc
@@ -4,8 +4,19 @@
#include "cc/test/fake_layer_tree_host_client.h"
+#include "cc/context_provider.h"
+#include "cc/test/test_web_graphics_context_3d.h"
+
namespace cc {
+FakeLayerImplTreeHostClient::FakeLayerImplTreeHostClient(bool useSoftwareRendering, bool useDelegatingRenderer)
+ : m_useSoftwareRendering(useSoftwareRendering)
+ , m_useDelegatingRenderer(useDelegatingRenderer)
+{
+}
+
+FakeLayerImplTreeHostClient::~FakeLayerImplTreeHostClient() { }
+
scoped_ptr<OutputSurface> FakeLayerImplTreeHostClient::createOutputSurface()
{
if (m_useSoftwareRendering) {
@@ -27,4 +38,16 @@ scoped_ptr<InputHandler> FakeLayerImplTreeHostClient::createInputHandler()
return scoped_ptr<InputHandler>();
}
+scoped_refptr<cc::ContextProvider> FakeLayerImplTreeHostClient::OffscreenContextProviderForMainThread() {
+ if (!m_mainThreadContexts || m_mainThreadContexts->DestroyedOnMainThread())
+ m_mainThreadContexts = new FakeContextProvider;
+ return m_mainThreadContexts;
+}
+
+scoped_refptr<cc::ContextProvider> FakeLayerImplTreeHostClient::OffscreenContextProviderForCompositorThread() {
+ if (!m_compositorThreadContexts || m_compositorThreadContexts->DestroyedOnMainThread())
+ m_compositorThreadContexts = new FakeContextProvider;
+ return m_compositorThreadContexts;
+}
+
} // namespace cc
diff --git a/cc/test/fake_layer_tree_host_client.h b/cc/test/fake_layer_tree_host_client.h
index f10ba59..65a40ef 100644
--- a/cc/test/fake_layer_tree_host_client.h
+++ b/cc/test/fake_layer_tree_host_client.h
@@ -8,17 +8,15 @@
#include "base/memory/scoped_ptr.h"
#include "cc/input_handler.h"
#include "cc/layer_tree_host.h"
+#include "cc/test/fake_context_provider.h"
#include "cc/test/fake_output_surface.h"
namespace cc {
class FakeLayerImplTreeHostClient : public LayerTreeHostClient {
public:
- FakeLayerImplTreeHostClient(bool useSoftwareRendering = false, bool useDelegatingRenderer = false)
- : m_useSoftwareRendering(useSoftwareRendering)
- , m_useDelegatingRenderer(useDelegatingRenderer)
- {
- }
+ FakeLayerImplTreeHostClient(bool useSoftwareRendering = false, bool useDelegatingRenderer = false);
+ virtual ~FakeLayerImplTreeHostClient();
virtual void willBeginFrame() OVERRIDE { }
virtual void didBeginFrame() OVERRIDE { }
@@ -37,9 +35,15 @@ public:
// Used only in the single-threaded path.
virtual void scheduleComposite() OVERRIDE { }
+ virtual scoped_refptr<cc::ContextProvider> OffscreenContextProviderForMainThread() OVERRIDE;
+ virtual scoped_refptr<cc::ContextProvider> OffscreenContextProviderForCompositorThread() OVERRIDE;
+
private:
bool m_useSoftwareRendering;
bool m_useDelegatingRenderer;
+
+ scoped_refptr<FakeContextProvider> m_mainThreadContexts;
+ scoped_refptr<FakeContextProvider> m_compositorThreadContexts;
};
} // namespace cc
diff --git a/cc/test/layer_tree_test_common.cc b/cc/test/layer_tree_test_common.cc
index 4bd689c..0100135 100644
--- a/cc/test/layer_tree_test_common.cc
+++ b/cc/test/layer_tree_test_common.cc
@@ -15,6 +15,7 @@
#include "cc/single_thread_proxy.h"
#include "cc/thread_impl.h"
#include "cc/test/animation_test_common.h"
+#include "cc/test/fake_layer_tree_host_client.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/occlusion_tracker_test_common.h"
#include "cc/test/tiled_layer_test_common.h"
@@ -28,6 +29,15 @@ using namespace WebKit;
namespace cc {
+TestHooks::TestHooks()
+{
+ bool useSoftwareRendering = false;
+ bool useDelegatingRenderer = false;
+ m_fakeClient.reset(new FakeLayerImplTreeHostClient(useSoftwareRendering, useDelegatingRenderer));
+}
+
+TestHooks::~TestHooks() { }
+
bool TestHooks::prepareToDrawOnThread(cc::LayerTreeHostImpl*, LayerTreeHostImpl::FrameData&, bool)
{
return true;
@@ -43,6 +53,16 @@ scoped_ptr<OutputSurface> TestHooks::createOutputSurface()
return createFakeOutputSurface();
}
+scoped_refptr<cc::ContextProvider> TestHooks::OffscreenContextProviderForMainThread()
+{
+ return m_fakeClient->OffscreenContextProviderForMainThread();
+}
+
+scoped_refptr<cc::ContextProvider> TestHooks::OffscreenContextProviderForCompositorThread()
+{
+ return m_fakeClient->OffscreenContextProviderForCompositorThread();
+}
+
scoped_ptr<MockLayerTreeHostImpl> MockLayerTreeHostImpl::create(TestHooks* testHooks, const LayerTreeSettings& settings, LayerTreeHostImplClient* client, Proxy* proxy)
{
return make_scoped_ptr(new MockLayerTreeHostImpl(testHooks, settings, client, proxy));
@@ -198,6 +218,11 @@ public:
m_testHooks->didRecreateOutputSurface(succeeded);
}
+ virtual void willRetryRecreateOutputSurface() OVERRIDE
+ {
+ m_testHooks->willRetryRecreateOutputSurface();
+ }
+
virtual scoped_ptr<InputHandler> createInputHandler() OVERRIDE
{
return scoped_ptr<InputHandler>();
@@ -226,6 +251,16 @@ public:
m_testHooks->scheduleComposite();
}
+ virtual scoped_refptr<cc::ContextProvider> OffscreenContextProviderForMainThread() OVERRIDE
+ {
+ return m_testHooks->OffscreenContextProviderForMainThread();
+ }
+
+ virtual scoped_refptr<cc::ContextProvider> OffscreenContextProviderForCompositorThread() OVERRIDE
+ {
+ return m_testHooks->OffscreenContextProviderForCompositorThread();
+ }
+
private:
explicit ThreadedMockLayerTreeHostClient(TestHooks* testHooks) : m_testHooks(testHooks) { }
@@ -312,8 +347,6 @@ void ThreadedTest::doBeginTest()
if (m_endWhenBeginReturns)
realEndTest();
- LayerTreeHost::setNeedsFilterContext(false);
-
// Allow commits to happen once beginTest() has had a chance to post tasks
// so that those tasks will happen before the first commit.
if (m_layerTreeHost)
diff --git a/cc/test/layer_tree_test_common.h b/cc/test/layer_tree_test_common.h
index 82144bd..b7352bf 100644
--- a/cc/test/layer_tree_test_common.h
+++ b/cc/test/layer_tree_test_common.h
@@ -13,7 +13,12 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebAnimationDelegate.h"
+namespace Webkit {
+class WebGraphicsContext3D;
+}
+
namespace cc {
+class FakeLayerImplTreeHostClient;
class LayerImpl;
class LayerTreeHost;
class LayerTreeHostClient;
@@ -22,6 +27,9 @@ class LayerTreeHostImpl;
// Used by test stubs to notify the test when something interesting happens.
class TestHooks : public WebKit::WebAnimationDelegate {
public:
+ TestHooks();
+ virtual ~TestHooks();
+
virtual void beginCommitOnThread(LayerTreeHostImpl*) { }
virtual void commitCompleteOnThread(LayerTreeHostImpl*) { }
virtual bool prepareToDrawOnThread(
@@ -34,6 +42,7 @@ public:
virtual void animate(base::TimeTicks monotonicTime) { }
virtual void layout() { }
virtual void didRecreateOutputSurface(bool succeeded) { }
+ virtual void willRetryRecreateOutputSurface() { }
virtual void didAddAnimation() { }
virtual void didCommit() { }
virtual void didCommitAndDrawFrame() { }
@@ -46,6 +55,12 @@ public:
virtual void notifyAnimationFinished(double time) OVERRIDE { }
virtual scoped_ptr<OutputSurface> createOutputSurface();
+
+ virtual scoped_refptr<cc::ContextProvider> OffscreenContextProviderForMainThread();
+ virtual scoped_refptr<cc::ContextProvider> OffscreenContextProviderForCompositorThread();
+
+private:
+ scoped_ptr<FakeLayerImplTreeHostClient> m_fakeClient;
};
class TimeoutTask;
diff --git a/cc/test/test_web_graphics_context_3d.cc b/cc/test/test_web_graphics_context_3d.cc
index c1ac0e7..b4a2c7e 100644
--- a/cc/test/test_web_graphics_context_3d.cc
+++ b/cc/test/test_web_graphics_context_3d.cc
@@ -302,6 +302,10 @@ void TestWebGraphicsContext3D::loseContextCHROMIUM(WGC3Denum current,
context_lost_ = true;
if (context_lost_callback_)
context_lost_callback_->onContextLost();
+
+ for (size_t i = 0; i < shared_contexts_.size(); ++i)
+ shared_contexts_[i]->loseContextCHROMIUM(current, other);
+ shared_contexts_.clear();
}
WebKit::WebGLId TestWebGraphicsContext3D::NextTextureId() {
diff --git a/cc/test/test_web_graphics_context_3d.h b/cc/test/test_web_graphics_context_3d.h
index abfd9c9..212da16 100644
--- a/cc/test/test_web_graphics_context_3d.h
+++ b/cc/test/test_web_graphics_context_3d.h
@@ -122,6 +122,11 @@ class TestWebGraphicsContext3D : public FakeWebGraphicsContext3D {
have_extension_egl_image_ = have;
}
+ // When this context is lost, all contexts in its share group are also lost.
+ void add_share_group_context(WebKit::WebGraphicsContext3D* context3d) {
+ shared_contexts_.push_back(context3d);
+ }
+
static const WebKit::WebGLId kExternalTextureId;
virtual WebKit::WebGLId NextTextureId();
@@ -142,6 +147,7 @@ class TestWebGraphicsContext3D : public FakeWebGraphicsContext3D {
WebGraphicsContextLostCallback* context_lost_callback_;
std::vector<WebKit::WebGLId> textures_;
base::hash_set<WebKit::WebGLId> used_textures_;
+ std::vector<WebKit::WebGraphicsContext3D*> shared_contexts_;
int width_;
int height_;
};
diff --git a/cc/thread_proxy.cc b/cc/thread_proxy.cc
index ddc61c0..51f073d 100644
--- a/cc/thread_proxy.cc
+++ b/cc/thread_proxy.cc
@@ -7,6 +7,7 @@
#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/debug/trace_event.h"
+#include "cc/context_provider.h"
#include "cc/delay_based_time_source.h"
#include "cc/draw_quad.h"
#include "cc/frame_rate_controller.h"
@@ -17,9 +18,6 @@
#include "cc/prioritized_resource_manager.h"
#include "cc/scheduler.h"
#include "cc/thread.h"
-#include "third_party/WebKit/Source/Platform/chromium/public/WebSharedGraphicsContext3D.h"
-
-using WebKit::WebSharedGraphicsContext3D;
namespace {
@@ -43,6 +41,7 @@ ThreadProxy::ThreadProxy(LayerTreeHost* layerTreeHost, scoped_ptr<Thread> implTh
, m_animateRequested(false)
, m_commitRequested(false)
, m_commitRequestSentToImplThread(false)
+ , m_createdOffscreenContextProvider(false)
, m_layerTreeHost(layerTreeHost)
, m_rendererInitialized(false)
, m_started(false)
@@ -228,9 +227,12 @@ bool ThreadProxy::recreateOutputSurface()
scoped_ptr<OutputSurface> outputSurface = m_layerTreeHost->createOutputSurface();
if (!outputSurface.get())
return false;
- if (m_layerTreeHost->needsSharedContext())
- if (!WebSharedGraphicsContext3D::createCompositorThreadContext())
+ scoped_refptr<cc::ContextProvider> offscreenContextProvider;
+ if (m_createdOffscreenContextProvider) {
+ offscreenContextProvider = m_layerTreeHost->client()->OffscreenContextProviderForCompositorThread();
+ if (!offscreenContextProvider->InitializeOnMainThread())
return false;
+ }
// Make a blocking call to recreateOutputSurfaceOnImplThread. The results of that
// call are pushed into the recreateSucceeded and capabilities local
@@ -243,6 +245,7 @@ bool ThreadProxy::recreateOutputSurface()
m_implThreadWeakPtr,
&completion,
base::Passed(&outputSurface),
+ offscreenContextProvider,
&recreateSucceeded,
&capabilities));
completion.wait();
@@ -314,6 +317,8 @@ void ThreadProxy::checkOutputSurfaceStatusOnImplThread()
TRACE_EVENT0("cc", "ThreadProxy::checkOutputSurfaceStatusOnImplThread");
if (!m_layerTreeHostImpl->isContextLost())
return;
+ if (cc::ContextProvider* offscreenContexts = m_layerTreeHostImpl->resourceProvider()->offscreenContextProvider())
+ offscreenContexts->VerifyContexts();
m_schedulerOnImplThread->didLoseOutputSurface();
}
@@ -599,9 +604,6 @@ void ThreadProxy::beginFrame(scoped_ptr<BeginFrameAndCommitState> beginFrameStat
return;
}
- if (m_layerTreeHost->needsSharedContext() && !WebSharedGraphicsContext3D::haveCompositorThreadContext())
- WebSharedGraphicsContext3D::createCompositorThreadContext();
-
// Do not notify the impl thread of commit requests that occur during
// the apply/animate/layout part of the beginFrameAndCommit process since
// those commit requests will get painted immediately. Once we have done
@@ -671,6 +673,15 @@ void ThreadProxy::beginFrame(scoped_ptr<BeginFrameAndCommitState> beginFrameStat
setNeedsAnimate();
}
+ scoped_refptr<cc::ContextProvider> offscreenContextProvider;
+ if (m_RendererCapabilitiesMainThreadCopy.usingOffscreenContext3d && m_layerTreeHost->needsOffscreenContext()) {
+ offscreenContextProvider = m_layerTreeHost->client()->OffscreenContextProviderForCompositorThread();
+ if (offscreenContextProvider->InitializeOnMainThread())
+ m_createdOffscreenContextProvider = true;
+ else
+ offscreenContextProvider = NULL;
+ }
+
// Notify the impl thread that the beginFrame has completed. This will
// begin the commit process, which is blocking from the main thread's
// point of view, but asynchronously performed on the impl thread,
@@ -682,7 +693,7 @@ void ThreadProxy::beginFrame(scoped_ptr<BeginFrameAndCommitState> beginFrameStat
base::TimeTicks startTime = base::TimeTicks::HighResNow();
CompletionEvent completion;
- Proxy::implThread()->postTask(base::Bind(&ThreadProxy::beginFrameCompleteOnImplThread, m_implThreadWeakPtr, &completion, queue.release()));
+ Proxy::implThread()->postTask(base::Bind(&ThreadProxy::beginFrameCompleteOnImplThread, m_implThreadWeakPtr, &completion, queue.release(), offscreenContextProvider));
completion.wait();
base::TimeTicks endTime = base::TimeTicks::HighResNow();
@@ -694,7 +705,7 @@ void ThreadProxy::beginFrame(scoped_ptr<BeginFrameAndCommitState> beginFrameStat
m_layerTreeHost->didBeginFrame();
}
-void ThreadProxy::beginFrameCompleteOnImplThread(CompletionEvent* completion, ResourceUpdateQueue* rawQueue)
+void ThreadProxy::beginFrameCompleteOnImplThread(CompletionEvent* completion, ResourceUpdateQueue* rawQueue, scoped_refptr<cc::ContextProvider> offscreenContextProvider)
{
scoped_ptr<ResourceUpdateQueue> queue(rawQueue);
@@ -710,6 +721,8 @@ void ThreadProxy::beginFrameCompleteOnImplThread(CompletionEvent* completion, Re
return;
}
+ m_layerTreeHostImpl->resourceProvider()->setOffscreenContextProvider(offscreenContextProvider);
+
if (m_layerTreeHost->contentsTextureManager()->linkedEvictedBackingsExist()) {
// Clear any uploads we were making to textures linked to evicted
// resources
@@ -721,7 +734,7 @@ void ThreadProxy::beginFrameCompleteOnImplThread(CompletionEvent* completion, Re
m_layerTreeHost->contentsTextureManager()->pushTexturePrioritiesToBackings();
- m_currentResourceUpdateControllerOnImplThread = ResourceUpdateController::create(this, Proxy::implThread(), queue.Pass(), m_layerTreeHostImpl->resourceProvider(), hasImplThread());
+ m_currentResourceUpdateControllerOnImplThread = ResourceUpdateController::create(this, Proxy::implThread(), queue.Pass(), m_layerTreeHostImpl->resourceProvider());
m_currentResourceUpdateControllerOnImplThread->performMoreUpdates(
m_schedulerOnImplThread->anticipatedDrawTime());
@@ -1059,7 +1072,7 @@ size_t ThreadProxy::maxPartialTextureUpdates() const
return ResourceUpdateController::maxPartialTextureUpdates();
}
-void ThreadProxy::recreateOutputSurfaceOnImplThread(CompletionEvent* completion, scoped_ptr<OutputSurface> outputSurface, bool* recreateSucceeded, RendererCapabilities* capabilities)
+void ThreadProxy::recreateOutputSurfaceOnImplThread(CompletionEvent* completion, scoped_ptr<OutputSurface> outputSurface, scoped_refptr<cc::ContextProvider> offscreenContextProvider, bool* recreateSucceeded, RendererCapabilities* capabilities)
{
TRACE_EVENT0("cc", "ThreadProxy::recreateOutputSurfaceOnImplThread");
DCHECK(isImplThread());
@@ -1067,7 +1080,10 @@ void ThreadProxy::recreateOutputSurfaceOnImplThread(CompletionEvent* completion,
*recreateSucceeded = m_layerTreeHostImpl->initializeRenderer(outputSurface.Pass());
if (*recreateSucceeded) {
*capabilities = m_layerTreeHostImpl->rendererCapabilities();
+ m_layerTreeHostImpl->resourceProvider()->setOffscreenContextProvider(offscreenContextProvider);
m_schedulerOnImplThread->didRecreateOutputSurface();
+ } else if (offscreenContextProvider) {
+ offscreenContextProvider->VerifyContexts();
}
completion->signal();
}
diff --git a/cc/thread_proxy.h b/cc/thread_proxy.h
index 9e383bb..504dca3 100644
--- a/cc/thread_proxy.h
+++ b/cc/thread_proxy.h
@@ -17,6 +17,7 @@
namespace cc {
+class ContextProvider;
class InputHandler;
class LayerTreeHost;
class ResourceUpdateQueue;
@@ -123,7 +124,7 @@ private:
bool commitPending;
};
void forceBeginFrameOnImplThread(CompletionEvent*);
- void beginFrameCompleteOnImplThread(CompletionEvent*, ResourceUpdateQueue*);
+ void beginFrameCompleteOnImplThread(CompletionEvent*, ResourceUpdateQueue*, scoped_refptr<cc::ContextProvider> offscreenContextProvider);
void beginFrameAbortedOnImplThread();
void requestReadbackOnImplThread(ReadbackRequest*);
void requestStartPageScaleAnimationOnImplThread(gfx::Vector2d targetOffset, bool useAnchor, float scale, base::TimeDelta duration);
@@ -137,7 +138,7 @@ private:
void manageTilesOnImplThread();
void setFullRootLayerDamageOnImplThread();
void acquireLayerTexturesForMainThreadOnImplThread(CompletionEvent*);
- void recreateOutputSurfaceOnImplThread(CompletionEvent*, scoped_ptr<OutputSurface>, bool* recreateSucceeded, RendererCapabilities*);
+ void recreateOutputSurfaceOnImplThread(CompletionEvent*, scoped_ptr<OutputSurface>, scoped_refptr<cc::ContextProvider> offscreenContextProvider, bool* recreateSucceeded, RendererCapabilities*);
void renderingStatsOnImplThread(CompletionEvent*, RenderingStats*);
ScheduledActionDrawAndSwapResult scheduledActionDrawAndSwapInternal(bool forcedDraw);
void forceSerializeOnSwapBuffersOnImplThread(CompletionEvent*);
@@ -153,6 +154,7 @@ private:
bool m_animateRequested; // Set only when setNeedsAnimate is called.
bool m_commitRequested; // Set only when setNeedsCommit is called.
bool m_commitRequestSentToImplThread; // Set by setNeedsCommit and setNeedsAnimate.
+ bool m_createdOffscreenContextProvider; // Set by beginFrame.
base::CancelableClosure m_outputSurfaceRecreationCallback;
LayerTreeHost* m_layerTreeHost;
bool m_rendererInitialized;
diff --git a/cc/tiled_layer_unittest.cc b/cc/tiled_layer_unittest.cc
index ac8baf5..73006b4 100644
--- a/cc/tiled_layer_unittest.cc
+++ b/cc/tiled_layer_unittest.cc
@@ -93,8 +93,7 @@ public:
NULL,
m_proxy->implThread(),
m_queue.Pass(),
- m_resourceProvider.get(),
- m_proxy->hasImplThread());
+ m_resourceProvider.get());
updateController->finalize();
m_queue = make_scoped_ptr(new ResourceUpdateQueue);
}
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 7954175..2b3a800 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -11,6 +11,7 @@
#include "base/command_line.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "cc/context_provider.h"
#include "cc/input_handler.h"
#include "cc/layer.h"
#include "cc/layer_tree_host.h"
@@ -326,6 +327,38 @@ void CompositorImpl::scheduleComposite() {
client_->ScheduleComposite();
}
+class NullContextProvider : public cc::ContextProvider {
+ virtual bool InitializeOnMainThread() { return false; }
+ virtual bool BindToCurrentThread() { return false; }
+ virtual WebKit::WebGraphicsContext3D* Context3d() { return NULL; }
+ virtual class GrContext* GrContext() { return NULL; }
+ virtual void VerifyContexts() {}
+ protected:
+ virtual ~NullContextProvider() {}
+};
+
+scoped_refptr<cc::ContextProvider>
+CompositorImpl::OffscreenContextProviderForMainThread() {
+ // There is no support for offscreen contexts, or compositor filters that
+ // would require them in this compositor instance. If they are needed,
+ // then implement a context provider that provides contexts from
+ // ImageTransportSurfaceAndroid.
+ if (!null_offscreen_context_provider_)
+ null_offscreen_context_provider_ = new NullContextProvider();
+ return null_offscreen_context_provider_;
+}
+
+scoped_refptr<cc::ContextProvider>
+CompositorImpl::OffscreenContextProviderForCompositorThread() {
+ // There is no support for offscreen contexts, or compositor filters that
+ // would require them in this compositor instance. If they are needed,
+ // then implement a context provider that provides contexts from
+ // ImageTransportSurfaceAndroid.
+ if (!null_offscreen_context_provider_)
+ null_offscreen_context_provider_ = new NullContextProvider();
+ return null_offscreen_context_provider_;
+}
+
void CompositorImpl::OnViewContextSwapBuffersPosted() {
TRACE_EVENT0("compositor", "CompositorImpl::OnViewContextSwapBuffersPosted");
}
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h
index 07a3353..eb9d9f3 100644
--- a/content/browser/renderer_host/compositor_impl_android.h
+++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -77,6 +77,10 @@ class CONTENT_EXPORT CompositorImpl
virtual void didCommitAndDrawFrame() OVERRIDE;
virtual void didCompleteSwapBuffers() OVERRIDE;
virtual void scheduleComposite() OVERRIDE;
+ virtual scoped_refptr<cc::ContextProvider>
+ OffscreenContextProviderForMainThread() OVERRIDE;
+ virtual scoped_refptr<cc::ContextProvider>
+ OffscreenContextProviderForCompositorThread() OVERRIDE;
// WebGraphicsContext3DSwapBuffersClient implementation.
virtual void OnViewContextSwapBuffersPosted() OVERRIDE;
@@ -100,6 +104,8 @@ class CONTENT_EXPORT CompositorImpl
Compositor::Client* client_;
base::WeakPtrFactory<CompositorImpl> weak_factory_;
+ scoped_refptr<cc::ContextProvider> null_offscreen_context_provider_;
+
DISALLOW_COPY_AND_ASSIGN(CompositorImpl);
};
diff --git a/content/browser/renderer_host/image_transport_factory.cc b/content/browser/renderer_host/image_transport_factory.cc
index 5b81dbf..9617b16 100644
--- a/content/browser/renderer_host/image_transport_factory.cc
+++ b/content/browser/renderer_host/image_transport_factory.cc
@@ -19,6 +19,7 @@
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/gpu/gpu_process_host.h"
#include "content/browser/gpu/gpu_surface_tracker.h"
+#include "content/common/gpu/client/context_provider_command_buffer.h"
#include "content/common/gpu/client/gl_helper.h"
#include "content/common/gpu/client/gpu_channel_host.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
@@ -28,7 +29,6 @@
#include "content/public/common/content_switches.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/ipc/command_buffer_proxy.h"
-#include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3D.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
#include "ui/compositor/compositor.h"
@@ -351,8 +351,7 @@ void BrowserCompositorOutputSurfaceProxy::OnUpdateVSyncParameters(
class GpuProcessTransportFactory
: public ui::ContextFactory,
- public ImageTransportFactory,
- public WebKit::WebGraphicsContext3D::WebGraphicsContextLostCallback {
+ public ImageTransportFactory {
public:
GpuProcessTransportFactory()
: ALLOW_THIS_IN_INITIALIZER_LIST(callback_factory_(this)) {
@@ -408,9 +407,10 @@ class GpuProcessTransportFactory
CreateSharedContextLazy();
gfx::GLSurfaceHandle handle = gfx::GLSurfaceHandle(
gfx::kNullPluginWindow, gfx::TEXTURE_TRANSPORT);
- handle.parent_gpu_process_id = shared_context_->GetGPUProcessID();
- handle.parent_client_id = shared_context_->GetChannelID();
-
+ handle.parent_gpu_process_id =
+ shared_contexts_main_thread_->Context3d()->GetGPUProcessID();
+ handle.parent_client_id =
+ shared_contexts_main_thread_->Context3d()->GetChannelID();
return handle;
}
@@ -420,11 +420,12 @@ class GpuProcessTransportFactory
virtual scoped_refptr<ui::Texture> CreateTransportClient(
float device_scale_factor) OVERRIDE {
- if (!shared_context_.get())
+ if (!shared_contexts_main_thread_)
return NULL;
scoped_refptr<ImageTransportClientTexture> image(
- new ImageTransportClientTexture(shared_context_.get(),
- device_scale_factor));
+ new ImageTransportClientTexture(
+ shared_contexts_main_thread_->Context3d(),
+ device_scale_factor));
return image;
}
@@ -432,31 +433,36 @@ class GpuProcessTransportFactory
const gfx::Size& size,
float device_scale_factor,
unsigned int texture_id) OVERRIDE {
- if (!shared_context_.get())
+ if (!shared_contexts_main_thread_)
return NULL;
- scoped_refptr<OwnedTexture> image(
- new OwnedTexture(shared_context_.get(), size, device_scale_factor,
- texture_id));
+ scoped_refptr<OwnedTexture> image(new OwnedTexture(
+ shared_contexts_main_thread_->Context3d(),
+ size,
+ device_scale_factor,
+ texture_id));
return image;
}
virtual GLHelper* GetGLHelper() OVERRIDE {
if (!gl_helper_.get()) {
CreateSharedContextLazy();
+ WebKit::WebGraphicsContext3D* context_for_main_thread =
+ shared_contexts_main_thread_->Context3d();
WebKit::WebGraphicsContext3D* context_for_thread =
CreateOffscreenContext();
if (!context_for_thread)
return NULL;
- gl_helper_.reset(new GLHelper(shared_context_.get(),
+
+ gl_helper_.reset(new GLHelper(context_for_main_thread,
context_for_thread));
}
return gl_helper_.get();
}
virtual uint32 InsertSyncPoint() OVERRIDE {
- if (!shared_context_.get())
+ if (!shared_contexts_main_thread_)
return 0;
- return shared_context_->insertSyncPoint();
+ return shared_contexts_main_thread_->Context3d()->insertSyncPoint();
}
virtual void AddObserver(ImageTransportFactoryObserver* observer) OVERRIDE {
@@ -468,15 +474,6 @@ class GpuProcessTransportFactory
observer_list_.RemoveObserver(observer);
}
- // WebGraphicsContextLostCallback implementation, called for the shared
- // context.
- virtual void onContextLost() {
- MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&GpuProcessTransportFactory::OnLostSharedContext,
- callback_factory_.GetWeakPtr()));
- }
-
void OnLostContext(ui::Compositor* compositor) {
LOG(ERROR) << "Lost UI compositor context.";
PerCompositorData* data = per_compositor_data_[compositor];
@@ -546,29 +543,91 @@ class GpuProcessTransportFactory
return context.release();
}
- void CreateSharedContextLazy() {
- if (shared_context_.get())
- return;
+ class MainThreadContextProvider : public ContextProviderCommandBuffer {
+ public:
+ explicit MainThreadContextProvider(GpuProcessTransportFactory* factory)
+ : factory_(factory) {}
+
+ protected:
+ virtual ~MainThreadContextProvider() {}
+
+ virtual scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
+ CreateOffscreenContext3d() {
+ return make_scoped_ptr(factory_->CreateOffscreenContext());
+ }
+
+ virtual void OnLostContext() OVERRIDE {
+ ContextProviderCommandBuffer::OnLostContext();
+
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&GpuProcessTransportFactory::OnLostMainThreadSharedContext,
+ factory_->callback_factory_.GetWeakPtr()));
+ }
+
+ private:
+ GpuProcessTransportFactory* factory_;
+ };
- shared_context_.reset(CreateOffscreenContext());
- if (!shared_context_.get()) {
- // If we can't recreate contexts, we won't be able to show the UI. Better
- // crash at this point.
+ virtual scoped_refptr<cc::ContextProvider>
+ OffscreenContextProviderForMainThread() OVERRIDE {
+ if (!shared_contexts_main_thread_ ||
+ shared_contexts_main_thread_->DestroyedOnMainThread()) {
+ shared_contexts_main_thread_ = new MainThreadContextProvider(this);
+ }
+ return shared_contexts_main_thread_;
+ }
+
+ class CompositorThreadContextProvider : public ContextProviderCommandBuffer {
+ public:
+ explicit CompositorThreadContextProvider(
+ GpuProcessTransportFactory* factory) : factory_(factory) {}
+
+ protected:
+ virtual ~CompositorThreadContextProvider() {}
+
+ virtual scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
+ CreateOffscreenContext3d() {
+ return make_scoped_ptr(factory_->CreateOffscreenContext());
+ }
+
+ private:
+ GpuProcessTransportFactory* factory_;
+ };
+
+ virtual scoped_refptr<cc::ContextProvider>
+ OffscreenContextProviderForCompositorThread() OVERRIDE {
+ if (!shared_contexts_compositor_thread_ ||
+ shared_contexts_compositor_thread_->DestroyedOnMainThread()) {
+ shared_contexts_compositor_thread_ =
+ new CompositorThreadContextProvider(this);
+ }
+ return shared_contexts_compositor_thread_;
+ }
+
+ void CreateSharedContextLazy() {
+ scoped_refptr<cc::ContextProvider> provider =
+ OffscreenContextProviderForMainThread();
+ if (!provider->InitializeOnMainThread()) {
+ // If we can't recreate contexts, we won't be able to show the UI.
+ // Better crash at this point.
LOG(FATAL) << "Failed to initialize UI shared context.";
}
- if (!shared_context_->makeContextCurrent()) {
- // If we can't recreate contexts, we won't be able to show the UI. Better
- // crash at this point.
+ if (!provider->BindToCurrentThread()) {
+ // If we can't recreate contexts, we won't be able to show the UI.
+ // Better crash at this point.
LOG(FATAL) << "Failed to make UI shared context current.";
}
- shared_context_->setContextLostCallback(this);
}
- void OnLostSharedContext() {
+ void OnLostMainThreadSharedContext() {
// Keep old resources around while we call the observers, but ensure that
// new resources are created if needed.
- scoped_ptr<WebGraphicsContext3DCommandBufferImpl> old_shared_context(
- shared_context_.release());
+
+ scoped_refptr<MainThreadContextProvider> old_contexts_main_thread =
+ shared_contexts_main_thread_;
+ shared_contexts_main_thread_ = NULL;
+
scoped_ptr<GLHelper> old_helper(gl_helper_.release());
FOR_EACH_OBSERVER(ImageTransportFactoryObserver,
@@ -578,7 +637,9 @@ class GpuProcessTransportFactory
typedef std::map<ui::Compositor*, PerCompositorData*> PerCompositorDataMap;
PerCompositorDataMap per_compositor_data_;
- scoped_ptr<WebGraphicsContext3DCommandBufferImpl> shared_context_;
+ scoped_refptr<MainThreadContextProvider> shared_contexts_main_thread_;
+ scoped_refptr<CompositorThreadContextProvider>
+ shared_contexts_compositor_thread_;
scoped_ptr<GLHelper> gl_helper_;
ObserverList<ImageTransportFactoryObserver> observer_list_;
base::WeakPtrFactory<GpuProcessTransportFactory> callback_factory_;
diff --git a/content/common/gpu/client/context_provider_command_buffer.cc b/content/common/gpu/client/context_provider_command_buffer.cc
new file mode 100644
index 0000000..76141e4
--- /dev/null
+++ b/content/common/gpu/client/context_provider_command_buffer.cc
@@ -0,0 +1,107 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/gpu/client/context_provider_command_buffer.h"
+
+#include "webkit/gpu/grcontext_for_webgraphicscontext3d.h"
+
+namespace content {
+
+class ContextProviderCommandBuffer::LostContextCallbackProxy
+ : public WebKit::WebGraphicsContext3D::WebGraphicsContextLostCallback {
+ public:
+ LostContextCallbackProxy(ContextProviderCommandBuffer* provider)
+ : provider_(provider) {
+ provider_->context3d_->setContextLostCallback(this);
+ }
+
+ virtual void onContextLost() {
+ provider_->OnLostContext();
+ }
+
+ private:
+ ContextProviderCommandBuffer* provider_;
+};
+
+class ContextProviderCommandBuffer::MemoryAllocationCallbackProxy
+ : public WebKit::WebGraphicsContext3D::
+ WebGraphicsMemoryAllocationChangedCallbackCHROMIUM {
+ public:
+ MemoryAllocationCallbackProxy(ContextProviderCommandBuffer* provider)
+ : provider_(provider) {
+ provider_->context3d_->setMemoryAllocationChangedCallbackCHROMIUM(this);
+ }
+
+ void onMemoryAllocationChanged(WebKit::WebGraphicsMemoryAllocation alloc) {
+ provider_->OnMemoryAllocationChanged(!!alloc.gpuResourceSizeInBytes);
+ }
+
+ private:
+ ContextProviderCommandBuffer* provider_;
+};
+
+ContextProviderCommandBuffer::ContextProviderCommandBuffer()
+ : destroyed_(false) {
+}
+
+ContextProviderCommandBuffer::~ContextProviderCommandBuffer() {}
+
+bool ContextProviderCommandBuffer::InitializeOnMainThread() {
+ if (destroyed_)
+ return false;
+ if (context3d_)
+ return true;
+
+ context3d_ = CreateOffscreenContext3d().Pass();
+ destroyed_ = !context3d_;
+ return !!context3d_;
+}
+
+bool ContextProviderCommandBuffer::BindToCurrentThread() {
+ if (lost_context_callback_proxy_)
+ return true;
+
+ bool result = context3d_->makeContextCurrent();
+ lost_context_callback_proxy_.reset(new LostContextCallbackProxy(this));
+ return result;
+}
+
+WebGraphicsContext3DCommandBufferImpl*
+ContextProviderCommandBuffer::Context3d() {
+ return context3d_.get();
+}
+
+class GrContext* ContextProviderCommandBuffer::GrContext() {
+ if (gr_context_)
+ return gr_context_->get();
+
+ gr_context_.reset(
+ new webkit::gpu::GrContextForWebGraphicsContext3D(context3d_.get()));
+ memory_allocation_callback_proxy_.reset(
+ new MemoryAllocationCallbackProxy(this));
+ return gr_context_->get();
+}
+
+void ContextProviderCommandBuffer::VerifyContexts() {
+ if (!destroyed_ && context3d_->isContextLost())
+ OnLostContext();
+}
+
+void ContextProviderCommandBuffer::OnLostContext() {
+ base::AutoLock lock(destroyed_lock_);
+ destroyed_ = true;
+}
+
+bool ContextProviderCommandBuffer::DestroyedOnMainThread() {
+ base::AutoLock lock(destroyed_lock_);
+ return destroyed_;
+}
+
+void ContextProviderCommandBuffer::OnMemoryAllocationChanged(
+ bool nonzero_allocation) {
+ if (gr_context_)
+ gr_context_->SetMemoryLimit(nonzero_allocation);
+}
+
+} // namespace content
diff --git a/content/common/gpu/client/context_provider_command_buffer.h b/content/common/gpu/client/context_provider_command_buffer.h
new file mode 100644
index 0000000..c415e0f
--- /dev/null
+++ b/content/common/gpu/client/context_provider_command_buffer.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_GPU_CLIENT_CONTEXT_PROVIDER_COMMAND_BUFFER
+#define CONTENT_COMMON_GPU_CLIENT_CONTEXT_PROVIDER_COMMAND_BUFFER
+
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/lock.h"
+#include "cc/context_provider.h"
+#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
+
+namespace webkit {
+namespace gpu {
+class GrContextForWebGraphicsContext3D;
+}
+}
+
+namespace content {
+
+// Implementation of cc::ContextProvider that provides a
+// WebGraphicsContext3DCommandBufferImpl context and a GrContext.
+class ContextProviderCommandBuffer : public cc::ContextProvider {
+ public:
+ ContextProviderCommandBuffer();
+
+ virtual bool InitializeOnMainThread() OVERRIDE;
+ virtual bool BindToCurrentThread() OVERRIDE;
+ virtual WebGraphicsContext3DCommandBufferImpl* Context3d() OVERRIDE;
+ virtual class GrContext* GrContext() OVERRIDE;
+ virtual void VerifyContexts() OVERRIDE;
+
+ bool DestroyedOnMainThread();
+
+ protected:
+ virtual ~ContextProviderCommandBuffer();
+
+ // Subclass must provide an implementation to create an offscreen context.
+ virtual scoped_ptr<WebGraphicsContext3DCommandBufferImpl>
+ CreateOffscreenContext3d() = 0;
+
+ virtual void OnLostContext();
+ virtual void OnMemoryAllocationChanged(bool nonzero_allocation);
+
+ private:
+
+ scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d_;
+ scoped_ptr<webkit::gpu::GrContextForWebGraphicsContext3D> gr_context_;
+
+ base::Lock destroyed_lock_;
+ bool destroyed_;
+
+ class LostContextCallbackProxy;
+ scoped_ptr<LostContextCallbackProxy> lost_context_callback_proxy_;
+
+ class MemoryAllocationCallbackProxy;
+ scoped_ptr<MemoryAllocationCallbackProxy> memory_allocation_callback_proxy_;
+};
+
+} // namespace content
+
+#endif // CONTENT_COMMON_GPU_CLIENT_CONTEXT_PROVIDER_COMMAND_BUFFER
diff --git a/content/content_common.gypi b/content/content_common.gypi
index fbec6c2..802f7c3 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -206,6 +206,8 @@
'common/geolocation_messages.h',
'common/gpu/client/command_buffer_proxy_impl.cc',
'common/gpu/client/command_buffer_proxy_impl.h',
+ 'common/gpu/client/context_provider_command_buffer.cc',
+ 'common/gpu/client/context_provider_command_buffer.h',
'common/gpu/client/gl_helper.cc',
'common/gpu/client/gl_helper.h',
'common/gpu/client/gpu_channel_host.cc',
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index 3aeecae..9e1df21 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -7,7 +7,9 @@
#include "base/command_line.h"
#include "base/logging.h"
#include "base/string_number_conversions.h"
+#include "base/synchronization/lock.h"
#include "base/time.h"
+#include "cc/context_provider.h"
#include "cc/layer.h"
#include "cc/layer_tree_debug_state.h"
#include "cc/layer_tree_host.h"
@@ -16,6 +18,7 @@
#include "content/renderer/gpu/compositor_thread.h"
#include "content/renderer/render_thread_impl.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebLayerTreeViewClient.h"
+#include "third_party/WebKit/Source/Platform/chromium/public/WebSharedGraphicsContext3D.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebSize.h"
#include "webkit/compositor_bindings/web_layer_impl.h"
#include "webkit/compositor_bindings/web_to_ccinput_handler_adapter.h"
@@ -439,4 +442,76 @@ void RenderWidgetCompositor::scheduleComposite() {
client_->scheduleComposite();
}
+class RenderWidgetCompositor::MainThreadContextProvider
+ : public cc::ContextProvider {
+ public:
+ virtual bool InitializeOnMainThread() OVERRIDE { return true; }
+ virtual bool BindToCurrentThread() OVERRIDE { return true; }
+
+ virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE {
+ return WebKit::WebSharedGraphicsContext3D::mainThreadContext();
+ }
+ virtual class GrContext* GrContext() OVERRIDE {
+ return WebKit::WebSharedGraphicsContext3D::mainThreadGrContext();
+ }
+
+ virtual void VerifyContexts() OVERRIDE {}
+
+ protected:
+ virtual ~MainThreadContextProvider() {}
+};
+
+scoped_refptr<cc::ContextProvider>
+RenderWidgetCompositor::OffscreenContextProviderForMainThread() {
+ if (!contexts_main_thread_)
+ contexts_main_thread_ = new MainThreadContextProvider;
+ return contexts_main_thread_;
+}
+
+class RenderWidgetCompositor::CompositorThreadContextProvider
+ : public cc::ContextProvider {
+ public:
+ CompositorThreadContextProvider() : destroyed_(false) {}
+
+ virtual bool InitializeOnMainThread() OVERRIDE {
+ return WebKit::WebSharedGraphicsContext3D::createCompositorThreadContext();
+ }
+ virtual bool BindToCurrentThread() OVERRIDE {
+ return Context3d()->makeContextCurrent();
+ }
+
+ virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE {
+ return WebKit::WebSharedGraphicsContext3D::compositorThreadContext();
+ }
+ virtual class GrContext* GrContext() OVERRIDE {
+ return WebKit::WebSharedGraphicsContext3D::compositorThreadGrContext();
+ }
+
+ virtual void VerifyContexts() OVERRIDE {
+ if (Context3d() && !Context3d()->isContextLost())
+ return;
+ base::AutoLock lock(destroyed_lock_);
+ destroyed_ = true;
+ }
+ bool DestroyedOnMainThread() {
+ base::AutoLock lock(destroyed_lock_);
+ return destroyed_;
+ }
+
+ protected:
+ virtual ~CompositorThreadContextProvider() {}
+
+ private:
+ base::Lock destroyed_lock_;
+ bool destroyed_;
+};
+
+scoped_refptr<cc::ContextProvider>
+RenderWidgetCompositor::OffscreenContextProviderForCompositorThread() {
+ if (!contexts_compositor_thread_ ||
+ contexts_compositor_thread_->DestroyedOnMainThread())
+ contexts_compositor_thread_ = new CompositorThreadContextProvider;
+ return contexts_compositor_thread_;
+}
+
} // namespace content
diff --git a/content/renderer/gpu/render_widget_compositor.h b/content/renderer/gpu/render_widget_compositor.h
index 5cebe9f..ea1a0f5 100644
--- a/content/renderer/gpu/render_widget_compositor.h
+++ b/content/renderer/gpu/render_widget_compositor.h
@@ -83,6 +83,10 @@ class RenderWidgetCompositor : public WebKit::WebLayerTreeView,
virtual void didCommitAndDrawFrame() OVERRIDE;
virtual void didCompleteSwapBuffers() OVERRIDE;
virtual void scheduleComposite() OVERRIDE;
+ virtual scoped_refptr<cc::ContextProvider>
+ OffscreenContextProviderForMainThread() OVERRIDE;
+ virtual scoped_refptr<cc::ContextProvider>
+ OffscreenContextProviderForCompositorThread() OVERRIDE;
private:
RenderWidgetCompositor(RenderWidget* widget,
@@ -94,6 +98,11 @@ private:
RenderWidget* widget_;
WebKit::WebLayerTreeViewClient* client_;
scoped_ptr<cc::LayerTreeHost> layer_tree_host_;
+
+ class MainThreadContextProvider;
+ scoped_refptr<MainThreadContextProvider> contexts_main_thread_;
+ class CompositorThreadContextProvider;
+ scoped_refptr<CompositorThreadContextProvider> contexts_compositor_thread_;
};
} // namespace content
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index 372a039..44c5ae2 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -9,10 +9,12 @@
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/memory/singleton.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
+#include "cc/context_provider.h"
#include "cc/input_handler.h"
#include "cc/layer.h"
#include "cc/layer_tree_host.h"
@@ -28,6 +30,7 @@
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gl_switches.h"
+#include "webkit/gpu/grcontext_for_webgraphicscontext3d.h"
#include "webkit/gpu/webgraphicscontext3d_in_process_impl.h"
#if defined(OS_CHROMEOS)
@@ -70,6 +73,34 @@ class PendingSwap {
DISALLOW_COPY_AND_ASSIGN(PendingSwap);
};
+class NullContextProvider : public cc::ContextProvider {
+ public:
+ virtual bool InitializeOnMainThread() OVERRIDE { return false; }
+ virtual bool BindToCurrentThread() OVERRIDE { return false; }
+ virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE { return NULL; }
+ virtual class GrContext* GrContext() OVERRIDE { return NULL; }
+ virtual void VerifyContexts() OVERRIDE {}
+
+ protected:
+ virtual ~NullContextProvider() {}
+};
+
+struct MainThreadNullContextProvider {
+ scoped_refptr<NullContextProvider> provider;
+
+ static MainThreadNullContextProvider* GetInstance() {
+ return Singleton<MainThreadNullContextProvider>::get();
+ }
+};
+
+struct CompositorThreadNullContextProvider {
+ scoped_refptr<NullContextProvider> provider;
+
+ static CompositorThreadNullContextProvider* GetInstance() {
+ return Singleton<CompositorThreadNullContextProvider>::get();
+ }
+};
+
} // namespace
namespace ui {
@@ -122,6 +153,73 @@ WebKit::WebGraphicsContext3D* DefaultContextFactory::CreateOffscreenContext() {
return CreateContextCommon(NULL, true);
}
+class DefaultContextFactory::DefaultContextProvider
+ : public cc::ContextProvider {
+ public:
+ DefaultContextProvider(ContextFactory* factory)
+ : factory_(factory),
+ destroyed_(false) {}
+
+ virtual bool InitializeOnMainThread() OVERRIDE {
+ context3d_.reset(factory_->CreateOffscreenContext());
+ return !!context3d_;
+ }
+
+ virtual bool BindToCurrentThread() {
+ return context3d_->makeContextCurrent();
+ }
+
+ virtual WebKit::WebGraphicsContext3D* Context3d() { return context3d_.get(); }
+
+ virtual class GrContext* GrContext() {
+ if (!gr_context_) {
+ gr_context_.reset(
+ new webkit::gpu::GrContextForWebGraphicsContext3D(context3d_.get()));
+ }
+ return gr_context_->get();
+ }
+
+ virtual void VerifyContexts() OVERRIDE {
+ if (context3d_ && !context3d_->isContextLost())
+ return;
+ base::AutoLock lock(destroyed_lock_);
+ destroyed_ = true;
+ }
+
+ bool DestroyedOnMainThread() {
+ base::AutoLock lock(destroyed_lock_);
+ return destroyed_;
+ }
+
+ protected:
+ virtual ~DefaultContextProvider() {}
+
+ private:
+ ContextFactory* factory_;
+ base::Lock destroyed_lock_;
+ bool destroyed_;
+ scoped_ptr<WebKit::WebGraphicsContext3D> context3d_;
+ scoped_ptr<webkit::gpu::GrContextForWebGraphicsContext3D> gr_context_;
+};
+
+scoped_refptr<cc::ContextProvider>
+DefaultContextFactory::OffscreenContextProviderForMainThread() {
+ if (!offscreen_contexts_main_thread_ ||
+ !offscreen_contexts_main_thread_->DestroyedOnMainThread()) {
+ offscreen_contexts_main_thread_ = new DefaultContextProvider(this);
+ }
+ return offscreen_contexts_main_thread_;
+}
+
+scoped_refptr<cc::ContextProvider>
+DefaultContextFactory::OffscreenContextProviderForCompositorThread() {
+ if (!offscreen_contexts_compositor_thread_ ||
+ !offscreen_contexts_compositor_thread_->DestroyedOnMainThread()) {
+ offscreen_contexts_compositor_thread_ = new DefaultContextProvider(this);
+ }
+ return offscreen_contexts_compositor_thread_;
+}
+
void DefaultContextFactory::RemoveCompositor(Compositor* compositor) {
}
@@ -518,6 +616,31 @@ void Compositor::scheduleComposite() {
ScheduleDraw();
}
+scoped_refptr<cc::ContextProvider>
+Compositor::OffscreenContextProviderForMainThread() {
+ if (g_test_compositor_enabled) {
+ if (!MainThreadNullContextProvider::GetInstance()->provider) {
+ MainThreadNullContextProvider::GetInstance()->provider =
+ new NullContextProvider;
+ }
+ return MainThreadNullContextProvider::GetInstance()->provider;
+ }
+ return ContextFactory::GetInstance()->OffscreenContextProviderForMainThread();
+}
+
+scoped_refptr<cc::ContextProvider>
+Compositor::OffscreenContextProviderForCompositorThread() {
+ if (g_test_compositor_enabled) {
+ if (!CompositorThreadNullContextProvider::GetInstance()->provider) {
+ CompositorThreadNullContextProvider::GetInstance()->provider =
+ new NullContextProvider;
+ }
+ return CompositorThreadNullContextProvider::GetInstance()->provider;
+ }
+ return ContextFactory::GetInstance()->
+ OffscreenContextProviderForCompositorThread();
+}
+
scoped_refptr<CompositorLock> Compositor::GetCompositorLock() {
if (!compositor_lock_) {
compositor_lock_ = new CompositorLock(this);
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h
index 3b46189..1f263e2 100644
--- a/ui/compositor/compositor.h
+++ b/ui/compositor/compositor.h
@@ -22,6 +22,7 @@
class SkBitmap;
namespace cc {
+class ContextProvider;
class Layer;
class LayerTreeHost;
}
@@ -69,6 +70,11 @@ class COMPOSITOR_EXPORT ContextFactory {
// with all compositors.
virtual WebKit::WebGraphicsContext3D* CreateOffscreenContext() = 0;
+ virtual scoped_refptr<cc::ContextProvider>
+ OffscreenContextProviderForMainThread() = 0;
+ virtual scoped_refptr<cc::ContextProvider>
+ OffscreenContextProviderForCompositorThread() = 0;
+
// Destroys per-compositor data.
virtual void RemoveCompositor(Compositor* compositor) = 0;
};
@@ -83,6 +89,10 @@ class COMPOSITOR_EXPORT DefaultContextFactory : public ContextFactory {
virtual cc::OutputSurface* CreateOutputSurface(
Compositor* compositor) OVERRIDE;
virtual WebKit::WebGraphicsContext3D* CreateOffscreenContext() OVERRIDE;
+ virtual scoped_refptr<cc::ContextProvider>
+ OffscreenContextProviderForMainThread() OVERRIDE;
+ virtual scoped_refptr<cc::ContextProvider>
+ OffscreenContextProviderForCompositorThread() OVERRIDE;
virtual void RemoveCompositor(Compositor* compositor) OVERRIDE;
bool Initialize();
@@ -97,6 +107,9 @@ class COMPOSITOR_EXPORT DefaultContextFactory : public ContextFactory {
bool offscreen);
scoped_refptr<gfx::GLShareGroup> share_group_;
+ class DefaultContextProvider;
+ scoped_refptr<DefaultContextProvider> offscreen_contexts_main_thread_;
+ scoped_refptr<DefaultContextProvider> offscreen_contexts_compositor_thread_;
DISALLOW_COPY_AND_ASSIGN(DefaultContextFactory);
};
@@ -273,7 +286,10 @@ class COMPOSITOR_EXPORT Compositor
virtual void didCommitAndDrawFrame() OVERRIDE;
virtual void didCompleteSwapBuffers() OVERRIDE;
virtual void scheduleComposite() OVERRIDE;
-
+ virtual scoped_refptr<cc::ContextProvider>
+ OffscreenContextProviderForMainThread() OVERRIDE;
+ virtual scoped_refptr<cc::ContextProvider>
+ OffscreenContextProviderForCompositorThread() OVERRIDE;
int last_started_frame() { return last_started_frame_; }
int last_ended_frame() { return last_ended_frame_; }
diff --git a/webkit/compositor_bindings/web_layer_tree_view_impl_for_testing.cc b/webkit/compositor_bindings/web_layer_tree_view_impl_for_testing.cc
index bc19555..5dd58fee 100644
--- a/webkit/compositor_bindings/web_layer_tree_view_impl_for_testing.cc
+++ b/webkit/compositor_bindings/web_layer_tree_view_impl_for_testing.cc
@@ -6,6 +6,8 @@
#include "base/command_line.h"
#include "base/string_number_conversions.h"
+#include "base/synchronization/lock.h"
+#include "cc/context_provider.h"
#include "cc/fake_web_graphics_context_3d.h"
#include "cc/input_handler.h"
#include "cc/layer.h"
@@ -21,6 +23,7 @@
#include "third_party/WebKit/Source/Platform/chromium/public/WebLayerTreeView.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebLayerTreeViewClient.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebRenderingStats.h"
+#include "third_party/WebKit/Source/Platform/chromium/public/WebSharedGraphicsContext3D.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebSize.h"
#include "webkit/compositor_bindings/web_compositor_support_impl.h"
#include "webkit/compositor_bindings/web_compositor_support_software_output_device.h"
@@ -222,4 +225,77 @@ void WebLayerTreeViewImplForTesting::scheduleComposite() {
client_->scheduleComposite();
}
+class WebLayerTreeViewImplForTesting::MainThreadContextProvider
+ : public cc::ContextProvider {
+ public:
+ virtual bool InitializeOnMainThread() OVERRIDE { return true; }
+ virtual bool BindToCurrentThread() OVERRIDE { return true; }
+
+ virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE {
+ return WebSharedGraphicsContext3D::mainThreadContext();
+ }
+ virtual class GrContext* GrContext() OVERRIDE {
+ return WebSharedGraphicsContext3D::mainThreadGrContext();
+ }
+
+ virtual void VerifyContexts() OVERRIDE {}
+
+ protected:
+ virtual ~MainThreadContextProvider() {}
+};
+
+scoped_refptr<cc::ContextProvider>
+WebLayerTreeViewImplForTesting::OffscreenContextProviderForMainThread() {
+ if (!contexts_main_thread_)
+ contexts_main_thread_ = new MainThreadContextProvider;
+ return contexts_main_thread_;
+}
+
+class WebLayerTreeViewImplForTesting::CompositorThreadContextProvider
+ : public cc::ContextProvider {
+ public:
+ CompositorThreadContextProvider() : destroyed_(false) {}
+
+ virtual bool InitializeOnMainThread() OVERRIDE {
+ return WebSharedGraphicsContext3D::createCompositorThreadContext();
+ }
+ virtual bool BindToCurrentThread() OVERRIDE {
+ return Context3d()->makeContextCurrent();
+ }
+
+ virtual WebKit::WebGraphicsContext3D* Context3d() OVERRIDE {
+ return WebSharedGraphicsContext3D::compositorThreadContext();
+ }
+ virtual class GrContext* GrContext() OVERRIDE {
+ return WebSharedGraphicsContext3D::compositorThreadGrContext();
+ }
+
+ virtual void VerifyContexts() OVERRIDE {
+ if (Context3d() && !Context3d()->isContextLost())
+ return;
+ base::AutoLock lock(destroyed_lock_);
+ destroyed_ = true;
+ }
+
+ bool DestroyedOnMainThread() {
+ base::AutoLock lock(destroyed_lock_);
+ return destroyed_;
+ }
+
+ protected:
+ virtual ~CompositorThreadContextProvider() {}
+
+ private:
+ base::Lock destroyed_lock_;
+ bool destroyed_;
+};
+
+scoped_refptr<cc::ContextProvider>
+WebLayerTreeViewImplForTesting::OffscreenContextProviderForCompositorThread() {
+ if (!contexts_compositor_thread_ ||
+ contexts_compositor_thread_->DestroyedOnMainThread())
+ contexts_compositor_thread_ = new CompositorThreadContextProvider;
+ return contexts_compositor_thread_;
+}
+
} // namespace WebKit
diff --git a/webkit/compositor_bindings/web_layer_tree_view_impl_for_testing.h b/webkit/compositor_bindings/web_layer_tree_view_impl_for_testing.h
index f84d3cc..135dcbc 100644
--- a/webkit/compositor_bindings/web_layer_tree_view_impl_for_testing.h
+++ b/webkit/compositor_bindings/web_layer_tree_view_impl_for_testing.h
@@ -76,11 +76,20 @@ class WebLayerTreeViewImplForTesting : public WebKit::WebLayerTreeView,
virtual void didCommitAndDrawFrame() OVERRIDE;
virtual void didCompleteSwapBuffers() OVERRIDE;
virtual void scheduleComposite() OVERRIDE;
+ virtual scoped_refptr<cc::ContextProvider>
+ OffscreenContextProviderForMainThread() OVERRIDE;
+ virtual scoped_refptr<cc::ContextProvider>
+ OffscreenContextProviderForCompositorThread() OVERRIDE;
private:
RenderingType type_;
WebKit::WebLayerTreeViewClient* client_;
scoped_ptr<cc::LayerTreeHost> layer_tree_host_;
+
+ class MainThreadContextProvider;
+ scoped_refptr<MainThreadContextProvider> contexts_main_thread_;
+ class CompositorThreadContextProvider;
+ scoped_refptr<CompositorThreadContextProvider> contexts_compositor_thread_;
};
} // namespace Web_kit
diff --git a/webkit/gpu/grcontext_for_webgraphicscontext3d.cc b/webkit/gpu/grcontext_for_webgraphicscontext3d.cc
new file mode 100644
index 0000000..a1d3abd
--- /dev/null
+++ b/webkit/gpu/grcontext_for_webgraphicscontext3d.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "webkit/gpu/grcontext_for_webgraphicscontext3d.h"
+
+#include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3D.h"
+#include "third_party/skia/include/gpu/GrContext.h"
+#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
+
+namespace webkit {
+namespace gpu {
+
+static void BindWebGraphicsContext3DGLContextCallback(
+ const GrGLInterface* interface) {
+ reinterpret_cast<WebKit::WebGraphicsContext3D*>(
+ interface->fCallbackData)->makeContextCurrent();
+}
+
+GrContextForWebGraphicsContext3D::GrContextForWebGraphicsContext3D(
+ WebKit::WebGraphicsContext3D* context3d) {
+ if (!context3d)
+ return;
+
+ skia::RefPtr<GrGLInterface> interface = skia::AdoptRef(
+ context3d->createGrGLInterface());
+ if (!interface)
+ return;
+
+ interface->fCallback = BindWebGraphicsContext3DGLContextCallback;
+ interface->fCallbackData =
+ reinterpret_cast<GrGLInterfaceCallbackData>(context3d);
+
+ gr_context_ = skia::AdoptRef(GrContext::Create(
+ kOpenGL_GrBackend,
+ reinterpret_cast<GrBackendContext>(interface.get())));
+ if (!gr_context_)
+ return;
+
+ bool nonzero_allocation = true;
+ SetMemoryLimit(nonzero_allocation);
+}
+
+GrContextForWebGraphicsContext3D::~GrContextForWebGraphicsContext3D() {
+ if (gr_context_)
+ gr_context_->contextDestroyed();
+}
+
+void GrContextForWebGraphicsContext3D::SetMemoryLimit(bool nonzero_allocation) {
+ if (!gr_context_)
+ return;
+
+ if (nonzero_allocation) {
+ // The limit of the number of textures we hold in the GrContext's
+ // bitmap->texture cache.
+ static const int kMaxGaneshTextureCacheCount = 2048;
+ // The limit of the bytes allocated toward textures in the GrContext's
+ // bitmap->texture cache.
+ static const size_t kMaxGaneshTextureCacheBytes = 96 * 1024 * 1024;
+
+ gr_context_->setTextureCacheLimits(
+ kMaxGaneshTextureCacheCount, kMaxGaneshTextureCacheBytes);
+ } else {
+ gr_context_->freeGpuResources();
+ gr_context_->setTextureCacheLimits(0, 0);
+ }
+}
+
+} // namespace gpu
+} // namespace webkit
diff --git a/webkit/gpu/grcontext_for_webgraphicscontext3d.h b/webkit/gpu/grcontext_for_webgraphicscontext3d.h
new file mode 100644
index 0000000..76e63b1
--- /dev/null
+++ b/webkit/gpu/grcontext_for_webgraphicscontext3d.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WEBKIT_GPU_GRCONTEXT_FOR_WEBGRAPHICSCONTEXT3D_H_
+#define WEBKIT_GPU_GRCONTEXT_FOR_WEBGRAPHICSCONTEXT3D_H_
+
+#include "skia/ext/refptr.h"
+#include "webkit/gpu/webkit_gpu_export.h"
+
+class GrContext;
+namespace WebKit { class WebGraphicsContext3D; }
+
+namespace webkit {
+namespace gpu {
+
+// This class binds an offscreen GrContext to an offscreen context3d. The
+// context3d is used by the GrContext so must be valid as long as this class
+// is alive.
+class WEBKIT_GPU_EXPORT GrContextForWebGraphicsContext3D {
+ public:
+ explicit GrContextForWebGraphicsContext3D(
+ WebKit::WebGraphicsContext3D* context3d);
+ virtual ~GrContextForWebGraphicsContext3D();
+
+ GrContext* get() { return gr_context_.get(); }
+
+ void SetMemoryLimit(bool nonzero_allocation);
+
+ private:
+ skia::RefPtr<class GrContext> gr_context_;
+};
+
+} // namespace gpu
+} // namespace webkit
+
+#endif // WEBKIT_GPU_GRCONTEXT_FOR_WEBGRAPHICSCONTEXT3D_H_
diff --git a/webkit/gpu/webkit_gpu.gypi b/webkit/gpu/webkit_gpu.gypi
index 33dd4f2..65fe0c1 100644
--- a/webkit/gpu/webkit_gpu.gypi
+++ b/webkit/gpu/webkit_gpu.gypi
@@ -35,6 +35,8 @@
# This list contains all .h and .cc in gpu except for test code.
'gl_bindings_skia_cmd_buffer.cc',
'gl_bindings_skia_cmd_buffer.h',
+ 'grcontext_for_webgraphicscontext3d.cc',
+ 'grcontext_for_webgraphicscontext3d.h',
'webgraphicscontext3d_in_process_command_buffer_impl.cc',
'webgraphicscontext3d_in_process_command_buffer_impl.h',
'webgraphicscontext3d_in_process_impl.cc',