Skip to content

Commit

Permalink
Allow giving TransferableResource as an input for cc.
Browse files Browse the repository at this point in the history
This lets LayerTreeResourceProvider accept a TransferableResource
in order to generate a ResourceId. Then, when exported as part of
a CompositorFrame, the TransferableResource is forwarded into the
CompositorFrame.

This can replace the use of TextureMailbox for passing resources
into the layer compositor for forwarding through to the display
compositor. Since the layer compositor always forwards resources,
it has no need of any other data format, and can just pass along
the TransferableResource verbatim (with a ResourceId change to
the local ResourceProvider's namespace).

Next steps from here would be to change cc clients to pass a
TransferableResource instead of a TextureMailbox through the
TextureLayer. Then remove all concept of "external" resources
in ResourceProvider, as resources usable by the ResourceProvider
client will always be "internal" in the layer compositor, and
will always be internal or delegated (soon to be always
delegated hopefully) in the display compositor.

R=piman@chromium.org

Bug: 769423
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel
Change-Id: I3d8674fbd7ab6830f52ba99c5ce4459d0c5241c8
Reviewed-on: https://chromium-review.googlesource.com/691080
Commit-Queue: danakj <danakj@chromium.org>
Reviewed-by: Antoine Labour <piman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#516587}
  • Loading branch information
danakj authored and Commit Bot committed Nov 15, 2017
1 parent 58dfbce commit c0bb5ec
Show file tree
Hide file tree
Showing 8 changed files with 604 additions and 26 deletions.
1 change: 1 addition & 0 deletions cc/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,7 @@ cc_test("cc_unittests") {
"raster/synchronous_task_graph_runner_unittest.cc",
"raster/task_graph_work_queue_unittest.cc",
"raster/texture_compressor_etc1_unittest.cc",
"resources/layer_tree_resource_provider_unittest.cc",
"resources/resource_pool_unittest.cc",
"resources/resource_provider_unittest.cc",
"resources/resource_util_unittest.cc",
Expand Down
2 changes: 1 addition & 1 deletion cc/layers/layer_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ void LayerImpl::NoteLayerPropertyChangedFromPropertyTrees() {

void LayerImpl::ValidateQuadResourcesInternal(viz::DrawQuad* quad) const {
#if DCHECK_IS_ON()
const ResourceProvider* resource_provider =
const LayerTreeResourceProvider* resource_provider =
layer_tree_impl_->resource_provider();
for (viz::ResourceId resource_id : quad->resources)
resource_provider->ValidateResource(resource_id);
Expand Down
154 changes: 139 additions & 15 deletions cc/resources/layer_tree_resource_provider.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,29 @@ namespace {
const unsigned int kInitialResourceId = 1;
} // namespace

struct LayerTreeResourceProvider::ImportedResource {
viz::TransferableResource resource;
std::unique_ptr<viz::SingleReleaseCallback> release_callback;
int exported_count = 0;
bool marked_for_deletion = false;

gpu::SyncToken returned_sync_token;
bool returned_lost = false;

ImportedResource(viz::ResourceId id,
const viz::TransferableResource& resource,
std::unique_ptr<viz::SingleReleaseCallback> release_callback)
: resource(resource), release_callback(std::move(release_callback)) {
// Replace the |resource| id with the local id from this
// LayerTreeResourceProvider.
this->resource.id = id;
}
~ImportedResource() = default;

ImportedResource(ImportedResource&&) = default;
ImportedResource& operator=(ImportedResource&&) = default;
};

LayerTreeResourceProvider::LayerTreeResourceProvider(
viz::ContextProvider* compositor_context_provider,
viz::SharedBitmapManager* shared_bitmap_manager,
Expand All @@ -34,7 +57,12 @@ LayerTreeResourceProvider::LayerTreeResourceProvider(
resource_settings,
kInitialResourceId) {}

LayerTreeResourceProvider::~LayerTreeResourceProvider() {}
LayerTreeResourceProvider::~LayerTreeResourceProvider() {
for (auto& pair : imported_resources_) {
ImportedResource& imported = pair.second;
imported.release_callback->Run(gpu::SyncToken(), true /* is_lost */);
}
}

viz::ResourceId LayerTreeResourceProvider::CreateResourceFromTextureMailbox(
const viz::TextureMailbox& mailbox,
Expand Down Expand Up @@ -112,22 +140,33 @@ gpu::SyncToken LayerTreeResourceProvider::GetSyncTokenForResources(
}

void LayerTreeResourceProvider::PrepareSendToParent(
const ResourceIdArray& resource_ids,
const ResourceIdArray& export_ids,
std::vector<viz::TransferableResource>* list) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
GLES2Interface* gl = ContextGL();

// This function goes through the array multiple times, store the resources
// as pointers so we don't have to look up the resource id multiple times.
std::vector<viz::internal::Resource*> resources;
resources.reserve(resource_ids.size());
for (const viz::ResourceId id : resource_ids)
resources.push_back(GetResource(id));
// Make sure the maps do not change while these vectors are alive or they
// will become invalid.
std::vector<std::pair<viz::internal::Resource*, viz::ResourceId>> resources;
std::vector<ImportedResource*> imports;
resources.reserve(export_ids.size());
imports.reserve(export_ids.size());
for (const viz::ResourceId id : export_ids) {
auto it = imported_resources_.find(id);
if (it != imported_resources_.end())
imports.push_back(&it->second);
else
resources.push_back({GetResource(id), id});
}
DCHECK_EQ(resources.size() + imports.size(), export_ids.size());

// Lazily create any mailboxes and verify all unverified sync tokens.
std::vector<GLbyte*> unverified_sync_tokens;
std::vector<viz::internal::Resource*> need_synchronization_resources;
for (viz::internal::Resource* resource : resources) {
for (auto& pair : resources) {
viz::internal::Resource* resource = pair.first;
if (!resource->is_gpu_resource_type())
continue;

Expand All @@ -141,6 +180,15 @@ void LayerTreeResourceProvider::PrepareSendToParent(
}
}
}
if (settings_.delegated_sync_points_required) {
for (ImportedResource* imported : imports) {
if (!imported->resource.is_software &&
!imported->resource.mailbox_holder.sync_token.verified_flush()) {
unverified_sync_tokens.push_back(
imported->resource.mailbox_holder.sync_token.GetData());
}
}
}

// Insert sync point to synchronize the mailbox creation or bound textures.
gpu::SyncToken new_sync_token;
Expand Down Expand Up @@ -170,11 +218,10 @@ void LayerTreeResourceProvider::PrepareSendToParent(
resource->SetSynchronized();
}

// Transfer Resources
DCHECK_EQ(resources.size(), resource_ids.size());
// Transfer Resources.
for (size_t i = 0; i < resources.size(); ++i) {
viz::internal::Resource* source = resources[i];
const viz::ResourceId id = resource_ids[i];
viz::internal::Resource* source = resources[i].first;
const viz::ResourceId id = resources[i].second;

DCHECK(!settings_.delegated_sync_points_required ||
!source->needs_sync_token());
Expand All @@ -186,7 +233,11 @@ void LayerTreeResourceProvider::PrepareSendToParent(
TransferResource(source, id, &resource);

source->exported_count++;
list->push_back(resource);
list->push_back(std::move(resource));
}
for (ImportedResource* imported : imports) {
list->push_back(imported->resource);
imported->exported_count++;
}
}

Expand All @@ -197,15 +248,44 @@ void LayerTreeResourceProvider::ReceiveReturnsFromParent(

for (const viz::ReturnedResource& returned : resources) {
viz::ResourceId local_id = returned.id;
ResourceMap::iterator map_iterator = resources_.find(local_id);

auto import_it = imported_resources_.find(local_id);
if (import_it != imported_resources_.end()) {
ImportedResource& imported = import_it->second;

DCHECK_GE(imported.exported_count, returned.count);
imported.exported_count -= returned.count;
imported.returned_lost |= returned.lost;

if (imported.exported_count)
continue;

if (returned.sync_token.HasData()) {
DCHECK(!imported.resource.is_software);
imported.returned_sync_token = returned.sync_token;
}

if (imported.marked_for_deletion) {
imported.release_callback->Run(imported.returned_sync_token,
imported.returned_lost);
imported_resources_.erase(import_it);
}

continue;
}

auto map_iterator = resources_.find(local_id);
DCHECK(map_iterator != resources_.end());
// Resource was already lost (e.g. it belonged to a child that was
// destroyed).
// TODO(danakj): Remove this. There is no "child" here anymore, and
// lost resources are still in the map until exported_count == 0.
if (map_iterator == resources_.end())
continue;

viz::internal::Resource* resource = &map_iterator->second;

CHECK_GE(resource->exported_count, returned.count);
DCHECK_GE(resource->exported_count, returned.count);
resource->exported_count -= returned.count;
resource->lost |= returned.lost;
if (resource->exported_count)
Expand All @@ -232,6 +312,33 @@ void LayerTreeResourceProvider::ReceiveReturnsFromParent(
}
}

viz::ResourceId LayerTreeResourceProvider::ImportResource(
const viz::TransferableResource& resource,
std::unique_ptr<viz::SingleReleaseCallback> release_callback) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// This field is only for LayerTreeResourceProvider-created resources.
DCHECK(!resource.read_lock_fences_enabled);

viz::ResourceId id = next_id_++;
auto result = imported_resources_.emplace(
id, ImportedResource(id, resource, std::move(release_callback)));
DCHECK(result.second); // If false, the id was already in the map.
return id;
}

void LayerTreeResourceProvider::RemoveImportedResource(viz::ResourceId id) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
auto it = imported_resources_.find(id);
DCHECK(it != imported_resources_.end());
ImportedResource& imported = it->second;
imported.marked_for_deletion = true;
if (imported.exported_count == 0) {
imported.release_callback->Run(imported.returned_sync_token,
imported.returned_lost);
imported_resources_.erase(it);
}
}

void LayerTreeResourceProvider::TransferResource(
viz::internal::Resource* source,
viz::ResourceId id,
Expand All @@ -242,7 +349,6 @@ void LayerTreeResourceProvider::TransferResource(
resource->id = id;
resource->format = source->format;
resource->buffer_format = source->buffer_format;
resource->mailbox_holder.texture_target = source->target;
resource->filter = source->filter;
resource->size = source->size;
resource->read_lock_fences_enabled = source->read_lock_fences_enabled;
Expand Down Expand Up @@ -311,4 +417,22 @@ gfx::GpuMemoryBuffer* LayerTreeResourceProvider::
return gpu_memory_buffer_.get();
}

void LayerTreeResourceProvider::ValidateResource(viz::ResourceId id) const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(id);
DCHECK(resources_.find(id) != resources_.end() ||
imported_resources_.find(id) != imported_resources_.end());
}

bool LayerTreeResourceProvider::OnMemoryDump(
const base::trace_event::MemoryDumpArgs& args,
base::trace_event::ProcessMemoryDump* pmd) {
// Imported resources should be tracked in the client where they
// originated, as this code has only a name to refer to them and
// is not keeping them alive.

// Non-imported resources are tracked in the base class.
return ResourceProvider::OnMemoryDump(args, pmd);
}

} // namespace cc
19 changes: 19 additions & 0 deletions cc/resources/layer_tree_resource_provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ class CC_EXPORT LayerTreeResourceProvider : public ResourceProvider {
void ReceiveReturnsFromParent(
const std::vector<viz::ReturnedResource>& transferable_resources);

// Receives a resource from an external client that can be used in compositor
// frames, via the returned ResourceId.
viz::ResourceId ImportResource(const viz::TransferableResource&,
std::unique_ptr<viz::SingleReleaseCallback>);
// Removes an imported resource, which will call the ReleaseCallback given
// originally, once the resource is no longer in use by any compositor frame.
void RemoveImportedResource(viz::ResourceId);

// Verify that the ResourceId is valid and is known to this class, for debug
// checks.
void ValidateResource(viz::ResourceId id) const;

// The following lock classes are part of the LayerTreeResourceProvider API
// and are needed to write the resource contents. The user must ensure that
// they only use GL locks on GL resources, etc, and this is enforced by
Expand Down Expand Up @@ -87,10 +99,17 @@ class CC_EXPORT LayerTreeResourceProvider : public ResourceProvider {
};

private:
// base::trace_event::MemoryDumpProvider implementation.
bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
base::trace_event::ProcessMemoryDump* pmd) override;

void TransferResource(viz::internal::Resource* source,
viz::ResourceId id,
viz::TransferableResource* resource);

struct ImportedResource;
base::flat_map<viz::ResourceId, ImportedResource> imported_resources_;

DISALLOW_COPY_AND_ASSIGN(LayerTreeResourceProvider);
};

Expand Down
Loading

0 comments on commit c0bb5ec

Please sign in to comment.