diff options
27 files changed, 1179 insertions, 772 deletions
@@ -493,12 +493,16 @@ 'surfaces/display_client.h', 'surfaces/surface.cc', 'surfaces/surface.h', - 'surfaces/surface_id.h', 'surfaces/surface_aggregator.cc', 'surfaces/surface_aggregator.h', - 'surfaces/surface_client.h', + 'surfaces/surface_factory.cc', + 'surfaces/surface_factory.h', + 'surfaces/surface_factory_client.h', + 'surfaces/surface_id.h', 'surfaces/surface_manager.cc', 'surfaces/surface_manager.h', + 'surfaces/surface_resource_holder.cc', + 'surfaces/surface_resource_holder.h', 'surfaces/surfaces_export.h', ], }, diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp index 72aab12..763bda9 100644 --- a/cc/cc_tests.gyp +++ b/cc/cc_tests.gyp @@ -121,6 +121,7 @@ 'surfaces/surface_aggregator_test_helpers.cc', 'surfaces/surface_aggregator_test_helpers.h', 'surfaces/surface_aggregator_unittest.cc', + 'surfaces/surface_factory_unittest.cc', 'surfaces/surface_unittest.cc', 'surfaces/surfaces_pixeltest.cc', ], diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc index a39695f..30e593d 100644 --- a/cc/surfaces/display.cc +++ b/cc/surfaces/display.cc @@ -4,48 +4,40 @@ #include "cc/surfaces/display.h" +#include "base/debug/trace_event.h" #include "base/message_loop/message_loop.h" #include "cc/output/compositor_frame.h" +#include "cc/output/compositor_frame_ack.h" #include "cc/output/direct_renderer.h" #include "cc/output/gl_renderer.h" #include "cc/output/software_renderer.h" #include "cc/surfaces/display_client.h" #include "cc/surfaces/surface.h" +#include "cc/surfaces/surface_aggregator.h" +#include "cc/surfaces/surface_factory.h" namespace cc { -static ResourceProvider::ResourceId ResourceRemapHelper( - bool* invalid_frame, - const ResourceProvider::ResourceIdMap& child_to_parent_map, - ResourceProvider::ResourceIdArray* resources_in_frame, - ResourceProvider::ResourceId id) { - ResourceProvider::ResourceIdMap::const_iterator it = - child_to_parent_map.find(id); - if (it == child_to_parent_map.end()) { - *invalid_frame = true; - return 0; - } - - DCHECK_EQ(it->first, id); - ResourceProvider::ResourceId remapped_id = it->second; - resources_in_frame->push_back(id); - return remapped_id; -} - Display::Display(DisplayClient* client, SurfaceManager* manager, + SurfaceFactory* factory, SharedBitmapManager* bitmap_manager) : client_(client), manager_(manager), - aggregator_(manager), - bitmap_manager_(bitmap_manager) { + bitmap_manager_(bitmap_manager), + factory_(factory) { } Display::~Display() { } void Display::Resize(const gfx::Size& size) { - current_surface_.reset(new Surface(manager_, this, size)); + if (size == current_surface_size_) + return; + if (!current_surface_id_.is_null()) + factory_->Destroy(current_surface_id_); + current_surface_id_ = factory_->Create(size); + current_surface_size_ = size; } void Display::InitializeOutputSurface() { @@ -91,55 +83,27 @@ void Display::InitializeOutputSurface() { output_surface_ = output_surface.Pass(); resource_provider_ = resource_provider.Pass(); - child_id_ = resource_provider_->CreateChild( - base::Bind(&Display::ReturnResources, base::Unretained(this))); + aggregator_.reset(new SurfaceAggregator(manager_, resource_provider_.get())); } bool Display::Draw() { - if (!current_surface_) + if (current_surface_id_.is_null()) return false; InitializeOutputSurface(); if (!output_surface_) return false; - // TODO(jamesr): Use the surface aggregator instead. - scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData); - CompositorFrame* current_frame = current_surface_->GetEligibleFrame(); - frame_data->resource_list = - current_frame->delegated_frame_data->resource_list; - RenderPass::CopyAll(current_frame->delegated_frame_data->render_pass_list, - &frame_data->render_pass_list); - - if (frame_data->render_pass_list.empty()) + scoped_ptr<CompositorFrame> frame = + aggregator_->Aggregate(current_surface_id_); + if (!frame) return false; - const ResourceProvider::ResourceIdMap& resource_map = - resource_provider_->GetChildToParentMap(child_id_); - resource_provider_->ReceiveFromChild(child_id_, frame_data->resource_list); - - bool invalid_frame = false; - ResourceProvider::ResourceIdArray resources_in_frame; - DrawQuad::ResourceIteratorCallback remap_resources_to_parent_callback = - base::Bind(&ResourceRemapHelper, - &invalid_frame, - resource_map, - &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) { - DrawQuad* quad = pass->quad_list[j]; - quad->IterateResources(remap_resources_to_parent_callback); - } - } - - if (invalid_frame) - return false; - resource_provider_->DeclareUsedResourcesFromChild(child_id_, - resources_in_frame); + TRACE_EVENT0("cc", "Display::Draw"); + DelegatedFrameData* frame_data = frame->delegated_frame_data.get(); float device_scale_factor = 1.0f; - gfx::Rect device_viewport_rect = gfx::Rect(current_surface_->size()); + gfx::Rect device_viewport_rect = gfx::Rect(current_surface_size_); gfx::Rect device_clip_rect = device_viewport_rect; bool disable_picture_quad_image_filtering = false; @@ -154,10 +118,7 @@ bool Display::Draw() { } SurfaceId Display::CurrentSurfaceId() { - return current_surface_ ? current_surface_->surface_id() : SurfaceId(); -} - -void Display::ReturnResources(const ReturnedResourceArray& resources) { + return current_surface_id_; } } // namespace cc diff --git a/cc/surfaces/display.h b/cc/surfaces/display.h index 191b28d..689045b 100644 --- a/cc/surfaces/display.h +++ b/cc/surfaces/display.h @@ -6,11 +6,10 @@ #define CC_SURFACES_DISPLAY_H_ #include "base/memory/scoped_ptr.h" - #include "cc/output/output_surface_client.h" #include "cc/output/renderer.h" +#include "cc/resources/returned_resource.h" #include "cc/surfaces/surface_aggregator.h" -#include "cc/surfaces/surface_client.h" #include "cc/surfaces/surface_id.h" #include "cc/surfaces/surfaces_export.h" @@ -26,14 +25,21 @@ class OutputSurface; class ResourceProvider; class SharedBitmapManager; class Surface; +class SurfaceAggregator; +class SurfaceFactory; class SurfaceManager; -class CC_SURFACES_EXPORT Display : public SurfaceClient, - public OutputSurfaceClient, +// A Display produces a surface that can be used to draw to a physical display +// (OutputSurface). Since a surface is a fixed size and displays can resize, a +// Display may create/destroy surfaces over its lifetime. Frames submitted to a +// display's surface will have their resources returned through the factory's +// client. +class CC_SURFACES_EXPORT Display : public OutputSurfaceClient, public RendererClient { public: Display(DisplayClient* client, SurfaceManager* manager, + SurfaceFactory* factory, SharedBitmapManager* bitmap_manager); virtual ~Display(); @@ -66,22 +72,20 @@ class CC_SURFACES_EXPORT Display : public SurfaceClient, virtual void SetFullRootLayerDamage() OVERRIDE {} virtual void RunOnDemandRasterTask(Task* on_demand_raster_task) OVERRIDE {} - // SurfaceClient implementation. - virtual void ReturnResources(const ReturnedResourceArray& resources) OVERRIDE; - private: void InitializeOutputSurface(); DisplayClient* client_; SurfaceManager* manager_; - SurfaceAggregator aggregator_; SharedBitmapManager* bitmap_manager_; + SurfaceFactory* factory_; + SurfaceId current_surface_id_; + gfx::Size current_surface_size_; LayerTreeSettings settings_; - scoped_ptr<Surface> current_surface_; scoped_ptr<OutputSurface> output_surface_; scoped_ptr<ResourceProvider> resource_provider_; + scoped_ptr<SurfaceAggregator> aggregator_; scoped_ptr<DirectRenderer> renderer_; - int child_id_; DISALLOW_COPY_AND_ASSIGN(Display); }; diff --git a/cc/surfaces/surface.cc b/cc/surfaces/surface.cc index ed5a0f6..bed727c 100644 --- a/cc/surfaces/surface.cc +++ b/cc/surfaces/surface.cc @@ -5,88 +5,39 @@ #include "cc/surfaces/surface.h" #include "cc/output/compositor_frame.h" -#include "cc/surfaces/surface_manager.h" +#include "cc/surfaces/surface_factory.h" namespace cc { -Surface::Surface(SurfaceManager* manager, - SurfaceClient* client, - const gfx::Size& size) - : manager_(manager), - client_(client), - size_(size) { - surface_id_ = manager_->RegisterAndAllocateIdForSurface(this); +Surface::Surface(SurfaceId id, const gfx::Size& size, SurfaceFactory* factory) + : surface_id_(id), size_(size), factory_(factory) { } Surface::~Surface() { - manager_->DeregisterSurface(surface_id_); + if (current_frame_) { + ReturnedResourceArray current_resources; + TransferableResource::ReturnResources( + current_frame_->delegated_frame_data->resource_list, + ¤t_resources); + factory_->UnrefResources(current_resources); + } } void Surface::QueueFrame(scoped_ptr<CompositorFrame> frame) { scoped_ptr<CompositorFrame> previous_frame = current_frame_.Pass(); current_frame_ = frame.Pass(); - ReceiveResourcesFromClient( + factory_->ReceiveFromChild( current_frame_->delegated_frame_data->resource_list); + if (previous_frame) { ReturnedResourceArray previous_resources; TransferableResource::ReturnResources( previous_frame->delegated_frame_data->resource_list, &previous_resources); - UnrefResources(previous_resources); + factory_->UnrefResources(previous_resources); } } CompositorFrame* Surface::GetEligibleFrame() { return current_frame_.get(); } -void Surface::ReturnUnusedResourcesToClient() { - client_->ReturnResources(resources_available_to_return_); - resources_available_to_return_.clear(); -} - -void Surface::RefCurrentFrameResources() { - if (!current_frame_) - return; - const TransferableResourceArray& current_frame_resources = - current_frame_->delegated_frame_data->resource_list; - for (size_t i = 0; i < current_frame_resources.size(); ++i) { - const TransferableResource& resource = current_frame_resources[i]; - ResourceIdCountMap::iterator it = - resource_id_use_count_map_.find(resource.id); - DCHECK(it != resource_id_use_count_map_.end()); - it->second.refs_holding_resource_alive++; - } -} - -Surface::ResourceRefs::ResourceRefs() - : refs_received_from_child(0), refs_holding_resource_alive(0) { -} - -void Surface::ReceiveResourcesFromClient( - const TransferableResourceArray& resources) { - for (TransferableResourceArray::const_iterator it = resources.begin(); - it != resources.end(); - ++it) { - ResourceRefs& ref = resource_id_use_count_map_[it->id]; - ref.refs_holding_resource_alive++; - ref.refs_received_from_child++; - } -} - -void Surface::UnrefResources(const ReturnedResourceArray& resources) { - for (ReturnedResourceArray::const_iterator it = resources.begin(); - it != resources.end(); - ++it) { - ResourceProvider::ResourceId id = it->id; - ResourceIdCountMap::iterator count_it = resource_id_use_count_map_.find(id); - DCHECK(count_it != resource_id_use_count_map_.end()); - count_it->second.refs_holding_resource_alive -= it->count; - if (count_it->second.refs_holding_resource_alive == 0) { - resources_available_to_return_.push_back(*it); - resources_available_to_return_.back().count = - count_it->second.refs_received_from_child; - resource_id_use_count_map_.erase(count_it); - } - } -} - } // namespace cc diff --git a/cc/surfaces/surface.h b/cc/surfaces/surface.h index 007f33d..f62a897 100644 --- a/cc/surfaces/surface.h +++ b/cc/surfaces/surface.h @@ -8,9 +8,6 @@ #include "base/containers/hash_tables.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" -#include "cc/resources/resource_provider.h" -#include "cc/resources/return_callback.h" -#include "cc/surfaces/surface_client.h" #include "cc/surfaces/surface_id.h" #include "cc/surfaces/surfaces_export.h" #include "ui/gfx/size.h" @@ -18,12 +15,12 @@ namespace cc { class CompositorFrame; class SurfaceManager; +class SurfaceFactory; +class SurfaceResourceHolder; class CC_SURFACES_EXPORT Surface { public: - Surface(SurfaceManager* manager, - SurfaceClient* client, - const gfx::Size& size); + Surface(SurfaceId id, const gfx::Size& size, SurfaceFactory* factory); ~Surface(); const gfx::Size& size() const { return size_; } @@ -33,40 +30,15 @@ class CC_SURFACES_EXPORT Surface { // Returns the most recent frame that is eligible to be rendered. CompositorFrame* GetEligibleFrame(); - // Takes a reference to all of the current frame's resources for an external - // consumer (e.g. a ResourceProvider). The caller to this should call - // UnrefResources() when they are done with the resources. - void RefCurrentFrameResources(); - void UnrefResources(const ReturnedResourceArray& resources); - - // Returns all resources that are currently not in use to the client. - void ReturnUnusedResourcesToClient(); + SurfaceFactory* factory() { return factory_; } private: - void ReceiveResourcesFromClient(const TransferableResourceArray& resources); - - SurfaceManager* manager_; - SurfaceClient* client_; - gfx::Size size_; SurfaceId surface_id_; + gfx::Size size_; + SurfaceFactory* factory_; // TODO(jamesr): Support multiple frames in flight. scoped_ptr<CompositorFrame> current_frame_; - struct ResourceRefs { - ResourceRefs(); - - int refs_received_from_child; - int refs_holding_resource_alive; - }; - // Keeps track of the number of users currently in flight for each resource - // ID we've received from the client. When this counter hits zero for a - // particular resource, that ID is available to return to the client. - typedef base::hash_map<ResourceProvider::ResourceId, ResourceRefs> - ResourceIdCountMap; - ResourceIdCountMap resource_id_use_count_map_; - - ReturnedResourceArray resources_available_to_return_; - DISALLOW_COPY_AND_ASSIGN(Surface); }; diff --git a/cc/surfaces/surface_aggregator.cc b/cc/surfaces/surface_aggregator.cc index 72300c0..2926140 100644 --- a/cc/surfaces/surface_aggregator.cc +++ b/cc/surfaces/surface_aggregator.cc @@ -4,7 +4,9 @@ #include "cc/surfaces/surface_aggregator.h" +#include "base/bind.h" #include "base/containers/hash_tables.h" +#include "base/debug/trace_event.h" #include "base/logging.h" #include "cc/output/compositor_frame.h" #include "cc/output/delegated_frame_data.h" @@ -13,31 +15,22 @@ #include "cc/quads/shared_quad_state.h" #include "cc/quads/surface_draw_quad.h" #include "cc/surfaces/surface.h" +#include "cc/surfaces/surface_factory.h" #include "cc/surfaces/surface_manager.h" namespace cc { -SurfaceAggregator::SurfaceAggregator(SurfaceManager* manager) - : manager_(manager) { +SurfaceAggregator::SurfaceAggregator(SurfaceManager* manager, + ResourceProvider* provider) + : manager_(manager), provider_(provider) { DCHECK(manager_); } SurfaceAggregator::~SurfaceAggregator() {} -DelegatedFrameData* SurfaceAggregator::GetReferencedDataForSurfaceId( - SurfaceId surface_id) { - Surface* referenced_surface = manager_->GetSurfaceForId(surface_id); - if (!referenced_surface) - return NULL; // Invalid surface id, skip this quad. - CompositorFrame* referenced_frame = referenced_surface->GetEligibleFrame(); - if (!referenced_frame) - return NULL; - return referenced_frame->delegated_frame_data.get(); -} - class SurfaceAggregator::RenderPassIdAllocator { public: - explicit RenderPassIdAllocator(int surface_id) + explicit RenderPassIdAllocator(SurfaceId surface_id) : surface_id_(surface_id), next_index_(1) {} ~RenderPassIdAllocator() {} @@ -49,12 +42,12 @@ class SurfaceAggregator::RenderPassIdAllocator { RenderPass::Id Remap(RenderPass::Id id) { DCHECK(id_to_index_map_.find(id) != id_to_index_map_.end()); - return RenderPass::Id(surface_id_, id_to_index_map_[id]); + return RenderPass::Id(surface_id_.id, id_to_index_map_[id]); } private: base::hash_map<RenderPass::Id, int> id_to_index_map_; - int surface_id_; + SurfaceId surface_id_; int next_index_; DISALLOW_COPY_AND_ASSIGN(RenderPassIdAllocator); @@ -62,7 +55,7 @@ class SurfaceAggregator::RenderPassIdAllocator { RenderPass::Id SurfaceAggregator::RemapPassId( RenderPass::Id surface_local_pass_id, - int surface_id) { + SurfaceId surface_id) { RenderPassIdAllocator* allocator = render_pass_allocator_map_.get(surface_id); if (!allocator) { allocator = new RenderPassIdAllocator(surface_id); @@ -72,26 +65,102 @@ RenderPass::Id SurfaceAggregator::RemapPassId( return allocator->Remap(surface_local_pass_id); } +int SurfaceAggregator::ChildIdForSurface(Surface* surface) { + SurfaceToResourceChildIdMap::iterator it = + surface_id_to_resource_child_id_.find(surface->surface_id()); + if (it == surface_id_to_resource_child_id_.end()) { + int child_id = provider_->CreateChild(base::Bind( + &SurfaceFactory::UnrefResources, surface->factory()->AsWeakPtr())); + surface_id_to_resource_child_id_[surface->surface_id()] = child_id; + return child_id; + } else { + return it->second; + } +} + +static ResourceProvider::ResourceId ResourceRemapHelper( + bool* invalid_frame, + const ResourceProvider::ResourceIdMap& child_to_parent_map, + ResourceProvider::ResourceIdArray* resources_in_frame, + ResourceProvider::ResourceId id) { + ResourceProvider::ResourceIdMap::const_iterator it = + child_to_parent_map.find(id); + if (it == child_to_parent_map.end()) { + *invalid_frame = true; + return 0; + } + + DCHECK_EQ(it->first, id); + ResourceProvider::ResourceId remapped_id = it->second; + resources_in_frame->push_back(id); + return remapped_id; +} + +bool SurfaceAggregator::TakeResources(Surface* surface, + DelegatedFrameData* frame_data) { + if (!provider_) // TODO(jamesr): hack for unit tests that don't set up rp + return false; + + int child_id = ChildIdForSurface(surface); + provider_->ReceiveFromChild(child_id, frame_data->resource_list); + surface->factory()->RefResources(frame_data->resource_list); + + typedef ResourceProvider::ResourceIdArray IdArray; + IdArray referenced_resources; + + bool invalid_frame = false; + DrawQuad::ResourceIteratorCallback remap = + base::Bind(&ResourceRemapHelper, + &invalid_frame, + provider_->GetChildToParentMap(child_id), + &referenced_resources); + const RenderPassList& referenced_passes = frame_data->render_pass_list; + for (RenderPassList::const_iterator it = referenced_passes.begin(); + it != referenced_passes.end(); + ++it) { + const QuadList& quad_list = (*it)->quad_list; + for (QuadList::const_iterator quad_it = quad_list.begin(); + quad_it != quad_list.end(); + ++quad_it) { + (*quad_it)->IterateResources(remap); + } + } + if (!invalid_frame) + provider_->DeclareUsedResourcesFromChild(child_id, referenced_resources); + + return invalid_frame; +} + void SurfaceAggregator::HandleSurfaceQuad(const SurfaceDrawQuad* surface_quad, RenderPass* dest_pass) { SurfaceId surface_id = surface_quad->surface_id; // If this surface's id is already in our referenced set then it creates // a cycle in the graph and should be dropped. - if (referenced_surfaces_.count(surface_id.id)) + if (referenced_surfaces_.count(surface_id)) + return; + Surface* surface = manager_->GetSurfaceForId(surface_id); + if (!surface) return; - DelegatedFrameData* referenced_data = - GetReferencedDataForSurfaceId(surface_id); - if (!referenced_data) + CompositorFrame* frame = surface->GetEligibleFrame(); + if (!frame) return; - std::set<int>::iterator it = referenced_surfaces_.insert(surface_id.id).first; + DelegatedFrameData* frame_data = frame->delegated_frame_data.get(); + if (!frame_data) + return; + + bool invalid_frame = TakeResources(surface, frame_data); + if (invalid_frame) + return; + + SurfaceSet::iterator it = referenced_surfaces_.insert(surface_id).first; - const RenderPassList& referenced_passes = referenced_data->render_pass_list; + const RenderPassList& referenced_passes = frame_data->render_pass_list; for (size_t j = 0; j + 1 < referenced_passes.size(); ++j) { const RenderPass& source = *referenced_passes[j]; scoped_ptr<RenderPass> copy_pass(RenderPass::Create()); - RenderPass::Id remapped_pass_id = RemapPassId(source.id, surface_id.id); + RenderPass::Id remapped_pass_id = RemapPassId(source.id, surface_id); copy_pass->SetAll(remapped_pass_id, source.output_rect, @@ -111,13 +180,13 @@ void SurfaceAggregator::HandleSurfaceQuad(const SurfaceDrawQuad* surface_quad, source.shared_quad_state_list, gfx::Transform(), copy_pass.get(), - surface_id.id); + surface_id); dest_pass_list_->push_back(copy_pass.Pass()); } // TODO(jamesr): Clean up last pass special casing. - const RenderPass& last_pass = *referenced_data->render_pass_list.back(); + const RenderPass& last_pass = *frame_data->render_pass_list.back(); const QuadList& quads = last_pass.quad_list; // TODO(jamesr): Make sure clipping is enforced. @@ -125,7 +194,7 @@ void SurfaceAggregator::HandleSurfaceQuad(const SurfaceDrawQuad* surface_quad, last_pass.shared_quad_state_list, surface_quad->quadTransform(), dest_pass, - surface_id.id); + surface_id); referenced_surfaces_.erase(it); } @@ -152,7 +221,7 @@ void SurfaceAggregator::CopyQuadsToPass( const SharedQuadStateList& source_shared_quad_state_list, const gfx::Transform& content_to_target_transform, RenderPass* dest_pass, - int surface_id) { + SurfaceId surface_id) { const SharedQuadState* last_copied_source_shared_quad_state = NULL; for (size_t i = 0, sqs_i = 0; i < source_quad_list.size(); ++i) { @@ -191,7 +260,7 @@ void SurfaceAggregator::CopyQuadsToPass( } void SurfaceAggregator::CopyPasses(const RenderPassList& source_pass_list, - int surface_id) { + SurfaceId surface_id) { for (size_t i = 0; i < source_pass_list.size(); ++i) { const RenderPass& source = *source_pass_list[i]; @@ -217,11 +286,11 @@ void SurfaceAggregator::CopyPasses(const RenderPassList& source_pass_list, scoped_ptr<CompositorFrame> SurfaceAggregator::Aggregate(SurfaceId surface_id) { Surface* surface = manager_->GetSurfaceForId(surface_id); - if (!surface) - return scoped_ptr<CompositorFrame>(); + DCHECK(surface); CompositorFrame* root_surface_frame = surface->GetEligibleFrame(); if (!root_surface_frame) return scoped_ptr<CompositorFrame>(); + TRACE_EVENT0("cc", "SurfaceAggregator::Aggregate"); scoped_ptr<CompositorFrame> frame(new CompositorFrame); frame->delegated_frame_data = make_scoped_ptr(new DelegatedFrameData); @@ -231,10 +300,16 @@ scoped_ptr<CompositorFrame> SurfaceAggregator::Aggregate(SurfaceId surface_id) { const RenderPassList& source_pass_list = root_surface_frame->delegated_frame_data->render_pass_list; - std::set<int>::iterator it = referenced_surfaces_.insert(surface_id.id).first; + SurfaceSet::iterator it = referenced_surfaces_.insert(surface_id).first; + dest_resource_list_ = &frame->delegated_frame_data->resource_list; dest_pass_list_ = &frame->delegated_frame_data->render_pass_list; - CopyPasses(source_pass_list, surface_id.id); + + bool invalid_frame = + TakeResources(surface, root_surface_frame->delegated_frame_data.get()); + DCHECK(!invalid_frame); + + CopyPasses(source_pass_list, surface_id); referenced_surfaces_.erase(it); DCHECK(referenced_surfaces_.empty()); diff --git a/cc/surfaces/surface_aggregator.h b/cc/surfaces/surface_aggregator.h index fe52050..02dc478 100644 --- a/cc/surfaces/surface_aggregator.h +++ b/cc/surfaces/surface_aggregator.h @@ -7,9 +7,11 @@ #include <set> +#include "base/containers/hash_tables.h" #include "base/containers/scoped_ptr_hash_map.h" #include "base/memory/scoped_ptr.h" #include "cc/quads/render_pass.h" +#include "cc/resources/transferable_resource.h" #include "cc/surfaces/surface_id.h" #include "cc/surfaces/surfaces_export.h" @@ -17,20 +19,21 @@ namespace cc { class CompositorFrame; class DelegatedFrameData; +class ResourceProvider; +class Surface; class SurfaceDrawQuad; class SurfaceManager; class CC_SURFACES_EXPORT SurfaceAggregator { public: - explicit SurfaceAggregator(SurfaceManager* manager); + SurfaceAggregator(SurfaceManager* manager, ResourceProvider* provider); ~SurfaceAggregator(); scoped_ptr<CompositorFrame> Aggregate(SurfaceId surface_id); private: - DelegatedFrameData* GetReferencedDataForSurfaceId(SurfaceId surface_id); RenderPass::Id RemapPassId(RenderPass::Id surface_local_pass_id, - int surface_id); + SurfaceId surface_id); void HandleSurfaceQuad(const SurfaceDrawQuad* surface_quad, RenderPass* dest_pass); @@ -41,27 +44,38 @@ class CC_SURFACES_EXPORT SurfaceAggregator { const SharedQuadStateList& source_shared_quad_state_list, const gfx::Transform& content_to_target_transform, RenderPass* dest_pass, - int surface_id); - void CopyPasses(const RenderPassList& source_pass_list, int surface_id); + SurfaceId surface_id); + void CopyPasses(const RenderPassList& source_pass_list, SurfaceId surface_id); + + bool TakeResources(Surface* surface, DelegatedFrameData* frame_data); + int ChildIdForSurface(Surface* surface); SurfaceManager* manager_; + ResourceProvider* provider_; class RenderPassIdAllocator; - typedef base::ScopedPtrHashMap<int, RenderPassIdAllocator> + typedef base::ScopedPtrHashMap<SurfaceId, RenderPassIdAllocator> RenderPassIdAllocatorMap; RenderPassIdAllocatorMap render_pass_allocator_map_; + typedef base::hash_map<SurfaceId, int> SurfaceToResourceChildIdMap; + SurfaceToResourceChildIdMap surface_id_to_resource_child_id_; + // The following state is only valid for the duration of one Aggregate call // and is only stored on the class to avoid having to pass through every // function call. // This is the set of surfaces referenced in the aggregation so far, used to // detect cycles. - std::set<int> referenced_surfaces_; + typedef std::set<SurfaceId> SurfaceSet; + SurfaceSet referenced_surfaces_; // This is the pass list for the aggregated frame. RenderPassList* dest_pass_list_; + // Resource list for the aggregated frame. + TransferableResourceArray* dest_resource_list_; + DISALLOW_COPY_AND_ASSIGN(SurfaceAggregator); }; diff --git a/cc/surfaces/surface_aggregator_test_helpers.cc b/cc/surfaces/surface_aggregator_test_helpers.cc index a653eb1..63a39af 100644 --- a/cc/surfaces/surface_aggregator_test_helpers.cc +++ b/cc/surfaces/surface_aggregator_test_helpers.cc @@ -145,28 +145,5 @@ void TestPassesMatchExpectations(Pass* expected_passes, } } -void SubmitFrame(Pass* passes, size_t pass_count, Surface* surface) { - RenderPassList pass_list; - AddPasses(&pass_list, gfx::Rect(surface->size()), passes, pass_count); - - scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData); - pass_list.swap(frame_data->render_pass_list); - - scoped_ptr<CompositorFrame> frame(new CompositorFrame); - frame->delegated_frame_data = frame_data.Pass(); - - surface->QueueFrame(frame.Pass()); -} - -void QueuePassAsFrame(scoped_ptr<RenderPass> pass, Surface* surface) { - scoped_ptr<DelegatedFrameData> delegated_frame_data(new DelegatedFrameData); - delegated_frame_data->render_pass_list.push_back(pass.Pass()); - - scoped_ptr<CompositorFrame> child_frame(new CompositorFrame); - child_frame->delegated_frame_data = delegated_frame_data.Pass(); - - surface->QueueFrame(child_frame.Pass()); -} - } // namespace test } // namespace cc diff --git a/cc/surfaces/surface_aggregator_test_helpers.h b/cc/surfaces/surface_aggregator_test_helpers.h index 10c5659..75bfaeb 100644 --- a/cc/surfaces/surface_aggregator_test_helpers.h +++ b/cc/surfaces/surface_aggregator_test_helpers.h @@ -85,10 +85,6 @@ void TestPassesMatchExpectations(Pass* expected_passes, size_t expected_pass_count, RenderPassList* passes); -void SubmitFrame(Pass* passes, size_t pass_count, Surface* surface); - -void QueuePassAsFrame(scoped_ptr<RenderPass> pass, Surface* surface); - } // namespace test } // namespace cc diff --git a/cc/surfaces/surface_aggregator_unittest.cc b/cc/surfaces/surface_aggregator_unittest.cc index 62ba079..bf49b57 100644 --- a/cc/surfaces/surface_aggregator_unittest.cc +++ b/cc/surfaces/surface_aggregator_unittest.cc @@ -8,12 +8,18 @@ #include "cc/quads/render_pass_draw_quad.h" #include "cc/quads/solid_color_draw_quad.h" #include "cc/quads/surface_draw_quad.h" +#include "cc/resources/shared_bitmap_manager.h" #include "cc/surfaces/surface.h" #include "cc/surfaces/surface_aggregator.h" #include "cc/surfaces/surface_aggregator_test_helpers.h" +#include "cc/surfaces/surface_factory.h" +#include "cc/surfaces/surface_factory_client.h" #include "cc/surfaces/surface_manager.h" +#include "cc/test/fake_output_surface.h" +#include "cc/test/fake_output_surface_client.h" #include "cc/test/render_pass_test_common.h" #include "cc/test/render_pass_test_utils.h" +#include "cc/test/test_shared_bitmap_manager.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkColor.h" @@ -26,35 +32,54 @@ SurfaceId InvalidSurfaceId() { return invalid; } +gfx::Size SurfaceSize() { + static gfx::Size size(5, 5); + return size; +} + +class EmptySurfaceFactoryClient : public SurfaceFactoryClient { + public: + virtual void ReturnResources( + const ReturnedResourceArray& resources) OVERRIDE {} +}; + class SurfaceAggregatorTest : public testing::Test { public: - SurfaceAggregatorTest() : aggregator_(&manager_) {} + SurfaceAggregatorTest() + : factory_(&manager_, &empty_client_), aggregator_(&manager_, NULL) {} protected: SurfaceManager manager_; + EmptySurfaceFactoryClient empty_client_; + SurfaceFactory factory_; SurfaceAggregator aggregator_; }; -TEST_F(SurfaceAggregatorTest, InvalidSurfaceId) { - scoped_ptr<CompositorFrame> frame = aggregator_.Aggregate(InvalidSurfaceId()); - EXPECT_FALSE(frame); -} - TEST_F(SurfaceAggregatorTest, ValidSurfaceNoFrame) { - Surface one(&manager_, NULL, gfx::Size(5, 5)); - scoped_ptr<CompositorFrame> frame = aggregator_.Aggregate(one.surface_id()); + SurfaceId one_id = factory_.Create(SurfaceSize()); + scoped_ptr<CompositorFrame> frame = aggregator_.Aggregate(one_id); EXPECT_FALSE(frame); + factory_.Destroy(one_id); } class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest { public: - SurfaceAggregatorValidSurfaceTest() - : root_surface_(&manager_, NULL, gfx::Size(5, 5)) {} + SurfaceAggregatorValidSurfaceTest() {} + + virtual void SetUp() { + SurfaceAggregatorTest::SetUp(); + root_surface_id_ = factory_.Create(SurfaceSize()); + } + + virtual void TearDown() { + factory_.Destroy(root_surface_id_); + SurfaceAggregatorTest::TearDown(); + } void AggregateAndVerify(test::Pass* expected_passes, size_t expected_pass_count) { scoped_ptr<CompositorFrame> aggregated_frame = - aggregator_.Aggregate(root_surface_.surface_id()); + aggregator_.Aggregate(root_surface_id_); ASSERT_TRUE(aggregated_frame); ASSERT_TRUE(aggregated_frame->delegated_frame_data); @@ -66,8 +91,33 @@ class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest { expected_passes, expected_pass_count, &frame_data->render_pass_list); } + void SubmitFrame(test::Pass* passes, + size_t pass_count, + SurfaceId surface_id) { + RenderPassList pass_list; + AddPasses(&pass_list, gfx::Rect(SurfaceSize()), passes, pass_count); + + scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData); + pass_list.swap(frame_data->render_pass_list); + + scoped_ptr<CompositorFrame> frame(new CompositorFrame); + frame->delegated_frame_data = frame_data.Pass(); + + factory_.SubmitFrame(surface_id, frame.Pass()); + } + + void QueuePassAsFrame(scoped_ptr<RenderPass> pass, SurfaceId surface_id) { + scoped_ptr<DelegatedFrameData> delegated_frame_data(new DelegatedFrameData); + delegated_frame_data->render_pass_list.push_back(pass.Pass()); + + scoped_ptr<CompositorFrame> child_frame(new CompositorFrame); + child_frame->delegated_frame_data = delegated_frame_data.Pass(); + + factory_.SubmitFrame(surface_id, child_frame.Pass()); + } + protected: - Surface root_surface_; + SurfaceId root_surface_id_; }; // Tests that a very simple frame containing only two solid color quads makes it @@ -77,7 +127,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleFrame) { test::Quad::SolidColorQuad(SK_ColorBLUE)}; test::Pass passes[] = {test::Pass(quads, arraysize(quads))}; - SubmitFrame(passes, arraysize(passes), &root_surface_); + SubmitFrame(passes, arraysize(passes), root_surface_id_); AggregateAndVerify(passes, arraysize(passes)); } @@ -90,7 +140,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSimpleFrame) { test::Pass passes[] = {test::Pass(quads[0], arraysize(quads[0])), test::Pass(quads[1], arraysize(quads[1]))}; - SubmitFrame(passes, arraysize(passes), &root_surface_); + SubmitFrame(passes, arraysize(passes), root_surface_id_); AggregateAndVerify(passes, arraysize(passes)); } @@ -100,23 +150,20 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSimpleFrame) { // embedded_surface has a frame containing only a solid color quad. The solid // color quad should be aggregated into the final frame. TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleSurfaceReference) { - gfx::Size surface_size(5, 5); - - Surface embedded_surface(&manager_, NULL, surface_size); + SurfaceId embedded_surface_id = factory_.Create(SurfaceSize()); test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)}; test::Pass embedded_passes[] = { test::Pass(embedded_quads, arraysize(embedded_quads))}; - SubmitFrame(embedded_passes, arraysize(embedded_passes), &embedded_surface); + SubmitFrame(embedded_passes, arraysize(embedded_passes), embedded_surface_id); - test::Quad root_quads[] = { - test::Quad::SolidColorQuad(SK_ColorWHITE), - test::Quad::SurfaceQuad(embedded_surface.surface_id()), - test::Quad::SolidColorQuad(SK_ColorBLACK)}; + test::Quad root_quads[] = {test::Quad::SolidColorQuad(SK_ColorWHITE), + test::Quad::SurfaceQuad(embedded_surface_id), + test::Quad::SolidColorQuad(SK_ColorBLACK)}; test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))}; - SubmitFrame(root_passes, arraysize(root_passes), &root_surface_); + SubmitFrame(root_passes, arraysize(root_passes), root_surface_id_); test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorWHITE), test::Quad::SolidColorQuad(SK_ColorGREEN), @@ -124,13 +171,13 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleSurfaceReference) { test::Pass expected_passes[] = { test::Pass(expected_quads, arraysize(expected_quads))}; AggregateAndVerify(expected_passes, arraysize(expected_passes)); + + factory_.Destroy(embedded_surface_id); } // This tests referencing a surface that has multiple render passes. TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSurfaceReference) { - gfx::Size surface_size(5, 5); - - Surface embedded_surface(&manager_, NULL, surface_size); + SurfaceId embedded_surface_id = factory_.Create(SurfaceSize()); RenderPass::Id pass_ids[] = {RenderPass::Id(1, 1), RenderPass::Id(1, 2), RenderPass::Id(1, 3)}; @@ -144,11 +191,11 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSurfaceReference) { test::Pass(embedded_quads[1], arraysize(embedded_quads[1]), pass_ids[1]), test::Pass(embedded_quads[2], arraysize(embedded_quads[2]), pass_ids[2])}; - SubmitFrame(embedded_passes, arraysize(embedded_passes), &embedded_surface); + SubmitFrame(embedded_passes, arraysize(embedded_passes), embedded_surface_id); test::Quad root_quads[][2] = { {test::Quad::SolidColorQuad(5), test::Quad::SolidColorQuad(6)}, - {test::Quad::SurfaceQuad(embedded_surface.surface_id()), + {test::Quad::SurfaceQuad(embedded_surface_id), test::Quad::RenderPassQuad(pass_ids[0])}, {test::Quad::SolidColorQuad(7), test::Quad::RenderPassQuad(pass_ids[1])}}; test::Pass root_passes[] = { @@ -156,10 +203,10 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSurfaceReference) { test::Pass(root_quads[1], arraysize(root_quads[1]), pass_ids[1]), test::Pass(root_quads[2], arraysize(root_quads[2]), pass_ids[2])}; - SubmitFrame(root_passes, arraysize(root_passes), &root_surface_); + SubmitFrame(root_passes, arraysize(root_passes), root_surface_id_); scoped_ptr<CompositorFrame> aggregated_frame = - aggregator_.Aggregate(root_surface_.surface_id()); + aggregator_.Aggregate(root_surface_id_); ASSERT_TRUE(aggregated_frame); ASSERT_TRUE(aggregated_frame->delegated_frame_data); @@ -257,6 +304,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSurfaceReference) { EXPECT_EQ(actual_pass_ids[3], fifth_pass_render_pass_draw_quad->render_pass_id); } + factory_.Destroy(embedded_surface_id); } // Tests an invalid surface reference in a frame. The surface quad should just @@ -267,7 +315,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, InvalidSurfaceReference) { test::Quad::SolidColorQuad(SK_ColorBLUE)}; test::Pass passes[] = {test::Pass(quads, arraysize(quads))}; - SubmitFrame(passes, arraysize(passes), &root_surface_); + SubmitFrame(passes, arraysize(passes), root_surface_id_); test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN), test::Quad::SolidColorQuad(SK_ColorBLUE)}; @@ -279,30 +327,30 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, InvalidSurfaceReference) { // Tests a reference to a valid surface with no submitted frame. This quad // should also just be dropped. TEST_F(SurfaceAggregatorValidSurfaceTest, ValidSurfaceReferenceWithNoFrame) { - Surface surface_with_no_frame(&manager_, NULL, gfx::Size(5, 5)); - test::Quad quads[] = { - test::Quad::SolidColorQuad(SK_ColorGREEN), - test::Quad::SurfaceQuad(surface_with_no_frame.surface_id()), - test::Quad::SolidColorQuad(SK_ColorBLUE)}; + SurfaceId surface_with_no_frame_id = factory_.Create(gfx::Size(5, 5)); + test::Quad quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN), + test::Quad::SurfaceQuad(surface_with_no_frame_id), + test::Quad::SolidColorQuad(SK_ColorBLUE)}; test::Pass passes[] = {test::Pass(quads, arraysize(quads))}; - SubmitFrame(passes, arraysize(passes), &root_surface_); + SubmitFrame(passes, arraysize(passes), root_surface_id_); test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN), test::Quad::SolidColorQuad(SK_ColorBLUE)}; test::Pass expected_passes[] = { test::Pass(expected_quads, arraysize(expected_quads))}; AggregateAndVerify(expected_passes, arraysize(expected_passes)); + factory_.Destroy(surface_with_no_frame_id); } // Tests a surface quad referencing itself, generating a trivial cycle. // The quad creating the cycle should be dropped from the final frame. TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleCyclicalReference) { - test::Quad quads[] = {test::Quad::SurfaceQuad(root_surface_.surface_id()), + test::Quad quads[] = {test::Quad::SurfaceQuad(root_surface_id_), test::Quad::SolidColorQuad(SK_ColorYELLOW)}; test::Pass passes[] = {test::Pass(quads, arraysize(quads))}; - SubmitFrame(passes, arraysize(passes), &root_surface_); + SubmitFrame(passes, arraysize(passes), root_surface_id_); test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorYELLOW)}; test::Pass expected_passes[] = { @@ -312,26 +360,22 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleCyclicalReference) { // Tests a more complex cycle with one intermediate surface. TEST_F(SurfaceAggregatorValidSurfaceTest, TwoSurfaceCyclicalReference) { - gfx::Size surface_size(5, 5); - - Surface child_surface(&manager_, NULL, surface_size); + SurfaceId child_surface_id = factory_.Create(SurfaceSize()); - test::Quad parent_quads[] = { - test::Quad::SolidColorQuad(SK_ColorBLUE), - test::Quad::SurfaceQuad(child_surface.surface_id()), - test::Quad::SolidColorQuad(SK_ColorCYAN)}; + test::Quad parent_quads[] = {test::Quad::SolidColorQuad(SK_ColorBLUE), + test::Quad::SurfaceQuad(child_surface_id), + test::Quad::SolidColorQuad(SK_ColorCYAN)}; test::Pass parent_passes[] = { test::Pass(parent_quads, arraysize(parent_quads))}; - SubmitFrame(parent_passes, arraysize(parent_passes), &root_surface_); + SubmitFrame(parent_passes, arraysize(parent_passes), root_surface_id_); - test::Quad child_quads[] = { - test::Quad::SolidColorQuad(SK_ColorGREEN), - test::Quad::SurfaceQuad(root_surface_.surface_id()), - test::Quad::SolidColorQuad(SK_ColorMAGENTA)}; + test::Quad child_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN), + test::Quad::SurfaceQuad(root_surface_id_), + test::Quad::SolidColorQuad(SK_ColorMAGENTA)}; test::Pass child_passes[] = {test::Pass(child_quads, arraysize(child_quads))}; - SubmitFrame(child_passes, arraysize(child_passes), &child_surface); + SubmitFrame(child_passes, arraysize(child_passes), child_surface_id); // The child surface's reference to the root_surface_ will be dropped, so // we'll end up with: @@ -346,14 +390,13 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, TwoSurfaceCyclicalReference) { test::Pass expected_passes[] = { test::Pass(expected_quads, arraysize(expected_quads))}; AggregateAndVerify(expected_passes, arraysize(expected_passes)); + factory_.Destroy(child_surface_id); } // Tests that we map render pass IDs from different surfaces into a unified // namespace and update RenderPassDrawQuad's id references to match. TEST_F(SurfaceAggregatorValidSurfaceTest, RenderPassIdMapping) { - gfx::Size surface_size(5, 5); - - Surface child_surface(&manager_, NULL, surface_size); + SurfaceId child_surface_id = factory_.Create(SurfaceSize()); RenderPass::Id child_pass_id[] = {RenderPass::Id(1, 1), RenderPass::Id(1, 2)}; test::Quad child_quad[][1] = {{test::Quad::SolidColorQuad(SK_ColorGREEN)}, @@ -362,21 +405,21 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, RenderPassIdMapping) { test::Pass(child_quad[0], arraysize(child_quad[0]), child_pass_id[0]), test::Pass(child_quad[1], arraysize(child_quad[1]), child_pass_id[1])}; - SubmitFrame(surface_passes, arraysize(surface_passes), &child_surface); + SubmitFrame(surface_passes, arraysize(surface_passes), child_surface_id); // Pass IDs from the parent surface may collide with ones from the child. RenderPass::Id parent_pass_id[] = {RenderPass::Id(2, 1), RenderPass::Id(1, 2)}; test::Quad parent_quad[][1] = { - {test::Quad::SurfaceQuad(child_surface.surface_id())}, + {test::Quad::SurfaceQuad(child_surface_id)}, {test::Quad::RenderPassQuad(parent_pass_id[0])}}; test::Pass parent_passes[] = { test::Pass(parent_quad[0], arraysize(parent_quad[0]), parent_pass_id[0]), test::Pass(parent_quad[1], arraysize(parent_quad[1]), parent_pass_id[1])}; - SubmitFrame(parent_passes, arraysize(parent_passes), &root_surface_); + SubmitFrame(parent_passes, arraysize(parent_passes), root_surface_id_); scoped_ptr<CompositorFrame> aggregated_frame = - aggregator_.Aggregate(root_surface_.surface_id()); + aggregator_.Aggregate(root_surface_id_); ASSERT_TRUE(aggregated_frame); ASSERT_TRUE(aggregated_frame->delegated_frame_data); @@ -409,6 +452,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, RenderPassIdMapping) { EXPECT_EQ( actual_pass_ids[1], RenderPassDrawQuad::MaterialCast(render_pass_quads[1])->render_pass_id); + factory_.Destroy(child_surface_id); } void AddSolidColorQuadWithBlendMode(const gfx::Size& size, @@ -470,8 +514,6 @@ void AddSolidColorQuadWithBlendMode(const gfx::Size& size, // quad_child_two_0 - blend_mode kSrcIn_Mode // quad_root_2 - blend_mode kDstIn_Mode TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) { - gfx::Size surface_size(5, 5); - const SkXfermode::Mode blend_modes[] = {SkXfermode::kClear_Mode, // 0 SkXfermode::kSrc_Mode, // 1 SkXfermode::kDst_Mode, // 2 @@ -482,71 +524,74 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) { }; RenderPass::Id pass_id(1, 1); - Surface grandchild_surface(&manager_, NULL, surface_size); + SurfaceId grandchild_surface_id = factory_.Create(SurfaceSize()); scoped_ptr<RenderPass> grandchild_pass = RenderPass::Create(); - gfx::Rect output_rect(surface_size); - gfx::Rect damage_rect(surface_size); + gfx::Rect output_rect(SurfaceSize()); + gfx::Rect damage_rect(SurfaceSize()); gfx::Transform transform_to_root_target; grandchild_pass->SetNew( pass_id, output_rect, damage_rect, transform_to_root_target); AddSolidColorQuadWithBlendMode( - surface_size, grandchild_pass.get(), blend_modes[2]); - test::QueuePassAsFrame(grandchild_pass.Pass(), &grandchild_surface); + SurfaceSize(), grandchild_pass.get(), blend_modes[2]); + QueuePassAsFrame(grandchild_pass.Pass(), grandchild_surface_id); - Surface child_one_surface(&manager_, NULL, surface_size); + SurfaceId child_one_surface_id = factory_.Create(SurfaceSize()); scoped_ptr<RenderPass> child_one_pass = RenderPass::Create(); child_one_pass->SetNew( pass_id, output_rect, damage_rect, transform_to_root_target); AddSolidColorQuadWithBlendMode( - surface_size, child_one_pass.get(), blend_modes[1]); + SurfaceSize(), child_one_pass.get(), blend_modes[1]); scoped_ptr<SurfaceDrawQuad> grandchild_surface_quad = SurfaceDrawQuad::Create(); grandchild_surface_quad->SetNew(child_one_pass->shared_quad_state_list.back(), - gfx::Rect(surface_size), - gfx::Rect(surface_size), - grandchild_surface.surface_id()); + gfx::Rect(SurfaceSize()), + gfx::Rect(SurfaceSize()), + grandchild_surface_id); child_one_pass->quad_list.push_back( grandchild_surface_quad.PassAs<DrawQuad>()); AddSolidColorQuadWithBlendMode( - surface_size, child_one_pass.get(), blend_modes[3]); - test::QueuePassAsFrame(child_one_pass.Pass(), &child_one_surface); + SurfaceSize(), child_one_pass.get(), blend_modes[3]); + QueuePassAsFrame(child_one_pass.Pass(), child_one_surface_id); - Surface child_two_surface(&manager_, NULL, surface_size); + SurfaceId child_two_surface_id = factory_.Create(SurfaceSize()); scoped_ptr<RenderPass> child_two_pass = RenderPass::Create(); child_two_pass->SetNew( pass_id, output_rect, damage_rect, transform_to_root_target); AddSolidColorQuadWithBlendMode( - surface_size, child_two_pass.get(), blend_modes[5]); - test::QueuePassAsFrame(child_two_pass.Pass(), &child_two_surface); + SurfaceSize(), child_two_pass.get(), blend_modes[5]); + QueuePassAsFrame(child_two_pass.Pass(), child_two_surface_id); scoped_ptr<RenderPass> root_pass = RenderPass::Create(); root_pass->SetNew( pass_id, output_rect, damage_rect, transform_to_root_target); - AddSolidColorQuadWithBlendMode(surface_size, root_pass.get(), blend_modes[0]); + AddSolidColorQuadWithBlendMode( + SurfaceSize(), root_pass.get(), blend_modes[0]); scoped_ptr<SurfaceDrawQuad> child_one_surface_quad = SurfaceDrawQuad::Create(); child_one_surface_quad->SetNew(root_pass->shared_quad_state_list.back(), - gfx::Rect(surface_size), - gfx::Rect(surface_size), - child_one_surface.surface_id()); + gfx::Rect(SurfaceSize()), + gfx::Rect(SurfaceSize()), + child_one_surface_id); root_pass->quad_list.push_back(child_one_surface_quad.PassAs<DrawQuad>()); - AddSolidColorQuadWithBlendMode(surface_size, root_pass.get(), blend_modes[4]); + AddSolidColorQuadWithBlendMode( + SurfaceSize(), root_pass.get(), blend_modes[4]); scoped_ptr<SurfaceDrawQuad> child_two_surface_quad = SurfaceDrawQuad::Create(); child_two_surface_quad->SetNew(root_pass->shared_quad_state_list.back(), - gfx::Rect(surface_size), - gfx::Rect(surface_size), - child_two_surface.surface_id()); + gfx::Rect(SurfaceSize()), + gfx::Rect(SurfaceSize()), + child_two_surface_id); root_pass->quad_list.push_back(child_two_surface_quad.PassAs<DrawQuad>()); - AddSolidColorQuadWithBlendMode(surface_size, root_pass.get(), blend_modes[6]); + AddSolidColorQuadWithBlendMode( + SurfaceSize(), root_pass.get(), blend_modes[6]); - test::QueuePassAsFrame(root_pass.Pass(), &root_surface_); + QueuePassAsFrame(root_pass.Pass(), root_surface_id_); scoped_ptr<CompositorFrame> aggregated_frame = - aggregator_.Aggregate(root_surface_.surface_id()); + aggregator_.Aggregate(root_surface_id_); ASSERT_TRUE(aggregated_frame); ASSERT_TRUE(aggregated_frame->delegated_frame_data); @@ -565,6 +610,9 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) { DrawQuad* quad = aggregated_quad_list[i]; EXPECT_EQ(blend_modes[i], quad->shared_quad_state->blend_mode) << i; } + factory_.Destroy(child_one_surface_id); + factory_.Destroy(child_two_surface_id); + factory_.Destroy(grandchild_surface_id); } // This tests that when aggregating a frame with multiple render passes that we @@ -583,9 +631,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) { // contributing render pass' transform in the aggregate frame should not be // affected. TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) { - gfx::Size surface_size(5, 5); - - Surface child_surface(&manager_, NULL, surface_size); + SurfaceId child_surface_id = factory_.Create(SurfaceSize()); RenderPass::Id child_pass_id[] = {RenderPass::Id(1, 1), RenderPass::Id(1, 2)}; test::Quad child_quads[][1] = { {test::Quad::SolidColorQuad(SK_ColorGREEN)}, @@ -596,7 +642,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) { RenderPassList child_pass_list; AddPasses(&child_pass_list, - gfx::Rect(surface_size), + gfx::Rect(SurfaceSize()), child_passes, arraysize(child_passes)); @@ -617,16 +663,15 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) { scoped_ptr<CompositorFrame> child_frame(new CompositorFrame); child_frame->delegated_frame_data = child_frame_data.Pass(); - child_surface.QueueFrame(child_frame.Pass()); + factory_.SubmitFrame(child_surface_id, child_frame.Pass()); - test::Quad root_quads[] = { - test::Quad::SolidColorQuad(1), - test::Quad::SurfaceQuad(child_surface.surface_id())}; + test::Quad root_quads[] = {test::Quad::SolidColorQuad(1), + test::Quad::SurfaceQuad(child_surface_id)}; test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))}; RenderPassList root_pass_list; AddPasses(&root_pass_list, - gfx::Rect(surface_size), + gfx::Rect(SurfaceSize()), root_passes, arraysize(root_passes)); @@ -643,10 +688,10 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) { scoped_ptr<CompositorFrame> root_frame(new CompositorFrame); root_frame->delegated_frame_data = root_frame_data.Pass(); - root_surface_.QueueFrame(root_frame.Pass()); + factory_.SubmitFrame(root_surface_id_, root_frame.Pass()); scoped_ptr<CompositorFrame> aggregated_frame = - aggregator_.Aggregate(root_surface_.surface_id()); + aggregator_.Aggregate(root_surface_id_); ASSERT_TRUE(aggregated_frame); ASSERT_TRUE(aggregated_frame->delegated_frame_data); @@ -701,6 +746,119 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) { quad->quadTransform().ToString()) << i; } + factory_.Destroy(child_surface_id); +} + +class ResourceTestDrawQuad : public DrawQuad { + public: + explicit ResourceTestDrawQuad(unsigned resource) : resource_(resource) { + material = DrawQuad::TEXTURE_CONTENT; + } + virtual ~ResourceTestDrawQuad() {} + + virtual void IterateResources( + const ResourceIteratorCallback& callback) OVERRIDE { + callback.Run(resource_); + } + + virtual void ExtendValue(base::DictionaryValue* value) const OVERRIDE {} + + private: + unsigned resource_; +}; + +class SurfaceAggregatorWithResourcesTest : public testing::Test { + public: + virtual void SetUp() { + output_surface_ = FakeOutputSurface::CreateSoftware( + make_scoped_ptr(new SoftwareOutputDevice)); + output_surface_->BindToClient(&output_surface_client_); + shared_bitmap_manager_.reset(new TestSharedBitmapManager); + + resource_provider_ = ResourceProvider::Create(output_surface_.get(), + shared_bitmap_manager_.get(), + 0, + false, + 1, + false); + + aggregator_.reset( + new SurfaceAggregator(&manager_, resource_provider_.get())); + } + + protected: + SurfaceManager manager_; + FakeOutputSurfaceClient output_surface_client_; + scoped_ptr<OutputSurface> output_surface_; + scoped_ptr<SharedBitmapManager> shared_bitmap_manager_; + scoped_ptr<ResourceProvider> resource_provider_; + scoped_ptr<SurfaceAggregator> aggregator_; +}; + +class ResourceTrackingSurfaceFactoryClient : public SurfaceFactoryClient { + public: + ResourceTrackingSurfaceFactoryClient() {} + virtual ~ResourceTrackingSurfaceFactoryClient() {} + + virtual void ReturnResources( + const ReturnedResourceArray& resources) OVERRIDE { + returned_resources_ = resources; + } + + ReturnedResourceArray returned_resources() const { + return returned_resources_; + } + + private: + ReturnedResourceArray returned_resources_; + + DISALLOW_COPY_AND_ASSIGN(ResourceTrackingSurfaceFactoryClient); +}; + +void SubmitFrameWithResources(ResourceProvider::ResourceId* resource_ids, + size_t num_resource_ids, + SurfaceFactory* factory, + SurfaceId surface_id) { + scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData); + scoped_ptr<RenderPass> pass = RenderPass::Create(); + SharedQuadState* sqs = pass->CreateAndAppendSharedQuadState(); + for (size_t i = 0u; i < num_resource_ids; ++i) { + TransferableResource resource; + resource.id = resource_ids[i]; + resource.is_software = true; + frame_data->resource_list.push_back(resource); + scoped_ptr<DrawQuad> quad(new ResourceTestDrawQuad(resource_ids[i])); + quad->shared_quad_state = sqs; + pass->quad_list.push_back(quad.Pass()); + } + frame_data->render_pass_list.push_back(pass.Pass()); + scoped_ptr<CompositorFrame> frame(new CompositorFrame); + frame->delegated_frame_data = frame_data.Pass(); + factory->SubmitFrame(surface_id, frame.Pass()); +} + +TEST_F(SurfaceAggregatorWithResourcesTest, TakeResourcesOneSurface) { + ResourceTrackingSurfaceFactoryClient client; + SurfaceFactory factory(&manager_, &client); + SurfaceId surface_id = factory.Create(SurfaceSize()); + + ResourceProvider::ResourceId ids[] = {11, 12, 13}; + SubmitFrameWithResources(ids, arraysize(ids), &factory, surface_id); + + scoped_ptr<CompositorFrame> frame = aggregator_->Aggregate(surface_id); + + // Nothing should be available to be returned yet. + EXPECT_TRUE(client.returned_resources().empty()); + + SubmitFrameWithResources(NULL, 0u, &factory, surface_id); + + frame = aggregator_->Aggregate(surface_id); + + ASSERT_EQ(3u, client.returned_resources().size()); + for (size_t i = 0; i < 3; ++i) { + EXPECT_EQ(ids[i], client.returned_resources()[i].id); + } + factory.Destroy(surface_id); } } // namespace diff --git a/cc/surfaces/surface_factory.cc b/cc/surfaces/surface_factory.cc new file mode 100644 index 0000000..09c9f45 --- /dev/null +++ b/cc/surfaces/surface_factory.cc @@ -0,0 +1,59 @@ +// Copyright 2014 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/surfaces/surface_factory.h" + +#include "cc/output/compositor_frame.h" +#include "cc/surfaces/surface.h" +#include "cc/surfaces/surface_manager.h" +#include "ui/gfx/geometry/size.h" + +namespace cc { +SurfaceFactory::SurfaceFactory(SurfaceManager* manager, + SurfaceFactoryClient* client) + : manager_(manager), client_(client), holder_(client) { +} + +SurfaceFactory::~SurfaceFactory() { + DCHECK_EQ(0u, surface_map_.size()); +} + +SurfaceId SurfaceFactory::Create(const gfx::Size& size) { + SurfaceId id = manager_->AllocateId(); + scoped_ptr<Surface> surface(new Surface(id, size, this)); + manager_->RegisterSurface(surface.get()); + surface_map_.add(id, surface.Pass()); + return id; +} + +void SurfaceFactory::Destroy(SurfaceId surface_id) { + OwningSurfaceMap::iterator it = surface_map_.find(surface_id); + DCHECK(it != surface_map_.end()); + DCHECK(it->second->factory() == this); + manager_->DeregisterSurface(surface_id); + surface_map_.erase(it); +} + +void SurfaceFactory::SubmitFrame(SurfaceId surface_id, + scoped_ptr<CompositorFrame> frame) { + OwningSurfaceMap::iterator it = surface_map_.find(surface_id); + DCHECK(it != surface_map_.end()); + DCHECK(it->second->factory() == this); + it->second->QueueFrame(frame.Pass()); +} + +void SurfaceFactory::ReceiveFromChild( + const TransferableResourceArray& resources) { + holder_.ReceiveFromChild(resources); +} + +void SurfaceFactory::RefResources(const TransferableResourceArray& resources) { + holder_.RefResources(resources); +} + +void SurfaceFactory::UnrefResources(const ReturnedResourceArray& resources) { + holder_.UnrefResources(resources); +} + +} // namespace cc diff --git a/cc/surfaces/surface_factory.h b/cc/surfaces/surface_factory.h new file mode 100644 index 0000000..5ea85d4 --- /dev/null +++ b/cc/surfaces/surface_factory.h @@ -0,0 +1,61 @@ +// Copyright 2014 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_SURFACES_SURFACE_FACTORY_H_ +#define CC_SURFACES_SURFACE_FACTORY_H_ + +#include "base/containers/scoped_ptr_hash_map.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "cc/surfaces/surface_id.h" +#include "cc/surfaces/surface_resource_holder.h" +#include "cc/surfaces/surfaces_export.h" + +namespace gfx { +class Size; +} + +namespace cc { +class CompositorFrame; +class Surface; +class SurfaceFactoryClient; +class SurfaceManager; + +// A SurfaceFactory is used to create surfaces that may share resources and +// receive returned resources for frames submitted to those surfaces. Resources +// submitted to frames created by a particular factory will be returned to that +// factory's client when they are no longer being used. This is the only class +// most users of surfaces will need to directly interact with. +class CC_SURFACES_EXPORT SurfaceFactory + : public base::SupportsWeakPtr<SurfaceFactory> { + public: + SurfaceFactory(SurfaceManager* manager, SurfaceFactoryClient* client); + ~SurfaceFactory(); + + SurfaceId Create(const gfx::Size& size); + void Destroy(SurfaceId surface_id); + // A frame can only be submitted to a surface created by this factory, + // although the frame may reference surfaces created by other factories. + void SubmitFrame(SurfaceId surface_id, scoped_ptr<CompositorFrame> frame); + + SurfaceFactoryClient* client() { return client_; } + + void ReceiveFromChild(const TransferableResourceArray& resources); + void RefResources(const TransferableResourceArray& resources); + void UnrefResources(const ReturnedResourceArray& resources); + + private: + SurfaceManager* manager_; + SurfaceFactoryClient* client_; + typedef base::ScopedPtrHashMap<SurfaceId, Surface> OwningSurfaceMap; + base::ScopedPtrHashMap<SurfaceId, Surface> surface_map_; + + SurfaceResourceHolder holder_; + + DISALLOW_COPY_AND_ASSIGN(SurfaceFactory); +}; + +} // namespace cc + +#endif // CC_SURFACES_SURFACE_FACTORY_H_ diff --git a/cc/surfaces/surface_client.h b/cc/surfaces/surface_factory_client.h index 8875872..9866b27 100644 --- a/cc/surfaces/surface_client.h +++ b/cc/surfaces/surface_factory_client.h @@ -2,21 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CC_SURFACES_SURFACE_CLIENT_H_ -#define CC_SURFACES_SURFACE_CLIENT_H_ +#ifndef CC_SURFACES_SURFACE_FACTORY_CLIENT_H_ +#define CC_SURFACES_SURFACE_FACTORY_CLIENT_H_ #include "cc/resources/returned_resource.h" #include "cc/surfaces/surfaces_export.h" namespace cc { -class CC_SURFACES_EXPORT SurfaceClient { +class CC_SURFACES_EXPORT SurfaceFactoryClient { public: - virtual ~SurfaceClient() {} + virtual ~SurfaceFactoryClient() {} virtual void ReturnResources(const ReturnedResourceArray& resources) = 0; }; } // namespace cc -#endif // CC_SURFACES_SURFACE_CLIENT_H_ +#endif // CC_SURFACES_SURFACE_FACTORY_CLIENT_H_ diff --git a/cc/surfaces/surface_factory_unittest.cc b/cc/surfaces/surface_factory_unittest.cc new file mode 100644 index 0000000..f6244e8 --- /dev/null +++ b/cc/surfaces/surface_factory_unittest.cc @@ -0,0 +1,360 @@ +// Copyright 2014 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/output/compositor_frame.h" +#include "cc/output/delegated_frame_data.h" +#include "cc/surfaces/surface.h" +#include "cc/surfaces/surface_factory.h" +#include "cc/surfaces/surface_factory_client.h" +#include "cc/surfaces/surface_manager.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/size.h" + +namespace cc { +namespace { + +class TestSurfaceFactoryClient : public SurfaceFactoryClient { + public: + TestSurfaceFactoryClient() {} + virtual ~TestSurfaceFactoryClient() {} + + virtual void ReturnResources( + const ReturnedResourceArray& resources) OVERRIDE { + returned_resources_.insert( + returned_resources_.end(), resources.begin(), resources.end()); + } + + const ReturnedResourceArray& returned_resources() const { + return returned_resources_; + } + + void clear_returned_resources() { returned_resources_.clear(); } + + private: + ReturnedResourceArray returned_resources_; + + DISALLOW_COPY_AND_ASSIGN(TestSurfaceFactoryClient); +}; + +class SurfaceFactoryTest : public testing::Test { + public: + SurfaceFactoryTest() + : factory_(&manager_, &client_), + surface_id_(factory_.Create(gfx::Size(5, 5))) {} + + virtual ~SurfaceFactoryTest() { factory_.Destroy(surface_id_); } + + void SubmitFrameWithResources(ResourceProvider::ResourceId* resource_ids, + size_t num_resource_ids) { + scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData); + for (size_t i = 0u; i < num_resource_ids; ++i) { + TransferableResource resource; + resource.id = resource_ids[i]; + resource.mailbox_holder.texture_target = GL_TEXTURE_2D; + frame_data->resource_list.push_back(resource); + } + scoped_ptr<CompositorFrame> frame(new CompositorFrame); + frame->delegated_frame_data = frame_data.Pass(); + factory_.SubmitFrame(surface_id_, frame.Pass()); + } + + void UnrefResources(ResourceProvider::ResourceId* ids_to_unref, + int* counts_to_unref, + size_t num_ids_to_unref) { + ReturnedResourceArray unref_array; + for (size_t i = 0; i < num_ids_to_unref; ++i) { + ReturnedResource resource; + resource.id = ids_to_unref[i]; + resource.count = counts_to_unref[i]; + unref_array.push_back(resource); + } + factory_.UnrefResources(unref_array); + } + + void CheckReturnedResourcesMatchExpected( + ResourceProvider::ResourceId* expected_returned_ids, + int* expected_returned_counts, + size_t expected_resources) { + const ReturnedResourceArray& actual_resources = + client_.returned_resources(); + ASSERT_EQ(expected_resources, actual_resources.size()); + for (size_t i = 0; i < expected_resources; ++i) { + ReturnedResource resource = actual_resources[i]; + EXPECT_EQ(expected_returned_ids[i], resource.id); + EXPECT_EQ(expected_returned_counts[i], resource.count); + } + client_.clear_returned_resources(); + } + + void RefCurrentFrameResources() { + Surface* surface = manager_.GetSurfaceForId(surface_id_); + factory_.RefResources( + surface->GetEligibleFrame()->delegated_frame_data->resource_list); + } + + protected: + SurfaceManager manager_; + TestSurfaceFactoryClient client_; + SurfaceFactory factory_; + SurfaceId surface_id_; +}; + +// Tests submitting a frame with resources followed by one with no resources +// with no resource provider action in between. +TEST_F(SurfaceFactoryTest, ResourceLifetimeSimple) { + ResourceProvider::ResourceId first_frame_ids[] = {1, 2, 3}; + SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids)); + + // All of the resources submitted in the first frame are still in use at this + // time by virtue of being in the pending frame, so none can be returned to + // the client yet. + EXPECT_EQ(0u, client_.returned_resources().size()); + client_.clear_returned_resources(); + + // The second frame references no resources and thus should make all resources + // available to be returned. + SubmitFrameWithResources(NULL, 0); + + ResourceProvider::ResourceId expected_returned_ids[] = {1, 2, 3}; + int expected_returned_counts[] = {1, 1, 1}; + CheckReturnedResourcesMatchExpected(expected_returned_ids, + expected_returned_counts, + arraysize(expected_returned_counts)); +} + +// Tests submitting a frame with resources followed by one with no resources +// with the resource provider holding everything alive. +TEST_F(SurfaceFactoryTest, ResourceLifetimeSimpleWithProviderHoldingAlive) { + ResourceProvider::ResourceId first_frame_ids[] = {1, 2, 3}; + SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids)); + + // All of the resources submitted in the first frame are still in use at this + // time by virtue of being in the pending frame, so none can be returned to + // the client yet. + EXPECT_EQ(0u, client_.returned_resources().size()); + client_.clear_returned_resources(); + + // Hold on to everything. + RefCurrentFrameResources(); + + // The second frame references no resources and thus should make all resources + // available to be returned as soon as the resource provider releases them. + SubmitFrameWithResources(NULL, 0); + + EXPECT_EQ(0u, client_.returned_resources().size()); + client_.clear_returned_resources(); + + int release_counts[] = {1, 1, 1}; + UnrefResources(first_frame_ids, release_counts, arraysize(first_frame_ids)); + + ResourceProvider::ResourceId expected_returned_ids[] = {1, 2, 3}; + int expected_returned_counts[] = {1, 1, 1}; + CheckReturnedResourcesMatchExpected(expected_returned_ids, + expected_returned_counts, + arraysize(expected_returned_counts)); +} + +// Tests referencing a resource, unref'ing it to zero, then using it again +// before returning it to the client. +TEST_F(SurfaceFactoryTest, ResourceReusedBeforeReturn) { + ResourceProvider::ResourceId first_frame_ids[] = {7}; + SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids)); + + // This removes all references to resource id 7. + SubmitFrameWithResources(NULL, 0); + + // This references id 7 again. + SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids)); + + // This removes it again. + SubmitFrameWithResources(NULL, 0); + + // Now it should be returned. + // We don't care how many entries are in the returned array for 7, so long as + // the total returned count matches the submitted count. + const ReturnedResourceArray& returned = client_.returned_resources(); + size_t return_count = 0; + for (size_t i = 0; i < returned.size(); ++i) { + EXPECT_EQ(7u, returned[i].id); + return_count += returned[i].count; + } + EXPECT_EQ(2u, return_count); +} + +// Tests having resources referenced multiple times, as if referenced by +// multiple providers. +TEST_F(SurfaceFactoryTest, ResourceRefMultipleTimes) { + ResourceProvider::ResourceId first_frame_ids[] = {3, 4}; + SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids)); + + // Ref resources from the first frame twice. + RefCurrentFrameResources(); + RefCurrentFrameResources(); + + ResourceProvider::ResourceId second_frame_ids[] = {4, 5}; + SubmitFrameWithResources(second_frame_ids, arraysize(second_frame_ids)); + + // Ref resources from the second frame 3 times. + RefCurrentFrameResources(); + RefCurrentFrameResources(); + RefCurrentFrameResources(); + + // Submit a frame with no resources to remove all current frame refs from + // submitted resources. + SubmitFrameWithResources(NULL, 0); + + EXPECT_EQ(0u, client_.returned_resources().size()); + client_.clear_returned_resources(); + + // Expected current refs: + // 3 -> 2 + // 4 -> 2 + 3 = 5 + // 5 -> 3 + { + SCOPED_TRACE("unref all 3"); + ResourceProvider::ResourceId ids_to_unref[] = {3, 4, 5}; + int counts[] = {1, 1, 1}; + UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref)); + + EXPECT_EQ(0u, client_.returned_resources().size()); + client_.clear_returned_resources(); + + UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref)); + + ResourceProvider::ResourceId expected_returned_ids[] = {3}; + int expected_returned_counts[] = {1}; + CheckReturnedResourcesMatchExpected(expected_returned_ids, + expected_returned_counts, + arraysize(expected_returned_counts)); + } + + // Expected refs remaining: + // 4 -> 3 + // 5 -> 1 + { + SCOPED_TRACE("unref 4 and 5"); + ResourceProvider::ResourceId ids_to_unref[] = {4, 5}; + int counts[] = {1, 1}; + UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref)); + + ResourceProvider::ResourceId expected_returned_ids[] = {5}; + int expected_returned_counts[] = {1}; + CheckReturnedResourcesMatchExpected(expected_returned_ids, + expected_returned_counts, + arraysize(expected_returned_counts)); + } + + // Now, just 2 refs remaining on resource 4. Unref both at once and make sure + // the returned count is correct. + { + SCOPED_TRACE("unref only 4"); + ResourceProvider::ResourceId ids_to_unref[] = {4}; + int counts[] = {2}; + UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref)); + + ResourceProvider::ResourceId expected_returned_ids[] = {4}; + int expected_returned_counts[] = {2}; + CheckReturnedResourcesMatchExpected(expected_returned_ids, + expected_returned_counts, + arraysize(expected_returned_counts)); + } +} + +TEST_F(SurfaceFactoryTest, ResourceLifetime) { + ResourceProvider::ResourceId first_frame_ids[] = {1, 2, 3}; + SubmitFrameWithResources(first_frame_ids, arraysize(first_frame_ids)); + + // All of the resources submitted in the first frame are still in use at this + // time by virtue of being in the pending frame, so none can be returned to + // the client yet. + EXPECT_EQ(0u, client_.returned_resources().size()); + client_.clear_returned_resources(); + + // The second frame references some of the same resources, but some different + // ones. We expect to receive back resource 1 with a count of 1 since it was + // only referenced by the first frame. + ResourceProvider::ResourceId second_frame_ids[] = {2, 3, 4}; + SubmitFrameWithResources(second_frame_ids, arraysize(second_frame_ids)); + + { + SCOPED_TRACE("second frame"); + ResourceProvider::ResourceId expected_returned_ids[] = {1}; + int expected_returned_counts[] = {1}; + CheckReturnedResourcesMatchExpected(expected_returned_ids, + expected_returned_counts, + arraysize(expected_returned_counts)); + } + + // The third frame references a disjoint set of resources, so we expect to + // receive back all resources from the first and second frames. Resource IDs 2 + // and 3 will have counts of 2, since they were used in both frames, and + // resource ID 4 will have a count of 1. + ResourceProvider::ResourceId third_frame_ids[] = {10, 11, 12, 13}; + SubmitFrameWithResources(third_frame_ids, arraysize(third_frame_ids)); + + { + SCOPED_TRACE("third frame"); + ResourceProvider::ResourceId expected_returned_ids[] = {2, 3, 4}; + int expected_returned_counts[] = {2, 2, 1}; + CheckReturnedResourcesMatchExpected(expected_returned_ids, + expected_returned_counts, + arraysize(expected_returned_counts)); + } + + // Simulate a ResourceProvider taking a ref on all of the resources. + RefCurrentFrameResources(); + + ResourceProvider::ResourceId fourth_frame_ids[] = {12, 13}; + SubmitFrameWithResources(fourth_frame_ids, arraysize(fourth_frame_ids)); + + EXPECT_EQ(0u, client_.returned_resources().size()); + + RefCurrentFrameResources(); + + // All resources are still being used by the external reference, so none can + // be returned to the client. + EXPECT_EQ(0u, client_.returned_resources().size()); + + // Release resources associated with the first RefCurrentFrameResources() call + // first. + { + ResourceProvider::ResourceId ids_to_unref[] = {10, 11, 12, 13}; + int counts[] = {1, 1, 1, 1}; + UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref)); + } + + { + SCOPED_TRACE("fourth frame, first unref"); + ResourceProvider::ResourceId expected_returned_ids[] = {10, 11}; + int expected_returned_counts[] = {1, 1}; + CheckReturnedResourcesMatchExpected(expected_returned_ids, + expected_returned_counts, + arraysize(expected_returned_counts)); + } + + { + ResourceProvider::ResourceId ids_to_unref[] = {12, 13}; + int counts[] = {1, 1}; + UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref)); + } + + // Resources 12 and 13 are still in use by the current frame, so they + // shouldn't be available to be returned. + EXPECT_EQ(0u, client_.returned_resources().size()); + + // If we submit an empty frame, however, they should become available. + SubmitFrameWithResources(NULL, 0u); + + { + SCOPED_TRACE("fourth frame, second unref"); + ResourceProvider::ResourceId expected_returned_ids[] = {12, 13}; + int expected_returned_counts[] = {2, 2}; + CheckReturnedResourcesMatchExpected(expected_returned_ids, + expected_returned_counts, + arraysize(expected_returned_counts)); + } +} + +} // namespace +} // namespace cc diff --git a/cc/surfaces/surface_id.h b/cc/surfaces/surface_id.h index aa9474d..9b59f64 100644 --- a/cc/surfaces/surface_id.h +++ b/cc/surfaces/surface_id.h @@ -5,6 +5,9 @@ #ifndef CC_SURFACES_SURFACE_ID_H_ #define CC_SURFACES_SURFACE_ID_H_ +#include "base/compiler_specific.h" +#include "base/containers/hash_tables.h" + namespace cc { struct SurfaceId { @@ -24,6 +27,25 @@ inline bool operator!=(const SurfaceId& a, const SurfaceId& b) { return !(a == b); } +inline bool operator<(const SurfaceId& a, const SurfaceId& b) { + return a.id < b.id; +} + } // namespace cc +namespace BASE_HASH_NAMESPACE { +#if defined(COMPILER_MSVC) +inline size_t hash_value(const cc::SurfaceId& key) { + return hash_value(key.id); +} +#elif defined(COMPILER_GCC) +template <> +struct hash<cc::SurfaceId> { + size_t operator()(cc::SurfaceId key) const { return hash<int>()(key.id); } +}; +#else +#error define a hash function for your compiler +#endif // COMPILER +} // namespace BASE_HASH_NAMESPACE + #endif // CC_SURFACES_SURFACE_ID_H_ diff --git a/cc/surfaces/surface_manager.cc b/cc/surfaces/surface_manager.cc index b41aefc..77ad3c1 100644 --- a/cc/surfaces/surface_manager.cc +++ b/cc/surfaces/surface_manager.cc @@ -5,30 +5,36 @@ #include "cc/surfaces/surface_manager.h" #include "base/logging.h" +#include "cc/surfaces/surface.h" namespace cc { -SurfaceManager::SurfaceManager() - : next_surface_id_(1) { +SurfaceManager::SurfaceManager() : next_surface_id_(1) { } -SurfaceManager::~SurfaceManager() {} +SurfaceManager::~SurfaceManager() { + DCHECK_EQ(0u, surface_map_.size()); +} -SurfaceId SurfaceManager::RegisterAndAllocateIdForSurface(Surface* surface) { - DCHECK(surface); +SurfaceId SurfaceManager::AllocateId() { int surface_id = next_surface_id_++; - surface_map_[surface_id] = surface; return SurfaceId(surface_id); } +void SurfaceManager::RegisterSurface(Surface* surface) { + DCHECK(surface); + DCHECK(!surface_map_.count(surface->surface_id())); + surface_map_[surface->surface_id()] = surface; +} + void SurfaceManager::DeregisterSurface(SurfaceId surface_id) { - SurfaceMap::iterator it = surface_map_.find(surface_id.id); + SurfaceMap::iterator it = surface_map_.find(surface_id); DCHECK(it != surface_map_.end()); surface_map_.erase(it); } Surface* SurfaceManager::GetSurfaceForId(SurfaceId surface_id) { - SurfaceMap::iterator it = surface_map_.find(surface_id.id); + SurfaceMap::iterator it = surface_map_.find(surface_id); if (it == surface_map_.end()) return NULL; return it->second; diff --git a/cc/surfaces/surface_manager.h b/cc/surfaces/surface_manager.h index b14259d..726ed85 100644 --- a/cc/surfaces/surface_manager.h +++ b/cc/surfaces/surface_manager.h @@ -13,20 +13,20 @@ namespace cc { class CompositorFrame; class Surface; -class SurfaceClient; class CC_SURFACES_EXPORT SurfaceManager { public: SurfaceManager(); ~SurfaceManager(); - SurfaceId RegisterAndAllocateIdForSurface(Surface* surface); + SurfaceId AllocateId(); + void RegisterSurface(Surface* surface); void DeregisterSurface(SurfaceId surface_id); Surface* GetSurfaceForId(SurfaceId surface_id); private: - typedef base::hash_map<int, Surface*> SurfaceMap; + typedef base::hash_map<SurfaceId, Surface*> SurfaceMap; SurfaceMap surface_map_; int next_surface_id_; diff --git a/cc/surfaces/surface_resource_holder.cc b/cc/surfaces/surface_resource_holder.cc new file mode 100644 index 0000000..d142f7f --- /dev/null +++ b/cc/surfaces/surface_resource_holder.cc @@ -0,0 +1,68 @@ +// Copyright 2014 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/surfaces/surface_resource_holder.h" + +#include "cc/surfaces/surface_factory_client.h" + +namespace cc { + +SurfaceResourceHolder::SurfaceResourceHolder(SurfaceFactoryClient* client) + : client_(client) { +} + +SurfaceResourceHolder::~SurfaceResourceHolder() { +} + +SurfaceResourceHolder::ResourceRefs::ResourceRefs() + : refs_received_from_child(0), refs_holding_resource_alive(0) { +} + +void SurfaceResourceHolder::ReceiveFromChild( + const TransferableResourceArray& resources) { + for (TransferableResourceArray::const_iterator it = resources.begin(); + it != resources.end(); + ++it) { + ResourceRefs& ref = resource_id_use_count_map_[it->id]; + ref.refs_holding_resource_alive++; + ref.refs_received_from_child++; + } +} + +void SurfaceResourceHolder::RefResources( + const TransferableResourceArray& resources) { + for (TransferableResourceArray::const_iterator it = resources.begin(); + it != resources.end(); + ++it) { + ResourceIdCountMap::iterator count_it = + resource_id_use_count_map_.find(it->id); + DCHECK(count_it != resource_id_use_count_map_.end()); + count_it->second.refs_holding_resource_alive++; + } +} + +void SurfaceResourceHolder::UnrefResources( + const ReturnedResourceArray& resources) { + ReturnedResourceArray resources_available_to_return; + + for (ReturnedResourceArray::const_iterator it = resources.begin(); + it != resources.end(); + ++it) { + ResourceProvider::ResourceId id = it->id; + ResourceIdCountMap::iterator count_it = resource_id_use_count_map_.find(id); + DCHECK(count_it != resource_id_use_count_map_.end()); + ResourceRefs& ref = count_it->second; + ref.refs_holding_resource_alive -= it->count; + if (ref.refs_holding_resource_alive == 0) { + ReturnedResource returned = *it; + returned.count = ref.refs_received_from_child; + resources_available_to_return.push_back(returned); + resource_id_use_count_map_.erase(count_it); + } + } + + client_->ReturnResources(resources_available_to_return); +} + +} // namespace cc diff --git a/cc/surfaces/surface_resource_holder.h b/cc/surfaces/surface_resource_holder.h new file mode 100644 index 0000000..20c9f29 --- /dev/null +++ b/cc/surfaces/surface_resource_holder.h @@ -0,0 +1,51 @@ +// Copyright 2014 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_SURFACES_SURFACE_RESOURCE_HOLDER_H_ +#define CC_SURFACES_SURFACE_RESOURCE_HOLDER_H_ + +#include "base/containers/hash_tables.h" +#include "base/macros.h" +#include "cc/resources/resource_provider.h" +#include "cc/resources/returned_resource.h" +#include "cc/surfaces/surfaces_export.h" + +namespace cc { +class SurfaceFactoryClient; + +// A SurfaceResourceHolder manages the lifetime of resources submitted by a +// particular SurfaceFactory. Each resource is held by the service until +// it is no longer referenced by any pending frames or by any +// resource providers. +class CC_SURFACES_EXPORT SurfaceResourceHolder { + public: + explicit SurfaceResourceHolder(SurfaceFactoryClient* client); + ~SurfaceResourceHolder(); + + void ReceiveFromChild(const TransferableResourceArray& resources); + void RefResources(const TransferableResourceArray& resources); + void UnrefResources(const ReturnedResourceArray& resources); + + private: + SurfaceFactoryClient* client_; + + struct ResourceRefs { + ResourceRefs(); + + int refs_received_from_child; + int refs_holding_resource_alive; + }; + // Keeps track of the number of users currently in flight for each resource + // ID we've received from the client. When this counter hits zero for a + // particular resource, that ID is available to return to the client. + typedef base::hash_map<ResourceProvider::ResourceId, ResourceRefs> + ResourceIdCountMap; + ResourceIdCountMap resource_id_use_count_map_; + + DISALLOW_COPY_AND_ASSIGN(SurfaceResourceHolder); +}; + +} // namespace cc + +#endif // CC_SURFACES_SURFACE_RESOURCE_HOLDER_H_ diff --git a/cc/surfaces/surface_unittest.cc b/cc/surfaces/surface_unittest.cc index 66890c4..7d91b0a 100644 --- a/cc/surfaces/surface_unittest.cc +++ b/cc/surfaces/surface_unittest.cc @@ -2,10 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "cc/output/compositor_frame.h" -#include "cc/output/delegated_frame_data.h" #include "cc/surfaces/surface.h" -#include "cc/surfaces/surface_client.h" +#include "cc/surfaces/surface_factory.h" #include "cc/surfaces/surface_manager.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/size.h" @@ -15,397 +13,18 @@ namespace { TEST(SurfaceTest, SurfaceLifetime) { SurfaceManager manager; + SurfaceFactory factory(&manager, NULL); SurfaceId surface_id; { - Surface surface(&manager, NULL, gfx::Size(5, 5)); - surface_id = surface.surface_id(); + surface_id = factory.Create(gfx::Size(5, 5)); EXPECT_TRUE(!surface_id.is_null()); - EXPECT_EQ(&surface, manager.GetSurfaceForId(surface_id)); + EXPECT_TRUE(!!manager.GetSurfaceForId(surface_id)); + factory.Destroy(surface_id); } EXPECT_EQ(NULL, manager.GetSurfaceForId(surface_id)); } -class TestSurfaceClient : public SurfaceClient { - public: - TestSurfaceClient() {} - virtual ~TestSurfaceClient() {} - - virtual void ReturnResources( - const ReturnedResourceArray& resources) OVERRIDE { - returned_resources_ = resources; - } - - const ReturnedResourceArray& returned_resources() const { - return returned_resources_; - } - - void clear_returned_resources() { returned_resources_.clear(); } - - private: - ReturnedResourceArray returned_resources_; - - DISALLOW_COPY_AND_ASSIGN(TestSurfaceClient); -}; - -void SubmitFrameWithResources(ResourceProvider::ResourceId* resource_ids, - size_t num_resource_ids, - Surface* surface) { - scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData); - for (size_t i = 0u; i < num_resource_ids; ++i) { - TransferableResource resource; - resource.id = resource_ids[i]; - resource.mailbox_holder.texture_target = GL_TEXTURE_2D; - frame_data->resource_list.push_back(resource); - } - scoped_ptr<CompositorFrame> frame(new CompositorFrame); - frame->delegated_frame_data = frame_data.Pass(); - surface->QueueFrame(frame.Pass()); -} - -void CheckReturnedResourcesMatchExpected( - ResourceProvider::ResourceId* expected_returned_ids, - int* expected_returned_counts, - size_t expected_resources, - const ReturnedResourceArray& actual_resources) { - ASSERT_EQ(expected_resources, actual_resources.size()); - for (size_t i = 0; i < expected_resources; ++i) { - ReturnedResource resource = actual_resources[i]; - EXPECT_EQ(expected_returned_ids[i], resource.id); - EXPECT_EQ(expected_returned_counts[i], resource.count); - } -} - -void UnrefResources(ResourceProvider::ResourceId* ids_to_unref, - int* counts_to_unref, - size_t num_ids_to_unref, - Surface* surface) { - ReturnedResourceArray unref_array; - for (size_t i = 0; i < num_ids_to_unref; ++i) { - ReturnedResource resource; - resource.id = ids_to_unref[i]; - resource.count = counts_to_unref[i]; - unref_array.push_back(resource); - } - surface->UnrefResources(unref_array); -} - -// Tests submitting a frame with resources followed by one with no resources -// with no resource provider action in between. -TEST(SurfaceTest, ResourceLifetimeSimple) { - SurfaceManager manager; - TestSurfaceClient client; - Surface surface(&manager, &client, gfx::Size(5, 5)); - - ResourceProvider::ResourceId first_frame_ids[] = {1, 2, 3}; - SubmitFrameWithResources( - first_frame_ids, arraysize(first_frame_ids), &surface); - - // All of the resources submitted in the first frame are still in use at this - // time by virtue of being in the pending frame, so none can be returned to - // the client yet. - surface.ReturnUnusedResourcesToClient(); - EXPECT_EQ(0u, client.returned_resources().size()); - client.clear_returned_resources(); - - // The second frame references no resources and thus should make all resources - // available to be returned. - SubmitFrameWithResources(NULL, 0, &surface); - - surface.ReturnUnusedResourcesToClient(); - ResourceProvider::ResourceId expected_returned_ids[] = {1, 2, 3}; - int expected_returned_counts[] = {1, 1, 1}; - CheckReturnedResourcesMatchExpected(expected_returned_ids, - expected_returned_counts, - arraysize(expected_returned_counts), - client.returned_resources()); -} - -// Tests submitting a frame with resources followed by one with no resources -// with the resource provider holding everything alive. -TEST(SurfaceTest, ResourceLifetimeSimpleWithProviderHoldingAlive) { - SurfaceManager manager; - TestSurfaceClient client; - Surface surface(&manager, &client, gfx::Size(5, 5)); - - ResourceProvider::ResourceId first_frame_ids[] = {1, 2, 3}; - SubmitFrameWithResources( - first_frame_ids, arraysize(first_frame_ids), &surface); - - // All of the resources submitted in the first frame are still in use at this - // time by virtue of being in the pending frame, so none can be returned to - // the client yet. - surface.ReturnUnusedResourcesToClient(); - EXPECT_EQ(0u, client.returned_resources().size()); - client.clear_returned_resources(); - - // Hold on to everything. - surface.RefCurrentFrameResources(); - - // The second frame references no resources and thus should make all resources - // available to be returned as soon as the resource provider releases them. - SubmitFrameWithResources(NULL, 0, &surface); - - surface.ReturnUnusedResourcesToClient(); - EXPECT_EQ(0u, client.returned_resources().size()); - client.clear_returned_resources(); - - int release_counts[] = {1, 1, 1}; - UnrefResources( - first_frame_ids, release_counts, arraysize(first_frame_ids), &surface); - - surface.ReturnUnusedResourcesToClient(); - ResourceProvider::ResourceId expected_returned_ids[] = {1, 2, 3}; - int expected_returned_counts[] = {1, 1, 1}; - CheckReturnedResourcesMatchExpected(expected_returned_ids, - expected_returned_counts, - arraysize(expected_returned_counts), - client.returned_resources()); -} - -// Tests referencing a resource, unref'ing it to zero, then using it again -// before returning it to the client. -TEST(SurfaceTest, ResourceReusedBeforeReturn) { - SurfaceManager manager; - TestSurfaceClient client; - Surface surface(&manager, &client, gfx::Size(5, 5)); - - ResourceProvider::ResourceId first_frame_ids[] = {7}; - SubmitFrameWithResources( - first_frame_ids, arraysize(first_frame_ids), &surface); - - // This removes all references to resource id 7. - SubmitFrameWithResources(NULL, 0, &surface); - - // This references id 7 again. - SubmitFrameWithResources( - first_frame_ids, arraysize(first_frame_ids), &surface); - - // This removes it again. - SubmitFrameWithResources(NULL, 0, &surface); - - // Now it should be returned. - surface.ReturnUnusedResourcesToClient(); - - // We don't care how many entries are in the returned array for 7, so long as - // the total returned count matches the submitted count. - const ReturnedResourceArray& returned = client.returned_resources(); - size_t return_count = 0; - for (size_t i = 0; i < returned.size(); ++i) { - EXPECT_EQ(7u, returned[i].id); - return_count += returned[i].count; - } - EXPECT_EQ(2u, return_count); -} - -// Tests having resources referenced multiple times, as if referenced by -// multiple providers. -TEST(SurfaceTest, ResourceRefMultipleTimes) { - SurfaceManager manager; - TestSurfaceClient client; - Surface surface(&manager, &client, gfx::Size(5, 5)); - - ResourceProvider::ResourceId first_frame_ids[] = {3, 4}; - SubmitFrameWithResources( - first_frame_ids, arraysize(first_frame_ids), &surface); - - // Ref resources from the first frame twice. - surface.RefCurrentFrameResources(); - surface.RefCurrentFrameResources(); - - ResourceProvider::ResourceId second_frame_ids[] = {4, 5}; - SubmitFrameWithResources( - second_frame_ids, arraysize(second_frame_ids), &surface); - - // Ref resources from the second frame 3 times. - surface.RefCurrentFrameResources(); - surface.RefCurrentFrameResources(); - surface.RefCurrentFrameResources(); - - // Submit a frame with no resources to remove all current frame refs from - // submitted resources. - SubmitFrameWithResources(NULL, 0, &surface); - - surface.ReturnUnusedResourcesToClient(); - EXPECT_EQ(0u, client.returned_resources().size()); - client.clear_returned_resources(); - - // Expected current refs: - // 3 -> 2 - // 4 -> 2 + 3 = 5 - // 5 -> 3 - { - SCOPED_TRACE("unref all 3"); - ResourceProvider::ResourceId ids_to_unref[] = {3, 4, 5}; - int counts[] = {1, 1, 1}; - UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref), &surface); - - surface.ReturnUnusedResourcesToClient(); - EXPECT_EQ(0u, client.returned_resources().size()); - client.clear_returned_resources(); - - UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref), &surface); - - surface.ReturnUnusedResourcesToClient(); - ResourceProvider::ResourceId expected_returned_ids[] = {3}; - int expected_returned_counts[] = {1}; - CheckReturnedResourcesMatchExpected(expected_returned_ids, - expected_returned_counts, - arraysize(expected_returned_counts), - client.returned_resources()); - } - - // Expected refs remaining: - // 4 -> 3 - // 5 -> 1 - { - SCOPED_TRACE("unref 4 and 5"); - ResourceProvider::ResourceId ids_to_unref[] = {4, 5}; - int counts[] = {1, 1}; - UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref), &surface); - - surface.ReturnUnusedResourcesToClient(); - ResourceProvider::ResourceId expected_returned_ids[] = {5}; - int expected_returned_counts[] = {1}; - CheckReturnedResourcesMatchExpected(expected_returned_ids, - expected_returned_counts, - arraysize(expected_returned_counts), - client.returned_resources()); - } - - // Now, just 2 refs remaining on resource 4. Unref both at once and make sure - // the returned count is correct. - { - SCOPED_TRACE("unref only 4"); - ResourceProvider::ResourceId ids_to_unref[] = {4}; - int counts[] = {2}; - UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref), &surface); - - surface.ReturnUnusedResourcesToClient(); - ResourceProvider::ResourceId expected_returned_ids[] = {4}; - int expected_returned_counts[] = {2}; - CheckReturnedResourcesMatchExpected(expected_returned_ids, - expected_returned_counts, - arraysize(expected_returned_counts), - client.returned_resources()); - } -} - -TEST(SurfaceTest, ResourceLifetime) { - SurfaceManager manager; - TestSurfaceClient client; - Surface surface(&manager, &client, gfx::Size(5, 5)); - - ResourceProvider::ResourceId first_frame_ids[] = {1, 2, 3}; - SubmitFrameWithResources( - first_frame_ids, arraysize(first_frame_ids), &surface); - - // All of the resources submitted in the first frame are still in use at this - // time by virtue of being in the pending frame, so none can be returned to - // the client yet. - surface.ReturnUnusedResourcesToClient(); - EXPECT_EQ(0u, client.returned_resources().size()); - client.clear_returned_resources(); - - // The second frame references some of the same resources, but some different - // ones. We expect to receive back resource 1 with a count of 1 since it was - // only referenced by the first frame. - ResourceProvider::ResourceId second_frame_ids[] = {2, 3, 4}; - SubmitFrameWithResources( - second_frame_ids, arraysize(second_frame_ids), &surface); - - surface.ReturnUnusedResourcesToClient(); - { - SCOPED_TRACE("second frame"); - ResourceProvider::ResourceId expected_returned_ids[] = {1}; - int expected_returned_counts[] = {1}; - CheckReturnedResourcesMatchExpected(expected_returned_ids, - expected_returned_counts, - arraysize(expected_returned_counts), - client.returned_resources()); - } - - // The third frame references a disjoint set of resources, so we expect to - // receive back all resources from the first and second frames. Resource IDs 2 - // and 3 will have counts of 2, since they were used in both frames, and - // resource ID 4 will have a count of 1. - ResourceProvider::ResourceId third_frame_ids[] = {10, 11, 12, 13}; - SubmitFrameWithResources( - third_frame_ids, arraysize(third_frame_ids), &surface); - - surface.ReturnUnusedResourcesToClient(); - { - SCOPED_TRACE("third frame"); - ResourceProvider::ResourceId expected_returned_ids[] = {2, 3, 4}; - int expected_returned_counts[] = {2, 2, 1}; - CheckReturnedResourcesMatchExpected(expected_returned_ids, - expected_returned_counts, - arraysize(expected_returned_counts), - client.returned_resources()); - } - - // Simulate a ResourceProvider taking a ref on all of the resources. - surface.RefCurrentFrameResources(); - - ResourceProvider::ResourceId fourth_frame_ids[] = {12, 13}; - SubmitFrameWithResources( - fourth_frame_ids, arraysize(fourth_frame_ids), &surface); - - surface.ReturnUnusedResourcesToClient(); - EXPECT_EQ(0u, client.returned_resources().size()); - - surface.RefCurrentFrameResources(); - - // All resources are still being used by the external reference, so none can - // be returned to the client. - surface.ReturnUnusedResourcesToClient(); - EXPECT_EQ(0u, client.returned_resources().size()); - - // Release resources associated with the first RefCurrentFrameResources() call - // first. - { - ResourceProvider::ResourceId ids_to_unref[] = {10, 11, 12, 13}; - int counts[] = {1, 1, 1, 1}; - UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref), &surface); - } - - surface.ReturnUnusedResourcesToClient(); - { - SCOPED_TRACE("fourth frame, first unref"); - ResourceProvider::ResourceId expected_returned_ids[] = {10, 11}; - int expected_returned_counts[] = {1, 1}; - CheckReturnedResourcesMatchExpected(expected_returned_ids, - expected_returned_counts, - arraysize(expected_returned_counts), - client.returned_resources()); - } - - { - ResourceProvider::ResourceId ids_to_unref[] = {12, 13}; - int counts[] = {1, 1}; - UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref), &surface); - } - - // Resources 12 and 13 are still in use by the current frame, so they - // shouldn't be available to be returned. - surface.ReturnUnusedResourcesToClient(); - EXPECT_EQ(0u, client.returned_resources().size()); - - // If we submit an empty frame, however, they should become available. - SubmitFrameWithResources(NULL, 0u, &surface); - - surface.ReturnUnusedResourcesToClient(); - { - SCOPED_TRACE("fourth frame, second unref"); - ResourceProvider::ResourceId expected_returned_ids[] = {12, 13}; - int expected_returned_counts[] = {2, 2}; - CheckReturnedResourcesMatchExpected(expected_returned_ids, - expected_returned_counts, - arraysize(expected_returned_counts), - client.returned_resources()); - } -} - } // namespace } // namespace cc diff --git a/cc/surfaces/surfaces_pixeltest.cc b/cc/surfaces/surfaces_pixeltest.cc index 9afb4c6..6947abc 100644 --- a/cc/surfaces/surfaces_pixeltest.cc +++ b/cc/surfaces/surfaces_pixeltest.cc @@ -8,6 +8,8 @@ #include "cc/quads/surface_draw_quad.h" #include "cc/surfaces/surface.h" #include "cc/surfaces/surface_aggregator.h" +#include "cc/surfaces/surface_factory.h" +#include "cc/surfaces/surface_factory_client.h" #include "cc/surfaces/surface_manager.h" #include "cc/test/pixel_comparator.h" #include "cc/test/pixel_test.h" @@ -18,9 +20,20 @@ namespace cc { namespace { +class EmptySurfaceFactoryClient : public SurfaceFactoryClient { + public: + virtual void ReturnResources( + const ReturnedResourceArray& resources) OVERRIDE {} +}; + class SurfacesPixelTest : public RendererPixelTest<GLRenderer> { + public: + SurfacesPixelTest() : factory_(&manager_, &client_) {} + protected: SurfaceManager manager_; + EmptySurfaceFactoryClient client_; + SurfaceFactory factory_; }; SharedQuadState* CreateAndAppendTestSharedQuadState( @@ -70,12 +83,13 @@ TEST_F(SurfacesPixelTest, DrawSimpleFrame) { scoped_ptr<CompositorFrame> root_frame(new CompositorFrame); root_frame->delegated_frame_data = delegated_frame_data.Pass(); - Surface root_surface(&manager_, NULL, device_viewport_size_); - root_surface.QueueFrame(root_frame.Pass()); + SurfaceId root_surface_id = factory_.Create(device_viewport_size_); + factory_.SubmitFrame(root_surface_id, root_frame.Pass()); - SurfaceAggregator aggregator(&manager_); + SurfaceAggregator aggregator(&manager_, resource_provider_.get()); scoped_ptr<CompositorFrame> aggregated_frame = - aggregator.Aggregate(root_surface.surface_id()); + aggregator.Aggregate(root_surface_id); + factory_.Destroy(root_surface_id); bool discard_alpha = false; ExactPixelComparator pixel_comparator(discard_alpha); @@ -89,8 +103,8 @@ TEST_F(SurfacesPixelTest, DrawSimpleFrame) { // Draws a frame with simple surface embedding. TEST_F(SurfacesPixelTest, DrawSimpleAggregatedFrame) { gfx::Size child_size(200, 100); - Surface child_surface(&manager_, NULL, child_size); - Surface root_surface(&manager_, NULL, device_viewport_size_); + SurfaceId child_surface_id = factory_.Create(child_size); + SurfaceId root_surface_id = factory_.Create(device_viewport_size_); { gfx::Rect rect(device_viewport_size_); @@ -105,7 +119,7 @@ TEST_F(SurfacesPixelTest, DrawSimpleAggregatedFrame) { surface_quad->SetNew(pass->shared_quad_state_list.back(), gfx::Rect(child_size), gfx::Rect(child_size), - child_surface.surface_id()); + child_surface_id); pass->quad_list.push_back(surface_quad.PassAs<DrawQuad>()); scoped_ptr<SolidColorDrawQuad> color_quad = SolidColorDrawQuad::Create(); @@ -123,7 +137,7 @@ TEST_F(SurfacesPixelTest, DrawSimpleAggregatedFrame) { scoped_ptr<CompositorFrame> root_frame(new CompositorFrame); root_frame->delegated_frame_data = delegated_frame_data.Pass(); - root_surface.QueueFrame(root_frame.Pass()); + factory_.SubmitFrame(root_surface_id, root_frame.Pass()); } { @@ -150,12 +164,12 @@ TEST_F(SurfacesPixelTest, DrawSimpleAggregatedFrame) { scoped_ptr<CompositorFrame> child_frame(new CompositorFrame); child_frame->delegated_frame_data = delegated_frame_data.Pass(); - child_surface.QueueFrame(child_frame.Pass()); + factory_.SubmitFrame(child_surface_id, child_frame.Pass()); } - SurfaceAggregator aggregator(&manager_); + SurfaceAggregator aggregator(&manager_, resource_provider_.get()); scoped_ptr<CompositorFrame> aggregated_frame = - aggregator.Aggregate(root_surface.surface_id()); + aggregator.Aggregate(root_surface_id); bool discard_alpha = false; ExactPixelComparator pixel_comparator(discard_alpha); @@ -164,6 +178,8 @@ TEST_F(SurfacesPixelTest, DrawSimpleAggregatedFrame) { EXPECT_TRUE(RunPixelTest(pass_list, base::FilePath(FILE_PATH_LITERAL("blue_yellow.png")), pixel_comparator)); + factory_.Destroy(root_surface_id); + factory_.Destroy(child_surface_id); } // Tests a surface quad that has a non-identity transform into its pass. @@ -177,9 +193,9 @@ TEST_F(SurfacesPixelTest, DrawAggregatedFrameWithSurfaceTransforms) { // bottom_blue_quad (100x100 @ 0x100) // right_child -> top_blue_quad (100x100 @ 0x0), // bottom_green_quad (100x100 @ 0x100) - Surface left_child(&manager_, NULL, child_size); - Surface right_child(&manager_, NULL, child_size); - Surface root_surface(&manager_, NULL, device_viewport_size_); + SurfaceId left_child_id = factory_.Create(child_size); + SurfaceId right_child_id = factory_.Create(child_size); + SurfaceId root_surface_id = factory_.Create(device_viewport_size_); { gfx::Rect rect(device_viewport_size_); @@ -195,7 +211,7 @@ TEST_F(SurfacesPixelTest, DrawAggregatedFrameWithSurfaceTransforms) { left_surface_quad->SetNew(pass->shared_quad_state_list.back(), gfx::Rect(child_size), gfx::Rect(child_size), - left_child.surface_id()); + left_child_id); pass->quad_list.push_back(left_surface_quad.PassAs<DrawQuad>()); surface_transform.Translate(100, 0); @@ -206,7 +222,7 @@ TEST_F(SurfacesPixelTest, DrawAggregatedFrameWithSurfaceTransforms) { right_surface_quad->SetNew(pass->shared_quad_state_list.back(), gfx::Rect(child_size), gfx::Rect(child_size), - right_child.surface_id()); + right_child_id); pass->quad_list.push_back(right_surface_quad.PassAs<DrawQuad>()); scoped_ptr<DelegatedFrameData> delegated_frame_data(new DelegatedFrameData); @@ -215,7 +231,7 @@ TEST_F(SurfacesPixelTest, DrawAggregatedFrameWithSurfaceTransforms) { scoped_ptr<CompositorFrame> root_frame(new CompositorFrame); root_frame->delegated_frame_data = delegated_frame_data.Pass(); - root_surface.QueueFrame(root_frame.Pass()); + factory_.SubmitFrame(root_surface_id, root_frame.Pass()); } { @@ -252,7 +268,7 @@ TEST_F(SurfacesPixelTest, DrawAggregatedFrameWithSurfaceTransforms) { scoped_ptr<CompositorFrame> child_frame(new CompositorFrame); child_frame->delegated_frame_data = delegated_frame_data.Pass(); - left_child.QueueFrame(child_frame.Pass()); + factory_.SubmitFrame(left_child_id, child_frame.Pass()); } { @@ -289,12 +305,12 @@ TEST_F(SurfacesPixelTest, DrawAggregatedFrameWithSurfaceTransforms) { scoped_ptr<CompositorFrame> child_frame(new CompositorFrame); child_frame->delegated_frame_data = delegated_frame_data.Pass(); - right_child.QueueFrame(child_frame.Pass()); + factory_.SubmitFrame(right_child_id, child_frame.Pass()); } - SurfaceAggregator aggregator(&manager_); + SurfaceAggregator aggregator(&manager_, resource_provider_.get()); scoped_ptr<CompositorFrame> aggregated_frame = - aggregator.Aggregate(root_surface.surface_id()); + aggregator.Aggregate(root_surface_id); bool discard_alpha = false; ExactPixelComparator pixel_comparator(discard_alpha); @@ -304,6 +320,10 @@ TEST_F(SurfacesPixelTest, DrawAggregatedFrameWithSurfaceTransforms) { pass_list, base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")), pixel_comparator)); + + factory_.Destroy(root_surface_id); + factory_.Destroy(left_child_id); + factory_.Destroy(right_child_id); } } // namespace diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc index bdf7cb4..b583393 100644 --- a/content/browser/compositor/gpu_process_transport_factory.cc +++ b/content/browser/compositor/gpu_process_transport_factory.cc @@ -188,8 +188,9 @@ scoped_ptr<cc::OutputSurface> GpuProcessTransportFactory::CreateOutputSurface( "Offscreen-Compositor"); } scoped_ptr<SurfaceDisplayOutputSurface> output_surface( - new SurfaceDisplayOutputSurface( - display_client->display(), manager, offscreen_context_provider)); + new SurfaceDisplayOutputSurface(manager, offscreen_context_provider)); + display_client->CreateDisplay(output_surface->factory()); + output_surface->set_display(display_client->display()); data->display_client = display_client.Pass(); return output_surface.PassAs<cc::OutputSurface>(); } diff --git a/content/browser/compositor/onscreen_display_client.cc b/content/browser/compositor/onscreen_display_client.cc index 814f0fc..3138f9d 100644 --- a/content/browser/compositor/onscreen_display_client.cc +++ b/content/browser/compositor/onscreen_display_client.cc @@ -5,6 +5,8 @@ #include "content/browser/compositor/onscreen_display_client.h" #include "cc/output/output_surface.h" +#include "cc/surfaces/surface_factory.h" +#include "cc/surfaces/surface_manager.h" #include "content/common/host_shared_bitmap_manager.h" namespace content { @@ -13,14 +15,19 @@ OnscreenDisplayClient::OnscreenDisplayClient( const scoped_refptr<cc::ContextProvider>& onscreen_context_provider, scoped_ptr<cc::OutputSurface> software_surface, cc::SurfaceManager* manager) - : onscreen_context_provider_(onscreen_context_provider), - software_surface_(software_surface.Pass()), - display_(this, manager, HostSharedBitmapManager::current()) { + : manager_(manager), + onscreen_context_provider_(onscreen_context_provider), + software_surface_(software_surface.Pass()) { } OnscreenDisplayClient::~OnscreenDisplayClient() { } +void OnscreenDisplayClient::CreateDisplay(cc::SurfaceFactory* factory) { + display_.reset(new cc::Display( + this, manager_, factory, HostSharedBitmapManager::current())); +} + scoped_ptr<cc::OutputSurface> OnscreenDisplayClient::CreateOutputSurface() { if (!onscreen_context_provider_) return software_surface_.Pass(); diff --git a/content/browser/compositor/onscreen_display_client.h b/content/browser/compositor/onscreen_display_client.h index 7ab6ff7..b518cc9 100644 --- a/content/browser/compositor/onscreen_display_client.h +++ b/content/browser/compositor/onscreen_display_client.h @@ -28,15 +28,18 @@ class OnscreenDisplayClient : cc::DisplayClient { cc::SurfaceManager* manager); virtual ~OnscreenDisplayClient(); - cc::Display* display() { return &display_; } + void CreateDisplay(cc::SurfaceFactory* factory); + + cc::Display* display() { return display_.get(); } // cc::DisplayClient implementation. virtual scoped_ptr<cc::OutputSurface> CreateOutputSurface() OVERRIDE; private: + cc::SurfaceManager* manager_; scoped_refptr<cc::ContextProvider> onscreen_context_provider_; scoped_ptr<cc::OutputSurface> software_surface_; - cc::Display display_; + scoped_ptr<cc::Display> display_; DISALLOW_COPY_AND_ASSIGN(OnscreenDisplayClient); }; diff --git a/content/browser/compositor/surface_display_output_surface.cc b/content/browser/compositor/surface_display_output_surface.cc index 46c4ad7..91dc0ab4 100644 --- a/content/browser/compositor/surface_display_output_surface.cc +++ b/content/browser/compositor/surface_display_output_surface.cc @@ -5,6 +5,7 @@ #include "content/browser/compositor/surface_display_output_surface.h" #include "cc/output/compositor_frame.h" +#include "cc/output/compositor_frame_ack.h" #include "cc/surfaces/display.h" #include "cc/surfaces/surface.h" #include "cc/surfaces/surface_manager.h" @@ -12,13 +13,13 @@ namespace content { SurfaceDisplayOutputSurface::SurfaceDisplayOutputSurface( - cc::Display* display, cc::SurfaceManager* surface_manager, const scoped_refptr<cc::ContextProvider>& context_provider) : cc::OutputSurface(context_provider, scoped_ptr<cc::SoftwareOutputDevice>()), - display_(display), - surface_manager_(surface_manager) { + display_(NULL), + surface_manager_(surface_manager), + factory_(surface_manager, this) { capabilities_.delegated_rendering = true; capabilities_.max_frames_pending = 1; } @@ -31,13 +32,12 @@ void SurfaceDisplayOutputSurface::SwapBuffers(cc::CompositorFrame* frame) { frame->delegated_frame_data->render_pass_list.back()->output_rect.size(); display_->Resize(frame_size); cc::SurfaceId surface_id = display_->CurrentSurfaceId(); - cc::Surface* surface = surface_manager_->GetSurfaceForId(surface_id); - if (!surface) + if (surface_id.is_null()) return; scoped_ptr<cc::CompositorFrame> frame_copy(new cc::CompositorFrame()); frame->AssignTo(frame_copy.get()); - surface->QueueFrame(frame_copy.Pass()); + factory_.SubmitFrame(surface_id, frame_copy.Pass()); if (!display_->Draw()) return; @@ -46,4 +46,11 @@ void SurfaceDisplayOutputSurface::SwapBuffers(cc::CompositorFrame* frame) { client_->DidSwapBuffersComplete(); } +void SurfaceDisplayOutputSurface::ReturnResources( + const cc::ReturnedResourceArray& resources) { + cc::CompositorFrameAck ack; + ack.resources = resources; + client_->ReclaimResources(&ack); +} + } // namespace content diff --git a/content/browser/compositor/surface_display_output_surface.h b/content/browser/compositor/surface_display_output_surface.h index 185e0ff..e8b126c 100644 --- a/content/browser/compositor/surface_display_output_surface.h +++ b/content/browser/compositor/surface_display_output_surface.h @@ -6,6 +6,8 @@ #define CONTENT_BROWSER_COMPOSITOR_SURFACE_DISPLAY_OUTPUT_SURFACE_H_ #include "cc/output/output_surface.h" +#include "cc/surfaces/surface_factory.h" +#include "cc/surfaces/surface_factory_client.h" namespace cc { class Display; @@ -17,21 +19,29 @@ namespace content { // This class is maps a compositor OutputSurface to the surface system's Display // concept, allowing a compositor client to submit frames for a native root // window or physical display. -class SurfaceDisplayOutputSurface : public cc::OutputSurface { +class SurfaceDisplayOutputSurface : public cc::OutputSurface, + public cc::SurfaceFactoryClient { public: // The underlying cc::Display and cc::SurfaceManager must outlive this class. SurfaceDisplayOutputSurface( - cc::Display* display, cc::SurfaceManager* surface_manager, const scoped_refptr<cc::ContextProvider>& context_provider); virtual ~SurfaceDisplayOutputSurface(); + void set_display(cc::Display* display) { display_ = display; } + cc::SurfaceFactory* factory() { return &factory_; } + // cc::OutputSurface implementation. virtual void SwapBuffers(cc::CompositorFrame* frame) OVERRIDE; + // cc::SurfaceFactoryClient implementation. + virtual void ReturnResources( + const cc::ReturnedResourceArray& resources) OVERRIDE; + private: cc::Display* display_; cc::SurfaceManager* surface_manager_; + cc::SurfaceFactory factory_; DISALLOW_COPY_AND_ASSIGN(SurfaceDisplayOutputSurface); }; |