diff options
-rw-r--r-- | cc/layers/delegated_renderer_layer.cc | 40 | ||||
-rw-r--r-- | cc/layers/delegated_renderer_layer.h | 17 | ||||
-rw-r--r-- | cc/layers/delegated_renderer_layer_impl.cc | 68 | ||||
-rw-r--r-- | cc/layers/delegated_renderer_layer_impl.h | 14 | ||||
-rw-r--r-- | cc/resources/resource_provider.cc | 340 | ||||
-rw-r--r-- | cc/resources/resource_provider.h | 35 | ||||
-rw-r--r-- | cc/resources/resource_provider_unittest.cc | 317 | ||||
-rw-r--r-- | cc/resources/return_callback.h | 17 | ||||
-rw-r--r-- | cc/test/fake_delegated_renderer_layer_impl.cc | 15 | ||||
-rw-r--r-- | cc/test/fake_delegated_renderer_layer_impl.h | 4 | ||||
-rw-r--r-- | cc/test/layer_tree_test.h | 3 | ||||
-rw-r--r-- | cc/trees/layer_tree_host_unittest_delegated.cc | 225 | ||||
-rw-r--r-- | cc/trees/single_thread_proxy.cc | 22 |
13 files changed, 771 insertions, 346 deletions
diff --git a/cc/layers/delegated_renderer_layer.cc b/cc/layers/delegated_renderer_layer.cc index 5286874..cc49c75 100644 --- a/cc/layers/delegated_renderer_layer.cc +++ b/cc/layers/delegated_renderer_layer.cc @@ -8,6 +8,7 @@ #include "cc/layers/delegated_renderer_layer_impl.h" #include "cc/output/delegated_frame_data.h" #include "cc/quads/render_pass_draw_quad.h" +#include "cc/trees/blocking_task_runner.h" #include "cc/trees/layer_tree_host.h" namespace cc { @@ -22,7 +23,9 @@ DelegatedRendererLayer::DelegatedRendererLayer( DelegatedRendererLayerClient* client) : Layer(), client_(client), - needs_filter_context_(false) {} + needs_filter_context_(false), + main_thread_runner_(BlockingTaskRunner::current()), + weak_ptrs_(this) {} DelegatedRendererLayer::~DelegatedRendererLayer() {} @@ -64,19 +67,23 @@ void DelegatedRendererLayer::PushPropertiesTo(LayerImpl* impl) { delegated_impl->SetDisplaySize(display_size_); + delegated_impl->CreateChildIdIfNeeded( + base::Bind(&DelegatedRendererLayer::ReceiveUnusedResourcesOnImplThread, + main_thread_runner_, + weak_ptrs_.GetWeakPtr())); + if (frame_data_) delegated_impl->SetFrameData(frame_data_.Pass(), damage_in_frame_); frame_data_.reset(); damage_in_frame_ = gfx::RectF(); - delegated_impl->CollectUnusedResources( - &unused_resources_for_child_compositor_); - + // The ResourceProvider will have the new frame as soon as we push it to the + // pending tree. So unused resources will be returned as well. if (client_) client_->DidCommitFrameData(); - // TODO(danakj): TakeUnusedResourcesForChildCompositor requires a push - // properties to happen in order to collect unused resources returned + // TODO(danakj): The DidCommitFrameData() notification requires a push + // properties to happen in order to notify about unused resources returned // from the parent compositor. crbug.com/259090 needs_push_properties_ = true; } @@ -90,6 +97,8 @@ void DelegatedRendererLayer::SetDisplaySize(gfx::Size size) { void DelegatedRendererLayer::SetFrameData( scoped_ptr<DelegatedFrameData> new_frame_data) { + DCHECK(new_frame_data); + if (frame_data_) { // Copy the resources from the last provided frame into the unused resources // list, as the new frame will provide its own resources. @@ -139,4 +148,23 @@ void DelegatedRendererLayer::TakeUnusedResourcesForChildCompositor( array->swap(unused_resources_for_child_compositor_); } +void DelegatedRendererLayer::ReceiveUnusedResources( + const ReturnedResourceArray& unused) { + unused_resources_for_child_compositor_.insert( + unused_resources_for_child_compositor_.end(), + unused.begin(), + unused.end()); +} + +// static +void DelegatedRendererLayer::ReceiveUnusedResourcesOnImplThread( + scoped_refptr<BlockingTaskRunner> task_runner, + base::WeakPtr<DelegatedRendererLayer> self, + const ReturnedResourceArray& unused) { + task_runner->PostTask( + FROM_HERE, + base::Bind( + &DelegatedRendererLayer::ReceiveUnusedResources, self, unused)); +} + } // namespace cc diff --git a/cc/layers/delegated_renderer_layer.h b/cc/layers/delegated_renderer_layer.h index b3a078f..60e9c3c 100644 --- a/cc/layers/delegated_renderer_layer.h +++ b/cc/layers/delegated_renderer_layer.h @@ -5,12 +5,15 @@ #ifndef CC_LAYERS_DELEGATED_RENDERER_LAYER_H_ #define CC_LAYERS_DELEGATED_RENDERER_LAYER_H_ +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "base/synchronization/lock.h" #include "cc/base/cc_export.h" #include "cc/layers/layer.h" #include "cc/resources/returned_resource.h" namespace cc { - +class BlockingTaskRunner; class DelegatedFrameData; class DelegatedRendererLayerClient; @@ -42,17 +45,27 @@ class CC_EXPORT DelegatedRendererLayer : public Layer { virtual ~DelegatedRendererLayer(); private: + void ReceiveUnusedResources(const ReturnedResourceArray& unused); + static void ReceiveUnusedResourcesOnImplThread( + scoped_refptr<BlockingTaskRunner> task_runner, + base::WeakPtr<DelegatedRendererLayer> self, + const ReturnedResourceArray& unused); + scoped_ptr<DelegatedFrameData> frame_data_; gfx::RectF damage_in_frame_; gfx::Size frame_size_; gfx::Size display_size_; - ReturnedResourceArray unused_resources_for_child_compositor_; DelegatedRendererLayerClient* client_; bool needs_filter_context_; + ReturnedResourceArray unused_resources_for_child_compositor_; + scoped_refptr<BlockingTaskRunner> main_thread_runner_; + base::WeakPtrFactory<DelegatedRendererLayer> weak_ptrs_; + DISALLOW_COPY_AND_ASSIGN(DelegatedRendererLayer); }; } // namespace cc + #endif // CC_LAYERS_DELEGATED_RENDERER_LAYER_H_ diff --git a/cc/layers/delegated_renderer_layer_impl.cc b/cc/layers/delegated_renderer_layer_impl.cc index b0a1b3f..34a1cd8 100644 --- a/cc/layers/delegated_renderer_layer_impl.cc +++ b/cc/layers/delegated_renderer_layer_impl.cc @@ -47,7 +47,7 @@ bool DelegatedRendererLayerImpl::HasContributingDelegatedRenderPasses() const { static ResourceProvider::ResourceId ResourceRemapHelper( bool* invalid_frame, const ResourceProvider::ResourceIdMap& child_to_parent_map, - ResourceProvider::ResourceIdSet *remapped_resources, + ResourceProvider::ResourceIdArray* resources_in_frame, ResourceProvider::ResourceId id) { ResourceProvider::ResourceIdMap::const_iterator it = @@ -59,7 +59,7 @@ static ResourceProvider::ResourceId ResourceRemapHelper( DCHECK_EQ(it->first, id); ResourceProvider::ResourceId remapped_id = it->second; - remapped_resources->insert(remapped_id); + resources_in_frame->push_back(id); return remapped_id; } @@ -85,23 +85,31 @@ void DelegatedRendererLayerImpl::PushPropertiesTo(LayerImpl* layer) { have_render_passes_to_push_ = false; } - // This is just a copy for testing since we keep the data on the pending layer - // for returning resources to the child for now. + // This is just a copy for testing, since resources are added to the + // ResourceProvider in the pending tree. delegated_layer->resources_ = resources_; } +void DelegatedRendererLayerImpl::CreateChildIdIfNeeded( + const ReturnCallback& return_callback) { + if (child_id_) + return; + + ResourceProvider* resource_provider = layer_tree_impl()->resource_provider(); + child_id_ = resource_provider->CreateChild(return_callback); + own_child_id_ = true; +} + void DelegatedRendererLayerImpl::SetFrameData( scoped_ptr<DelegatedFrameData> frame_data, gfx::RectF damage_in_frame) { DCHECK(frame_data); + DCHECK(child_id_) << "CreateChildIdIfNeeded must be called first."; // A frame with an empty root render pass is invalid. DCHECK(frame_data->render_pass_list.empty() || !frame_data->render_pass_list.back()->output_rect.IsEmpty()); - CreateChildIdIfNeeded(); - DCHECK(child_id_); - ResourceProvider* resource_provider = layer_tree_impl()->resource_provider(); const ResourceProvider::ResourceIdMap& resource_map = resource_provider->GetChildToParentMap(child_id_); @@ -109,12 +117,12 @@ void DelegatedRendererLayerImpl::SetFrameData( resource_provider->ReceiveFromChild(child_id_, frame_data->resource_list); bool invalid_frame = false; - ResourceProvider::ResourceIdSet used_resources; + ResourceProvider::ResourceIdArray resources_in_frame; DrawQuad::ResourceIteratorCallback remap_resources_to_parent_callback = base::Bind(&ResourceRemapHelper, &invalid_frame, resource_map, - &used_resources); + &resources_in_frame); for (size_t i = 0; i < frame_data->render_pass_list.size(); ++i) { RenderPass* pass = frame_data->render_pass_list[i]; for (size_t j = 0; j < pass->quad_list.size(); ++j) { @@ -123,8 +131,15 @@ void DelegatedRendererLayerImpl::SetFrameData( } } - if (invalid_frame) + if (invalid_frame) { + // Declare we are still using the last frame's resources. + resource_provider->DeclareUsedResourcesFromChild(child_id_, resources_); return; + } + + // Declare we are using the new frame's resources. + resources_.swap(resources_in_frame); + resource_provider->DeclareUsedResourcesFromChild(child_id_, resources_); // Display size is already set so we can compute what the damage rect // will be in layer space. @@ -140,33 +155,9 @@ void DelegatedRendererLayerImpl::SetFrameData( // Save the remapped quads on the layer. This steals the quads and render // passes from the frame_data. SetRenderPasses(&frame_data->render_pass_list); - resources_.swap(used_resources); have_render_passes_to_push_ = true; } -void DelegatedRendererLayerImpl::CollectUnusedResources( - ReturnedResourceArray* resources_for_ack) { - CreateChildIdIfNeeded(); - DCHECK(child_id_); - - ResourceProvider* resource_provider = layer_tree_impl()->resource_provider(); - const ResourceProvider::ResourceIdMap& resource_map = - resource_provider->GetChildToParentMap(child_id_); - - ResourceProvider::ResourceIdArray unused_resources; - for (ResourceProvider::ResourceIdMap::const_iterator it = - resource_map.begin(); - it != resource_map.end(); - ++it) { - bool resource_is_in_current_frame = resources_.count(it->second) > 0; - bool resource_is_in_use = resource_provider->InUseByConsumer(it->second); - if (!resource_is_in_current_frame && !resource_is_in_use) - unused_resources.push_back(it->second); - } - resource_provider->PrepareSendReturnsToChild( - child_id_, unused_resources, resources_for_ack); -} - void DelegatedRendererLayerImpl::SetDisplaySize(gfx::Size size) { if (display_size_ == size) return; @@ -477,15 +468,6 @@ const char* DelegatedRendererLayerImpl::LayerTypeAsString() const { return "cc::DelegatedRendererLayerImpl"; } -void DelegatedRendererLayerImpl::CreateChildIdIfNeeded() { - if (child_id_) - return; - - ResourceProvider* resource_provider = layer_tree_impl()->resource_provider(); - child_id_ = resource_provider->CreateChild(); - own_child_id_ = true; -} - void DelegatedRendererLayerImpl::ClearChildId() { if (!child_id_) return; diff --git a/cc/layers/delegated_renderer_layer_impl.h b/cc/layers/delegated_renderer_layer_impl.h index 5f55050..7d774f1 100644 --- a/cc/layers/delegated_renderer_layer_impl.h +++ b/cc/layers/delegated_renderer_layer_impl.h @@ -40,11 +40,14 @@ class CC_EXPORT DelegatedRendererLayerImpl : public LayerImpl { void AppendContributingRenderPasses(RenderPassSink* render_pass_sink); + // Creates an ID with the resource provider for the child renderer + // that will be sending quads to the layer. Registers the callback to + // inform when resources are no longer in use. + void CreateChildIdIfNeeded(const ReturnCallback& return_callback); + void SetFrameData(scoped_ptr<DelegatedFrameData> frame_data, gfx::RectF damage_in_frame); - void CollectUnusedResources(ReturnedResourceArray* resources_for_ack); - void SetDisplaySize(gfx::Size size); protected: @@ -54,14 +57,11 @@ class CC_EXPORT DelegatedRendererLayerImpl : public LayerImpl { const ScopedPtrVector<RenderPass>& RenderPassesInDrawOrderForTesting() const { return render_passes_in_draw_order_; } - const ResourceProvider::ResourceIdSet& ResourcesForTesting() const { + const ResourceProvider::ResourceIdArray& ResourcesForTesting() const { return resources_; } private: - // Creates an ID with the resource provider for the child renderer - // that will be sending quads to the layer. - void CreateChildIdIfNeeded(); void ClearChildId(); void AppendRainbowDebugBorder(QuadSink* quad_sink, @@ -92,7 +92,7 @@ class CC_EXPORT DelegatedRendererLayerImpl : public LayerImpl { bool have_render_passes_to_push_; ScopedPtrVector<RenderPass> render_passes_in_draw_order_; base::hash_map<RenderPass::Id, int> render_passes_index_by_id_; - ResourceProvider::ResourceIdSet resources_; + ResourceProvider::ResourceIdArray resources_; gfx::Size display_size_; int child_id_; diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc index e1cbba5..6ee8be0 100644 --- a/cc/resources/resource_provider.cc +++ b/cc/resources/resource_provider.cc @@ -86,7 +86,8 @@ class ScopedSetActiveTexture { } // namespace ResourceProvider::Resource::Resource() - : gl_id(0), + : child_id(0), + gl_id(0), gl_pixel_buffer_id(0), gl_upload_query_id(0), pixels(NULL), @@ -115,15 +116,15 @@ ResourceProvider::Resource::Resource() ResourceProvider::Resource::~Resource() {} -ResourceProvider::Resource::Resource( - unsigned texture_id, - gfx::Size size, - GLenum filter, - GLenum texture_pool, - GLint wrap_mode, - TextureUsageHint hint, - ResourceFormat format) - : gl_id(texture_id), +ResourceProvider::Resource::Resource(unsigned texture_id, + gfx::Size size, + GLenum filter, + GLenum texture_pool, + GLint wrap_mode, + TextureUsageHint hint, + ResourceFormat format) + : child_id(0), + gl_id(texture_id), gl_pixel_buffer_id(0), gl_upload_query_id(0), pixels(NULL), @@ -152,12 +153,12 @@ ResourceProvider::Resource::Resource( DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT); } -ResourceProvider::Resource::Resource( - uint8_t* pixels, - gfx::Size size, - GLenum filter, - GLint wrap_mode) - : gl_id(0), +ResourceProvider::Resource::Resource(uint8_t* pixels, + gfx::Size size, + GLenum filter, + GLint wrap_mode) + : child_id(0), + gl_id(0), gl_pixel_buffer_id(0), gl_upload_query_id(0), pixels(pixels), @@ -215,6 +216,8 @@ scoped_ptr<ResourceProvider> ResourceProvider::Create( } ResourceProvider::~ResourceProvider() { + while (!children_.empty()) + DestroyChild(children_.begin()->first); while (!resources_.empty()) DeleteResourceInternal(resources_.begin(), ForShutdown); @@ -810,9 +813,12 @@ void ResourceProvider::CleanUpGLIfNeeded() { Finish(); } -int ResourceProvider::CreateChild() { +int ResourceProvider::CreateChild(const ReturnCallback& return_callback) { DCHECK(thread_checker_.CalledOnValidThread()); + Child child_info; + child_info.return_callback = return_callback; + int child = next_child_++; children_[child] = child_info; return child; @@ -820,20 +826,26 @@ int ResourceProvider::CreateChild() { void ResourceProvider::DestroyChild(int child_id) { DCHECK(thread_checker_.CalledOnValidThread()); + ChildMap::iterator it = children_.find(child_id); DCHECK(it != children_.end()); Child& child = it->second; + + ResourceIdArray resources_for_child; + for (ResourceIdMap::iterator child_it = child.child_to_parent_map.begin(); child_it != child.child_to_parent_map.end(); ++child_it) { ResourceId id = child_it->second; - // We're abandoning this resource, it will not get recycled. - // crbug.com/224062 - ResourceMap::iterator resource_it = resources_.find(id); - CHECK(resource_it != resources_.end()); - resource_it->second.imported_count = 0; - DeleteResource(id); + resources_for_child.push_back(id); } + + // If the child is going away, don't consider any resources in use. + child.in_use_resources.clear(); + + DeleteAndReturnUnusedResourcesToChild( + &child, ForShutdown, resources_for_child); + children_.erase(it); } @@ -875,62 +887,6 @@ void ResourceProvider::PrepareSendToParent(const ResourceIdArray& resources, } } -void ResourceProvider::PrepareSendReturnsToChild( - int child, - const ResourceIdArray& resources, - ReturnedResourceArray* list) { - DCHECK(thread_checker_.CalledOnValidThread()); - WebGraphicsContext3D* context3d = Context3d(); - if (!context3d || !context3d->makeContextCurrent()) { - // TODO(skaslev): Implement this path for software compositing. - return; - } - Child& child_info = children_.find(child)->second; - bool need_sync_point = false; - for (ResourceIdArray::const_iterator it = resources.begin(); - it != resources.end(); ++it) { - Resource* resource = GetResource(*it); - DCHECK(!resource->locked_for_write); - DCHECK(!resource->lock_for_read_count); - DCHECK(child_info.parent_to_child_map.find(*it) != - child_info.parent_to_child_map.end()); - - if (resource->filter != resource->original_filter) { - DCHECK(resource->target); - DCHECK(resource->gl_id); - - GLC(context3d, context3d->bindTexture(resource->target, resource->gl_id)); - GLC(context3d, context3d->texParameteri(resource->target, - GL_TEXTURE_MIN_FILTER, - resource->original_filter)); - GLC(context3d, context3d->texParameteri(resource->target, - GL_TEXTURE_MAG_FILTER, - resource->original_filter)); - } - - ReturnedResource returned; - returned.id = child_info.parent_to_child_map[*it]; - returned.sync_point = resource->mailbox.sync_point(); - if (!returned.sync_point) - need_sync_point = true; - returned.count = resource->imported_count; - list->push_back(returned); - - child_info.parent_to_child_map.erase(*it); - child_info.child_to_parent_map.erase(returned.id); - resources_[*it].imported_count = 0; - DeleteResource(*it); - } - if (need_sync_point) { - unsigned int sync_point = context3d->insertSyncPoint(); - for (ReturnedResourceArray::iterator it = list->begin(); - it != list->end(); ++it) { - if (!it->sync_point) - it->sync_point = sync_point; - } - } -} - void ResourceProvider::ReceiveFromChild( int child, const TransferableResourceArray& resources) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -962,26 +918,65 @@ void ResourceProvider::ReceiveFromChild( GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, texture_id)); GLC(context3d, context3d->consumeTextureCHROMIUM(GL_TEXTURE_2D, it->mailbox.name)); - - ResourceId id = next_id_++; - Resource resource( - texture_id, - it->size, - it->filter, - 0, - GL_CLAMP_TO_EDGE, - TextureUsageAny, - it->format); + ResourceId local_id = next_id_++; + Resource resource(texture_id, + it->size, + it->filter, + 0, + GL_CLAMP_TO_EDGE, + TextureUsageAny, + it->format); resource.mailbox.SetName(it->mailbox); + resource.child_id = child; // Don't allocate a texture for a child. resource.allocated = true; resource.imported_count = 1; - resources_[id] = resource; - child_info.parent_to_child_map[id] = it->id; - child_info.child_to_parent_map[it->id] = id; + resources_[local_id] = resource; + child_info.parent_to_child_map[local_id] = it->id; + child_info.child_to_parent_map[it->id] = local_id; } } +void ResourceProvider::DeclareUsedResourcesFromChild( + int child, + const ResourceIdArray& resources_from_child) { + DCHECK(thread_checker_.CalledOnValidThread()); + + Child& child_info = children_.find(child)->second; + child_info.in_use_resources.clear(); + + for (size_t i = 0; i < resources_from_child.size(); ++i) { + ResourceIdMap::iterator it = + child_info.child_to_parent_map.find(resources_from_child[i]); + DCHECK(it != child_info.child_to_parent_map.end()); + + ResourceId local_id = it->second; + child_info.in_use_resources.insert(local_id); + } + + ResourceIdArray unused; + for (ResourceIdMap::iterator it = child_info.child_to_parent_map.begin(); + it != child_info.child_to_parent_map.end(); + ++it) { + ResourceId local_id = it->second; + bool resource_is_in_use = child_info.in_use_resources.count(local_id) > 0; + if (!resource_is_in_use) + unused.push_back(local_id); + } + DeleteAndReturnUnusedResourcesToChild(&child_info, Normal, unused); +} + +// static +bool ResourceProvider::CompareResourceMapIteratorsByChildId( + const std::pair<ReturnedResource, ResourceMap::iterator>& a, + const std::pair<ReturnedResource, ResourceMap::iterator>& b) { + const ResourceMap::iterator& a_it = a.second; + const ResourceMap::iterator& b_it = b.second; + const Resource& a_resource = a_it->second; + const Resource& b_resource = b_it->second; + return a_resource.child_id < b_resource.child_id; +} + void ResourceProvider::ReceiveReturnsFromParent( const ReturnedResourceArray& resources) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -990,25 +985,83 @@ void ResourceProvider::ReceiveReturnsFromParent( // TODO(skaslev): Implement this path for software compositing. return; } + + int child_id = 0; + Child* child_info = NULL; + ResourceIdArray resources_for_child; + + std::vector<std::pair<ReturnedResource, ResourceMap::iterator> > + sorted_resources; + for (ReturnedResourceArray::const_iterator it = resources.begin(); it != resources.end(); ++it) { - ResourceMap::iterator map_iterator = resources_.find(it->id); - DCHECK(map_iterator != resources_.end()); + ResourceId local_id = it->id; + ResourceMap::iterator map_iterator = resources_.find(local_id); + + // Resource was already lost (e.g. it belonged to a child that was + // destroyed). + if (map_iterator == resources_.end()) + continue; + + sorted_resources.push_back( + std::pair<ReturnedResource, ResourceMap::iterator>(*it, map_iterator)); + } + + std::sort(sorted_resources.begin(), + sorted_resources.end(), + CompareResourceMapIteratorsByChildId); + + for (size_t i = 0; i < sorted_resources.size(); ++i) { + ReturnedResource& returned = sorted_resources[i].first; + ResourceMap::iterator& map_iterator = sorted_resources[i].second; + ResourceId local_id = map_iterator->first; Resource* resource = &map_iterator->second; - CHECK_GE(resource->exported_count, it->count); - resource->exported_count -= it->count; + + CHECK_GE(resource->exported_count, returned.count); + resource->exported_count -= returned.count; if (resource->exported_count) continue; + if (resource->gl_id) { - if (it->sync_point) - GLC(context3d, context3d->waitSyncPoint(it->sync_point)); + if (returned.sync_point) + GLC(context3d, context3d->waitSyncPoint(returned.sync_point)); } else { resource->mailbox = - TextureMailbox(resource->mailbox.name(), it->sync_point); + TextureMailbox(resource->mailbox.name(), returned.sync_point); } - if (resource->marked_for_deletion) + + if (!resource->marked_for_deletion) + continue; + + if (!resource->child_id) { + // The resource belongs to this ResourceProvider, so it can be destroyed. DeleteResourceInternal(map_iterator, Normal); + continue; + } + + // Delete the resource and return it to the child it came from one. + if (resource->child_id != child_id) { + ChildMap::iterator child_it = children_.find(resource->child_id); + DCHECK(child_it != children_.end()); + + if (child_id) { + DCHECK_NE(resources_for_child.size(), 0u); + DeleteAndReturnUnusedResourcesToChild( + child_info, Normal, resources_for_child); + resources_for_child.clear(); + } + + child_info = &child_it->second; + child_id = resource->child_id; + } + resources_for_child.push_back(local_id); + } + + if (child_id) { + DCHECK_NE(resources_for_child.size(), 0u); + DeleteAndReturnUnusedResourcesToChild( + child_info, Normal, resources_for_child); } } @@ -1046,6 +1099,93 @@ void ResourceProvider::TransferResource(WebGraphicsContext3D* context, } } +void ResourceProvider::DeleteAndReturnUnusedResourcesToChild( + Child* child_info, + DeleteStyle style, + const ResourceIdArray& unused) { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(child_info); + + if (unused.empty()) + return; + + WebGraphicsContext3D* context3d = Context3d(); + if (!context3d || !context3d->makeContextCurrent()) { + // TODO(skaslev): Implement this path for software compositing. + return; + } + + ReturnedResourceArray to_return; + + bool need_sync_point = false; + for (size_t i = 0; i < unused.size(); ++i) { + ResourceId local_id = unused[i]; + + ResourceMap::iterator it = resources_.find(local_id); + CHECK(it != resources_.end()); + Resource& resource = it->second; + + DCHECK(!resource.locked_for_write); + DCHECK(!resource.lock_for_read_count); + DCHECK_EQ(0u, child_info->in_use_resources.count(local_id)); + DCHECK(child_info->parent_to_child_map.count(local_id)); + + ResourceId child_id = child_info->parent_to_child_map[local_id]; + DCHECK(child_info->child_to_parent_map.count(child_id)); + + // TODO(danakj): bool is_lost = false; + if (resource.exported_count > 0) { + if (style != ForShutdown) { + // Defer this until we receive the resource back from the parent. + resource.marked_for_deletion = true; + continue; + } + + // We still have an exported_count, so we'll have to lose it. + // TODO(danakj): is_lost = true; + } + + if (resource.filter != resource.original_filter) { + DCHECK(resource.target); + DCHECK(resource.gl_id); + + GLC(context3d, context3d->bindTexture(resource.target, resource.gl_id)); + GLC(context3d, + context3d->texParameteri(resource.target, + GL_TEXTURE_MIN_FILTER, + resource.original_filter)); + GLC(context3d, + context3d->texParameteri(resource.target, + GL_TEXTURE_MAG_FILTER, + resource.original_filter)); + } + + ReturnedResource returned; + returned.id = child_id; + returned.sync_point = resource.mailbox.sync_point(); + if (!returned.sync_point) + need_sync_point = true; + returned.count = resource.imported_count; + // TODO(danakj): Save the |is_lost| bit. + to_return.push_back(returned); + + child_info->parent_to_child_map.erase(local_id); + child_info->child_to_parent_map.erase(child_id); + resource.imported_count = 0; + DeleteResourceInternal(it, style); + } + if (need_sync_point) { + unsigned int sync_point = context3d->insertSyncPoint(); + for (size_t i = 0; i < to_return.size(); ++i) { + if (!to_return[i].sync_point) + to_return[i].sync_point = sync_point; + } + } + + if (!to_return.empty()) + child_info->return_callback.Run(to_return); +} + void ResourceProvider::AcquirePixelBuffer(ResourceId id) { Resource* resource = GetResource(id); DCHECK(!resource->external); diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h index e73ea15..0a70b02 100644 --- a/cc/resources/resource_provider.h +++ b/cc/resources/resource_provider.h @@ -8,6 +8,7 @@ #include <deque> #include <set> #include <string> +#include <utility> #include <vector> #include "base/basictypes.h" @@ -20,6 +21,7 @@ #include "cc/output/output_surface.h" #include "cc/resources/release_callback.h" #include "cc/resources/resource_format.h" +#include "cc/resources/return_callback.h" #include "cc/resources/single_release_callback.h" #include "cc/resources/texture_mailbox.h" #include "cc/resources/transferable_resource.h" @@ -144,7 +146,7 @@ class CC_EXPORT ResourceProvider { bool ShallowFlushIfSupported(); // Creates accounting for a child. Returns a child ID. - int CreateChild(); + int CreateChild(const ReturnCallback& return_callback); // Destroys accounting for the child, deleting all accounted resources. void DestroyChild(int child); @@ -159,23 +161,25 @@ class CC_EXPORT ResourceProvider { void PrepareSendToParent(const ResourceIdArray& resources, TransferableResourceArray* transferable_resources); - // Prepares resources to be transfered back to the child, moving them to - // mailboxes and serializing meta-data into TransferableResources. - // Resources are removed from the ResourceProvider. Note: the resource IDs - // passed are in the parent namespace and will be translated to the child - // namespace when returned. - void PrepareSendReturnsToChild(int child, - const ResourceIdArray& resources, - ReturnedResourceArray* returned_resources); - // Receives resources from a child, moving them from mailboxes. Resource IDs // passed are in the child namespace, and will be translated to the parent // namespace, added to the child->parent map. + // This adds the resources to the working set in the ResourceProvider without + // declaring which resources are in use. Use DeclareUsedResourcesFromChild + // after calling this method to do that. All calls to ReceiveFromChild should + // be followed by a DeclareUsedResourcesFromChild. // NOTE: if the sync_point is set on any TransferableResource, this will // wait on it. void ReceiveFromChild( int child, const TransferableResourceArray& transferable_resources); + // Once a set of resources have been received, they may or may not be used. + // This declares what set of resources are currently in use from the child, + // releasing any other resources back to the child. + void DeclareUsedResourcesFromChild( + int child, + const ResourceIdArray& resources_from_child); + // Receives resources from the parent, moving them from mailboxes. Resource // IDs passed are in the child namespace. // NOTE: if the sync_point is set on any TransferableResource, this will @@ -359,6 +363,7 @@ class CC_EXPORT ResourceProvider { GLenum filter, GLint wrap_mode); + int child_id; unsigned gl_id; // Pixel buffer used for set pixels without unnecessary copying. unsigned gl_pixel_buffer_id; @@ -392,12 +397,19 @@ class CC_EXPORT ResourceProvider { ResourceFormat format; }; typedef base::hash_map<ResourceId, Resource> ResourceMap; + + static bool CompareResourceMapIteratorsByChildId( + const std::pair<ReturnedResource, ResourceMap::iterator>& a, + const std::pair<ReturnedResource, ResourceMap::iterator>& b); + struct Child { Child(); ~Child(); ResourceIdMap child_to_parent_map; ResourceIdMap parent_to_child_map; + ReturnCallback return_callback; + ResourceIdSet in_use_resources; }; typedef base::hash_map<int, Child> ChildMap; @@ -428,6 +440,9 @@ class CC_EXPORT ResourceProvider { ForShutdown, }; void DeleteResourceInternal(ResourceMap::iterator it, DeleteStyle style); + void DeleteAndReturnUnusedResourcesToChild(Child* child_info, + DeleteStyle style, + const ResourceIdArray& unused); void LazyCreate(Resource* resource); void LazyAllocate(Resource* resource); diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc index 7df9412..e3e14c1 100644 --- a/cc/resources/resource_provider_unittest.cc +++ b/cc/resources/resource_provider_unittest.cc @@ -424,9 +424,18 @@ class ResourceProviderTest output_surface_.get(), 0, false); } + static void CollectResources(ReturnedResourceArray* array, + const ReturnedResourceArray& returned) { + array->insert(array->end(), returned.begin(), returned.end()); + } + + static ReturnCallback GetReturnCallback(ReturnedResourceArray* array) { + return base::Bind(&ResourceProviderTest::CollectResources, array); + } + static void SetResourceFilter(ResourceProvider* resource_provider, - ResourceProvider::ResourceId id, - WGC3Denum filter) { + ResourceProvider::ResourceId id, + WGC3Denum filter) { ResourceProvider::ScopedSamplerGL sampler( resource_provider, id, GL_TEXTURE_2D, filter); } @@ -578,7 +587,9 @@ TEST_P(ResourceProviderTest, TransferResources) { uint8_t data2[4] = { 5, 5, 5, 5 }; child_resource_provider->SetPixels(id2, data2, rect, rect, gfx::Vector2d()); - int child_id = resource_provider_->CreateChild(); + ReturnedResourceArray returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); { // Transfer some resources to the parent. ResourceProvider::ResourceIdArray resource_ids_to_transfer; @@ -593,6 +604,8 @@ TEST_P(ResourceProviderTest, TransferResources) { EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1)); EXPECT_TRUE(child_resource_provider->InUseByConsumer(id2)); resource_provider_->ReceiveFromChild(child_id, list); + resource_provider_->DeclareUsedResourcesFromChild(child_id, + resource_ids_to_transfer); } EXPECT_EQ(2u, resource_provider_->num_resources()); @@ -631,17 +644,18 @@ TEST_P(ResourceProviderTest, TransferResources) { EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1)); } { - // Transfer resources back from the parent to the child. - ResourceProvider::ResourceIdArray resource_ids_to_transfer; - resource_ids_to_transfer.push_back(mapped_id1); - resource_ids_to_transfer.push_back(mapped_id2); - ReturnedResourceArray list; - resource_provider_->PrepareSendReturnsToChild( - child_id, resource_ids_to_transfer, &list); - ASSERT_EQ(2u, list.size()); - EXPECT_NE(0u, list[0].sync_point); - EXPECT_NE(0u, list[1].sync_point); - child_resource_provider->ReceiveReturnsFromParent(list); + EXPECT_EQ(0u, returned_to_child.size()); + + // Transfer resources back from the parent to the child. Set no resources as + // being in use. + ResourceProvider::ResourceIdArray no_resources; + resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources); + + ASSERT_EQ(2u, returned_to_child.size()); + EXPECT_NE(0u, returned_to_child[0].sync_point); + EXPECT_NE(0u, returned_to_child[1].sync_point); + child_resource_provider->ReceiveReturnsFromParent(returned_to_child); + returned_to_child.clear(); } EXPECT_FALSE(child_resource_provider->InUseByConsumer(id1)); EXPECT_FALSE(child_resource_provider->InUseByConsumer(id2)); @@ -674,11 +688,231 @@ TEST_P(ResourceProviderTest, TransferResources) { EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1)); EXPECT_TRUE(child_resource_provider->InUseByConsumer(id2)); resource_provider_->ReceiveFromChild(child_id, list); + resource_provider_->DeclareUsedResourcesFromChild(child_id, + resource_ids_to_transfer); } + EXPECT_EQ(0u, returned_to_child.size()); + EXPECT_EQ(2u, resource_provider_->num_resources()); resource_provider_->DestroyChild(child_id); EXPECT_EQ(0u, resource_provider_->num_resources()); + + ASSERT_EQ(2u, returned_to_child.size()); + // TODO(danakj): Verify the resources are not marked as lost. + EXPECT_NE(0u, returned_to_child[0].sync_point); + EXPECT_NE(0u, returned_to_child[1].sync_point); +} + +TEST_P(ResourceProviderTest, DeleteExportedResources) { + // Resource transfer is only supported with GL textures for now. + if (GetParam() != ResourceProvider::GLTexture) + return; + + scoped_ptr<ResourceProviderContext> child_context_owned( + ResourceProviderContext::Create(shared_data_.get())); + + FakeOutputSurfaceClient child_output_surface_client; + scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d( + child_context_owned.PassAs<TestWebGraphicsContext3D>())); + CHECK(child_output_surface->BindToClient(&child_output_surface_client)); + + scoped_ptr<ResourceProvider> child_resource_provider( + ResourceProvider::Create(child_output_surface.get(), 0, false)); + + gfx::Size size(1, 1); + ResourceFormat format = RGBA_8888; + size_t pixel_size = TextureSize(size, format); + ASSERT_EQ(4U, pixel_size); + + ResourceProvider::ResourceId id1 = child_resource_provider->CreateResource( + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + uint8_t data1[4] = {1, 2, 3, 4}; + gfx::Rect rect(size); + child_resource_provider->SetPixels(id1, data1, rect, rect, gfx::Vector2d()); + + ResourceProvider::ResourceId id2 = child_resource_provider->CreateResource( + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + uint8_t data2[4] = {5, 5, 5, 5}; + child_resource_provider->SetPixels(id2, data2, rect, rect, gfx::Vector2d()); + + ReturnedResourceArray returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); + { + // Transfer some resources to the parent. + ResourceProvider::ResourceIdArray resource_ids_to_transfer; + resource_ids_to_transfer.push_back(id1); + resource_ids_to_transfer.push_back(id2); + TransferableResourceArray list; + child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, + &list); + ASSERT_EQ(2u, list.size()); + EXPECT_NE(0u, list[0].sync_point); + EXPECT_NE(0u, list[1].sync_point); + EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1)); + EXPECT_TRUE(child_resource_provider->InUseByConsumer(id2)); + resource_provider_->ReceiveFromChild(child_id, list); + resource_provider_->DeclareUsedResourcesFromChild(child_id, + resource_ids_to_transfer); + } + + EXPECT_EQ(2u, resource_provider_->num_resources()); + ResourceProvider::ResourceIdMap resource_map = + resource_provider_->GetChildToParentMap(child_id); + ResourceProvider::ResourceId mapped_id1 = resource_map[id1]; + ResourceProvider::ResourceId mapped_id2 = resource_map[id2]; + EXPECT_NE(0u, mapped_id1); + EXPECT_NE(0u, mapped_id2); + EXPECT_FALSE(resource_provider_->InUseByConsumer(id1)); + EXPECT_FALSE(resource_provider_->InUseByConsumer(id2)); + + { + // The parent transfers the resources to the grandparent. + ResourceProvider::ResourceIdArray resource_ids_to_transfer; + resource_ids_to_transfer.push_back(mapped_id1); + resource_ids_to_transfer.push_back(mapped_id2); + TransferableResourceArray list; + resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list); + + ASSERT_EQ(2u, list.size()); + EXPECT_NE(0u, list[0].sync_point); + EXPECT_NE(0u, list[1].sync_point); + EXPECT_TRUE(resource_provider_->InUseByConsumer(id1)); + EXPECT_TRUE(resource_provider_->InUseByConsumer(id2)); + + // Release the resource in the parent. Set no resources as being in use. The + // resources are exported so that can't be transferred back yet. + ResourceProvider::ResourceIdArray no_resources; + resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources); + + EXPECT_EQ(0u, returned_to_child.size()); + EXPECT_EQ(2u, resource_provider_->num_resources()); + + // Return the resources from the grandparent to the parent. They should be + // returned to the child then. + EXPECT_EQ(2u, list.size()); + EXPECT_EQ(mapped_id1, list[0].id); + EXPECT_EQ(mapped_id2, list[1].id); + ReturnedResourceArray returned; + TransferableResource::ReturnResources(list, &returned); + resource_provider_->ReceiveReturnsFromParent(returned); + + EXPECT_EQ(0u, resource_provider_->num_resources()); + ASSERT_EQ(2u, returned_to_child.size()); + // TODO(danakj): Verify the resources are not marked as lost. + EXPECT_NE(0u, returned_to_child[0].sync_point); + EXPECT_NE(0u, returned_to_child[1].sync_point); + } +} + +TEST_P(ResourceProviderTest, DestroyChildWithExportedResources) { + // Resource transfer is only supported with GL textures for now. + if (GetParam() != ResourceProvider::GLTexture) + return; + + scoped_ptr<ResourceProviderContext> child_context_owned( + ResourceProviderContext::Create(shared_data_.get())); + + FakeOutputSurfaceClient child_output_surface_client; + scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d( + child_context_owned.PassAs<TestWebGraphicsContext3D>())); + CHECK(child_output_surface->BindToClient(&child_output_surface_client)); + + scoped_ptr<ResourceProvider> child_resource_provider( + ResourceProvider::Create(child_output_surface.get(), 0, false)); + + gfx::Size size(1, 1); + ResourceFormat format = RGBA_8888; + size_t pixel_size = TextureSize(size, format); + ASSERT_EQ(4U, pixel_size); + + ResourceProvider::ResourceId id1 = child_resource_provider->CreateResource( + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + uint8_t data1[4] = {1, 2, 3, 4}; + gfx::Rect rect(size); + child_resource_provider->SetPixels(id1, data1, rect, rect, gfx::Vector2d()); + + ResourceProvider::ResourceId id2 = child_resource_provider->CreateResource( + size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format); + uint8_t data2[4] = {5, 5, 5, 5}; + child_resource_provider->SetPixels(id2, data2, rect, rect, gfx::Vector2d()); + + ReturnedResourceArray returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); + { + // Transfer some resources to the parent. + ResourceProvider::ResourceIdArray resource_ids_to_transfer; + resource_ids_to_transfer.push_back(id1); + resource_ids_to_transfer.push_back(id2); + TransferableResourceArray list; + child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, + &list); + ASSERT_EQ(2u, list.size()); + EXPECT_NE(0u, list[0].sync_point); + EXPECT_NE(0u, list[1].sync_point); + EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1)); + EXPECT_TRUE(child_resource_provider->InUseByConsumer(id2)); + resource_provider_->ReceiveFromChild(child_id, list); + resource_provider_->DeclareUsedResourcesFromChild(child_id, + resource_ids_to_transfer); + } + + EXPECT_EQ(2u, resource_provider_->num_resources()); + ResourceProvider::ResourceIdMap resource_map = + resource_provider_->GetChildToParentMap(child_id); + ResourceProvider::ResourceId mapped_id1 = resource_map[id1]; + ResourceProvider::ResourceId mapped_id2 = resource_map[id2]; + EXPECT_NE(0u, mapped_id1); + EXPECT_NE(0u, mapped_id2); + EXPECT_FALSE(resource_provider_->InUseByConsumer(id1)); + EXPECT_FALSE(resource_provider_->InUseByConsumer(id2)); + + { + // The parent transfers the resources to the grandparent. + ResourceProvider::ResourceIdArray resource_ids_to_transfer; + resource_ids_to_transfer.push_back(mapped_id1); + resource_ids_to_transfer.push_back(mapped_id2); + TransferableResourceArray list; + resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list); + + ASSERT_EQ(2u, list.size()); + EXPECT_NE(0u, list[0].sync_point); + EXPECT_NE(0u, list[1].sync_point); + EXPECT_TRUE(resource_provider_->InUseByConsumer(id1)); + EXPECT_TRUE(resource_provider_->InUseByConsumer(id2)); + + // Release the resource in the parent. Set no resources as being in use. The + // resources are exported so that can't be transferred back yet. + ResourceProvider::ResourceIdArray no_resources; + resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources); + + // Destroy the child, the resources should be returned immediately from the + // parent and marked as lost. + EXPECT_EQ(0u, returned_to_child.size()); + EXPECT_EQ(2u, resource_provider_->num_resources()); + + resource_provider_->DestroyChild(child_id); + + EXPECT_EQ(0u, resource_provider_->num_resources()); + ASSERT_EQ(2u, returned_to_child.size()); + // TODO(danakj): Verify the resources are marked as lost. + EXPECT_NE(0u, returned_to_child[0].sync_point); + EXPECT_NE(0u, returned_to_child[1].sync_point); + returned_to_child.clear(); + + // Return the resources from the grandparent to the parent. They should be + // dropped on the floor since they were already returned to the child. + EXPECT_EQ(2u, list.size()); + EXPECT_EQ(mapped_id1, list[0].id); + EXPECT_EQ(mapped_id2, list[1].id); + ReturnedResourceArray returned; + TransferableResource::ReturnResources(list, &returned); + resource_provider_->ReceiveReturnsFromParent(returned); + + EXPECT_EQ(0u, returned_to_child.size()); + } } TEST_P(ResourceProviderTest, DeleteTransferredResources) { @@ -709,7 +943,9 @@ TEST_P(ResourceProviderTest, DeleteTransferredResources) { gfx::Rect rect(size); child_resource_provider->SetPixels(id, data, rect, rect, gfx::Vector2d()); - int child_id = resource_provider_->CreateChild(); + ReturnedResourceArray returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); { // Transfer some resource to the parent. ResourceProvider::ResourceIdArray resource_ids_to_transfer; @@ -721,25 +957,24 @@ TEST_P(ResourceProviderTest, DeleteTransferredResources) { EXPECT_NE(0u, list[0].sync_point); EXPECT_TRUE(child_resource_provider->InUseByConsumer(id)); resource_provider_->ReceiveFromChild(child_id, list); + resource_provider_->DeclareUsedResourcesFromChild(child_id, + resource_ids_to_transfer); } // Delete textures in the child, while they are transfered. child_resource_provider->DeleteResource(id); EXPECT_EQ(1u, child_resource_provider->num_resources()); { - // Transfer resources back from the parent to the child. - ResourceProvider::ResourceIdMap resource_map = - resource_provider_->GetChildToParentMap(child_id); - ResourceProvider::ResourceId mapped_id = resource_map[id]; - EXPECT_NE(0u, mapped_id); - ResourceProvider::ResourceIdArray resource_ids_to_transfer; - resource_ids_to_transfer.push_back(mapped_id); - ReturnedResourceArray list; - resource_provider_->PrepareSendReturnsToChild( - child_id, resource_ids_to_transfer, &list); - ASSERT_EQ(1u, list.size()); - EXPECT_NE(0u, list[0].sync_point); - child_resource_provider->ReceiveReturnsFromParent(list); + EXPECT_EQ(0u, returned_to_child.size()); + + // Transfer resources back from the parent to the child. Set no resources as + // being in use. + ResourceProvider::ResourceIdArray no_resources; + resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources); + + ASSERT_EQ(1u, returned_to_child.size()); + EXPECT_NE(0u, returned_to_child[0].sync_point); + child_resource_provider->ReceiveReturnsFromParent(returned_to_child); } EXPECT_EQ(0u, child_resource_provider->num_resources()); } @@ -821,7 +1056,9 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest { SetResourceFilter(child_resource_provider.get(), id, child_filter); Mock::VerifyAndClearExpectations(child_context); - int child_id = parent_resource_provider->CreateChild(); + ReturnedResourceArray returned_to_child; + int child_id = parent_resource_provider->CreateChild( + GetReturnCallback(&returned_to_child)); { // Transfer some resource to the parent. ResourceProvider::ResourceIdArray resource_ids_to_transfer; @@ -844,6 +1081,10 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest { consumeTextureCHROMIUM(GL_TEXTURE_2D, _)); parent_resource_provider->ReceiveFromChild(child_id, list); Mock::VerifyAndClearExpectations(parent_context); + + parent_resource_provider->DeclareUsedResourcesFromChild( + child_id, resource_ids_to_transfer); + Mock::VerifyAndClearExpectations(parent_context); } ResourceProvider::ResourceIdMap resource_map = parent_resource_provider->GetChildToParentMap(child_id); @@ -872,19 +1113,19 @@ class ResourceProviderTestTextureFilters : public ResourceProviderTest { texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, child_filter)); { - // Transfer resources back from the parent to the child. - ResourceProvider::ResourceIdArray resource_ids_to_transfer; - resource_ids_to_transfer.push_back(mapped_id); - ReturnedResourceArray list; + EXPECT_EQ(0u, returned_to_child.size()); + // Transfer resources back from the parent to the child. Set no resources + // as being in use. + ResourceProvider::ResourceIdArray no_resources; EXPECT_CALL(*parent_context, insertSyncPoint()); + parent_resource_provider->DeclareUsedResourcesFromChild(child_id, + no_resources); + Mock::VerifyAndClearExpectations(parent_context); - parent_resource_provider->PrepareSendReturnsToChild( - child_id, resource_ids_to_transfer, &list); - ASSERT_EQ(1u, list.size()); - child_resource_provider->ReceiveReturnsFromParent(list); + ASSERT_EQ(1u, returned_to_child.size()); + child_resource_provider->ReceiveReturnsFromParent(returned_to_child); } - Mock::VerifyAndClearExpectations(parent_context); // The child remembers the texture filter is set to |child_filter|. EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, texture_id)); diff --git a/cc/resources/return_callback.h b/cc/resources/return_callback.h new file mode 100644 index 0000000..d12254b --- /dev/null +++ b/cc/resources/return_callback.h @@ -0,0 +1,17 @@ +// 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_RESOURCES_RETURN_CALLBACK_H_ +#define CC_RESOURCES_RETURN_CALLBACK_H_ + +#include "base/callback.h" +#include "cc/resources/returned_resource.h" + +namespace cc { + +typedef base::Callback<void(const ReturnedResourceArray&)> ReturnCallback; + +} // namespace cc + +#endif // CC_RESOURCES_RETURN_CALLBACK_H_ diff --git a/cc/test/fake_delegated_renderer_layer_impl.cc b/cc/test/fake_delegated_renderer_layer_impl.cc index 782bc1c..1420ae2 100644 --- a/cc/test/fake_delegated_renderer_layer_impl.cc +++ b/cc/test/fake_delegated_renderer_layer_impl.cc @@ -32,6 +32,18 @@ static ResourceProvider::ResourceId AddResourceToFrame( return resource_id; } +ResourceProvider::ResourceIdSet FakeDelegatedRendererLayerImpl::Resources() + const { + ResourceProvider::ResourceIdSet set; + ResourceProvider::ResourceIdArray array; + array = ResourcesForTesting(); + for (size_t i = 0; i < array.size(); ++i) + set.insert(array[i]); + return set; +} + +void NoopReturnCallback(const ReturnedResourceArray& returned) {} + void FakeDelegatedRendererLayerImpl::SetFrameDataForRenderPasses( ScopedPtrVector<RenderPass>* pass_list) { scoped_ptr<DelegatedFrameData> delegated_frame(new DelegatedFrameData); @@ -46,9 +58,8 @@ void FakeDelegatedRendererLayerImpl::SetFrameDataForRenderPasses( pass->quad_list[j]->IterateResources(add_resource_to_frame_callback); } - ReturnedResourceArray resources_for_ack; + CreateChildIdIfNeeded(base::Bind(&NoopReturnCallback)); SetFrameData(delegated_frame.Pass(), gfx::RectF()); - CollectUnusedResources(&resources_for_ack); } } // namespace cc diff --git a/cc/test/fake_delegated_renderer_layer_impl.h b/cc/test/fake_delegated_renderer_layer_impl.h index a9ca0f9..a958baf 100644 --- a/cc/test/fake_delegated_renderer_layer_impl.h +++ b/cc/test/fake_delegated_renderer_layer_impl.h @@ -24,9 +24,7 @@ class FakeDelegatedRendererLayerImpl : public DelegatedRendererLayerImpl { const ScopedPtrVector<RenderPass>& RenderPassesInDrawOrder() const { return RenderPassesInDrawOrderForTesting(); } - const ResourceProvider::ResourceIdSet& Resources() const { - return ResourcesForTesting(); - } + ResourceProvider::ResourceIdSet Resources() const; void SetFrameDataForRenderPasses(ScopedPtrVector<RenderPass>* pass_list); diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h index 6d44019..f3e0fec 100644 --- a/cc/test/layer_tree_test.h +++ b/cc/test/layer_tree_test.h @@ -152,6 +152,9 @@ class LayerTreeTest : public testing::Test, public TestHooks { return proxy()->ImplThreadTaskRunner() ? proxy()->ImplThreadTaskRunner() : main_task_runner_.get(); } + base::SingleThreadTaskRunner* MainThreadTaskRunner() { + return main_task_runner_.get(); + } Proxy* proxy() const { return layer_tree_host_ ? layer_tree_host_->proxy() : NULL; } diff --git a/cc/trees/layer_tree_host_unittest_delegated.cc b/cc/trees/layer_tree_host_unittest_delegated.cc index af79c84..012f6f8 100644 --- a/cc/trees/layer_tree_host_unittest_delegated.cc +++ b/cc/trees/layer_tree_host_unittest_delegated.cc @@ -7,6 +7,7 @@ #include <algorithm> #include "base/bind.h" +#include "base/location.h" #include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" #include "base/time/time.h" @@ -765,8 +766,8 @@ class LayerTreeHostDelegatedTestMergeResources EXPECT_EQ(1u, map.count(555)); EXPECT_EQ(2u, delegated_impl->Resources().size()); - EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(999)->second)); - EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(555)->second)); + EXPECT_EQ(1u, delegated_impl->Resources().count(999)); + EXPECT_EQ(1u, delegated_impl->Resources().count(555)); EndTest(); } @@ -850,11 +851,6 @@ class LayerTreeHostDelegatedTestReturnUnusedResources delegated_->SetFrameData(frame.Pass()); break; case 2: - // Retrieve unused resources to the main thread. - // TODO(danakj): Shouldn't need to commit to get resources. - layer_tree_host()->SetNeedsCommit(); - return; - case 3: // All of the resources are in use. delegated_->TakeUnusedResourcesForChildCompositor(&resources); EXPECT_EQ(0u, resources.size()); @@ -862,16 +858,12 @@ class LayerTreeHostDelegatedTestReturnUnusedResources // Keep using 999 but stop using 555. frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); AddTextureQuad(frame.get(), 999); + AddTransferableResource(frame.get(), 999); AddTextureQuad(frame.get(), 444); AddTransferableResource(frame.get(), 444); delegated_->SetFrameData(frame.Pass()); break; - case 4: - // Retrieve unused resources to the main thread. - // TODO(danakj): Shouldn't need to commit to get resources. - layer_tree_host()->SetNeedsCommit(); - return; - case 5: + case 3: // 555 is no longer in use. delegated_->TakeUnusedResourcesForChildCompositor(&resources); { @@ -883,16 +875,17 @@ class LayerTreeHostDelegatedTestReturnUnusedResources frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); delegated_->SetFrameData(frame.Pass()); break; - case 6: + case 4: // Postpone collecting resources for a frame. They should still be there // the next frame. layer_tree_host()->SetNeedsCommit(); return; - case 7: - // 444 and 999 are no longer in use. + case 5: + // 444 and 999 are no longer in use. We sent two refs to 999, so we + // should get two back. delegated_->TakeUnusedResourcesForChildCompositor(&resources); { - unsigned expected[] = {444, 999}; + unsigned expected[] = {444, 999, 999}; EXPECT_RESOURCES(expected, resources); } EndTest(); @@ -941,11 +934,6 @@ class LayerTreeHostDelegatedTestReusedResources delegated_->SetFrameData(frame.Pass()); break; case 2: - // Retrieve unused resources to the main thread. - // TODO(danakj): Shouldn't need to commit to get resources. - layer_tree_host()->SetNeedsCommit(); - return; - case 3: // All of the resources are in use. delegated_->TakeUnusedResourcesForChildCompositor(&resources); EXPECT_EQ(0u, resources.size()); @@ -953,6 +941,7 @@ class LayerTreeHostDelegatedTestReusedResources // Keep using 999 but stop using 555 and 444. frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); AddTextureQuad(frame.get(), 999); + AddTransferableResource(frame.get(), 999); delegated_->SetFrameData(frame.Pass()); // Resource are not immediately released. @@ -962,19 +951,17 @@ class LayerTreeHostDelegatedTestReusedResources // Now using 555 and 444 again, but not 999. frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); AddTextureQuad(frame.get(), 555); + AddTransferableResource(frame.get(), 555); AddTextureQuad(frame.get(), 444); + AddTransferableResource(frame.get(), 444); delegated_->SetFrameData(frame.Pass()); break; - case 4: - // Retrieve unused resources to the main thread. - // TODO(danakj): Shouldn't need to commit to get resources. - layer_tree_host()->SetNeedsCommit(); - return; - case 5: - // The 999 resource is the only unused one. + case 3: + // The 999 resource is the only unused one. Two references were sent, so + // two should be returned. delegated_->TakeUnusedResourcesForChildCompositor(&resources); { - unsigned expected[] = {999}; + unsigned expected[] = {999, 999}; EXPECT_RESOURCES(expected, resources); } EndTest(); @@ -1017,11 +1004,6 @@ class LayerTreeHostDelegatedTestFrameBeforeAck delegated_->SetFrameData(frame.Pass()); break; case 2: - // Retrieve unused resources to the main thread. - // TODO(danakj): Shouldn't need to commit to get resources. - layer_tree_host()->SetNeedsCommit(); - return; - case 3: // All of the resources are in use. delegated_->TakeUnusedResourcesForChildCompositor(&resources); EXPECT_EQ(0u, resources.size()); @@ -1029,6 +1011,7 @@ class LayerTreeHostDelegatedTestFrameBeforeAck // Keep using 999 but stop using 555 and 444. frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); AddTextureQuad(frame.get(), 999); + AddTransferableResource(frame.get(), 999); delegated_->SetFrameData(frame.Pass()); // Resource are not immediately released. @@ -1037,20 +1020,15 @@ class LayerTreeHostDelegatedTestFrameBeforeAck // The parent compositor (this one) does a commit. break; - case 4: - // Retrieve unused resources to the main thread. - // TODO(danakj): Shouldn't need to commit to get resources. - layer_tree_host()->SetNeedsCommit(); - return; - case 5: + case 3: delegated_->TakeUnusedResourcesForChildCompositor(&resources); { unsigned expected[] = {444, 555}; EXPECT_RESOURCES(expected, resources); } - // The child compositor sends a frame before receiving an for the - // second frame. It uses 999, 444, and 555 again. + // The child compositor sends a frame referring to resources not in the + // frame. frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); AddTextureQuad(frame.get(), 999); AddTextureQuad(frame.get(), 555); @@ -1061,7 +1039,7 @@ class LayerTreeHostDelegatedTestFrameBeforeAck } virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { - if (host_impl->active_tree()->source_frame_number() != 5) + if (host_impl->active_tree()->source_frame_number() != 3) return; LayerImpl* root_impl = host_impl->active_tree()->root_layer(); @@ -1079,7 +1057,7 @@ class LayerTreeHostDelegatedTestFrameBeforeAck EXPECT_EQ(1u, map.count(999)); EXPECT_EQ(1u, delegated_impl->Resources().size()); - EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(999)->second)); + EXPECT_EQ(1u, delegated_impl->Resources().count(999)); const RenderPass* pass = delegated_impl->RenderPassesInDrawOrder()[0]; EXPECT_EQ(1u, pass->quad_list.size()); @@ -1125,11 +1103,6 @@ class LayerTreeHostDelegatedTestFrameBeforeTakeResources delegated_->SetFrameData(frame.Pass()); break; case 2: - // Retrieve unused resources to the main thread. - // TODO(danakj): Shouldn't need to commit to get resources. - layer_tree_host()->SetNeedsCommit(); - return; - case 3: // All of the resources are in use. delegated_->TakeUnusedResourcesForChildCompositor(&resources); EXPECT_EQ(0u, resources.size()); @@ -1146,12 +1119,7 @@ class LayerTreeHostDelegatedTestFrameBeforeTakeResources // The parent compositor (this one) does a commit. break; - case 4: - // Retrieve unused resources to the main thread. - // TODO(danakj): Shouldn't need to commit to get resources. - layer_tree_host()->SetNeedsCommit(); - return; - case 5: + case 3: // The child compositor sends a frame before taking resources back // from the previous commit. This frame makes use of the resources 555 // and 444, which were just released during commit. @@ -1172,12 +1140,7 @@ class LayerTreeHostDelegatedTestFrameBeforeTakeResources EXPECT_RESOURCES(expected, resources); } break; - case 6: - // Retrieve unused resources to the main thread. - // TODO(danakj): Shouldn't need to commit to get resources. - layer_tree_host()->SetNeedsCommit(); - return; - case 7: + case 4: delegated_->TakeUnusedResourcesForChildCompositor(&resources); EXPECT_EQ(0u, resources.size()); EndTest(); @@ -1186,7 +1149,7 @@ class LayerTreeHostDelegatedTestFrameBeforeTakeResources } virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { - if (host_impl->active_tree()->source_frame_number() != 5) + if (host_impl->active_tree()->source_frame_number() != 3) return; LayerImpl* root_impl = host_impl->active_tree()->root_layer(); @@ -1205,9 +1168,9 @@ class LayerTreeHostDelegatedTestFrameBeforeTakeResources EXPECT_EQ(1u, map.count(444)); EXPECT_EQ(3u, delegated_impl->Resources().size()); - EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(999)->second)); - EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(555)->second)); - EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(444)->second)); + EXPECT_EQ(1u, delegated_impl->Resources().count(999)); + EXPECT_EQ(1u, delegated_impl->Resources().count(555)); + EXPECT_EQ(1u, delegated_impl->Resources().count(444)); const RenderPass* pass = delegated_impl->RenderPassesInDrawOrder()[0]; EXPECT_EQ(3u, pass->quad_list.size()); @@ -1256,11 +1219,6 @@ class LayerTreeHostDelegatedTestBadFrame delegated_->SetFrameData(frame.Pass()); break; case 2: - // Retrieve unused resources to the main thread. - // TODO(danakj): Shouldn't need to commit to get resources. - layer_tree_host()->SetNeedsCommit(); - return; - case 3: // All of the resources are in use. delegated_->TakeUnusedResourcesForChildCompositor(&resources); EXPECT_EQ(0u, resources.size()); @@ -1279,12 +1237,7 @@ class LayerTreeHostDelegatedTestBadFrame // The parent compositor (this one) does a commit. break; - case 4: - // Retrieve unused resources to the main thread. - // TODO(danakj): Shouldn't need to commit to get resources. - layer_tree_host()->SetNeedsCommit(); - return; - case 5: + case 3: // The bad frame's resource is given back to the child compositor. delegated_->TakeUnusedResourcesForChildCompositor(&resources); { @@ -1297,12 +1250,7 @@ class LayerTreeHostDelegatedTestBadFrame AddTextureQuad(frame.get(), 999); delegated_->SetFrameData(frame.Pass()); break; - case 6: - // Retrieve unused resources to the main thread. - // TODO(danakj): Shouldn't need to commit to get resources. - layer_tree_host()->SetNeedsCommit(); - return; - case 7: + case 4: // The unused 555 from the last good frame is now released. delegated_->TakeUnusedResourcesForChildCompositor(&resources); { @@ -1339,8 +1287,8 @@ class LayerTreeHostDelegatedTestBadFrame EXPECT_EQ(1u, map.count(555)); EXPECT_EQ(2u, delegated_impl->Resources().size()); - EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(999)->second)); - EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(555)->second)); + EXPECT_EQ(1u, delegated_impl->Resources().count(999)); + EXPECT_EQ(1u, delegated_impl->Resources().count(555)); const RenderPass* pass = delegated_impl->RenderPassesInDrawOrder()[0]; EXPECT_EQ(2u, pass->quad_list.size()); @@ -1352,15 +1300,15 @@ class LayerTreeHostDelegatedTestBadFrame EXPECT_EQ(map.find(555)->second, quad2->resource_id); break; } - case 3: { + case 2: { // We only keep resources from the last valid frame. EXPECT_EQ(2u, map.size()); EXPECT_EQ(1u, map.count(999)); EXPECT_EQ(1u, map.count(555)); EXPECT_EQ(2u, delegated_impl->Resources().size()); - EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(999)->second)); - EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(555)->second)); + EXPECT_EQ(1u, delegated_impl->Resources().count(999)); + EXPECT_EQ(1u, delegated_impl->Resources().count(555)); // The bad frame is dropped though, we still have the frame with 999 and // 555 in it. @@ -1374,20 +1322,13 @@ class LayerTreeHostDelegatedTestBadFrame EXPECT_EQ(map.find(555)->second, quad2->resource_id); break; } - case 5: - // Resources given to our parent compositor will be returned now, but - // the DelegatedRendererLayerImpl doesn't know about it until the next - // commit. - // TODO(danakj): Shouldn't need a commit to return resources to the - // DelegatedRendererLayerImpl or to the main thread. - break; - case 6: { + case 3: { // We have the new good frame with just 999 in it. EXPECT_EQ(1u, map.size()); EXPECT_EQ(1u, map.count(999)); EXPECT_EQ(1u, delegated_impl->Resources().size()); - EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(999)->second)); + EXPECT_EQ(1u, delegated_impl->Resources().count(999)); const RenderPass* pass = delegated_impl->RenderPassesInDrawOrder()[0]; EXPECT_EQ(1u, pass->quad_list.size()); @@ -1455,7 +1396,7 @@ class LayerTreeHostDelegatedTestUnnamedResource EXPECT_EQ(1u, map.count(555)); EXPECT_EQ(1u, delegated_impl->Resources().size()); - EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(555)->second)); + EXPECT_EQ(1u, delegated_impl->Resources().count(555)); } virtual void AfterTest() OVERRIDE {} @@ -1470,7 +1411,7 @@ class LayerTreeHostDelegatedTestDontLeakResource PostSetNeedsCommitToMainThread(); } - virtual void DidCommit() OVERRIDE { + virtual void DidCommitAndDrawFrame() OVERRIDE { scoped_ptr<DelegatedFrameData> frame; ReturnedResourceArray resources; @@ -1504,11 +1445,6 @@ class LayerTreeHostDelegatedTestDontLeakResource delegated_->SetFrameData(frame.Pass()); break; case 3: - // The impl side will get back the resource at some point. - // TODO(piman): The test should work without this. - layer_tree_host()->SetNeedsCommit(); - break; - case 4: // The now unused resource 555 should be returned. resources.clear(); delegated_->TakeUnusedResourcesForChildCompositor(&resources); @@ -1538,7 +1474,7 @@ class LayerTreeHostDelegatedTestDontLeakResource EXPECT_EQ(1u, map.count(555)); EXPECT_EQ(1u, delegated_impl->Resources().size()); - EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(555)->second)); + EXPECT_EQ(1u, delegated_impl->Resources().count(555)); } virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, @@ -1577,6 +1513,7 @@ class LayerTreeHostDelegatedTestResourceSentToParent // it present. frame = CreateFrameData(gfx::Rect(0, 0, 1, 1), gfx::Rect(0, 0, 1, 1)); AddTextureQuad(frame.get(), 555); + AddTransferableResource(frame.get(), 555); delegated_->SetFrameData(frame.Pass()); break; case 3: @@ -1585,20 +1522,46 @@ class LayerTreeHostDelegatedTestResourceSentToParent EXPECT_EQ(0u, resources.size()); // The impl side will get back the resource at some point. - // TODO(danakj): The test should work without this. - layer_tree_host()->SetNeedsCommit(); + ImplThreadTaskRunner()->PostTask(FROM_HERE, + receive_resource_on_thread_); break; - case 4: - // 999 was returned from the grandparent and could be released. - delegated_->TakeUnusedResourcesForChildCompositor(&resources); - { - unsigned expected[] = {999}; - EXPECT_RESOURCES(expected, resources); - } + } + } - EndTest(); - break; + void ReceiveResourceOnThread(LayerTreeHostImpl* host_impl) { + LayerImpl* root_impl = host_impl->active_tree()->root_layer(); + FakeDelegatedRendererLayerImpl* delegated_impl = + static_cast<FakeDelegatedRendererLayerImpl*>(root_impl->children()[0]); + + const ResourceProvider::ResourceIdMap& map = + host_impl->resource_provider()->GetChildToParentMap( + delegated_impl->ChildId()); + + // Receive 999 back from the grandparent. + CompositorFrameAck ack; + output_surface()->ReturnResource(map.find(999)->second, &ack); + host_impl->ReclaimResources(&ack); + host_impl->OnSwapBuffersComplete(); + + // And then it should be released by the DelegatedRendererLayer. + MainThreadTaskRunner()->PostTask( + FROM_HERE, + base::Bind(&LayerTreeHostDelegatedTestResourceSentToParent:: + DidReceiveResourceOnMainThread, + base::Unretained(this))); + } + + void DidReceiveResourceOnMainThread() { + ReturnedResourceArray resources; + + // 999 was returned from the grandparent and could be released. + delegated_->TakeUnusedResourcesForChildCompositor(&resources); + { + unsigned expected[] = {999}; + EXPECT_RESOURCES(expected, resources); } + + EndTest(); } virtual void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) OVERRIDE { @@ -1620,8 +1583,8 @@ class LayerTreeHostDelegatedTestResourceSentToParent EXPECT_EQ(1u, map.count(555)); EXPECT_EQ(2u, delegated_impl->Resources().size()); - EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(999)->second)); - EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(555)->second)); + EXPECT_EQ(1u, delegated_impl->Resources().count(999)); + EXPECT_EQ(1u, delegated_impl->Resources().count(555)); // The 999 resource will be sent to a grandparent compositor. break; @@ -1633,13 +1596,13 @@ class LayerTreeHostDelegatedTestResourceSentToParent // 999 is in the parent, so not held by delegated renderer layer. EXPECT_EQ(1u, delegated_impl->Resources().size()); - EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(555)->second)); + EXPECT_EQ(1u, delegated_impl->Resources().count(555)); - // Receive 999 back from the grandparent. - CompositorFrameAck ack; - output_surface()->ReturnResource(map.find(999)->second, &ack); - host_impl->ReclaimResources(&ack); - host_impl->OnSwapBuffersComplete(); + receive_resource_on_thread_ = + base::Bind(&LayerTreeHostDelegatedTestResourceSentToParent:: + ReceiveResourceOnThread, + base::Unretained(this), + host_impl); break; } case 3: @@ -1655,7 +1618,7 @@ class LayerTreeHostDelegatedTestResourceSentToParent virtual void AfterTest() OVERRIDE {} - TransferableResource resource_in_grandparent; + base::Closure receive_resource_on_thread_; }; SINGLE_AND_MULTI_THREAD_DELEGATING_RENDERER_TEST_F( @@ -1753,16 +1716,16 @@ class LayerTreeHostDelegatedTestCommitWithoutTake EXPECT_EQ(1u, map.count(444)); EXPECT_EQ(3u, delegated_impl->Resources().size()); - EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(999)->second)); - EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(555)->second)); - EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(444)->second)); + EXPECT_EQ(1u, delegated_impl->Resources().count(999)); + EXPECT_EQ(1u, delegated_impl->Resources().count(555)); + EXPECT_EQ(1u, delegated_impl->Resources().count(444)); break; case 2: EXPECT_EQ(1u, map.size()); EXPECT_EQ(1u, map.count(555)); EXPECT_EQ(1u, delegated_impl->Resources().size()); - EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(555)->second)); + EXPECT_EQ(1u, delegated_impl->Resources().count(555)); break; case 3: EXPECT_EQ(2u, map.size()); @@ -1770,8 +1733,8 @@ class LayerTreeHostDelegatedTestCommitWithoutTake EXPECT_EQ(1u, map.count(555)); EXPECT_EQ(2u, delegated_impl->Resources().size()); - EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(999)->second)); - EXPECT_EQ(1u, delegated_impl->Resources().count(map.find(555)->second)); + EXPECT_EQ(1u, delegated_impl->Resources().count(999)); + EXPECT_EQ(1u, delegated_impl->Resources().count(555)); } } diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc index 689cc452..3d5e7a5 100644 --- a/cc/trees/single_thread_proxy.cc +++ b/cc/trees/single_thread_proxy.cc @@ -125,7 +125,7 @@ void SingleThreadProxy::CreateAndInitializeOutputSurface() { } { - DebugScopedSetMainThreadBlocked mainThreadBlocked(this); + DebugScopedSetMainThreadBlocked main_thread_blocked(this); DebugScopedSetImplThread impl(this); layer_tree_host_->DeleteContentsTexturesOnImplThread( layer_tree_host_impl_->resource_provider()); @@ -182,7 +182,7 @@ void SingleThreadProxy::DoCommit(scoped_ptr<ResourceUpdateQueue> queue) { DCHECK(Proxy::IsMainThread()); // Commit immediately. { - DebugScopedSetMainThreadBlocked mainThreadBlocked(this); + DebugScopedSetMainThreadBlocked main_thread_blocked(this); DebugScopedSetImplThread impl(this); // This CapturePostTasks should be destroyed before CommitComplete() is @@ -263,7 +263,7 @@ void SingleThreadProxy::Stop() { TRACE_EVENT0("cc", "SingleThreadProxy::stop"); DCHECK(Proxy::IsMainThread()); { - DebugScopedSetMainThreadBlocked mainThreadBlocked(this); + DebugScopedSetMainThreadBlocked main_thread_blocked(this); DebugScopedSetImplThread impl(this); layer_tree_host_->DeleteContentsTexturesOnImplThread( @@ -365,7 +365,21 @@ void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) { device_viewport_damage_rect, false, // for_readback &frame)) { - layer_tree_host_impl_->SwapBuffers(frame); + { + DebugScopedSetMainThreadBlocked main_thread_blocked(this); + DebugScopedSetImplThread impl(this); + + // This CapturePostTasks should be destroyed before + // DidCommitAndDrawFrame() is called since that goes out to the embedder, + // and we want the embedder to receive its callbacks before that. + // NOTE: This maintains consistent ordering with the ThreadProxy since + // the DidCommitAndDrawFrame() must be post-tasked from the impl thread + // there as the main thread is not blocked, so any posted tasks inside + // the swap buffers will execute first. + BlockingTaskRunner::CapturePostTasks blocked; + + layer_tree_host_impl_->SwapBuffers(frame); + } DidSwapFrame(); } } |