Commit 53bc536c authored by Fritz Koenig's avatar Fritz Koenig Committed by Commit Bot

media/gpu: Add modifiers to gpu buffer layout

Modifiers are associated with buffers.  They
need to be passed along to V4L2 decoders so
they can take advantage of the modifier.

BUG=b:149525848
TEST=decode with modifiers on trogdor
TEST=PlatformVideoFramePoolTest.ModifierIsPassed

Change-Id: I2708918d6fce43f75579908ab9f3292f03aa0095
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2343043
Commit-Queue: Fritz Koenig <frkoenig@chromium.org>
Reviewed-by: default avatarChih-Yu Huang <akahuang@chromium.org>
Reviewed-by: default avatarAndres Calderon Jaramillo <andrescj@chromium.org>
Reviewed-by: default avatarDale Curtis <dalecurtis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#802707}
parent 091629ca
......@@ -564,13 +564,27 @@ scoped_refptr<VideoFrame> VideoFrame::WrapExternalGpuMemoryBuffer(
return nullptr;
}
uint64_t modifier = gfx::NativePixmapHandle::kNoModifier;
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
if (gpu_memory_buffer->GetType() == gfx::NATIVE_PIXMAP) {
const auto gmb_handle = gpu_memory_buffer->CloneHandle();
if (gmb_handle.is_null() ||
gmb_handle.native_pixmap_handle.planes.empty()) {
DLOG(ERROR) << "Failed to clone the GpuMemoryBufferHandle";
return nullptr;
}
modifier = gmb_handle.native_pixmap_handle.modifier;
}
#endif
const size_t num_planes =
NumberOfPlanesForLinearBufferFormat(gpu_memory_buffer->GetFormat());
std::vector<int32_t> strides;
for (size_t i = 0; i < num_planes; ++i)
strides.push_back(gpu_memory_buffer->stride(i));
const auto layout = VideoFrameLayout::CreateWithStrides(*format, coded_size,
std::move(strides));
const auto layout = VideoFrameLayout::CreateWithStrides(
*format, coded_size, std::move(strides),
VideoFrameLayout::kBufferAddressAlignment, modifier);
if (!layout) {
DLOG(ERROR) << __func__ << " Invalid layout";
return nullptr;
......
......@@ -97,8 +97,11 @@ base::Optional<VideoFrameLayout> VideoFrameLayout::Create(
base::Optional<VideoFrameLayout> VideoFrameLayout::CreateWithStrides(
VideoPixelFormat format,
const gfx::Size& coded_size,
std::vector<int32_t> strides) {
return CreateWithPlanes(format, coded_size, PlanesFromStrides(strides));
std::vector<int32_t> strides,
size_t buffer_addr_align,
uint64_t modifier) {
return CreateWithPlanes(format, coded_size, PlanesFromStrides(strides),
buffer_addr_align, modifier);
}
// static
......
......@@ -62,7 +62,9 @@ class MEDIA_EXPORT VideoFrameLayout {
static base::Optional<VideoFrameLayout> CreateWithStrides(
VideoPixelFormat format,
const gfx::Size& coded_size,
std::vector<int32_t> strides);
std::vector<int32_t> strides,
size_t buffer_addr_align = kBufferAddressAlignment,
uint64_t modifier = gfx::NativePixmapHandle::kNoModifier);
// Create a layout suitable for |format| at |coded_size|, with the |planes|
// fully provided.
......
......@@ -441,9 +441,14 @@ TEST(VideoFrame, WrapExternalGpuMemoryBuffer) {
gfx::Size coded_size = gfx::Size(256, 256);
gfx::Rect visible_rect(coded_size);
auto timestamp = base::TimeDelta::FromMilliseconds(1);
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
const uint64_t modifier = 0x001234567890abcdULL;
#else
const uint64_t modifier = gfx::NativePixmapHandle::kNoModifier;
#endif
std::unique_ptr<gfx::GpuMemoryBuffer> gmb =
std::make_unique<FakeGpuMemoryBuffer>(
coded_size, gfx::BufferFormat::YUV_420_BIPLANAR);
coded_size, gfx::BufferFormat::YUV_420_BIPLANAR, modifier);
gfx::GpuMemoryBuffer* gmb_raw_ptr = gmb.get();
gpu::MailboxHolder mailbox_holders[media::VideoFrame::kMaxPlanes] = {
gpu::MailboxHolder(gpu::Mailbox::Generate(), gpu::SyncToken(), 5),
......@@ -459,6 +464,7 @@ TEST(VideoFrame, WrapExternalGpuMemoryBuffer) {
for (size_t i = 0; i < 2; ++i) {
EXPECT_EQ(frame->layout().planes()[i].stride, coded_size.width());
}
EXPECT_EQ(frame->layout().modifier(), modifier);
EXPECT_EQ(frame->storage_type(), VideoFrame::STORAGE_GPU_MEMORY_BUFFER);
EXPECT_TRUE(frame->HasGpuMemoryBuffer());
EXPECT_EQ(frame->GetGpuMemoryBuffer(), gmb_raw_ptr);
......
......@@ -32,23 +32,26 @@ std::string VectorToString(const std::vector<T>& vec) {
base::Optional<GpuBufferLayout> GpuBufferLayout::Create(
const Fourcc& fourcc,
const gfx::Size& size,
const std::vector<ColorPlaneLayout>& planes) {
const std::vector<ColorPlaneLayout>& planes,
uint64_t modifier) {
// TODO(akahuang): Check planes.size() is equal to the expected value
// according to |fourcc|.
if (size.IsEmpty() || planes.size() == 0) {
VLOGF(1) << "Invalid parameters. fourcc: " << fourcc.ToString()
<< ", size: " << size.ToString()
<< ", planes: " << VectorToString(planes);
<< ", planes: " << VectorToString(planes)
<< ", modifier: " << std::hex << modifier;
return base::nullopt;
}
return GpuBufferLayout(fourcc, size, planes);
return GpuBufferLayout(fourcc, size, planes, modifier);
}
GpuBufferLayout::GpuBufferLayout(const Fourcc& fourcc,
const gfx::Size& size,
const std::vector<ColorPlaneLayout>& planes)
: fourcc_(fourcc), size_(size), planes_(planes) {}
const std::vector<ColorPlaneLayout>& planes,
uint64_t modifier)
: fourcc_(fourcc), size_(size), planes_(planes), modifier_(modifier) {}
GpuBufferLayout::~GpuBufferLayout() = default;
GpuBufferLayout::GpuBufferLayout(const GpuBufferLayout&) = default;
......@@ -57,7 +60,8 @@ GpuBufferLayout& GpuBufferLayout::operator=(const GpuBufferLayout& other) =
default;
bool GpuBufferLayout::operator==(const GpuBufferLayout& rhs) const {
return fourcc_ == rhs.fourcc_ && size_ == rhs.size_ && planes_ == rhs.planes_;
return fourcc_ == rhs.fourcc_ && size_ == rhs.size_ &&
planes_ == rhs.planes_ && modifier_ == rhs.modifier_;
}
bool GpuBufferLayout::operator!=(const GpuBufferLayout& rhs) const {
......@@ -68,7 +72,8 @@ std::ostream& operator<<(std::ostream& ostream, const GpuBufferLayout& layout) {
ostream << "GpuBufferLayout(fourcc: " << layout.fourcc().ToString()
<< ", size: " << layout.size().ToString()
<< ", planes (stride, offset, size): "
<< VectorToString(layout.planes());
<< VectorToString(layout.planes()) << ", modifier: " << std::hex
<< layout.modifier();
return ostream;
}
......
......@@ -22,7 +22,8 @@ class MEDIA_GPU_EXPORT GpuBufferLayout {
static base::Optional<GpuBufferLayout> Create(
const Fourcc& fourcc,
const gfx::Size& size,
const std::vector<ColorPlaneLayout>& planes);
const std::vector<ColorPlaneLayout>& planes,
uint64_t modifier);
GpuBufferLayout() = delete;
GpuBufferLayout(const GpuBufferLayout&);
GpuBufferLayout(GpuBufferLayout&&);
......@@ -35,11 +36,13 @@ class MEDIA_GPU_EXPORT GpuBufferLayout {
const Fourcc& fourcc() const { return fourcc_; }
const gfx::Size& size() const { return size_; }
const std::vector<ColorPlaneLayout>& planes() const { return planes_; }
uint64_t modifier() const { return modifier_; }
private:
GpuBufferLayout(const Fourcc& fourcc,
const gfx::Size& size,
const std::vector<ColorPlaneLayout>& planes);
const std::vector<ColorPlaneLayout>& planes,
uint64_t modifier);
// Fourcc format of the buffer.
Fourcc fourcc_;
......@@ -51,6 +54,8 @@ class MEDIA_GPU_EXPORT GpuBufferLayout {
gfx::Size size_;
// Layout property for each color planes, e.g. stride and buffer offset.
std::vector<ColorPlaneLayout> planes_;
// DRM format modifier associated with buffer.
uint64_t modifier_;
};
// Outputs GpuBufferLayout to stream.
......
......@@ -160,7 +160,8 @@ base::Optional<GpuBufferLayout> PlatformVideoFramePool::Initialize(
return base::nullopt;
}
frame_layout_ = GpuBufferLayout::Create(fourcc, frame->coded_size(),
frame->layout().planes());
frame->layout().planes(),
frame->layout().modifier());
}
visible_rect_ = visible_rect;
......
......@@ -23,6 +23,7 @@ namespace media {
namespace {
template <uint64_t modifier>
scoped_refptr<VideoFrame> CreateGpuMemoryBufferVideoFrame(
gpu::GpuMemoryBufferFactory* factory,
VideoPixelFormat format,
......@@ -36,7 +37,7 @@ scoped_refptr<VideoFrame> CreateGpuMemoryBufferVideoFrame(
const gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes] = {};
return VideoFrame::WrapExternalGpuMemoryBuffer(
visible_rect, natural_size,
std::make_unique<FakeGpuMemoryBuffer>(coded_size, *gfx_format),
std::make_unique<FakeGpuMemoryBuffer>(coded_size, *gfx_format, modifier),
mailbox_holders, base::NullCallback(), timestamp);
}
......@@ -48,7 +49,9 @@ class PlatformVideoFramePoolTest
PlatformVideoFramePoolTest()
: task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME),
pool_(new PlatformVideoFramePool(nullptr)) {
SetCreateFrameCB(base::BindRepeating(&CreateGpuMemoryBufferVideoFrame));
SetCreateFrameCB(
base::BindRepeating(&CreateGpuMemoryBufferVideoFrame<
gfx::NativePixmapHandle::kNoModifier>));
pool_->set_parent_task_runner(base::ThreadTaskRunnerHandle::Get());
}
......@@ -73,6 +76,7 @@ class PlatformVideoFramePoolTest
scoped_refptr<VideoFrame> frame = pool_->GetFrame();
frame->set_timestamp(base::TimeDelta::FromMilliseconds(timestamp_ms));
EXPECT_EQ(layout_->modifier(), frame->layout().modifier());
EXPECT_EQ(layout_->fourcc(),
*Fourcc::FromVideoPixelFormat(frame->format()));
EXPECT_EQ(layout_->size(), frame->coded_size());
......@@ -292,6 +296,18 @@ TEST_P(PlatformVideoFramePoolTest, InitializeFail) {
EXPECT_FALSE(Initialize(fourcc.value()));
}
TEST_P(PlatformVideoFramePoolTest, ModifierIsPassed) {
const uint64_t kSampleModifier = 0x001234567890abcdULL;
const auto fourcc = Fourcc::FromVideoPixelFormat(GetParam());
ASSERT_TRUE(fourcc.has_value());
SetCreateFrameCB(
base::BindRepeating(&CreateGpuMemoryBufferVideoFrame<kSampleModifier>));
ASSERT_TRUE(Initialize(fourcc.value()));
EXPECT_EQ(layout_->modifier(), kSampleModifier);
EXPECT_TRUE(GetFrame(10));
}
// TODO(akahuang): Add a testcase to verify calling Initialize() only with
// different |max_num_frames|.
......
......@@ -329,20 +329,26 @@ void VdVideoDecodeAccelerator::ImportBufferForPicture(
return;
}
const uint64_t modifier = gmb_handle.type == gfx::NATIVE_PIXMAP
? gmb_handle.native_pixmap_handle.modifier
: gfx::NativePixmapHandle::kNoModifier;
std::vector<ColorPlaneLayout> planes = ExtractColorPlaneLayout(gmb_handle);
layout_ =
VideoFrameLayout::CreateWithPlanes(pixel_format, coded_size_, planes);
layout_ = VideoFrameLayout::CreateWithPlanes(
pixel_format, coded_size_, planes,
VideoFrameLayout::kBufferAddressAlignment, modifier);
if (!layout_) {
VLOGF(1) << "Failed to create VideoFrameLayout. format: "
<< VideoPixelFormatToString(pixel_format)
<< ", coded_size: " << coded_size_.ToString()
<< ", planes: " << VectorToString(planes);
<< ", planes: " << VectorToString(planes)
<< ", modifier: " << std::hex << modifier;
std::move(notify_layout_changed_cb_).Run(base::nullopt);
return;
}
std::move(notify_layout_changed_cb_)
.Run(GpuBufferLayout::Create(*fourcc, coded_size_, planes));
.Run(GpuBufferLayout::Create(*fourcc, coded_size_, planes, modifier));
}
if (!layout_)
......
......@@ -110,7 +110,8 @@ void VdaVideoFramePool::ImportFrame(scoped_refptr<VideoFrame> frame) {
DCHECK_CALLED_ON_VALID_SEQUENCE(parent_sequence_checker_);
if (!layout_ || layout_->fourcc().ToVideoPixelFormat() != frame->format() ||
layout_->size() != frame->coded_size()) {
layout_->size() != frame->coded_size() ||
layout_->modifier() != frame->layout().modifier()) {
return;
}
......
......@@ -58,6 +58,11 @@ base::ScopedFD GetDummyFD() {
FakeGpuMemoryBuffer::FakeGpuMemoryBuffer(const gfx::Size& size,
gfx::BufferFormat format)
: FakeGpuMemoryBuffer(size, format, gfx::NativePixmapHandle::kNoModifier) {}
FakeGpuMemoryBuffer::FakeGpuMemoryBuffer(const gfx::Size& size,
gfx::BufferFormat format,
uint64_t modifier)
: size_(size), format_(format) {
base::Optional<VideoPixelFormat> video_pixel_format =
GfxBufferFormatToVideoPixelFormat(format);
......@@ -81,6 +86,7 @@ FakeGpuMemoryBuffer::FakeGpuMemoryBuffer(const gfx::Size& size,
plane_size_in_bytes.width(), 0, plane_size_in_bytes.GetArea(),
GetDummyFD());
}
handle_.native_pixmap_handle.modifier = modifier;
#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)
}
......
......@@ -17,6 +17,9 @@ namespace media {
class FakeGpuMemoryBuffer : public gfx::GpuMemoryBuffer {
public:
FakeGpuMemoryBuffer(const gfx::Size& size, gfx::BufferFormat format);
FakeGpuMemoryBuffer(const gfx::Size& size,
gfx::BufferFormat format,
uint64_t modifier);
// gfx::GpuMemoryBuffer implementation.
~FakeGpuMemoryBuffer() override;
......
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