Commit 64cc5178 authored by Alexandre Courbot's avatar Alexandre Courbot Committed by Commit Bot

media/gpu/v4l2: lazy-assign EGLImages to image processor buffers

Right now the VDA and IP devices are tightly coupled: notably, their
buffers follow a 1:1 mapping, and the VDA decides which IP processor
buffer to use. This seriously restricts the applicability of the IP
interface.

In order to remove this constraint, the VDA must not make any assumption
about which IP buffer it will receive, the number of buffers it will use,
or even their memory type. Doing so means that the VDA will see the IP
buffers for the first time as the FrameProcessed() callback is called,
and thus that it cannot create an EGLImage for them ahead of time as we
used to do.

This patch thus delays EGLImage assignment to the first time we meet a
given buffer in the FrameProcessed() callback. Thanks to the fact that
every picture needs to be cleared on the child thread first, we can
schedule the EGLImage creation on the same thread before this happens,
thus ensuring that no synchronization issue occur.

BUG=792790
TEST=Checked that VDA unittest was passing on Hana, in import and
non-import mode, with rendering enabled or not.

Change-Id: Ia89b7620fe890fcd4bbd6791fd59660d9bd89f46
Reviewed-on: https://chromium-review.googlesource.com/c/1288498
Commit-Queue: Alexandre Courbot <acourbot@chromium.org>
Reviewed-by: default avatarHirokazu Honda <hiroh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#607484}
parent e3265de8
......@@ -515,16 +515,8 @@ void V4L2VideoDecodeAccelerator::AssignEGLImage(size_t buffer_index,
OutputRecord& output_record = output_buffer_map_[buffer_index];
DCHECK_EQ(output_record.egl_image, EGL_NO_IMAGE_KHR);
DCHECK(!output_record.egl_fence);
DCHECK_EQ(output_record.state, kFree);
output_record.egl_image = egl_image;
// Drop our reference so the buffer returns to the queue and can be reused.
output_wait_map_.erase(picture_buffer_id);
if (decoder_state_ != kChangingResolution) {
Enqueue();
ScheduleDecodeBufferTaskIfNeeded();
}
}
void V4L2VideoDecodeAccelerator::ImportBufferForPicture(
......@@ -654,20 +646,26 @@ void V4L2VideoDecodeAccelerator::ImportBufferForPictureTask(
}
size_t index = iter - output_buffer_map_.begin();
child_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&V4L2VideoDecodeAccelerator::CreateEGLImageFor,
weak_this_, index, picture_buffer_id,
base::Passed(&dmabuf_fds), iter->texture_id,
egl_image_size_, egl_image_format_fourcc_));
} else {
// No need for an EGLImage, start using this buffer now.
output_wait_map_.erase(picture_buffer_id);
if (decoder_state_ != kChangingResolution) {
Enqueue();
ScheduleDecodeBufferTaskIfNeeded();
// If we are not using an image processor, create the EGL image ahead of
// time since we already have its DMABUF fds. It is guaranteed that
// CreateEGLImageFor will run before the picture is passed to the client
// because the picture will need to be cleared on the child thread first.
if (!image_processor_) {
child_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&V4L2VideoDecodeAccelerator::CreateEGLImageFor,
weak_this_, index, picture_buffer_id,
base::Passed(&dmabuf_fds), iter->texture_id,
egl_image_size_, egl_image_format_fourcc_));
}
}
// The buffer can now be used for decoding
output_wait_map_.erase(picture_buffer_id);
if (decoder_state_ != kChangingResolution) {
Enqueue();
ScheduleDecodeBufferTaskIfNeeded();
}
}
void V4L2VideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_buffer_id) {
......@@ -2621,9 +2619,26 @@ void V4L2VideoDecodeAccelerator::FrameProcessed(
DCHECK_EQ(output_record.state, kAtProcessor);
DCHECK_NE(output_record.picture_id, -1);
image_processor_bitstream_buffer_ids_.pop();
// If the picture has not been cleared yet, this means it is the first time
// we are seeing this buffer from the image processor. Schedule a call to
// CreateEGLImageFor before the picture is sent to the client. It is
// guaranteed that CreateEGLImageFor will complete before the picture is sent
// to the client as both events happen on the child thread due to the picture
// uncleared status.
if (output_record.texture_id != 0 && !output_record.cleared) {
DCHECK(frame->HasDmaBufs());
child_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&V4L2VideoDecodeAccelerator::CreateEGLImageFor, weak_this_,
output_buffer_index, output_record.picture_id,
media::DuplicateFDs(frame->DmabufFds()), output_record.texture_id,
egl_image_size_, egl_image_format_fourcc_));
}
SendBufferToClient(output_buffer_index, bitstream_buffer_id);
// Flush or resolution change may be waiting image processor to finish.
image_processor_bitstream_buffer_ids_.pop();
if (image_processor_bitstream_buffer_ids_.empty()) {
NotifyFlushDoneIfNeeded();
if (decoder_state_ == kChangingResolution)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment