| Index: cc/resources/video_resource_updater.cc
|
| diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc
|
| deleted file mode 100644
|
| index ed57e6fb9edbf95f7b4277b868f8dce2fe8969ec..0000000000000000000000000000000000000000
|
| --- a/cc/resources/video_resource_updater.cc
|
| +++ /dev/null
|
| @@ -1,464 +0,0 @@
|
| -// Copyright 2013 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "cc/resources/video_resource_updater.h"
|
| -
|
| -#include <algorithm>
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/trace_event/trace_event.h"
|
| -#include "cc/base/util.h"
|
| -#include "cc/output/gl_renderer.h"
|
| -#include "cc/resources/resource_provider.h"
|
| -#include "gpu/GLES2/gl2extchromium.h"
|
| -#include "gpu/command_buffer/client/gles2_interface.h"
|
| -#include "media/base/video_frame.h"
|
| -#include "media/blink/skcanvas_video_renderer.h"
|
| -#include "third_party/khronos/GLES2/gl2.h"
|
| -#include "third_party/khronos/GLES2/gl2ext.h"
|
| -#include "ui/gfx/geometry/size_conversions.h"
|
| -
|
| -namespace cc {
|
| -
|
| -namespace {
|
| -
|
| -const ResourceFormat kRGBResourceFormat = RGBA_8888;
|
| -
|
| -class SyncPointClientImpl : public media::VideoFrame::SyncPointClient {
|
| - public:
|
| - explicit SyncPointClientImpl(gpu::gles2::GLES2Interface* gl) : gl_(gl) {}
|
| - ~SyncPointClientImpl() override {}
|
| - uint32 InsertSyncPoint() override {
|
| - return GLC(gl_, gl_->InsertSyncPointCHROMIUM());
|
| - }
|
| - void WaitSyncPoint(uint32 sync_point) override {
|
| - GLC(gl_, gl_->WaitSyncPointCHROMIUM(sync_point));
|
| - }
|
| -
|
| - private:
|
| - gpu::gles2::GLES2Interface* gl_;
|
| -};
|
| -
|
| -} // namespace
|
| -
|
| -VideoResourceUpdater::PlaneResource::PlaneResource(
|
| - unsigned int resource_id,
|
| - const gfx::Size& resource_size,
|
| - ResourceFormat resource_format,
|
| - gpu::Mailbox mailbox)
|
| - : resource_id(resource_id),
|
| - resource_size(resource_size),
|
| - resource_format(resource_format),
|
| - mailbox(mailbox),
|
| - ref_count(0),
|
| - frame_ptr(nullptr),
|
| - plane_index(0) {
|
| -}
|
| -
|
| -bool VideoResourceUpdater::PlaneResourceMatchesUniqueID(
|
| - const PlaneResource& plane_resource,
|
| - const media::VideoFrame* video_frame,
|
| - int plane_index) {
|
| - return plane_resource.frame_ptr == video_frame &&
|
| - plane_resource.plane_index == plane_index &&
|
| - plane_resource.timestamp == video_frame->timestamp();
|
| -}
|
| -
|
| -void VideoResourceUpdater::SetPlaneResourceUniqueId(
|
| - const media::VideoFrame* video_frame,
|
| - int plane_index,
|
| - PlaneResource* plane_resource) {
|
| - plane_resource->frame_ptr = video_frame;
|
| - plane_resource->plane_index = plane_index;
|
| - plane_resource->timestamp = video_frame->timestamp();
|
| -}
|
| -
|
| -VideoFrameExternalResources::VideoFrameExternalResources() : type(NONE) {}
|
| -
|
| -VideoFrameExternalResources::~VideoFrameExternalResources() {}
|
| -
|
| -VideoResourceUpdater::VideoResourceUpdater(ContextProvider* context_provider,
|
| - ResourceProvider* resource_provider)
|
| - : context_provider_(context_provider),
|
| - resource_provider_(resource_provider) {
|
| -}
|
| -
|
| -VideoResourceUpdater::~VideoResourceUpdater() {
|
| - 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::TEXTURE_HINT_IMMUTABLE, 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(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::
|
| - CreateExternalResourcesFromVideoFrame(
|
| - const scoped_refptr<media::VideoFrame>& video_frame) {
|
| - if (!VerifyFrame(video_frame))
|
| - return VideoFrameExternalResources();
|
| -
|
| - if (video_frame->format() == media::VideoFrame::NATIVE_TEXTURE)
|
| - return CreateForHardwarePlanes(video_frame);
|
| - else
|
| - return CreateForSoftwarePlanes(video_frame);
|
| -}
|
| -
|
| -bool VideoResourceUpdater::VerifyFrame(
|
| - const scoped_refptr<media::VideoFrame>& video_frame) {
|
| - switch (video_frame->format()) {
|
| - // Acceptable inputs.
|
| - case media::VideoFrame::YV12:
|
| - case media::VideoFrame::I420:
|
| - case media::VideoFrame::YV12A:
|
| - case media::VideoFrame::YV16:
|
| - case media::VideoFrame::YV12J:
|
| - case media::VideoFrame::YV12HD:
|
| - case media::VideoFrame::YV24:
|
| - case media::VideoFrame::NATIVE_TEXTURE:
|
| -#if defined(VIDEO_HOLE)
|
| - case media::VideoFrame::HOLE:
|
| -#endif // defined(VIDEO_HOLE)
|
| - case media::VideoFrame::ARGB:
|
| - return true;
|
| -
|
| - // Unacceptable inputs. ¯\(°_o)/¯
|
| - case media::VideoFrame::UNKNOWN:
|
| - case media::VideoFrame::NV12:
|
| - break;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -// For frames that we receive in software format, determine the dimensions of
|
| -// each plane in the frame.
|
| -static gfx::Size SoftwarePlaneDimension(
|
| - const scoped_refptr<media::VideoFrame>& input_frame,
|
| - bool software_compositor,
|
| - size_t plane_index) {
|
| - if (!software_compositor) {
|
| - return media::VideoFrame::PlaneSize(
|
| - input_frame->format(), plane_index, input_frame->coded_size());
|
| - }
|
| - return input_frame->coded_size();
|
| -}
|
| -
|
| -VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
|
| - const scoped_refptr<media::VideoFrame>& video_frame) {
|
| - TRACE_EVENT0("cc", "VideoResourceUpdater::CreateForSoftwarePlanes");
|
| - media::VideoFrame::Format input_frame_format = video_frame->format();
|
| -
|
| -#if defined(VIDEO_HOLE)
|
| - if (input_frame_format == media::VideoFrame::HOLE) {
|
| - VideoFrameExternalResources external_resources;
|
| - external_resources.type = VideoFrameExternalResources::HOLE;
|
| - return external_resources;
|
| - }
|
| -#endif // defined(VIDEO_HOLE)
|
| -
|
| - // Only YUV software video frames are supported.
|
| - 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::YV12HD &&
|
| - input_frame_format != media::VideoFrame::YV16 &&
|
| - input_frame_format != media::VideoFrame::YV24) {
|
| - NOTREACHED() << input_frame_format;
|
| - return VideoFrameExternalResources();
|
| - }
|
| -
|
| - bool software_compositor = context_provider_ == NULL;
|
| -
|
| - ResourceFormat output_resource_format =
|
| - resource_provider_->yuv_resource_format();
|
| - size_t output_plane_count = media::VideoFrame::NumPlanes(input_frame_format);
|
| -
|
| - // TODO(skaslev): If we're in software compositing mode, we do the YUV -> RGB
|
| - // conversion here. That involves an extra copy of each frame to a bitmap.
|
| - // Obviously, this is suboptimal and should be addressed once ubercompositor
|
| - // starts shaping up.
|
| - if (software_compositor) {
|
| - output_resource_format = kRGBResourceFormat;
|
| - output_plane_count = 1;
|
| - }
|
| -
|
| - // 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) {
|
| - break;
|
| - }
|
| -
|
| - // Try recycle a previously-allocated resource.
|
| - 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 need to allocate a new resource.
|
| - if (resource_it == all_resources_.end()) {
|
| - resource_it =
|
| - AllocateResource(output_plane_resource_size, output_resource_format,
|
| - !software_compositor);
|
| - }
|
| - if (resource_it == all_resources_.end())
|
| - break;
|
| -
|
| - ++resource_it->ref_count;
|
| - plane_resources.push_back(resource_it);
|
| - }
|
| -
|
| - 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();
|
| - }
|
| -
|
| - VideoFrameExternalResources external_resources;
|
| -
|
| - if (software_compositor) {
|
| - DCHECK_EQ(plane_resources.size(), 1u);
|
| - PlaneResource& plane_resource = *plane_resources[0];
|
| - DCHECK_EQ(plane_resource.resource_format, kRGBResourceFormat);
|
| - DCHECK(plane_resource.mailbox.IsZero());
|
| -
|
| - 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_resource.resource_id);
|
| - SkCanvas canvas(lock.sk_bitmap());
|
| - // This is software path, so canvas and video_frame are always backed
|
| - // by software.
|
| - video_renderer_->Copy(video_frame, &canvas, media::Context3D());
|
| - SetPlaneResourceUniqueId(video_frame.get(), 0, &plane_resource);
|
| - }
|
| -
|
| - external_resources.software_resources.push_back(plane_resource.resource_id);
|
| - external_resources.software_release_callback =
|
| - 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_resource.resource_format,
|
| - resource_provider_->yuv_resource_format());
|
| -
|
| - if (!PlaneResourceMatchesUniqueID(plane_resource, video_frame.get(), i)) {
|
| - // We need to transfer data from |video_frame| to the plane resource.
|
| - // TODO(reveman): Can use GpuMemoryBuffers here to improve performance.
|
| -
|
| - // The |resource_size_pixels| is the size of the resource we want to
|
| - // upload to.
|
| - gfx::Size resource_size_pixels = plane_resource.resource_size;
|
| - // The |video_stride_pixels| is the width of the video frame we are
|
| - // uploading (including non-frame data to fill in the stride).
|
| - size_t video_stride_pixels = video_frame->stride(i);
|
| -
|
| - size_t bytes_per_pixel = BitsPerPixel(plane_resource.resource_format) / 8;
|
| - // Use 4-byte row alignment (OpenGL default) for upload performance.
|
| - // Assuming that GL_UNPACK_ALIGNMENT has not changed from default.
|
| - size_t upload_image_stride =
|
| - RoundUp<size_t>(bytes_per_pixel * resource_size_pixels.width(), 4u);
|
| -
|
| - const uint8_t* pixels;
|
| - if (upload_image_stride == video_stride_pixels * bytes_per_pixel) {
|
| - pixels = video_frame->data(i);
|
| - } else {
|
| - // Avoid malloc for each frame/plane if possible.
|
| - size_t needed_size =
|
| - upload_image_stride * resource_size_pixels.height();
|
| - if (upload_pixels_.size() < needed_size)
|
| - upload_pixels_.resize(needed_size);
|
| - for (int row = 0; row < resource_size_pixels.height(); ++row) {
|
| - uint8_t* dst = &upload_pixels_[upload_image_stride * row];
|
| - const uint8_t* src = video_frame->data(i) +
|
| - bytes_per_pixel * video_stride_pixels * row;
|
| - memcpy(dst, src, resource_size_pixels.width() * bytes_per_pixel);
|
| - }
|
| - pixels = &upload_pixels_[0];
|
| - }
|
| -
|
| - resource_provider_->CopyToResource(plane_resource.resource_id, pixels,
|
| - resource_size_pixels);
|
| - SetPlaneResourceUniqueId(video_frame.get(), i, &plane_resource);
|
| - }
|
| -
|
| - external_resources.mailboxes.push_back(
|
| - TextureMailbox(plane_resource.mailbox, GL_TEXTURE_2D, 0));
|
| - external_resources.release_callbacks.push_back(
|
| - base::Bind(&RecycleResource, AsWeakPtr(), plane_resource.resource_id));
|
| - }
|
| -
|
| - external_resources.type = VideoFrameExternalResources::YUV_RESOURCE;
|
| - return external_resources;
|
| -}
|
| -
|
| -// static
|
| -void VideoResourceUpdater::ReturnTexture(
|
| - base::WeakPtr<VideoResourceUpdater> updater,
|
| - const scoped_refptr<media::VideoFrame>& video_frame,
|
| - uint32 sync_point,
|
| - bool lost_resource,
|
| - BlockingTaskRunner* main_thread_task_runner) {
|
| - // TODO(dshwang) this case should be forwarded to the decoder as lost
|
| - // resource.
|
| - if (lost_resource || !updater.get())
|
| - return;
|
| - // VideoFrame::UpdateReleaseSyncPoint() creates new sync point using the same
|
| - // GL context which created the given |sync_point|, so discard the
|
| - // |sync_point|.
|
| - SyncPointClientImpl client(updater->context_provider_->ContextGL());
|
| - video_frame->UpdateReleaseSyncPoint(&client);
|
| -}
|
| -
|
| -VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes(
|
| - const scoped_refptr<media::VideoFrame>& video_frame) {
|
| - TRACE_EVENT0("cc", "VideoResourceUpdater::CreateForHardwarePlanes");
|
| - media::VideoFrame::Format frame_format = video_frame->format();
|
| -
|
| - DCHECK_EQ(frame_format, media::VideoFrame::NATIVE_TEXTURE);
|
| - if (frame_format != media::VideoFrame::NATIVE_TEXTURE)
|
| - return VideoFrameExternalResources();
|
| -
|
| - if (!context_provider_)
|
| - return VideoFrameExternalResources();
|
| -
|
| - const gpu::MailboxHolder* mailbox_holder = video_frame->mailbox_holder();
|
| - VideoFrameExternalResources external_resources;
|
| - switch (mailbox_holder->texture_target) {
|
| - case GL_TEXTURE_2D:
|
| - external_resources.type = VideoFrameExternalResources::RGB_RESOURCE;
|
| - break;
|
| - case GL_TEXTURE_EXTERNAL_OES:
|
| - external_resources.type =
|
| - VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE;
|
| - break;
|
| - case GL_TEXTURE_RECTANGLE_ARB:
|
| - external_resources.type = VideoFrameExternalResources::IO_SURFACE;
|
| - break;
|
| - default:
|
| - NOTREACHED();
|
| - return VideoFrameExternalResources();
|
| - }
|
| -
|
| - external_resources.mailboxes.push_back(
|
| - TextureMailbox(mailbox_holder->mailbox,
|
| - mailbox_holder->texture_target,
|
| - mailbox_holder->sync_point));
|
| - external_resources.mailboxes.back().set_allow_overlay(
|
| - video_frame->allow_overlay());
|
| - external_resources.release_callbacks.push_back(
|
| - base::Bind(&ReturnTexture, AsWeakPtr(), video_frame));
|
| - return external_resources;
|
| -}
|
| -
|
| -// static
|
| -void VideoResourceUpdater::RecycleResource(
|
| - base::WeakPtr<VideoResourceUpdater> updater,
|
| - ResourceProvider::ResourceId resource_id,
|
| - uint32 sync_point,
|
| - bool lost_resource,
|
| - BlockingTaskRunner* main_thread_task_runner) {
|
| - if (!updater.get()) {
|
| - // Resource was already deleted.
|
| - 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(),
|
| - context_provider->ContextGL()->WaitSyncPointCHROMIUM(sync_point));
|
| - }
|
| -
|
| - if (lost_resource) {
|
| - resource_it->ref_count = 0;
|
| - updater->DeleteResource(resource_it);
|
| - return;
|
| - }
|
| -
|
| - --resource_it->ref_count;
|
| - DCHECK_GE(resource_it->ref_count, 0);
|
| -}
|
| -
|
| -} // namespace cc
|
|
|