| Index: cc/resources/resource_provider.cc
|
| diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
|
| index e1cbba56053bdb6b3ddfd43bad47cbebda23d31e..6ee8be02c9972e0904319f64170c897eee43a22a 100644
|
| --- a/cc/resources/resource_provider.cc
|
| +++ b/cc/resources/resource_provider.cc
|
| @@ -86,7 +86,8 @@ class ScopedSetActiveTexture {
|
| } // namespace
|
|
|
| ResourceProvider::Resource::Resource()
|
| - : gl_id(0),
|
| + : child_id(0),
|
| + gl_id(0),
|
| gl_pixel_buffer_id(0),
|
| gl_upload_query_id(0),
|
| pixels(NULL),
|
| @@ -115,15 +116,15 @@ ResourceProvider::Resource::Resource()
|
|
|
| ResourceProvider::Resource::~Resource() {}
|
|
|
| -ResourceProvider::Resource::Resource(
|
| - unsigned texture_id,
|
| - gfx::Size size,
|
| - GLenum filter,
|
| - GLenum texture_pool,
|
| - GLint wrap_mode,
|
| - TextureUsageHint hint,
|
| - ResourceFormat format)
|
| - : gl_id(texture_id),
|
| +ResourceProvider::Resource::Resource(unsigned texture_id,
|
| + gfx::Size size,
|
| + GLenum filter,
|
| + GLenum texture_pool,
|
| + GLint wrap_mode,
|
| + TextureUsageHint hint,
|
| + ResourceFormat format)
|
| + : child_id(0),
|
| + gl_id(texture_id),
|
| gl_pixel_buffer_id(0),
|
| gl_upload_query_id(0),
|
| pixels(NULL),
|
| @@ -152,12 +153,12 @@ ResourceProvider::Resource::Resource(
|
| DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
|
| }
|
|
|
| -ResourceProvider::Resource::Resource(
|
| - uint8_t* pixels,
|
| - gfx::Size size,
|
| - GLenum filter,
|
| - GLint wrap_mode)
|
| - : gl_id(0),
|
| +ResourceProvider::Resource::Resource(uint8_t* pixels,
|
| + gfx::Size size,
|
| + GLenum filter,
|
| + GLint wrap_mode)
|
| + : child_id(0),
|
| + gl_id(0),
|
| gl_pixel_buffer_id(0),
|
| gl_upload_query_id(0),
|
| pixels(pixels),
|
| @@ -215,6 +216,8 @@ scoped_ptr<ResourceProvider> ResourceProvider::Create(
|
| }
|
|
|
| ResourceProvider::~ResourceProvider() {
|
| + while (!children_.empty())
|
| + DestroyChild(children_.begin()->first);
|
| while (!resources_.empty())
|
| DeleteResourceInternal(resources_.begin(), ForShutdown);
|
|
|
| @@ -810,9 +813,12 @@ void ResourceProvider::CleanUpGLIfNeeded() {
|
| Finish();
|
| }
|
|
|
| -int ResourceProvider::CreateChild() {
|
| +int ResourceProvider::CreateChild(const ReturnCallback& return_callback) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| Child child_info;
|
| + child_info.return_callback = return_callback;
|
| +
|
| int child = next_child_++;
|
| children_[child] = child_info;
|
| return child;
|
| @@ -820,20 +826,26 @@ int ResourceProvider::CreateChild() {
|
|
|
| void ResourceProvider::DestroyChild(int child_id) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| ChildMap::iterator it = children_.find(child_id);
|
| DCHECK(it != children_.end());
|
| Child& child = it->second;
|
| +
|
| + ResourceIdArray resources_for_child;
|
| +
|
| for (ResourceIdMap::iterator child_it = child.child_to_parent_map.begin();
|
| child_it != child.child_to_parent_map.end();
|
| ++child_it) {
|
| ResourceId id = child_it->second;
|
| - // We're abandoning this resource, it will not get recycled.
|
| - // crbug.com/224062
|
| - ResourceMap::iterator resource_it = resources_.find(id);
|
| - CHECK(resource_it != resources_.end());
|
| - resource_it->second.imported_count = 0;
|
| - DeleteResource(id);
|
| + resources_for_child.push_back(id);
|
| }
|
| +
|
| + // If the child is going away, don't consider any resources in use.
|
| + child.in_use_resources.clear();
|
| +
|
| + DeleteAndReturnUnusedResourcesToChild(
|
| + &child, ForShutdown, resources_for_child);
|
| +
|
| children_.erase(it);
|
| }
|
|
|
| @@ -875,62 +887,6 @@ void ResourceProvider::PrepareSendToParent(const ResourceIdArray& resources,
|
| }
|
| }
|
|
|
| -void ResourceProvider::PrepareSendReturnsToChild(
|
| - int child,
|
| - const ResourceIdArray& resources,
|
| - ReturnedResourceArray* list) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - WebGraphicsContext3D* context3d = Context3d();
|
| - if (!context3d || !context3d->makeContextCurrent()) {
|
| - // TODO(skaslev): Implement this path for software compositing.
|
| - return;
|
| - }
|
| - Child& child_info = children_.find(child)->second;
|
| - bool need_sync_point = false;
|
| - for (ResourceIdArray::const_iterator it = resources.begin();
|
| - it != resources.end(); ++it) {
|
| - Resource* resource = GetResource(*it);
|
| - DCHECK(!resource->locked_for_write);
|
| - DCHECK(!resource->lock_for_read_count);
|
| - DCHECK(child_info.parent_to_child_map.find(*it) !=
|
| - child_info.parent_to_child_map.end());
|
| -
|
| - if (resource->filter != resource->original_filter) {
|
| - DCHECK(resource->target);
|
| - DCHECK(resource->gl_id);
|
| -
|
| - GLC(context3d, context3d->bindTexture(resource->target, resource->gl_id));
|
| - GLC(context3d, context3d->texParameteri(resource->target,
|
| - GL_TEXTURE_MIN_FILTER,
|
| - resource->original_filter));
|
| - GLC(context3d, context3d->texParameteri(resource->target,
|
| - GL_TEXTURE_MAG_FILTER,
|
| - resource->original_filter));
|
| - }
|
| -
|
| - ReturnedResource returned;
|
| - returned.id = child_info.parent_to_child_map[*it];
|
| - returned.sync_point = resource->mailbox.sync_point();
|
| - if (!returned.sync_point)
|
| - need_sync_point = true;
|
| - returned.count = resource->imported_count;
|
| - list->push_back(returned);
|
| -
|
| - child_info.parent_to_child_map.erase(*it);
|
| - child_info.child_to_parent_map.erase(returned.id);
|
| - resources_[*it].imported_count = 0;
|
| - DeleteResource(*it);
|
| - }
|
| - if (need_sync_point) {
|
| - unsigned int sync_point = context3d->insertSyncPoint();
|
| - for (ReturnedResourceArray::iterator it = list->begin();
|
| - it != list->end(); ++it) {
|
| - if (!it->sync_point)
|
| - it->sync_point = sync_point;
|
| - }
|
| - }
|
| -}
|
| -
|
| void ResourceProvider::ReceiveFromChild(
|
| int child, const TransferableResourceArray& resources) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| @@ -962,26 +918,65 @@ void ResourceProvider::ReceiveFromChild(
|
| GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, texture_id));
|
| GLC(context3d, context3d->consumeTextureCHROMIUM(GL_TEXTURE_2D,
|
| it->mailbox.name));
|
| -
|
| - ResourceId id = next_id_++;
|
| - Resource resource(
|
| - texture_id,
|
| - it->size,
|
| - it->filter,
|
| - 0,
|
| - GL_CLAMP_TO_EDGE,
|
| - TextureUsageAny,
|
| - it->format);
|
| + ResourceId local_id = next_id_++;
|
| + Resource resource(texture_id,
|
| + it->size,
|
| + it->filter,
|
| + 0,
|
| + GL_CLAMP_TO_EDGE,
|
| + TextureUsageAny,
|
| + it->format);
|
| resource.mailbox.SetName(it->mailbox);
|
| + resource.child_id = child;
|
| // Don't allocate a texture for a child.
|
| resource.allocated = true;
|
| resource.imported_count = 1;
|
| - resources_[id] = resource;
|
| - child_info.parent_to_child_map[id] = it->id;
|
| - child_info.child_to_parent_map[it->id] = id;
|
| + resources_[local_id] = resource;
|
| + child_info.parent_to_child_map[local_id] = it->id;
|
| + child_info.child_to_parent_map[it->id] = local_id;
|
| }
|
| }
|
|
|
| +void ResourceProvider::DeclareUsedResourcesFromChild(
|
| + int child,
|
| + const ResourceIdArray& resources_from_child) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + Child& child_info = children_.find(child)->second;
|
| + child_info.in_use_resources.clear();
|
| +
|
| + for (size_t i = 0; i < resources_from_child.size(); ++i) {
|
| + ResourceIdMap::iterator it =
|
| + child_info.child_to_parent_map.find(resources_from_child[i]);
|
| + DCHECK(it != child_info.child_to_parent_map.end());
|
| +
|
| + ResourceId local_id = it->second;
|
| + child_info.in_use_resources.insert(local_id);
|
| + }
|
| +
|
| + ResourceIdArray unused;
|
| + for (ResourceIdMap::iterator it = child_info.child_to_parent_map.begin();
|
| + it != child_info.child_to_parent_map.end();
|
| + ++it) {
|
| + ResourceId local_id = it->second;
|
| + bool resource_is_in_use = child_info.in_use_resources.count(local_id) > 0;
|
| + if (!resource_is_in_use)
|
| + unused.push_back(local_id);
|
| + }
|
| + DeleteAndReturnUnusedResourcesToChild(&child_info, Normal, unused);
|
| +}
|
| +
|
| +// static
|
| +bool ResourceProvider::CompareResourceMapIteratorsByChildId(
|
| + const std::pair<ReturnedResource, ResourceMap::iterator>& a,
|
| + const std::pair<ReturnedResource, ResourceMap::iterator>& b) {
|
| + const ResourceMap::iterator& a_it = a.second;
|
| + const ResourceMap::iterator& b_it = b.second;
|
| + const Resource& a_resource = a_it->second;
|
| + const Resource& b_resource = b_it->second;
|
| + return a_resource.child_id < b_resource.child_id;
|
| +}
|
| +
|
| void ResourceProvider::ReceiveReturnsFromParent(
|
| const ReturnedResourceArray& resources) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| @@ -990,25 +985,83 @@ void ResourceProvider::ReceiveReturnsFromParent(
|
| // TODO(skaslev): Implement this path for software compositing.
|
| return;
|
| }
|
| +
|
| + int child_id = 0;
|
| + Child* child_info = NULL;
|
| + ResourceIdArray resources_for_child;
|
| +
|
| + std::vector<std::pair<ReturnedResource, ResourceMap::iterator> >
|
| + sorted_resources;
|
| +
|
| for (ReturnedResourceArray::const_iterator it = resources.begin();
|
| it != resources.end();
|
| ++it) {
|
| - ResourceMap::iterator map_iterator = resources_.find(it->id);
|
| - DCHECK(map_iterator != resources_.end());
|
| + ResourceId local_id = it->id;
|
| + ResourceMap::iterator map_iterator = resources_.find(local_id);
|
| +
|
| + // Resource was already lost (e.g. it belonged to a child that was
|
| + // destroyed).
|
| + if (map_iterator == resources_.end())
|
| + continue;
|
| +
|
| + sorted_resources.push_back(
|
| + std::pair<ReturnedResource, ResourceMap::iterator>(*it, map_iterator));
|
| + }
|
| +
|
| + std::sort(sorted_resources.begin(),
|
| + sorted_resources.end(),
|
| + CompareResourceMapIteratorsByChildId);
|
| +
|
| + for (size_t i = 0; i < sorted_resources.size(); ++i) {
|
| + ReturnedResource& returned = sorted_resources[i].first;
|
| + ResourceMap::iterator& map_iterator = sorted_resources[i].second;
|
| + ResourceId local_id = map_iterator->first;
|
| Resource* resource = &map_iterator->second;
|
| - CHECK_GE(resource->exported_count, it->count);
|
| - resource->exported_count -= it->count;
|
| +
|
| + CHECK_GE(resource->exported_count, returned.count);
|
| + resource->exported_count -= returned.count;
|
| if (resource->exported_count)
|
| continue;
|
| +
|
| if (resource->gl_id) {
|
| - if (it->sync_point)
|
| - GLC(context3d, context3d->waitSyncPoint(it->sync_point));
|
| + if (returned.sync_point)
|
| + GLC(context3d, context3d->waitSyncPoint(returned.sync_point));
|
| } else {
|
| resource->mailbox =
|
| - TextureMailbox(resource->mailbox.name(), it->sync_point);
|
| + TextureMailbox(resource->mailbox.name(), returned.sync_point);
|
| }
|
| - if (resource->marked_for_deletion)
|
| +
|
| + if (!resource->marked_for_deletion)
|
| + continue;
|
| +
|
| + if (!resource->child_id) {
|
| + // The resource belongs to this ResourceProvider, so it can be destroyed.
|
| DeleteResourceInternal(map_iterator, Normal);
|
| + continue;
|
| + }
|
| +
|
| + // Delete the resource and return it to the child it came from one.
|
| + if (resource->child_id != child_id) {
|
| + ChildMap::iterator child_it = children_.find(resource->child_id);
|
| + DCHECK(child_it != children_.end());
|
| +
|
| + if (child_id) {
|
| + DCHECK_NE(resources_for_child.size(), 0u);
|
| + DeleteAndReturnUnusedResourcesToChild(
|
| + child_info, Normal, resources_for_child);
|
| + resources_for_child.clear();
|
| + }
|
| +
|
| + child_info = &child_it->second;
|
| + child_id = resource->child_id;
|
| + }
|
| + resources_for_child.push_back(local_id);
|
| + }
|
| +
|
| + if (child_id) {
|
| + DCHECK_NE(resources_for_child.size(), 0u);
|
| + DeleteAndReturnUnusedResourcesToChild(
|
| + child_info, Normal, resources_for_child);
|
| }
|
| }
|
|
|
| @@ -1046,6 +1099,93 @@ void ResourceProvider::TransferResource(WebGraphicsContext3D* context,
|
| }
|
| }
|
|
|
| +void ResourceProvider::DeleteAndReturnUnusedResourcesToChild(
|
| + Child* child_info,
|
| + DeleteStyle style,
|
| + const ResourceIdArray& unused) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(child_info);
|
| +
|
| + if (unused.empty())
|
| + return;
|
| +
|
| + WebGraphicsContext3D* context3d = Context3d();
|
| + if (!context3d || !context3d->makeContextCurrent()) {
|
| + // TODO(skaslev): Implement this path for software compositing.
|
| + return;
|
| + }
|
| +
|
| + ReturnedResourceArray to_return;
|
| +
|
| + bool need_sync_point = false;
|
| + for (size_t i = 0; i < unused.size(); ++i) {
|
| + ResourceId local_id = unused[i];
|
| +
|
| + ResourceMap::iterator it = resources_.find(local_id);
|
| + CHECK(it != resources_.end());
|
| + Resource& resource = it->second;
|
| +
|
| + DCHECK(!resource.locked_for_write);
|
| + DCHECK(!resource.lock_for_read_count);
|
| + DCHECK_EQ(0u, child_info->in_use_resources.count(local_id));
|
| + DCHECK(child_info->parent_to_child_map.count(local_id));
|
| +
|
| + ResourceId child_id = child_info->parent_to_child_map[local_id];
|
| + DCHECK(child_info->child_to_parent_map.count(child_id));
|
| +
|
| + // TODO(danakj): bool is_lost = false;
|
| + if (resource.exported_count > 0) {
|
| + if (style != ForShutdown) {
|
| + // Defer this until we receive the resource back from the parent.
|
| + resource.marked_for_deletion = true;
|
| + continue;
|
| + }
|
| +
|
| + // We still have an exported_count, so we'll have to lose it.
|
| + // TODO(danakj): is_lost = true;
|
| + }
|
| +
|
| + if (resource.filter != resource.original_filter) {
|
| + DCHECK(resource.target);
|
| + DCHECK(resource.gl_id);
|
| +
|
| + GLC(context3d, context3d->bindTexture(resource.target, resource.gl_id));
|
| + GLC(context3d,
|
| + context3d->texParameteri(resource.target,
|
| + GL_TEXTURE_MIN_FILTER,
|
| + resource.original_filter));
|
| + GLC(context3d,
|
| + context3d->texParameteri(resource.target,
|
| + GL_TEXTURE_MAG_FILTER,
|
| + resource.original_filter));
|
| + }
|
| +
|
| + ReturnedResource returned;
|
| + returned.id = child_id;
|
| + returned.sync_point = resource.mailbox.sync_point();
|
| + if (!returned.sync_point)
|
| + need_sync_point = true;
|
| + returned.count = resource.imported_count;
|
| + // TODO(danakj): Save the |is_lost| bit.
|
| + to_return.push_back(returned);
|
| +
|
| + child_info->parent_to_child_map.erase(local_id);
|
| + child_info->child_to_parent_map.erase(child_id);
|
| + resource.imported_count = 0;
|
| + DeleteResourceInternal(it, style);
|
| + }
|
| + if (need_sync_point) {
|
| + unsigned int sync_point = context3d->insertSyncPoint();
|
| + for (size_t i = 0; i < to_return.size(); ++i) {
|
| + if (!to_return[i].sync_point)
|
| + to_return[i].sync_point = sync_point;
|
| + }
|
| + }
|
| +
|
| + if (!to_return.empty())
|
| + child_info->return_callback.Run(to_return);
|
| +}
|
| +
|
| void ResourceProvider::AcquirePixelBuffer(ResourceId id) {
|
| Resource* resource = GetResource(id);
|
| DCHECK(!resource->external);
|
|
|