Skip to content

Commit

Permalink
GpuMemoryBufferVideoFramePool: Split shared image binding from copying
Browse files Browse the repository at this point in the history
Creating a frame using GpuMemoryBufferVideoFramePool has the following
steps:
 A1. Create GpuMemoryBuffers (in FrameResources) on the media thread
 A2. Copy into those GpuMemoryBuffers on a worker thread
 A3. Create SharedImages for the GpuMemoryBuffers and wrap them in a
     VideoFrame on the media thread

For the canvas capture path, the sequence of events will be
 B1. Create GpuMemoryBuffers
 B2. Create SharedImages and wrap them in a VideoFrame
 B3. Blit the source into those SharedImages

Towards enabling the new path, take the function that does A3 or B2,
BindAndCreateMailboxesHardwareFrameResources, and make it no longer
depend on the copy that is done in A2 (or even the existence of a
source video frame).

Bug: 1207111
Change-Id: If9b73e710e9b9dd7ee848d0ca6e9442d90a17ff7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2942207
Reviewed-by: Dan Sanders <sandersd@chromium.org>
Commit-Queue: ccameron <ccameron@chromium.org>
Cr-Commit-Position: refs/heads/master@{#891260}
  • Loading branch information
ccameron-chromium authored and Chromium LUCI CQ committed Jun 10, 2021
1 parent 9477af3 commit 9f2b58b
Showing 1 changed file with 63 additions and 33 deletions.
96 changes: 63 additions & 33 deletions media/video/gpu_memory_buffer_video_frame_pool.cc
Original file line number Diff line number Diff line change
Expand Up @@ -172,13 +172,22 @@ class GpuMemoryBufferVideoFramePool::PoolImpl
scoped_refptr<VideoFrame> video_frame,
FrameResources* frame_resources);

// Prepares GL resources, mailboxes and calls |frame_ready_cb| with the new
// VideoFrame. This has to be run on |media_task_runner_| where
// |frame_ready_cb| associated with video_frame will also be run.
void BindAndCreateMailboxesHardwareFrameResources(
bool copy_failed,
scoped_refptr<VideoFrame> video_frame,
FrameResources* frame_resources);
// Called on the media thread when all data has been copied.
void OnCopiesDoneOnMediaThread(bool copy_failed,
scoped_refptr<VideoFrame> video_frame,
FrameResources* frame_resources);

// Prepares GL resources, mailboxes and allocates the new VideoFrame. This has
// to be run on `media_task_runner_`. On failure, this will release
// `frame_resources` and return nullptr.
scoped_refptr<VideoFrame> BindAndCreateMailboxesHardwareFrameResources(
FrameResources* frame_resources,
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
const gfx::Size& natural_size,
const gfx::ColorSpace& color_space,
base::TimeDelta timestamp,
bool allow_i420_overlay);

// Return true if |resources| can be used to represent a frame for
// specific |format| and |size|.
Expand Down Expand Up @@ -840,9 +849,8 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::OnCopiesDone(

media_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&PoolImpl::BindAndCreateMailboxesHardwareFrameResources,
this, copy_failed, std::move(video_frame),
frame_resources));
base::BindOnce(&PoolImpl::OnCopiesDoneOnMediaThread, this, copy_failed,
std::move(video_frame), frame_resources));
}

void GpuMemoryBufferVideoFramePool::PoolImpl::StartCopy() {
Expand Down Expand Up @@ -1018,11 +1026,11 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::CopyVideoFrameToGpuMemoryBuffers(
}
}

