diff options
author | boliu@chromium.org <boliu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-13 03:50:20 +0000 |
---|---|---|
committer | boliu@chromium.org <boliu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-13 03:50:20 +0000 |
commit | 50af3c2667e37abedccfb137c08f7875c3989013 (patch) | |
tree | 83c7380ee2d8bbd1c49f85fac69ca42844c55f48 /cc | |
parent | b1960cd7669a83698e84212acfaac10d949b8cee (diff) | |
download | chromium_src-50af3c2667e37abedccfb137c08f7875c3989013.zip chromium_src-50af3c2667e37abedccfb137c08f7875c3989013.tar.gz chromium_src-50af3c2667e37abedccfb137c08f7875c3989013.tar.bz2 |
OutputSurfaceClient::ReleaseGL
For Android WebView, when the webview is detached from the view tree, it
is the last chance we have of releasing all GL resources. This is
essentially the reverse of DeferredInitialize, synchronously releasing
GL resources and reverting back to software mode and zero-budget.
BUG=256276
Review URL: https://chromiumcodereview.appspot.com/18279003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@211523 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc')
-rw-r--r-- | cc/cc_tests.gyp | 3 | ||||
-rw-r--r-- | cc/output/output_surface.cc | 18 | ||||
-rw-r--r-- | cc/output/output_surface.h | 2 | ||||
-rw-r--r-- | cc/output/output_surface_client.h | 1 | ||||
-rw-r--r-- | cc/output/output_surface_unittest.cc | 70 | ||||
-rw-r--r-- | cc/output/software_renderer.cc | 2 | ||||
-rw-r--r-- | cc/resources/resource_provider.cc | 73 | ||||
-rw-r--r-- | cc/resources/resource_provider.h | 14 | ||||
-rw-r--r-- | cc/resources/resource_provider_unittest.cc | 154 | ||||
-rw-r--r-- | cc/test/fake_output_surface.cc | 1 | ||||
-rw-r--r-- | cc/test/fake_output_surface.h | 2 | ||||
-rw-r--r-- | cc/test/fake_output_surface_client.cc | 30 | ||||
-rw-r--r-- | cc/test/fake_output_surface_client.h | 69 | ||||
-rw-r--r-- | cc/test/pixel_test.cc | 1 | ||||
-rw-r--r-- | cc/trees/layer_tree_host_impl.cc | 65 | ||||
-rw-r--r-- | cc/trees/layer_tree_host_impl.h | 6 | ||||
-rw-r--r-- | cc/trees/layer_tree_host_impl_unittest.cc | 6 | ||||
-rw-r--r-- | cc/trees/layer_tree_host_unittest.cc | 56 |
18 files changed, 399 insertions, 174 deletions
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp index 48fef90..d4c4586 100644 --- a/cc/cc_tests.gyp +++ b/cc/cc_tests.gyp @@ -105,7 +105,6 @@ 'test/fake_delegated_renderer_layer_impl.cc', 'test/fake_delegated_renderer_layer_impl.h', 'test/fake_impl_proxy.h', - 'test/fake_output_surface.h', 'test/fake_layer_tree_host_client.cc', 'test/fake_layer_tree_host_client.h', 'test/fake_layer_tree_host_impl.cc', @@ -133,6 +132,8 @@ 'test/fake_tile_manager_client.cc', 'test/fake_output_surface.cc', 'test/fake_output_surface.h', + 'test/fake_output_surface_client.cc', + 'test/fake_output_surface_client.h', 'test/fake_video_frame_provider.cc', 'test/fake_video_frame_provider.h', 'test/geometry_test_utils.cc', diff --git a/cc/output/output_surface.cc b/cc/output/output_surface.cc index 1cd1a7a..4847ef8 100644 --- a/cc/output/output_surface.cc +++ b/cc/output/output_surface.cc @@ -324,14 +324,19 @@ bool OutputSurface::InitializeAndSetContext3D( success = true; } - if (!success) { - context3d_.reset(); - callbacks_.reset(); - } + if (!success) + ResetContext3D(); return success; } +void OutputSurface::ReleaseGL() { + DCHECK(client_); + DCHECK(context3d_); + client_->ReleaseGL(); + ResetContext3D(); +} + void OutputSurface::SetContext3D( scoped_ptr<WebKit::WebGraphicsContext3D> context3d) { DCHECK(!context3d_); @@ -355,6 +360,11 @@ void OutputSurface::SetContext3D( context3d_->setMemoryAllocationChangedCallbackCHROMIUM(callbacks_.get()); } +void OutputSurface::ResetContext3D() { + context3d_.reset(); + callbacks_.reset(); +} + void OutputSurface::EnsureBackbuffer() { DCHECK(context3d_); if (has_gl_discard_backbuffer_) diff --git a/cc/output/output_surface.h b/cc/output/output_surface.h index df449bc..4489c10 100644 --- a/cc/output/output_surface.h +++ b/cc/output/output_surface.h @@ -133,6 +133,7 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient { bool InitializeAndSetContext3D( scoped_ptr<WebKit::WebGraphicsContext3D> context3d, scoped_refptr<ContextProvider> offscreen_context_provider); + void ReleaseGL(); void PostSwapBuffersComplete(); @@ -179,6 +180,7 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient { friend class OutputSurfaceCallbacks; void SetContext3D(scoped_ptr<WebKit::WebGraphicsContext3D> context3d); + void ResetContext3D(); void SetMemoryPolicy(const ManagedMemoryPolicy& policy, bool discard_backbuffer_when_not_visible); diff --git a/cc/output/output_surface_client.h b/cc/output/output_surface_client.h index 72126cd..516f075 100644 --- a/cc/output/output_surface_client.h +++ b/cc/output/output_surface_client.h @@ -28,6 +28,7 @@ class CC_EXPORT OutputSurfaceClient { // committed. virtual bool DeferredInitialize( scoped_refptr<ContextProvider> offscreen_context_provider) = 0; + virtual void ReleaseGL() = 0; virtual void SetNeedsRedrawRect(gfx::Rect damage_rect) = 0; virtual void BeginFrame(const BeginFrameArgs& args) = 0; virtual void OnSwapBuffersComplete(const CompositorFrameAck* ack) = 0; diff --git a/cc/output/output_surface_unittest.cc b/cc/output/output_surface_unittest.cc index 9ac699a..b0b34ba 100644 --- a/cc/output/output_surface_unittest.cc +++ b/cc/output/output_surface_unittest.cc @@ -8,6 +8,8 @@ #include "cc/output/managed_memory_policy.h" #include "cc/output/output_surface_client.h" #include "cc/output/software_output_device.h" +#include "cc/test/fake_output_surface.h" +#include "cc/test/fake_output_surface_client.h" #include "cc/test/scheduler_test_common.h" #include "cc/test/test_web_graphics_context_3d.h" #include "gpu/GLES2/gl2extchromium.h" @@ -38,6 +40,8 @@ class TestOutputSurface : public OutputSurface { scoped_refptr<ContextProvider>()); } + using OutputSurface::ReleaseGL; + bool HasClientForTesting() { return HasClient(); } @@ -80,69 +84,6 @@ class TestOutputSurface : public OutputSurface { base::TimeDelta retroactive_begin_frame_period_; }; -class FakeOutputSurfaceClient : public OutputSurfaceClient { - public: - FakeOutputSurfaceClient() - : begin_frame_count_(0), - deferred_initialize_result_(true), - deferred_initialize_called_(false), - did_lose_output_surface_called_(false), - memory_policy_(0), - discard_backbuffer_when_not_visible_(false) {} - - virtual bool DeferredInitialize( - scoped_refptr<ContextProvider> offscreen_context_provider) OVERRIDE { - deferred_initialize_called_ = true; - return deferred_initialize_result_; - } - virtual void SetNeedsRedrawRect(gfx::Rect damage_rect) OVERRIDE {} - virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE { - begin_frame_count_++; - } - virtual void OnSwapBuffersComplete(const CompositorFrameAck* ack) OVERRIDE {} - virtual void DidLoseOutputSurface() OVERRIDE { - did_lose_output_surface_called_ = true; - } - virtual void SetExternalDrawConstraints(const gfx::Transform& transform, - gfx::Rect viewport) OVERRIDE {} - virtual void SetMemoryPolicy( - const ManagedMemoryPolicy& policy, - bool discard_backbuffer_when_not_visible) OVERRIDE { - memory_policy_ = policy; - discard_backbuffer_when_not_visible_ = discard_backbuffer_when_not_visible; - } - - int begin_frame_count() { - return begin_frame_count_; - } - - void set_deferred_initialize_result(bool result) { - deferred_initialize_result_ = result; - } - - bool deferred_initialize_called() { - return deferred_initialize_called_; - } - - bool did_lose_output_surface_called() { - return did_lose_output_surface_called_; - } - - const ManagedMemoryPolicy& memory_policy() const { return memory_policy_; } - - bool discard_backbuffer_when_not_visible() const { - return discard_backbuffer_when_not_visible_; - } - - private: - int begin_frame_count_; - bool deferred_initialize_result_; - bool deferred_initialize_called_; - bool did_lose_output_surface_called_; - ManagedMemoryPolicy memory_policy_; - bool discard_backbuffer_when_not_visible_; -}; - TEST(OutputSurfaceTest, ClientPointerIndicatesBindToClientSuccess) { scoped_ptr<TestWebGraphicsContext3D> context3d = TestWebGraphicsContext3D::Create(); @@ -218,6 +159,9 @@ TEST_F(InitializeNewContext3D, Success) { output_surface_.context3d()->loseContextCHROMIUM( GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB); EXPECT_TRUE(client_.did_lose_output_surface_called()); + + output_surface_.ReleaseGL(); + EXPECT_FALSE(output_surface_.context3d()); } TEST_F(InitializeNewContext3D, Context3dMakeCurrentFails) { diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc index 5c745c0..c164d52 100644 --- a/cc/output/software_renderer.cc +++ b/cc/output/software_renderer.cc @@ -198,6 +198,8 @@ bool SoftwareRenderer::IsSoftwareResource( return false; case ResourceProvider::Bitmap: return true; + case ResourceProvider::InvalidType: + break; } LOG(FATAL) << "Invalid resource type."; diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc index 7e1d4f8..054e980 100644 --- a/cc/resources/resource_provider.cc +++ b/cc/resources/resource_provider.cc @@ -155,9 +155,20 @@ scoped_ptr<ResourceProvider> ResourceProvider::Create( OutputSurface* output_surface, int highp_threshold_min) { scoped_ptr<ResourceProvider> resource_provider( - new ResourceProvider(output_surface)); - if (!resource_provider->Initialize(highp_threshold_min)) + new ResourceProvider(output_surface, highp_threshold_min)); + + bool success = false; + if (output_surface->context3d()) { + success = resource_provider->InitializeGL(); + } else { + resource_provider->InitializeSoftware(); + success = true; + } + + if (!success) return scoped_ptr<ResourceProvider>(); + + DCHECK_NE(InvalidType, resource_provider->default_resource_type()); return resource_provider.Pass(); } @@ -165,10 +176,7 @@ ResourceProvider::~ResourceProvider() { while (!resources_.empty()) DeleteResourceInternal(resources_.begin(), ForShutdown); - WebGraphicsContext3D* context3d = output_surface_->context3d(); - if (!context3d || !context3d->makeContextCurrent()) - return; - texture_uploader_.reset(); + CleanUpGLIfNeeded(); } WebGraphicsContext3D* ResourceProvider::GraphicsContext3D() { @@ -194,6 +202,8 @@ ResourceProvider::ResourceId ResourceProvider::CreateResource( case Bitmap: DCHECK(format == GL_RGBA); return CreateBitmap(size); + case InvalidType: + break; } LOG(FATAL) << "Invalid default resource type."; @@ -210,6 +220,8 @@ ResourceProvider::ResourceId ResourceProvider::CreateManagedResource( case Bitmap: DCHECK(format == GL_RGBA); return CreateBitmap(size); + case InvalidType: + break; } LOG(FATAL) << "Invalid default resource type."; @@ -641,28 +653,39 @@ ResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware() { resource_provider_->UnlockForWrite(resource_id_); } -ResourceProvider::ResourceProvider(OutputSurface* output_surface) +ResourceProvider::ResourceProvider(OutputSurface* output_surface, + int highp_threshold_min) : output_surface_(output_surface), lost_output_surface_(false), + highp_threshold_min_(highp_threshold_min), next_id_(1), next_child_(1), - default_resource_type_(GLTexture), + default_resource_type_(InvalidType), use_texture_storage_ext_(false), use_texture_usage_hint_(false), use_shallow_flush_(false), max_texture_size_(0), - best_texture_format_(0) { + best_texture_format_(0) {} + +void ResourceProvider::InitializeSoftware() { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK_NE(Bitmap, default_resource_type_); + + CleanUpGLIfNeeded(); + + default_resource_type_ = Bitmap; + max_texture_size_ = INT_MAX / 2; + best_texture_format_ = GL_RGBA; } -bool ResourceProvider::Initialize(int highp_threshold_min) { +bool ResourceProvider::InitializeGL() { DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(!texture_uploader_); + DCHECK_NE(GLTexture, default_resource_type_); + WebGraphicsContext3D* context3d = output_surface_->context3d(); - if (!context3d) { - default_resource_type_ = Bitmap; - max_texture_size_ = INT_MAX / 2; - best_texture_format_ = GL_RGBA; - return true; - } + DCHECK(context3d); + if (!context3d->makeContextCurrent()) return false; @@ -696,13 +719,19 @@ bool ResourceProvider::Initialize(int highp_threshold_min) { return true; } -bool ResourceProvider::Reinitialize(int highp_threshold_min) { - DCHECK(thread_checker_.CalledOnValidThread()); - - // Only supports reinitializing from software mode. - DCHECK(!texture_uploader_); +void ResourceProvider::CleanUpGLIfNeeded() { + WebGraphicsContext3D* context3d = output_surface_->context3d(); + if (default_resource_type_ != GLTexture) { + // We are not in GL mode, but double check before returning. + DCHECK(!context3d); + DCHECK(!texture_uploader_); + return; + } - return Initialize(highp_threshold_min); + DCHECK(context3d); + context3d->makeContextCurrent(); + texture_uploader_.reset(); + Finish(); } int ResourceProvider::CreateChild() { diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h index c91d252..8e33aaf 100644 --- a/cc/resources/resource_provider.h +++ b/cc/resources/resource_provider.h @@ -48,6 +48,7 @@ class CC_EXPORT ResourceProvider { TextureUsageFramebuffer, }; enum ResourceType { + InvalidType = 0, GLTexture = 1, Bitmap, }; @@ -57,7 +58,8 @@ class CC_EXPORT ResourceProvider { virtual ~ResourceProvider(); - bool Reinitialize(int highp_threshold_min); + void InitializeSoftware(); + bool InitializeGL(); void DidLoseOutputSurface() { lost_output_surface_ = true; } @@ -72,9 +74,6 @@ class CC_EXPORT ResourceProvider { // Producer interface. - void set_default_resource_type(ResourceType type) { - default_resource_type_ = type; - } ResourceType default_resource_type() const { return default_resource_type_; } ResourceType GetResourceType(ResourceId id); @@ -386,8 +385,10 @@ class CC_EXPORT ResourceProvider { resource->read_lock_fence->HasPassed(); } - explicit ResourceProvider(OutputSurface* output_surface); - bool Initialize(int highp_threshold_min); + explicit ResourceProvider(OutputSurface* output_surface, + int highp_threshold_min); + + void CleanUpGLIfNeeded(); const Resource* LockForRead(ResourceId id); void UnlockForRead(ResourceId id); @@ -409,6 +410,7 @@ class CC_EXPORT ResourceProvider { OutputSurface* output_surface_; bool lost_output_surface_; + int highp_threshold_min_; ResourceId next_id_; ResourceMap resources_; int next_child_; diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc index e21a68b..df14e22 100644 --- a/cc/resources/resource_provider_unittest.cc +++ b/cc/resources/resource_provider_unittest.cc @@ -13,6 +13,7 @@ #include "cc/base/scoped_ptr_deque.h" #include "cc/output/output_surface.h" #include "cc/test/fake_output_surface.h" +#include "cc/test/fake_output_surface_client.h" #include "cc/test/test_web_graphics_context_3d.h" #include "gpu/GLES2/gl2extchromium.h" #include "testing/gmock/include/gmock/gmock.h" @@ -333,40 +334,60 @@ class ResourceProviderContext : public TestWebGraphicsContext3D { PendingProduceTextureList pending_produce_textures_; }; +void GetResourcePixels(ResourceProvider* resource_provider, + ResourceProviderContext* context, + ResourceProvider::ResourceId id, + gfx::Size size, + WGC3Denum format, + uint8_t* pixels) { + switch (resource_provider->default_resource_type()) { + case ResourceProvider::GLTexture: { + ResourceProvider::ScopedReadLockGL lock_gl(resource_provider, id); + ASSERT_NE(0U, lock_gl.texture_id()); + context->bindTexture(GL_TEXTURE_2D, lock_gl.texture_id()); + context->GetPixels(size, format, pixels); + break; + } + case ResourceProvider::Bitmap: { + ResourceProvider::ScopedReadLockSoftware lock_software(resource_provider, + id); + memcpy(pixels, + lock_software.sk_bitmap()->getPixels(), + lock_software.sk_bitmap()->getSize()); + break; + } + case ResourceProvider::InvalidType: + NOTREACHED(); + break; + } +} + class ResourceProviderTest : public testing::TestWithParam<ResourceProvider::ResourceType> { public: ResourceProviderTest() - : shared_data_(ContextSharedData::Create()), - output_surface_(FakeOutputSurface::Create3d( - ResourceProviderContext::Create(shared_data_.get()) - .PassAs<WebKit::WebGraphicsContext3D>())), - resource_provider_(ResourceProvider::Create(output_surface_.get(), 0)) { - resource_provider_->set_default_resource_type(GetParam()); + : shared_data_(ContextSharedData::Create()) { + switch (GetParam()) { + case ResourceProvider::GLTexture: + output_surface_ = + FakeOutputSurface::Create3d(ResourceProviderContext::Create( + shared_data_.get()).PassAs<WebKit::WebGraphicsContext3D>()); + break; + case ResourceProvider::Bitmap: + output_surface_ = FakeOutputSurface::CreateSoftware( + make_scoped_ptr(new SoftwareOutputDevice)); + break; + case ResourceProvider::InvalidType: + NOTREACHED(); + break; + } + resource_provider_ = ResourceProvider::Create(output_surface_.get(), 0); } ResourceProviderContext* context() { return static_cast<ResourceProviderContext*>(output_surface_->context3d()); } - void GetResourcePixels(ResourceProvider::ResourceId id, - gfx::Size size, - WGC3Denum format, - uint8_t* pixels) { - if (GetParam() == ResourceProvider::GLTexture) { - ResourceProvider::ScopedReadLockGL lock_gl(resource_provider_.get(), id); - ASSERT_NE(0U, lock_gl.texture_id()); - context()->bindTexture(GL_TEXTURE_2D, lock_gl.texture_id()); - context()->GetPixels(size, format, pixels); - } else if (GetParam() == ResourceProvider::Bitmap) { - ResourceProvider::ScopedReadLockSoftware lock_software( - resource_provider_.get(), id); - memcpy(pixels, - lock_software.sk_bitmap()->getPixels(), - lock_software.sk_bitmap()->getSize()); - } - } - void SetResourceFilter(ResourceProvider* resource_provider, ResourceProvider::ResourceId id, WGC3Denum filter) { @@ -391,32 +412,40 @@ class ResourceProviderTest scoped_ptr<ResourceProvider> resource_provider_; }; -TEST_P(ResourceProviderTest, Basic) { +void CheckCreateResource(ResourceProvider::ResourceType expected_default_type, + ResourceProvider* resource_provider, + ResourceProviderContext* context) { + DCHECK_EQ(expected_default_type, resource_provider->default_resource_type()); + gfx::Size size(1, 1); WGC3Denum format = GL_RGBA; size_t pixel_size = TextureSize(size, format); ASSERT_EQ(4U, pixel_size); - ResourceProvider::ResourceId id = resource_provider_->CreateResource( + ResourceProvider::ResourceId id = resource_provider->CreateResource( size, format, ResourceProvider::TextureUsageAny); - EXPECT_EQ(1, static_cast<int>(resource_provider_->num_resources())); - if (GetParam() == ResourceProvider::GLTexture) - EXPECT_EQ(0, context()->texture_count()); + EXPECT_EQ(1, static_cast<int>(resource_provider->num_resources())); + if (expected_default_type == ResourceProvider::GLTexture) + EXPECT_EQ(0, context->texture_count()); uint8_t data[4] = { 1, 2, 3, 4 }; gfx::Rect rect(size); - resource_provider_->SetPixels(id, data, rect, rect, gfx::Vector2d()); - if (GetParam() == ResourceProvider::GLTexture) - EXPECT_EQ(1, context()->texture_count()); + resource_provider->SetPixels(id, data, rect, rect, gfx::Vector2d()); + if (expected_default_type == ResourceProvider::GLTexture) + EXPECT_EQ(1, context->texture_count()); uint8_t result[4] = { 0 }; - GetResourcePixels(id, size, format, result); + GetResourcePixels(resource_provider, context, id, size, format, result); EXPECT_EQ(0, memcmp(data, result, pixel_size)); - resource_provider_->DeleteResource(id); - EXPECT_EQ(0, static_cast<int>(resource_provider_->num_resources())); - if (GetParam() == ResourceProvider::GLTexture) - EXPECT_EQ(0, context()->texture_count()); + resource_provider->DeleteResource(id); + EXPECT_EQ(0, static_cast<int>(resource_provider->num_resources())); + if (expected_default_type == ResourceProvider::GLTexture) + EXPECT_EQ(0, context->texture_count()); +} + +TEST_P(ResourceProviderTest, Basic) { + CheckCreateResource(GetParam(), resource_provider_.get(), context()); } TEST_P(ResourceProviderTest, Upload) { @@ -444,7 +473,8 @@ TEST_P(ResourceProviderTest, Upload) { id, image, image_rect, source_rect, dest_offset); uint8_t expected[16] = { 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - GetResourcePixels(id, size, format, result); + GetResourcePixels( + resource_provider_.get(), context(), id, size, format, result); EXPECT_EQ(0, memcmp(expected, result, pixel_size)); } { @@ -454,7 +484,8 @@ TEST_P(ResourceProviderTest, Upload) { id, image, image_rect, source_rect, dest_offset); uint8_t expected[16] = { 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3 }; - GetResourcePixels(id, size, format, result); + GetResourcePixels( + resource_provider_.get(), context(), id, size, format, result); EXPECT_EQ(0, memcmp(expected, result, pixel_size)); } { @@ -464,7 +495,8 @@ TEST_P(ResourceProviderTest, Upload) { id, image, image_rect, source_rect, dest_offset); uint8_t expected[16] = { 0, 1, 2, 3, 0, 0, 0, 0, 4, 5, 6, 7, 0, 1, 2, 3 }; - GetResourcePixels(id, size, format, result); + GetResourcePixels( + resource_provider_.get(), context(), id, size, format, result); EXPECT_EQ(0, memcmp(expected, result, pixel_size)); } { @@ -475,7 +507,8 @@ TEST_P(ResourceProviderTest, Upload) { id, image, offset_image_rect, source_rect, dest_offset); uint8_t expected[16] = { 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3 }; - GetResourcePixels(id, size, format, result); + GetResourcePixels( + resource_provider_.get(), context(), id, size, format, result); EXPECT_EQ(0, memcmp(expected, result, pixel_size)); } @@ -537,10 +570,12 @@ TEST_P(ResourceProviderTest, TransferResources) { EXPECT_FALSE(resource_provider_->InUseByConsumer(id2)); uint8_t result[4] = { 0 }; - GetResourcePixels(mapped_id1, size, format, result); + GetResourcePixels( + resource_provider_.get(), context(), mapped_id1, size, format, result); EXPECT_EQ(0, memcmp(data1, result, pixel_size)); - GetResourcePixels(mapped_id2, size, format, result); + GetResourcePixels( + resource_provider_.get(), context(), mapped_id2, size, format, result); EXPECT_EQ(0, memcmp(data2, result, pixel_size)); { // Check that transfering again the same resource from the child to the @@ -1657,6 +1692,39 @@ TEST_P(ResourceProviderTest, Image_Bitmap) { resource_provider->DeleteResource(id); } +void InitializeGLAndCheck(ResourceProvider* resource_provider, + FakeOutputSurface* output_surface) { + scoped_ptr<ContextSharedData> shared_data = ContextSharedData::Create(); + scoped_ptr<ResourceProviderContext> context = + ResourceProviderContext::Create(shared_data.release()); + output_surface->SetAndInitializeContext3D( + context.PassAs<WebKit::WebGraphicsContext3D>()); + EXPECT_TRUE(resource_provider->InitializeGL()); + CheckCreateResource( + ResourceProvider::GLTexture, + resource_provider, + static_cast<ResourceProviderContext*>(output_surface->context3d())); +} + +TEST(ResourceProviderTest, BasicInitializeGLSoftware) { + FakeOutputSurfaceClient client; + scoped_ptr<FakeOutputSurface> output_surface( + FakeOutputSurface::CreateDeferredGL( + scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice))); + EXPECT_TRUE(output_surface->BindToClient(&client)); + scoped_ptr<ResourceProvider> resource_provider( + ResourceProvider::Create(output_surface.get(), 0)); + + CheckCreateResource(ResourceProvider::Bitmap, resource_provider.get(), NULL); + + InitializeGLAndCheck(resource_provider.get(), output_surface.get()); + + resource_provider->InitializeSoftware(); + CheckCreateResource(ResourceProvider::Bitmap, resource_provider.get(), NULL); + + InitializeGLAndCheck(resource_provider.get(), output_surface.get()); +} + INSTANTIATE_TEST_CASE_P( ResourceProviderTests, ResourceProviderTest, diff --git a/cc/test/fake_output_surface.cc b/cc/test/fake_output_surface.cc index eee4529..195c603 100644 --- a/cc/test/fake_output_surface.cc +++ b/cc/test/fake_output_surface.cc @@ -93,6 +93,7 @@ bool FakeOutputSurface::ForcedDrawToSoftwareDevice() const { bool FakeOutputSurface::SetAndInitializeContext3D( scoped_ptr<WebKit::WebGraphicsContext3D> context3d) { + context3d_.reset(); return InitializeAndSetContext3D(context3d.Pass(), scoped_refptr<ContextProvider>()); } diff --git a/cc/test/fake_output_surface.h b/cc/test/fake_output_surface.h index 95814b8..25ee201 100644 --- a/cc/test/fake_output_surface.h +++ b/cc/test/fake_output_surface.h @@ -83,6 +83,8 @@ class FakeOutputSurface : public OutputSurface { bool SetAndInitializeContext3D( scoped_ptr<WebKit::WebGraphicsContext3D> context3d); + using OutputSurface::ReleaseGL; + protected: FakeOutputSurface( scoped_ptr<WebKit::WebGraphicsContext3D> context3d, diff --git a/cc/test/fake_output_surface_client.cc b/cc/test/fake_output_surface_client.cc new file mode 100644 index 0000000..7b371ca --- /dev/null +++ b/cc/test/fake_output_surface_client.cc @@ -0,0 +1,30 @@ +// 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_output_surface_client.h" + +namespace cc { + +bool FakeOutputSurfaceClient::DeferredInitialize( + scoped_refptr<ContextProvider> offscreen_context_provider) { + deferred_initialize_called_ = true; + return deferred_initialize_result_; +} + +void FakeOutputSurfaceClient::BeginFrame(const BeginFrameArgs& args) { + begin_frame_count_++; +} + +void FakeOutputSurfaceClient::DidLoseOutputSurface() { + did_lose_output_surface_called_ = true; +} + +void FakeOutputSurfaceClient::SetMemoryPolicy( + const ManagedMemoryPolicy& policy, + bool discard_backbuffer_when_not_visible) { + memory_policy_ = policy; + discard_backbuffer_when_not_visible_ = discard_backbuffer_when_not_visible; +} + +} // namespace cc diff --git a/cc/test/fake_output_surface_client.h b/cc/test/fake_output_surface_client.h new file mode 100644 index 0000000..b948958 --- /dev/null +++ b/cc/test/fake_output_surface_client.h @@ -0,0 +1,69 @@ +// 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_OUTPUT_SURFACE_CLIENT_H_ +#define CC_TEST_FAKE_OUTPUT_SURFACE_CLIENT_H_ + +#include "cc/output/managed_memory_policy.h" +#include "cc/output/output_surface_client.h" + +namespace cc { + +class FakeOutputSurfaceClient : public OutputSurfaceClient { + public: + FakeOutputSurfaceClient() + : begin_frame_count_(0), + deferred_initialize_result_(true), + deferred_initialize_called_(false), + did_lose_output_surface_called_(false), + memory_policy_(0), + discard_backbuffer_when_not_visible_(false) {} + + virtual bool DeferredInitialize( + scoped_refptr<ContextProvider> offscreen_context_provider) OVERRIDE; + virtual void ReleaseGL() OVERRIDE {} + virtual void SetNeedsRedrawRect(gfx::Rect damage_rect) OVERRIDE {} + virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE; + virtual void OnSwapBuffersComplete(const CompositorFrameAck* ack) OVERRIDE {} + virtual void DidLoseOutputSurface() OVERRIDE; + virtual void SetExternalDrawConstraints(const gfx::Transform& transform, + gfx::Rect viewport) OVERRIDE {} + virtual void SetMemoryPolicy( + const ManagedMemoryPolicy& policy, + bool discard_backbuffer_when_not_visible) OVERRIDE; + + int begin_frame_count() { + return begin_frame_count_; + } + + void set_deferred_initialize_result(bool result) { + deferred_initialize_result_ = result; + } + + bool deferred_initialize_called() { + return deferred_initialize_called_; + } + + bool did_lose_output_surface_called() { + return did_lose_output_surface_called_; + } + + const ManagedMemoryPolicy& memory_policy() const { return memory_policy_; } + + bool discard_backbuffer_when_not_visible() const { + return discard_backbuffer_when_not_visible_; + } + + private: + int begin_frame_count_; + bool deferred_initialize_result_; + bool deferred_initialize_called_; + bool did_lose_output_surface_called_; + ManagedMemoryPolicy memory_policy_; + bool discard_backbuffer_when_not_visible_; +}; + +} // namespace cc + +#endif // CC_TEST_FAKE_OUTPUT_SURFACE_CLIENT_H_ diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc index ed1ad5a..ae4e102 100644 --- a/cc/test/pixel_test.cc +++ b/cc/test/pixel_test.cc @@ -56,6 +56,7 @@ class PixelTest::PixelTestRendererClient scoped_refptr<ContextProvider> offscreen_context_provider) OVERRIDE { return false; } + virtual void ReleaseGL() OVERRIDE {} virtual void SetNeedsRedrawRect(gfx::Rect damage_rect) OVERRIDE {} virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE {} virtual void OnSwapBuffersComplete(const CompositorFrameAck* ack) OVERRIDE {} diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 5c3bdc7..f2dc1be 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc @@ -1480,12 +1480,13 @@ void LayerTreeHostImpl::ReleaseTreeResources() { void LayerTreeHostImpl::CreateAndSetRenderer( OutputSurface* output_surface, - ResourceProvider* resource_provider) { + ResourceProvider* resource_provider, + bool skip_gl_renderer) { DCHECK(!renderer_); if (output_surface->capabilities().delegated_rendering) { renderer_ = DelegatingRenderer::Create(this, output_surface, resource_provider); - } else if (output_surface->context3d()) { + } else if (output_surface->context3d() && !skip_gl_renderer) { renderer_ = GLRenderer::Create(this, output_surface, resource_provider, @@ -1502,6 +1503,20 @@ void LayerTreeHostImpl::CreateAndSetRenderer( } } +void LayerTreeHostImpl::CreateAndSetTileManager( + ResourceProvider* resource_provider, + bool using_map_image) { + DCHECK(settings_.impl_side_painting); + DCHECK(resource_provider); + tile_manager_ = TileManager::Create(this, + resource_provider, + settings_.num_raster_threads, + rendering_stats_instrumentation_, + using_map_image); + UpdateTileManagerMemoryPolicy(ActualManagedMemoryPolicy()); + need_check_for_completed_tile_uploads_before_draw_ = false; +} + void LayerTreeHostImpl::EnforceZeroBudget(bool zero_budget) { if (zero_budget_ == zero_budget) return; @@ -1544,19 +1559,16 @@ bool LayerTreeHostImpl::InitializeRenderer( if (output_surface->capabilities().deferred_gl_initialization) EnforceZeroBudget(true); - CreateAndSetRenderer(output_surface.get(), resource_provider.get()); + bool skip_gl_renderer = false; + CreateAndSetRenderer( + output_surface.get(), resource_provider.get(), skip_gl_renderer); if (!renderer_) return false; if (settings_.impl_side_painting) { - bool using_map_image = GetRendererCapabilities().using_map_image; - tile_manager_ = TileManager::Create(this, - resource_provider.get(), - settings_.num_raster_threads, - rendering_stats_instrumentation_, - using_map_image); - UpdateTileManagerMemoryPolicy(ActualManagedMemoryPolicy()); + CreateAndSetTileManager(resource_provider.get(), + GetRendererCapabilities().using_map_image); } // Setup BeginFrameEmulation if it's not supported natively @@ -1601,8 +1613,10 @@ bool LayerTreeHostImpl::DeferredInitialize( ReleaseTreeResources(); renderer_.reset(); - resource_provider_->Reinitialize(settings_.highp_threshold_min); - CreateAndSetRenderer(output_surface_.get(), resource_provider_.get()); + resource_provider_->InitializeGL(); + bool skip_gl_renderer = false; + CreateAndSetRenderer( + output_surface_.get(), resource_provider_.get(), skip_gl_renderer); bool success = !!renderer_.get(); client_->DidTryInitializeRendererOnImplThread(success, @@ -1614,6 +1628,33 @@ bool LayerTreeHostImpl::DeferredInitialize( return success; } +void LayerTreeHostImpl::ReleaseGL() { + DCHECK(output_surface_->capabilities().deferred_gl_initialization); + DCHECK(settings_.impl_side_painting); + DCHECK(settings_.solid_color_scrollbars); + DCHECK(output_surface_->context3d()); + + ReleaseTreeResources(); + renderer_.reset(); + tile_manager_.reset(); + resource_provider_->InitializeSoftware(); + + bool skip_gl_renderer = true; + CreateAndSetRenderer( + output_surface_.get(), resource_provider_.get(), skip_gl_renderer); + DCHECK(renderer_); + + EnforceZeroBudget(true); + CreateAndSetTileManager(resource_provider_.get(), + GetRendererCapabilities().using_map_image); + DCHECK(tile_manager_); + + bool success = true; + client_->DidTryInitializeRendererOnImplThread( + success, scoped_refptr<ContextProvider>()); + client_->SetNeedsCommitOnImplThread(); +} + void LayerTreeHostImpl::SetViewportSize(gfx::Size device_viewport_size) { if (device_viewport_size == device_viewport_size_) return; diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h index 8c41ece..69bb40a 100644 --- a/cc/trees/layer_tree_host_impl.h +++ b/cc/trees/layer_tree_host_impl.h @@ -199,6 +199,7 @@ class CC_EXPORT LayerTreeHostImpl // OutputSurfaceClient implementation. virtual bool DeferredInitialize( scoped_refptr<ContextProvider> offscreen_context_provider) OVERRIDE; + virtual void ReleaseGL() OVERRIDE; virtual void SetNeedsRedrawRect(gfx::Rect rect) OVERRIDE; virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE; virtual void SetExternalDrawConstraints(const gfx::Transform& transform, @@ -399,7 +400,10 @@ class CC_EXPORT LayerTreeHostImpl private: void CreateAndSetRenderer(OutputSurface* output_surface, - ResourceProvider* resource_provider); + ResourceProvider* resource_provider, + bool skip_gl_renderer); + void CreateAndSetTileManager(ResourceProvider* resource_provider, + bool using_map_image); void ReleaseTreeResources(); void EnforceZeroBudget(bool zero_budget); diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 536d433..85c9836 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc @@ -6027,6 +6027,12 @@ TEST_F(LayerTreeHostImplTest, DeferredInitializeSmoke) { // Defer intialized GL draw. DrawFrame(); + + // Revert back to software. + did_try_initialize_renderer_ = false; + output_surface_ptr->ReleaseGL(); + EXPECT_TRUE(did_try_initialize_renderer_); + DrawFrame(); } class ContextThatDoesNotSupportMemoryManagmentExtensions diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index 2934cd7..c7310cb 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc @@ -3106,8 +3106,8 @@ class LayerTreeHostTestDeferredInitialize : public LayerTreeHostTest { } virtual void BeginTest() OVERRIDE { - initialized_gl_ = false; - num_draws_ = 0; + did_initialize_gl_ = false; + did_release_gl_ = false; PostSetNeedsCommitToMainThread(); } @@ -3125,44 +3125,56 @@ class LayerTreeHostTestDeferredInitialize : public LayerTreeHostTest { ASSERT_TRUE(host_impl->RootLayer()); FakePictureLayerImpl* layer_impl = static_cast<FakePictureLayerImpl*>(host_impl->RootLayer()); - if (!initialized_gl_) { + if (!did_initialize_gl_) { EXPECT_EQ(1u, layer_impl->append_quads_count()); - ImplThreadTaskRunner()->PostTask(FROM_HERE, base::Bind( - &LayerTreeHostTestDeferredInitialize::DeferredInitializeAndRedraw, - base::Unretained(this), - base::Unretained(host_impl))); - } else { - if (!num_draws_) { - EXPECT_EQ(2u, layer_impl->append_quads_count()); - EndTest(); - } - num_draws_++; + ImplThreadTaskRunner()->PostTask( + FROM_HERE, + base::Bind( + &LayerTreeHostTestDeferredInitialize::DeferredInitializeAndRedraw, + base::Unretained(this), + base::Unretained(host_impl))); + } else if (did_initialize_gl_ && !did_release_gl_) { + EXPECT_EQ(2u, layer_impl->append_quads_count()); + ImplThreadTaskRunner()->PostTask( + FROM_HERE, + base::Bind( + &LayerTreeHostTestDeferredInitialize::ReleaseGLAndRedraw, + base::Unretained(this), + base::Unretained(host_impl))); + } else if (did_initialize_gl_ && did_release_gl_) { + EXPECT_EQ(3u, layer_impl->append_quads_count()); + EndTest(); } } void DeferredInitializeAndRedraw(LayerTreeHostImpl* host_impl) { + EXPECT_FALSE(did_initialize_gl_); + // SetAndInitializeContext3D calls SetNeedsCommit. EXPECT_TRUE(static_cast<FakeOutputSurface*>(host_impl->output_surface()) ->SetAndInitializeContext3D( scoped_ptr<WebKit::WebGraphicsContext3D>( TestWebGraphicsContext3D::Create()))); - initialized_gl_ = true; - - // Force redraw again. - host_impl->SetNeedsRedrawRect(gfx::Rect(1, 1)); + did_initialize_gl_ = true; + } - // If we didn't swap this begin frame, we need to request another one. - host_impl->SetNeedsBeginFrame(true); + void ReleaseGLAndRedraw(LayerTreeHostImpl* host_impl) { + EXPECT_TRUE(did_initialize_gl_); + EXPECT_FALSE(did_release_gl_); + // ReleaseGL calls SetNeedsCommit. + static_cast<FakeOutputSurface*>(host_impl->output_surface())->ReleaseGL(); + did_release_gl_ = true; } virtual void AfterTest() OVERRIDE { - EXPECT_TRUE(initialized_gl_); + EXPECT_TRUE(did_initialize_gl_); + EXPECT_TRUE(did_release_gl_); } private: FakeContentLayerClient client_; scoped_refptr<FakePictureLayer> layer_; - bool initialized_gl_; - int num_draws_; + bool did_initialize_gl_; + bool did_release_gl_; }; MULTI_THREAD_TEST_F(LayerTreeHostTestDeferredInitialize); |