diff options
author | danakj@chromium.org <danakj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-22 20:32:05 +0000 |
---|---|---|
committer | danakj@chromium.org <danakj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-22 20:32:05 +0000 |
commit | 0a4517266a77d10a276d6c674efafc79e4c7f7a5 (patch) | |
tree | 88b095919aa268128698e980d9b780b09f839aad | |
parent | 3395887c69c58e75b084ef919dc88fd037bb9bc0 (diff) | |
download | chromium_src-0a4517266a77d10a276d6c674efafc79e4c7f7a5.zip chromium_src-0a4517266a77d10a276d6c674efafc79e4c7f7a5.tar.gz chromium_src-0a4517266a77d10a276d6c674efafc79e4c7f7a5.tar.bz2 |
cc: Route offscreen context creation for compositor to the browser.
Currently the compositor asks WebKit for the SharedGraphicsContext. For the
browser compositor, we instead route requests for an offscreen context to
ui/compositor, where we are able to create the context.
This patch only addresses offscreen contexts for the browser compositor. The
renderer compositor still gets its contexts from WebKit, but now via the
LayerTreeHostClient interface instead of directly going to the
WebSharedGraphicsContext3D.
Tested by the lost context unit tests. They now test that on context loss, the
shared context is also recreated, and that if it fails to be recreated that we
retry context creation.
BUG=169373,175383
Review URL: https://chromiumcodereview.appspot.com/12212007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@184165 0039d316-1c4b-4281-b951-d872f2087c98
45 files changed, 1376 insertions, 178 deletions
@@ -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', |