void GpuMemoryBufferVideoFramePool::PoolImpl::
BindAndCreateMailboxesHardwareFrameResources(
bool copy_failed,
scoped_refptr<VideoFrame> video_frame,
FrameResources* frame_resources) {
void GpuMemoryBufferVideoFramePool::PoolImpl::OnCopiesDoneOnMediaThread(
bool copy_failed,
scoped_refptr<VideoFrame> video_frame,
FrameResources* frame_resources) {
DCHECK(media_task_runner_->BelongsToCurrentThread());
if (copy_failed) {
// Drop the resources if there was an error with them.
auto it = std::find(resources_pool_.begin(), resources_pool_.end(),
Expand All @@ -1036,14 +1044,42 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::
return;
}

scoped_refptr<VideoFrame> frame =
BindAndCreateMailboxesHardwareFrameResources(
frame_resources, CodedSize(video_frame.get(), output_format_),
gfx::Rect(video_frame->visible_rect().size()),
video_frame->natural_size(), video_frame->ColorSpace(),
video_frame->timestamp(), video_frame->metadata().allow_overlay);
if (!frame) {
CompleteCopyRequestAndMaybeStartNextCopy(std::move(video_frame));
return;
}

bool new_allow_overlay = frame->metadata().allow_overlay;
bool new_read_lock_fences_enabled =
frame->metadata().read_lock_fences_enabled;
frame->metadata().MergeMetadataFrom(video_frame->metadata());
frame->metadata().allow_overlay = new_allow_overlay;
frame->metadata().read_lock_fences_enabled = new_read_lock_fences_enabled;
CompleteCopyRequestAndMaybeStartNextCopy(std::move(frame));
}

scoped_refptr<VideoFrame> GpuMemoryBufferVideoFramePool::PoolImpl::
BindAndCreateMailboxesHardwareFrameResources(
FrameResources* frame_resources,
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
const gfx::Size& natural_size,
const gfx::ColorSpace& color_space,
base::TimeDelta timestamp,
bool allow_i420_overlay) {
DCHECK(media_task_runner_->BelongsToCurrentThread());
gpu::SharedImageInterface* sii = gpu_factories_->SharedImageInterface();
if (!sii) {
frame_resources->MarkUnused(tick_clock_->NowTicks());
CompleteCopyRequestAndMaybeStartNextCopy(std::move(video_frame));
return;
return nullptr;
}

const gfx::Size coded_size = CodedSize(video_frame.get(), output_format_);
gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes];
// Set up the planes creating the mailboxes needed to refer to the textures.
for (size_t plane = 0; plane < NumSharedImages(output_format_); plane++) {
Expand All @@ -1065,9 +1101,8 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::
gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT;
plane_resource.mailbox = sii->CreateSharedImage(
gpu_memory_buffer, gpu_factories_->GpuMemoryBufferManager(),
GetSharedImageBufferPlane(output_format_, plane),
video_frame->ColorSpace(), kTopLeft_GrSurfaceOrigin,
kPremul_SkAlphaType, usage);
GetSharedImageBufferPlane(output_format_, plane), color_space,
kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, usage);
} else if (!plane_resource.mailbox.IsZero()) {
sii->UpdateSharedImage(frame_resources->sync_token,
plane_resource.mailbox);
Expand All @@ -1086,22 +1121,19 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::
VideoPixelFormat frame_format = VideoFormat(output_format_);

// Create the VideoFrame backed by native textures.
gfx::Size visible_size = video_frame->visible_rect().size();
scoped_refptr<VideoFrame> frame = VideoFrame::WrapNativeTextures(
frame_format, mailbox_holders, VideoFrame::ReleaseMailboxCB(), coded_size,
gfx::Rect(visible_size), video_frame->natural_size(),
video_frame->timestamp());
visible_rect, natural_size, timestamp);

if (!frame) {
frame_resources->MarkUnused(tick_clock_->NowTicks());
MailboxHoldersReleased(frame_resources, sync_token);
CompleteCopyRequestAndMaybeStartNextCopy(std::move(video_frame));
return;
return nullptr;
}
frame->SetReleaseMailboxCB(
base::BindOnce(&PoolImpl::MailboxHoldersReleased, this, frame_resources));

frame->set_color_space(video_frame->ColorSpace());
frame->set_color_space(color_space);

bool allow_overlay = false;
#if defined(OS_WIN)
Expand All @@ -1111,7 +1143,7 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::
#else
switch (output_format_) {
case GpuVideoAcceleratorFactories::OutputFormat::I420:
allow_overlay = video_frame->metadata().allow_overlay;
allow_overlay = allow_i420_overlay;
break;
case GpuVideoAcceleratorFactories::OutputFormat::P010:
case GpuVideoAcceleratorFactories::OutputFormat::NV12_SINGLE_GMB:
Expand All @@ -1125,13 +1157,13 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::
// TODO(mcasas): Enable this for ChromeOS https://crbug.com/776093.
allow_overlay = false;
#if defined(OS_MAC)
allow_overlay = IOSurfaceCanSetColorSpace(video_frame->ColorSpace());
allow_overlay = IOSurfaceCanSetColorSpace(color_space);
#endif
// We've converted the YUV to RGB, fix the color space.
// TODO(hubbe): The libyuv YUV to RGB conversion may not have
// honored the color space conversion 100%. We should either fix
// libyuv or find a way for later passes to make up the difference.
frame->set_color_space(video_frame->ColorSpace().GetAsRGB());
frame->set_color_space(color_space.GetAsRGB());
break;
case GpuVideoAcceleratorFactories::OutputFormat::RGBA:
case GpuVideoAcceleratorFactories::OutputFormat::BGRA:
Expand All @@ -1141,11 +1173,9 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::
break;
}
#endif // OS_WIN
frame->metadata().MergeMetadataFrom(video_frame->metadata());
frame->metadata().allow_overlay = allow_overlay;
frame->metadata().read_lock_fences_enabled = true;

CompleteCopyRequestAndMaybeStartNextCopy(std::move(frame));
return frame;
}

// Destroy all the resources posting one task per FrameResources
Expand Down

0 comments on commit 9f2b58b

Please sign in to comment.