diff options
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', |