| Index: cc/resources/video_resource_updater.cc
|
| diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc
|
| index 2c9a688619adeb0087018be964281b8f9d17dcb8..edbea9b53c92f110b28024a3814f31bfabe2ad46 100644
|
| --- a/cc/resources/video_resource_updater.cc
|
| +++ b/cc/resources/video_resource_updater.cc
|
| @@ -4,6 +4,8 @@
|
|
|
| #include "cc/resources/video_resource_updater.h"
|
|
|
| +#include <algorithm>
|
| +
|
| #include "base/bind.h"
|
| #include "base/debug/trace_event.h"
|
| #include "cc/output/gl_renderer.h"
|
| @@ -48,6 +50,7 @@ VideoResourceUpdater::PlaneResource::PlaneResource(
|
| resource_size(resource_size),
|
| resource_format(resource_format),
|
| mailbox(mailbox),
|
| + ref_count(0),
|
| frame_ptr(nullptr),
|
| plane_index(0) {
|
| }
|
| @@ -81,17 +84,43 @@ VideoResourceUpdater::VideoResourceUpdater(ContextProvider* context_provider,
|
| }
|
|
|
| VideoResourceUpdater::~VideoResourceUpdater() {
|
| - while (!all_resources_.empty()) {
|
| - resource_provider_->DeleteResource(all_resources_.back());
|
| - all_resources_.pop_back();
|
| + for (const PlaneResource& plane_resource : all_resources_)
|
| + resource_provider_->DeleteResource(plane_resource.resource_id);
|
| +}
|
| +
|
| +VideoResourceUpdater::ResourceList::iterator
|
| +VideoResourceUpdater::AllocateResource(const gfx::Size& plane_size,
|
| + ResourceFormat format,
|
| + bool has_mailbox) {
|
| + // TODO(danakj): Abstract out hw/sw resource create/delete from
|
| + // ResourceProvider and stop using ResourceProvider in this class.
|
| + const ResourceProvider::ResourceId resource_id =
|
| + resource_provider_->CreateResource(plane_size, GL_CLAMP_TO_EDGE,
|
| + ResourceProvider::TextureHintImmutable,
|
| + format);
|
| + if (resource_id == 0)
|
| + return all_resources_.end();
|
| +
|
| + gpu::Mailbox mailbox;
|
| + if (has_mailbox) {
|
| + DCHECK(context_provider_);
|
| +
|
| + gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
|
| +
|
| + GLC(gl, gl->GenMailboxCHROMIUM(mailbox.name));
|
| + ResourceProvider::ScopedWriteLockGL lock(resource_provider_, resource_id);
|
| + GLC(gl, gl->ProduceTextureDirectCHROMIUM(lock.texture_id(), GL_TEXTURE_2D,
|
| + mailbox.name));
|
| }
|
| + all_resources_.push_front(
|
| + PlaneResource(resource_id, plane_size, format, mailbox));
|
| + return all_resources_.begin();
|
| }
|
|
|
| -void VideoResourceUpdater::DeleteResource(unsigned resource_id) {
|
| - resource_provider_->DeleteResource(resource_id);
|
| - all_resources_.erase(std::remove(all_resources_.begin(),
|
| - all_resources_.end(),
|
| - resource_id));
|
| +void VideoResourceUpdater::DeleteResource(ResourceList::iterator resource_it) {
|
| + DCHECK_EQ(resource_it->ref_count, 0);
|
| + resource_provider_->DeleteResource(resource_it->resource_id);
|
| + all_resources_.erase(resource_it);
|
| }
|
|
|
| VideoFrameExternalResources VideoResourceUpdater::
|
| @@ -157,19 +186,15 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
|
| #endif // defined(VIDEO_HOLE)
|
|
|
| // Only YUV software video frames are supported.
|
| - DCHECK(input_frame_format == media::VideoFrame::YV12 ||
|
| - input_frame_format == media::VideoFrame::I420 ||
|
| - input_frame_format == media::VideoFrame::YV12A ||
|
| - input_frame_format == media::VideoFrame::YV12J ||
|
| - input_frame_format == media::VideoFrame::YV16 ||
|
| - input_frame_format == media::VideoFrame::YV24);
|
| if (input_frame_format != media::VideoFrame::YV12 &&
|
| input_frame_format != media::VideoFrame::I420 &&
|
| input_frame_format != media::VideoFrame::YV12A &&
|
| input_frame_format != media::VideoFrame::YV12J &&
|
| input_frame_format != media::VideoFrame::YV16 &&
|
| - input_frame_format != media::VideoFrame::YV24)
|
| + input_frame_format != media::VideoFrame::YV24) {
|
| + NOTREACHED() << input_frame_format;
|
| return VideoFrameExternalResources();
|
| + }
|
|
|
| bool software_compositor = context_provider_ == NULL;
|
|
|
| @@ -186,81 +211,69 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
|
| output_plane_count = 1;
|
| }
|
|
|
| - int max_resource_size = resource_provider_->max_texture_size();
|
| - std::vector<PlaneResource> plane_resources;
|
| - bool allocation_success = true;
|
| + // Drop recycled resources that are the wrong format.
|
| + for (auto it = all_resources_.begin(); it != all_resources_.end();) {
|
| + if (it->ref_count == 0 && it->resource_format != output_resource_format)
|
| + DeleteResource(it++);
|
| + else
|
| + ++it;
|
| + }
|
|
|
| + const int max_resource_size = resource_provider_->max_texture_size();
|
| + std::vector<ResourceList::iterator> plane_resources;
|
| for (size_t i = 0; i < output_plane_count; ++i) {
|
| gfx::Size output_plane_resource_size =
|
| SoftwarePlaneDimension(video_frame, software_compositor, i);
|
| if (output_plane_resource_size.IsEmpty() ||
|
| output_plane_resource_size.width() > max_resource_size ||
|
| output_plane_resource_size.height() > max_resource_size) {
|
| - allocation_success = false;
|
| break;
|
| }
|
|
|
| // Try recycle a previously-allocated resource.
|
| - auto recycled_it = recycled_resources_.end();
|
| - for (auto it = recycled_resources_.begin(); it != recycled_resources_.end();
|
| - ++it) {
|
| - const bool resource_matches =
|
| - it->resource_format == output_resource_format &&
|
| - it->resource_size == output_plane_resource_size;
|
| - const bool in_use = software_compositor &&
|
| - resource_provider_->InUseByConsumer(it->resource_id);
|
| - if (resource_matches && !in_use) {
|
| - // We found a recycled resource with the allocation size and format we
|
| - // are looking for.
|
| - recycled_it = it;
|
| - // Keep looking for a recycled resource that also contains the data we
|
| - // are planning to put in it.
|
| - if (PlaneResourceMatchesUniqueID(*it, video_frame.get(), i))
|
| + ResourceList::iterator resource_it = all_resources_.end();
|
| + for (auto it = all_resources_.begin(); it != all_resources_.end(); ++it) {
|
| + if (it->resource_size == output_plane_resource_size &&
|
| + it->resource_format == output_resource_format) {
|
| + if (PlaneResourceMatchesUniqueID(*it, video_frame.get(), i)) {
|
| + // Bingo, we found a resource that already contains the data we are
|
| + // planning to put in it. It's safe to reuse it even if
|
| + // resource_provider_ holds some references to it, because those
|
| + // references are read-only.
|
| + resource_it = it;
|
| break;
|
| + }
|
| +
|
| + // This extra check is needed because resources backed by SharedMemory
|
| + // are not ref-counted, unlike mailboxes. Full discussion in
|
| + // codereview.chromium.org/145273021.
|
| + const bool in_use =
|
| + software_compositor &&
|
| + resource_provider_->InUseByConsumer(it->resource_id);
|
| + if (it->ref_count == 0 && !in_use) {
|
| + // We found a resource with the correct size that we can overwrite.
|
| + resource_it = it;
|
| + }
|
| }
|
| }
|
|
|
| - // Check if we can avoid allocating a new resource.
|
| - if (recycled_it != recycled_resources_.end()) {
|
| - plane_resources.push_back(*recycled_it);
|
| - recycled_resources_.erase(recycled_it);
|
| - continue;
|
| + // Check if we need to allocate a new resource.
|
| + if (resource_it == all_resources_.end()) {
|
| + resource_it =
|
| + AllocateResource(output_plane_resource_size, output_resource_format,
|
| + !software_compositor);
|
| }
|
| -
|
| - // TODO(danakj): Abstract out hw/sw resource create/delete from
|
| - // ResourceProvider and stop using ResourceProvider in this class.
|
| - const ResourceProvider::ResourceId resource_id =
|
| - resource_provider_->CreateResource(
|
| - output_plane_resource_size, GL_CLAMP_TO_EDGE,
|
| - ResourceProvider::TextureHintImmutable, output_resource_format);
|
| - if (resource_id == 0) {
|
| - allocation_success = false;
|
| + if (resource_it == all_resources_.end())
|
| break;
|
| - }
|
| - all_resources_.push_back(resource_id);
|
| -
|
| - gpu::Mailbox mailbox;
|
| - if (!software_compositor) {
|
| - DCHECK(context_provider_);
|
|
|
| - gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
|
| -
|
| - GLC(gl, gl->GenMailboxCHROMIUM(mailbox.name));
|
| - ResourceProvider::ScopedWriteLockGL lock(resource_provider_, resource_id);
|
| - GLC(gl, gl->ProduceTextureDirectCHROMIUM(lock.texture_id(), GL_TEXTURE_2D,
|
| - mailbox.name));
|
| - }
|
| -
|
| - DCHECK(software_compositor || !mailbox.IsZero());
|
| - plane_resources.push_back(PlaneResource(resource_id,
|
| - output_plane_resource_size,
|
| - output_resource_format,
|
| - mailbox));
|
| + ++resource_it->ref_count;
|
| + plane_resources.push_back(resource_it);
|
| }
|
|
|
| - if (!allocation_success) {
|
| - for (size_t i = 0; i < plane_resources.size(); ++i)
|
| - DeleteResource(plane_resources[i].resource_id);
|
| + if (plane_resources.size() != output_plane_count) {
|
| + // Allocation failed, nothing will be returned so restore reference counts.
|
| + for (ResourceList::iterator resource_it : plane_resources)
|
| + --resource_it->ref_count;
|
| return VideoFrameExternalResources();
|
| }
|
|
|
| @@ -268,54 +281,52 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
|
|
|
| if (software_compositor) {
|
| DCHECK_EQ(plane_resources.size(), 1u);
|
| - DCHECK_EQ(plane_resources[0].resource_format, kRGBResourceFormat);
|
| - DCHECK(plane_resources[0].mailbox.IsZero());
|
| + PlaneResource& plane_resource = *plane_resources[0];
|
| + DCHECK_EQ(plane_resource.resource_format, kRGBResourceFormat);
|
| + DCHECK(plane_resource.mailbox.IsZero());
|
|
|
| - if (!PlaneResourceMatchesUniqueID(plane_resources[0], video_frame.get(),
|
| - 0)) {
|
| + if (!PlaneResourceMatchesUniqueID(plane_resource, video_frame.get(), 0)) {
|
| // We need to transfer data from |video_frame| to the plane resource.
|
| if (!video_renderer_)
|
| video_renderer_.reset(new media::SkCanvasVideoRenderer);
|
|
|
| ResourceProvider::ScopedWriteLockSoftware lock(
|
| - resource_provider_, plane_resources[0].resource_id);
|
| + resource_provider_, plane_resource.resource_id);
|
| SkCanvas canvas(lock.sk_bitmap());
|
| video_renderer_->Copy(video_frame, &canvas);
|
| - SetPlaneResourceUniqueId(video_frame.get(), 0, &plane_resources[0]);
|
| + SetPlaneResourceUniqueId(video_frame.get(), 0, &plane_resource);
|
| }
|
|
|
| - external_resources.software_resources.push_back(
|
| - plane_resources[0].resource_id);
|
| + external_resources.software_resources.push_back(plane_resource.resource_id);
|
| external_resources.software_release_callback =
|
| - base::Bind(&RecycleResource, AsWeakPtr(), plane_resources[0]);
|
| + base::Bind(&RecycleResource, AsWeakPtr(), plane_resource.resource_id);
|
| external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE;
|
| -
|
| return external_resources;
|
| }
|
|
|
| for (size_t i = 0; i < plane_resources.size(); ++i) {
|
| + PlaneResource& plane_resource = *plane_resources[i];
|
| // Update each plane's resource id with its content.
|
| - DCHECK_EQ(plane_resources[i].resource_format,
|
| + DCHECK_EQ(plane_resource.resource_format,
|
| resource_provider_->yuv_resource_format());
|
|
|
| - if (!PlaneResourceMatchesUniqueID(plane_resources[i], video_frame.get(),
|
| - i)) {
|
| + if (!PlaneResourceMatchesUniqueID(plane_resource, video_frame.get(), i)) {
|
| // We need to transfer data from |video_frame| to the plane resource.
|
| const uint8_t* input_plane_pixels = video_frame->data(i);
|
|
|
| gfx::Rect image_rect(0, 0, video_frame->stride(i),
|
| - plane_resources[i].resource_size.height());
|
| - gfx::Rect source_rect(plane_resources[i].resource_size);
|
| - resource_provider_->SetPixels(plane_resources[i].resource_id,
|
| + plane_resource.resource_size.height());
|
| + gfx::Rect source_rect(plane_resource.resource_size);
|
| + resource_provider_->SetPixels(plane_resource.resource_id,
|
| input_plane_pixels, image_rect, source_rect,
|
| gfx::Vector2d());
|
| - SetPlaneResourceUniqueId(video_frame.get(), i, &plane_resources[i]);
|
| + SetPlaneResourceUniqueId(video_frame.get(), i, &plane_resource);
|
| }
|
|
|
| external_resources.mailboxes.push_back(
|
| - TextureMailbox(plane_resources[i].mailbox, GL_TEXTURE_2D, 0));
|
| + TextureMailbox(plane_resource.mailbox, GL_TEXTURE_2D, 0));
|
| external_resources.release_callbacks.push_back(
|
| - base::Bind(&RecycleResource, AsWeakPtr(), plane_resources[i]));
|
| + base::Bind(&RecycleResource, AsWeakPtr(), plane_resource.resource_id));
|
| }
|
|
|
| external_resources.type = VideoFrameExternalResources::YUV_RESOURCE;
|
| @@ -382,7 +393,7 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes(
|
| // static
|
| void VideoResourceUpdater::RecycleResource(
|
| base::WeakPtr<VideoResourceUpdater> updater,
|
| - PlaneResource data,
|
| + ResourceProvider::ResourceId resource_id,
|
| uint32 sync_point,
|
| bool lost_resource,
|
| BlockingTaskRunner* main_thread_task_runner) {
|
| @@ -391,6 +402,14 @@ void VideoResourceUpdater::RecycleResource(
|
| return;
|
| }
|
|
|
| + const ResourceList::iterator resource_it = std::find_if(
|
| + updater->all_resources_.begin(), updater->all_resources_.end(),
|
| + [resource_id](const PlaneResource& plane_resource) {
|
| + return plane_resource.resource_id == resource_id;
|
| + });
|
| + if (resource_it == updater->all_resources_.end())
|
| + return;
|
| +
|
| ContextProvider* context_provider = updater->context_provider_;
|
| if (context_provider && sync_point) {
|
| GLC(context_provider->ContextGL(),
|
| @@ -398,19 +417,13 @@ void VideoResourceUpdater::RecycleResource(
|
| }
|
|
|
| if (lost_resource) {
|
| - updater->DeleteResource(data.resource_id);
|
| + resource_it->ref_count = 0;
|
| + updater->DeleteResource(resource_it);
|
| return;
|
| }
|
|
|
| - // Drop recycled resources that are the wrong format.
|
| - while (!updater->recycled_resources_.empty() &&
|
| - updater->recycled_resources_.back().resource_format !=
|
| - data.resource_format) {
|
| - updater->DeleteResource(updater->recycled_resources_.back().resource_id);
|
| - updater->recycled_resources_.pop_back();
|
| - }
|
| -
|
| - updater->recycled_resources_.push_back(data);
|
| + --resource_it->ref_count;
|
| + DCHECK_GE(resource_it->ref_count, 0);
|
| }
|
|
|
| } // namespace cc
|
|
|