blob: a80f0fbb65a9efe9e9e6b5e3efac493cfd4e3ea3 [file] [log] [blame]
// Copyright 2018 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 "media/gpu/test/texture_ref.h"
#include <utility>
#include <vector>
#if defined(OS_CHROMEOS)
#include <libdrm/drm_fourcc.h>
#include "media/gpu/format_utils.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/native_pixmap.h"
#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/surface_factory_ozone.h"
#endif
namespace media {
namespace test {
TextureRef::TextureRef(uint32_t texture_id,
base::OnceClosure no_longer_needed_cb)
: texture_id_(texture_id),
no_longer_needed_cb_(std::move(no_longer_needed_cb)) {}
TextureRef::~TextureRef() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
std::move(no_longer_needed_cb_).Run();
}
// static
scoped_refptr<TextureRef> TextureRef::Create(
uint32_t texture_id,
base::OnceClosure no_longer_needed_cb) {
return base::WrapRefCounted(
new TextureRef(texture_id, std::move(no_longer_needed_cb)));
}
// static
scoped_refptr<TextureRef> TextureRef::CreatePreallocated(
uint32_t texture_id,
base::OnceClosure no_longer_needed_cb,
VideoPixelFormat pixel_format,
const gfx::Size& size,
gfx::BufferUsage buffer_usage) {
scoped_refptr<TextureRef> texture_ref;
#if defined(OS_CHROMEOS)
texture_ref = TextureRef::Create(texture_id, std::move(no_longer_needed_cb));
LOG_ASSERT(texture_ref);
ui::OzonePlatform* platform = ui::OzonePlatform::GetInstance();
ui::SurfaceFactoryOzone* factory = platform->GetSurfaceFactoryOzone();
gfx::BufferFormat buffer_format =
VideoPixelFormatToGfxBufferFormat(pixel_format);
texture_ref->pixmap_ = factory->CreateNativePixmap(
gfx::kNullAcceleratedWidget, size, buffer_format, buffer_usage);
LOG_ASSERT(texture_ref->pixmap_);
texture_ref->coded_size_ = size;
#endif
return texture_ref;
}
gfx::GpuMemoryBufferHandle TextureRef::ExportGpuMemoryBufferHandle() const {
gfx::GpuMemoryBufferHandle handle;
#if defined(OS_CHROMEOS)
CHECK(pixmap_);
handle.type = gfx::NATIVE_PIXMAP;
size_t num_planes =
gfx::NumberOfPlanesForBufferFormat(pixmap_->GetBufferFormat());
for (size_t i = 0; i < num_planes; ++i) {
handle.native_pixmap_handle.planes.emplace_back(
pixmap_->GetDmaBufPitch(i), pixmap_->GetDmaBufOffset(i), i,
pixmap_->GetDmaBufModifier(i));
}
size_t num_fds = pixmap_->GetDmaBufFdCount();
LOG_ASSERT(num_fds == num_planes || num_fds == 1);
for (size_t i = 0; i < num_fds; ++i) {
int duped_fd = HANDLE_EINTR(dup(pixmap_->GetDmaBufFd(i)));
LOG_ASSERT(duped_fd != -1) << "Failed duplicating dmabuf fd";
handle.native_pixmap_handle.fds.emplace_back(
base::FileDescriptor(duped_fd, true));
}
#endif
return handle;
}
scoped_refptr<VideoFrame> TextureRef::CreateVideoFrame(
const gfx::Rect& visible_rect) const {
scoped_refptr<VideoFrame> video_frame;
#if defined(OS_CHROMEOS)
VideoPixelFormat pixel_format =
GfxBufferFormatToVideoPixelFormat(pixmap_->GetBufferFormat());
CHECK_NE(pixel_format, PIXEL_FORMAT_UNKNOWN);
size_t num_planes = VideoFrame::NumPlanes(pixel_format);
std::vector<VideoFrameLayout::Plane> planes(num_planes);
std::vector<int> plane_height(num_planes, 0u);
for (size_t i = 0; i < num_planes; ++i) {
planes[i].stride = pixmap_->GetDmaBufPitch(i);
planes[i].offset = pixmap_->GetDmaBufOffset(i);
plane_height[i] = VideoFrame::Rows(i, pixel_format, coded_size_.height());
}
std::vector<base::ScopedFD> dmabuf_fds;
size_t num_fds = pixmap_->GetDmaBufFdCount();
LOG_ASSERT(num_fds <= num_planes);
for (size_t i = 0; i < num_fds; ++i) {
int duped_fd = HANDLE_EINTR(dup(pixmap_->GetDmaBufFd(i)));
LOG_ASSERT(duped_fd != -1) << "Failed duplicating dmabuf fd";
dmabuf_fds.emplace_back(duped_fd);
}
std::vector<size_t> buffer_sizes(num_fds, 0u);
for (size_t plane = 0, i = 0; plane < num_planes; ++plane) {
if (plane + 1 < buffer_sizes.size()) {
buffer_sizes[i] =
planes[plane].offset + planes[plane].stride * plane_height[plane];
++i;
} else {
buffer_sizes[i] = std::max(
buffer_sizes[i],
planes[plane].offset + planes[plane].stride * plane_height[plane]);
}
}
auto layout = VideoFrameLayout::CreateWithPlanes(
pixel_format, coded_size_, std::move(planes), std::move(buffer_sizes));
LOG_ASSERT(layout.has_value() == true);
video_frame = VideoFrame::WrapExternalDmabufs(
*layout, visible_rect, visible_rect.size(), std::move(dmabuf_fds),
base::TimeDelta());
#endif
return video_frame;
}
bool TextureRef::IsDirectlyMappable() const {
#if defined(OS_CHROMEOS)
return pixmap_->GetDmaBufModifier(0) == DRM_FORMAT_MOD_LINEAR;
#else
return false;
#endif
}
} // namespace test
} // namespace media