Commit 7bcda057 authored by Bryan Bernhart's avatar Bryan Bernhart Committed by Chromium LUCI CQ

Use shared images with DXVA decoder

Adds support to bind video textures used for overlays
with the shared image system. This change enables
overlays to be backed by DXVA decoded output textures
by wrapping them in a mailbox per plane.

Bug: 1011555
Change-Id: Ide149097c1331c0bcb3dc99ae67def8bf4768472
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2485682Reviewed-by: default avatarSunny Sachanandani <sunnyps@chromium.org>
Reviewed-by: default avatarFrank Liberato <liberato@chromium.org>
Commit-Queue: Bryan Bernhart <bryan.bernhart@intel.com>
Cr-Commit-Position: refs/heads/master@{#842699}
parent 652d8f66
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/synchronization/lock.h" #include "base/synchronization/lock.h"
#include "base/thread_annotations.h" #include "base/thread_annotations.h"
#include "components/viz/common/resources/resource_format_utils.h"
#include "gpu/command_buffer/common/mailbox_holder.h" #include "gpu/command_buffer/common/mailbox_holder.h"
#include "media/base/video_util.h" #include "media/base/video_util.h"
...@@ -83,13 +84,11 @@ class PictureBufferManagerImpl : public PictureBufferManager { ...@@ -83,13 +84,11 @@ class PictureBufferManagerImpl : public PictureBufferManager {
DCHECK(planes); DCHECK(planes);
DCHECK_LE(planes, static_cast<uint32_t>(VideoFrame::kMaxPlanes)); DCHECK_LE(planes, static_cast<uint32_t>(VideoFrame::kMaxPlanes));
if (!use_shared_image) { // TODO(sandersd): Consider requiring that CreatePictureBuffers() is
// TODO(sandersd): Consider requiring that CreatePictureBuffers() is // called with the context current.
// called with the context current. if (!command_buffer_helper_->MakeContextCurrent()) {
if (!command_buffer_helper_->MakeContextCurrent()) { DVLOG(1) << "Failed to make context current";
DVLOG(1) << "Failed to make context current"; return std::vector<PictureBuffer>();
return std::vector<PictureBuffer>();
}
} }
std::vector<PictureBuffer> picture_buffers; std::vector<PictureBuffer> picture_buffers;
...@@ -97,25 +96,34 @@ class PictureBufferManagerImpl : public PictureBufferManager { ...@@ -97,25 +96,34 @@ class PictureBufferManagerImpl : public PictureBufferManager {
PictureBufferData picture_data = {pixel_format, texture_size, PictureBufferData picture_data = {pixel_format, texture_size,
use_shared_image}; use_shared_image};
if (!use_shared_image) { for (uint32_t j = 0; j < planes; j++) {
for (uint32_t j = 0; j < planes; j++) { // Use the plane size for texture-backed shared and non-shared images.
// Create a texture for this plane. // Adjust the size by the subsampling factor.
GLuint service_id = command_buffer_helper_->CreateTexture( const size_t width =
texture_target, GL_RGBA, texture_size.width(), VideoFrame::Columns(j, pixel_format, texture_size.width());
texture_size.height(), GL_RGBA, GL_UNSIGNED_BYTE); const size_t height =
DCHECK(service_id); VideoFrame::Rows(j, pixel_format, texture_size.height());
picture_data.service_ids.push_back(service_id);
picture_data.texture_sizes.emplace_back(width, height);
// The texture is not cleared yet, but it will be before the VDA
// outputs it. Rather than requiring output to happen on the GPU // Create a texture for this plane.
// thread, mark the texture as cleared immediately. // When using shared images, the VDA might not require GL textures to
command_buffer_helper_->SetCleared(service_id); // exist.
// TODO(crbug.com/1011555): Do not allocate GL textures when unused.
// Generate a mailbox while we are still on the GPU thread. GLuint service_id = command_buffer_helper_->CreateTexture(
picture_data.mailbox_holders[j] = gpu::MailboxHolder( texture_target, GL_RGBA, width, height, GL_RGBA, GL_UNSIGNED_BYTE);
command_buffer_helper_->CreateMailbox(service_id), DCHECK(service_id);
gpu::SyncToken(), texture_target); picture_data.service_ids.push_back(service_id);
}
// The texture is not cleared yet, but it will be before the VDA
// outputs it. Rather than requiring output to happen on the GPU
// thread, mark the texture as cleared immediately.
command_buffer_helper_->SetCleared(service_id);
// Generate a mailbox while we are still on the GPU thread.
picture_data.mailbox_holders[j] = gpu::MailboxHolder(
command_buffer_helper_->CreateMailbox(service_id), gpu::SyncToken(),
texture_target);
} }
// Generate a picture buffer ID and record the picture buffer. // Generate a picture buffer ID and record the picture buffer.
...@@ -132,8 +140,9 @@ class PictureBufferManagerImpl : public PictureBufferManager { ...@@ -132,8 +140,9 @@ class PictureBufferManagerImpl : public PictureBufferManager {
// TODO(sandersd): Refactor the bind image callback to use service IDs so // TODO(sandersd): Refactor the bind image callback to use service IDs so
// that we can get rid of the client IDs altogether. // that we can get rid of the client IDs altogether.
picture_buffers.emplace_back( picture_buffers.emplace_back(
picture_buffer_id, texture_size, picture_data.service_ids, picture_buffer_id, texture_size, picture_data.texture_sizes,
picture_data.service_ids, texture_target, pixel_format); picture_data.service_ids, picture_data.service_ids, texture_target,
pixel_format);
} }
return picture_buffers; return picture_buffers;
} }
...@@ -216,12 +225,12 @@ class PictureBufferManagerImpl : public PictureBufferManager { ...@@ -216,12 +225,12 @@ class PictureBufferManagerImpl : public PictureBufferManager {
// If this |picture| has a SharedImage, then keep a reference to the // If this |picture| has a SharedImage, then keep a reference to the
// SharedImage in |picture_buffer_data| and update the gpu::MailboxHolder. // SharedImage in |picture_buffer_data| and update the gpu::MailboxHolder.
DCHECK_EQ(picture_buffer_data.use_shared_image, for (uint32_t i = 0; i < VideoFrame::kMaxPlanes; i++) {
!!picture.scoped_shared_image()); if (auto scoped_shared_image = picture.scoped_shared_image(i)) {
if (auto scoped_shared_image = picture.scoped_shared_image()) { picture_buffer_data.scoped_shared_images.push_back(scoped_shared_image);
picture_buffer_data.scoped_shared_image = scoped_shared_image; picture_buffer_data.mailbox_holders[i] =
picture_buffer_data.mailbox_holders[0] = scoped_shared_image->GetMailboxHolder();
scoped_shared_image->GetMailboxHolder(); }
} }
// Create and return a VideoFrame for the picture buffer. // Create and return a VideoFrame for the picture buffer.
...@@ -313,7 +322,6 @@ class PictureBufferManagerImpl : public PictureBufferManager { ...@@ -313,7 +322,6 @@ class PictureBufferManagerImpl : public PictureBufferManager {
DCHECK(gpu_task_runner_->BelongsToCurrentThread()); DCHECK(gpu_task_runner_->BelongsToCurrentThread());
std::vector<GLuint> service_ids; std::vector<GLuint> service_ids;
scoped_refptr<Picture::ScopedSharedImage> scoped_shared_image;
{ {
base::AutoLock lock(picture_buffers_lock_); base::AutoLock lock(picture_buffers_lock_);
const auto& it = picture_buffers_.find(picture_buffer_id); const auto& it = picture_buffers_.find(picture_buffer_id);
...@@ -321,16 +329,9 @@ class PictureBufferManagerImpl : public PictureBufferManager { ...@@ -321,16 +329,9 @@ class PictureBufferManagerImpl : public PictureBufferManager {
DCHECK(it->second.dismissed); DCHECK(it->second.dismissed);
DCHECK(!it->second.IsInUse()); DCHECK(!it->second.IsInUse());
service_ids = std::move(it->second.service_ids); service_ids = std::move(it->second.service_ids);
scoped_shared_image = std::move(it->second.scoped_shared_image);
picture_buffers_.erase(it); picture_buffers_.erase(it);
} }
// If this PictureBuffer is using a SharedImage, let it fall out of scope.
if (scoped_shared_image) {
DCHECK(service_ids.empty());
return;
}
if (!command_buffer_helper_->MakeContextCurrent()) if (!command_buffer_helper_->MakeContextCurrent())
return; return;
...@@ -351,7 +352,8 @@ class PictureBufferManagerImpl : public PictureBufferManager { ...@@ -351,7 +352,8 @@ class PictureBufferManagerImpl : public PictureBufferManager {
bool use_shared_image = false; bool use_shared_image = false;
std::vector<GLuint> service_ids; std::vector<GLuint> service_ids;
gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes]; gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes];
scoped_refptr<Picture::ScopedSharedImage> scoped_shared_image; std::vector<gfx::Size> texture_sizes;
std::vector<scoped_refptr<Picture::ScopedSharedImage>> scoped_shared_images;
bool dismissed = false; bool dismissed = false;
// The same picture buffer can be output from the VDA multiple times // The same picture buffer can be output from the VDA multiple times
......
...@@ -768,6 +768,10 @@ gpu::SharedImageStub* VdaVideoDecoder::GetSharedImageStub() const { ...@@ -768,6 +768,10 @@ gpu::SharedImageStub* VdaVideoDecoder::GetSharedImageStub() const {
return command_buffer_helper_->GetSharedImageStub(); return command_buffer_helper_->GetSharedImageStub();
} }
CommandBufferHelper* VdaVideoDecoder::GetCommandBufferHelper() const {
return command_buffer_helper_.get();
}
void VdaVideoDecoder::NotifyErrorOnParentThread( void VdaVideoDecoder::NotifyErrorOnParentThread(
VideoDecodeAccelerator::Error error) { VideoDecodeAccelerator::Error error) {
DVLOG(1) << __func__ << "(" << error << ")"; DVLOG(1) << __func__ << "(" << error << ")";
......
...@@ -129,6 +129,7 @@ class VdaVideoDecoder : public VideoDecoder, ...@@ -129,6 +129,7 @@ class VdaVideoDecoder : public VideoDecoder,
void NotifyResetDone() override; void NotifyResetDone() override;
void NotifyError(VideoDecodeAccelerator::Error error) override; void NotifyError(VideoDecodeAccelerator::Error error) override;
gpu::SharedImageStub* GetSharedImageStub() const override; gpu::SharedImageStub* GetSharedImageStub() const override;
CommandBufferHelper* GetCommandBufferHelper() const override;
// Tasks and thread hopping. // Tasks and thread hopping.
static void CleanupOnGpuThread(std::unique_ptr<VdaVideoDecoder>); static void CleanupOnGpuThread(std::unique_ptr<VdaVideoDecoder>);
......
...@@ -494,6 +494,8 @@ bool EGLStreamPictureBuffer::BindSampleToTexture( ...@@ -494,6 +494,8 @@ bool EGLStreamPictureBuffer::BindSampleToTexture(
DCHECK_EQ(BOUND, state_); DCHECK_EQ(BOUND, state_);
state_ = IN_CLIENT; state_ = IN_CLIENT;
shared_images_.resize(picture_buffer_.service_texture_ids().size());
current_d3d_sample_ = sample; current_d3d_sample_ = sample;
EGLDisplay egl_display = gl::GLSurfaceEGL::GetHardwareDisplay(); EGLDisplay egl_display = gl::GLSurfaceEGL::GetHardwareDisplay();
......
...@@ -68,6 +68,31 @@ class DXVAPictureBuffer { ...@@ -68,6 +68,31 @@ class DXVAPictureBuffer {
color_space_ = color_space; color_space_ = color_space;
} }
const std::vector<scoped_refptr<Picture::ScopedSharedImage>>& shared_images()
const {
return shared_images_;
}
void set_shared_image(
size_t plane,
scoped_refptr<Picture::ScopedSharedImage> shared_image) {
DCHECK(plane < shared_images_.size());
shared_images_[plane] = std::move(shared_image);
}
// Picture buffer data used to create a shared image backing.
const PictureBuffer::TextureIds& service_texture_ids() const {
return picture_buffer_.service_texture_ids();
}
gfx::Size texture_size(size_t plane) {
return picture_buffer_.texture_size(plane);
}
VideoPixelFormat pixel_format() const {
return picture_buffer_.pixel_format();
}
// Returns true if these could in theory be used as an overlay. May // Returns true if these could in theory be used as an overlay. May
// still be drawn using GL depending on the scene and precise hardware // still be drawn using GL depending on the scene and precise hardware
// support. // support.
...@@ -96,6 +121,8 @@ class DXVAPictureBuffer { ...@@ -96,6 +121,8 @@ class DXVAPictureBuffer {
gfx::ColorSpace color_space_; gfx::ColorSpace color_space_;
scoped_refptr<gl::GLImage> gl_image_; scoped_refptr<gl::GLImage> gl_image_;
std::vector<scoped_refptr<Picture::ScopedSharedImage>> shared_images_;
DISALLOW_COPY_AND_ASSIGN(DXVAPictureBuffer); DISALLOW_COPY_AND_ASSIGN(DXVAPictureBuffer);
}; };
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "base/atomicops.h" #include "base/atomicops.h"
#include "base/base_paths_win.h" #include "base/base_paths_win.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/bind_post_task.h"
#include "base/callback.h" #include "base/callback.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/file_version_info.h" #include "base/file_version_info.h"
...@@ -38,12 +39,19 @@ ...@@ -38,12 +39,19 @@
#include "base/win/scoped_co_mem.h" #include "base/win/scoped_co_mem.h"
#include "base/win/windows_version.h" #include "base/win/windows_version.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "components/viz/common/resources/resource_format_utils.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/command_buffer/service/shared_image_backing_d3d.h"
#include "gpu/command_buffer/service/shared_image_factory.h"
#include "gpu/config/gpu_driver_bug_workarounds.h" #include "gpu/config/gpu_driver_bug_workarounds.h"
#include "gpu/config/gpu_preferences.h" #include "gpu/config/gpu_preferences.h"
#include "gpu/ipc/service/shared_image_stub.h"
#include "media/base/media_log.h" #include "media/base/media_log.h"
#include "media/base/media_switches.h" #include "media/base/media_switches.h"
#include "media/base/video_frame.h"
#include "media/base/win/mf_helpers.h" #include "media/base/win/mf_helpers.h"
#include "media/filters/vp9_parser.h" #include "media/filters/vp9_parser.h"
#include "media/gpu/command_buffer_helper.h"
#include "media/gpu/windows/d3d11_video_device_format_support.h" #include "media/gpu/windows/d3d11_video_device_format_support.h"
#include "media/gpu/windows/dxva_picture_buffer_win.h" #include "media/gpu/windows/dxva_picture_buffer_win.h"
#include "media/gpu/windows/supported_profile_helpers.h" #include "media/gpu/windows/supported_profile_helpers.h"
...@@ -59,6 +67,7 @@ ...@@ -59,6 +67,7 @@
#include "ui/gl/gl_bindings.h" #include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h" #include "ui/gl/gl_context.h"
#include "ui/gl/gl_fence.h" #include "ui/gl/gl_fence.h"
#include "ui/gl/gl_image_dxgi.h"
#include "ui/gl/gl_surface_egl.h" #include "ui/gl/gl_surface_egl.h"
#include "ui/gl/gl_switches.h" #include "ui/gl/gl_switches.h"
...@@ -172,6 +181,36 @@ HRESULT g_last_device_removed_reason; ...@@ -172,6 +181,36 @@ HRESULT g_last_device_removed_reason;
namespace media { namespace media {
bool VideoPixelFormatToVizFormat(
VideoPixelFormat pixel_format,
size_t textures_per_picture,
std::array<viz::ResourceFormat, VideoFrame::kMaxPlanes>& texture_formats) {
switch (pixel_format) {
case PIXEL_FORMAT_ARGB:
case PIXEL_FORMAT_XRGB:
case PIXEL_FORMAT_ABGR:
case PIXEL_FORMAT_BGRA:
DCHECK_EQ(textures_per_picture, 1u);
texture_formats[0] =
(pixel_format == PIXEL_FORMAT_ABGR) ? viz::RGBA_8888 : viz::BGRA_8888;
return true;
case PIXEL_FORMAT_NV12:
DCHECK_EQ(textures_per_picture, 2u);
texture_formats[0] = viz::RED_8; // Y
texture_formats[1] = viz::RG_88; // UV
return true;
case PIXEL_FORMAT_P016LE:
// TODO(crbug.com/1011555): P010 formats are not fully supported.
// The required Viz formats (viz::R16_EXT and viz::RG16_EXT) are not yet
// supported.
DCHECK_EQ(textures_per_picture, 2u);
return false;
default: // Unsupported
NOTREACHED();
return false;
}
}
constexpr VideoCodecProfile kSupportedProfiles[] = { constexpr VideoCodecProfile kSupportedProfiles[] = {
H264PROFILE_BASELINE, H264PROFILE_MAIN, H264PROFILE_HIGH, H264PROFILE_BASELINE, H264PROFILE_MAIN, H264PROFILE_HIGH,
VP8PROFILE_ANY, VP9PROFILE_PROFILE0, VP9PROFILE_PROFILE2, VP8PROFILE_ANY, VP9PROFILE_PROFILE0, VP9PROFILE_PROFILE2,
...@@ -1325,6 +1364,13 @@ GLenum DXVAVideoDecodeAccelerator::GetSurfaceInternalFormat() const { ...@@ -1325,6 +1364,13 @@ GLenum DXVAVideoDecodeAccelerator::GetSurfaceInternalFormat() const {
return GL_BGRA_EXT; return GL_BGRA_EXT;
} }
bool DXVAVideoDecodeAccelerator::SupportsSharedImagePictureBuffers() const {
// Shared image is needed to display overlays which can be used directly
// by the video processor.
// TODO(crbug.com/1011555): Support for non-bind cases.
return GetPictureBufferMechanism() == PictureBufferMechanism::BIND;
}
// static // static
VideoDecodeAccelerator::SupportedProfiles VideoDecodeAccelerator::SupportedProfiles
DXVAVideoDecodeAccelerator::GetSupportedProfiles( DXVAVideoDecodeAccelerator::GetSupportedProfiles(
...@@ -2118,12 +2164,18 @@ void DXVAVideoDecodeAccelerator::NotifyPictureReady( ...@@ -2118,12 +2164,18 @@ void DXVAVideoDecodeAccelerator::NotifyPictureReady(
int input_buffer_id, int input_buffer_id,
const gfx::Rect& visible_rect, const gfx::Rect& visible_rect,
const gfx::ColorSpace& color_space, const gfx::ColorSpace& color_space,
bool allow_overlay) { bool allow_overlay,
std::vector<scoped_refptr<Picture::ScopedSharedImage>> shared_images) {
DCHECK(main_thread_task_runner_->BelongsToCurrentThread()); DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
// This task could execute after the decoder has been torn down. // This task could execute after the decoder has been torn down.
if (GetState() != kUninitialized && client_) { if (GetState() != kUninitialized && client_) {
Picture picture(picture_buffer_id, input_buffer_id, visible_rect, Picture picture(picture_buffer_id, input_buffer_id, visible_rect,
color_space, allow_overlay); color_space, allow_overlay);
for (uint32_t i = 0; i < shared_images.size(); i++) {
picture.set_scoped_shared_image(shared_images[i], i);
}
client_->PictureReady(picture); client_->PictureReady(picture);
} }
} }
...@@ -2591,13 +2643,100 @@ void DXVAVideoDecodeAccelerator::BindPictureBufferToSample( ...@@ -2591,13 +2643,100 @@ void DXVAVideoDecodeAccelerator::BindPictureBufferToSample(
DCHECK(!output_picture_buffers_.empty()); DCHECK(!output_picture_buffers_.empty());
// BindSampleToTexture configures GLImage with the DX11 output texture.
// The DX11 texture is then accessed through the GLImage to create a shared
// image backing below.
bool result = picture_buffer->BindSampleToTexture(this, sample); bool result = picture_buffer->BindSampleToTexture(this, sample);
RETURN_AND_NOTIFY_ON_FAILURE(result, "Failed to complete copying surface", RETURN_AND_NOTIFY_ON_FAILURE(result, "Failed to bind sample to texture",
PLATFORM_FAILURE, ); PLATFORM_FAILURE, );
// Create the DX11 texture backed shared images (texture per plane).
std::vector<scoped_refptr<Picture::ScopedSharedImage>> scoped_shared_images;
if (SupportsSharedImagePictureBuffers()) {
gl::GLImageDXGI* gl_image_dxgi =
gl::GLImageDXGI::FromGLImage(picture_buffer->gl_image().get());
DCHECK(gl_image_dxgi);
const size_t textures_per_picture =
picture_buffer->service_texture_ids().size();
// Get the viz resource format per texture.
std::array<viz::ResourceFormat, VideoFrame::kMaxPlanes> viz_formats;
{
const bool result = VideoPixelFormatToVizFormat(
picture_buffer->pixel_format(), textures_per_picture, viz_formats);
RETURN_AND_NOTIFY_ON_FAILURE(
result, "Could not convert pixel format to viz format",
PLATFORM_FAILURE, );
}
CommandBufferHelper* helper = client_->GetCommandBufferHelper();
DCHECK(helper);
for (uint32_t texture_idx = 0; texture_idx < textures_per_picture;
texture_idx++) {
// Usage flags to allow the display compositor to draw from it, video
// to decode, and allow webgl/canvas access.
constexpr uint32_t shared_image_usage =
gpu::SHARED_IMAGE_USAGE_VIDEO_DECODE | gpu::SHARED_IMAGE_USAGE_GLES2 |
gpu::SHARED_IMAGE_USAGE_RASTER | gpu::SHARED_IMAGE_USAGE_DISPLAY |
gpu::SHARED_IMAGE_USAGE_SCANOUT;
// Create a shared image
// TODO(crbug.com/1011555): Need key shared mutex if shared image is ever
// used by another device.
scoped_refptr<gpu::gles2::TexturePassthrough> gl_texture =
gpu::gles2::TexturePassthrough::CheckedCast(helper->GetTexture(
picture_buffer->service_texture_ids()[texture_idx]));
// Create a new shared image mailbox. The existing mailbox belonging to
// this |picture_buffer| will be updated when the video frame is created.
const auto& mailbox = gpu::Mailbox::GenerateForSharedImage();
auto shared_image = std::make_unique<gpu::SharedImageBackingD3D>(
mailbox, viz_formats[texture_idx],
picture_buffer->texture_size(texture_idx),
picture_buffer->color_space(), kTopLeft_GrSurfaceOrigin,
kPremul_SkAlphaType, shared_image_usage,
/*swap_chain=*/nullptr, std::move(gl_texture),
picture_buffer->gl_image(),
/*buffer_index=*/0, gl_image_dxgi->texture(),
base::win::ScopedHandle(),
/*dxgi_keyed_mutex=*/nullptr);
// Caller is assumed to provide cleared d3d textures.
shared_image->SetCleared();
gpu::SharedImageStub* shared_image_stub = client_->GetSharedImageStub();
DCHECK(shared_image_stub);
const bool success = shared_image_stub->factory()->RegisterBacking(
std::move(shared_image), /* legacy_mailbox */ true);
if (!success) {
RETURN_AND_NOTIFY_ON_FAILURE(false, "Failed to register shared image",
PLATFORM_FAILURE, );
}
auto destroy_shared_image_callback = base::BindPostTask(
main_thread_task_runner_,
base::BindOnce(
shared_image_stub->GetSharedImageDestructionCallback(mailbox),
gpu::SyncToken()));
// Wrap the factory ref with a scoped shared image. The factory ref
// is used instead of requiring a destruction call-back.
auto scoped_shared_image =
base::MakeRefCounted<Picture::ScopedSharedImage>(
mailbox, GetTextureTarget(),
std::move(destroy_shared_image_callback));
scoped_shared_images.push_back(std::move(scoped_shared_image));
}
}
NotifyPictureReady( NotifyPictureReady(
picture_buffer->id(), input_buffer_id, picture_buffer->visible_rect(), picture_buffer->id(), input_buffer_id, picture_buffer->visible_rect(),
picture_buffer->color_space(), picture_buffer->AllowOverlay()); picture_buffer->color_space(), picture_buffer->AllowOverlay(),
std::move(scoped_shared_images));
{ {
base::AutoLock lock(decoder_lock_); base::AutoLock lock(decoder_lock_);
......
...@@ -112,6 +112,7 @@ class MEDIA_GPU_EXPORT DXVAVideoDecodeAccelerator ...@@ -112,6 +112,7 @@ class MEDIA_GPU_EXPORT DXVAVideoDecodeAccelerator
const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner) const scoped_refptr<base::SingleThreadTaskRunner>& decode_task_runner)
override; override;
GLenum GetSurfaceInternalFormat() const override; GLenum GetSurfaceInternalFormat() const override;
bool SupportsSharedImagePictureBuffers() const override;
static VideoDecodeAccelerator::SupportedProfiles GetSupportedProfiles( static VideoDecodeAccelerator::SupportedProfiles GetSupportedProfiles(
const gpu::GpuPreferences& gpu_preferences, const gpu::GpuPreferences& gpu_preferences,
...@@ -248,7 +249,9 @@ class MEDIA_GPU_EXPORT DXVAVideoDecodeAccelerator ...@@ -248,7 +249,9 @@ class MEDIA_GPU_EXPORT DXVAVideoDecodeAccelerator
int input_buffer_id, int input_buffer_id,
const gfx::Rect& visible_rect, const gfx::Rect& visible_rect,
const gfx::ColorSpace& color_space, const gfx::ColorSpace& color_space,
bool allow_overlay); bool allow_overlay,
std::vector<scoped_refptr<Picture::ScopedSharedImage>>
shared_images = {});
// Sends pending input buffer processed acks to the client if we don't have // Sends pending input buffer processed acks to the client if we don't have
// output samples waiting to be processed. // output samples waiting to be processed.
......
...@@ -53,17 +53,37 @@ PictureBuffer::PictureBuffer(int32_t id, ...@@ -53,17 +53,37 @@ PictureBuffer::PictureBuffer(int32_t id,
DCHECK_EQ(client_texture_ids.size(), texture_mailboxes.size()); DCHECK_EQ(client_texture_ids.size(), texture_mailboxes.size());
} }
PictureBuffer::PictureBuffer(int32_t id,
const gfx::Size& size,
const TextureSizes& texture_sizes,
const TextureIds& client_texture_ids,
const TextureIds& service_texture_ids,
uint32_t texture_target,
VideoPixelFormat pixel_format)
: id_(id),
size_(size),
texture_sizes_(texture_sizes),
client_texture_ids_(client_texture_ids),
service_texture_ids_(service_texture_ids),
texture_target_(texture_target),
pixel_format_(pixel_format) {
// We either not have client texture ids at all, or if we do, then their
// number must be the same as the number of service texture ids.
DCHECK(client_texture_ids_.empty() ||
client_texture_ids_.size() == service_texture_ids_.size());
}
PictureBuffer::PictureBuffer(const PictureBuffer& other) = default; PictureBuffer::PictureBuffer(const PictureBuffer& other) = default;
PictureBuffer::~PictureBuffer() = default; PictureBuffer::~PictureBuffer() = default;
gpu::Mailbox PictureBuffer::texture_mailbox(size_t plane) const { gfx::Size PictureBuffer::texture_size(size_t plane) const {
if (plane >= texture_mailboxes_.size()) { if (plane >= texture_sizes_.size()) {
LOG(ERROR) << "No mailbox for plane " << plane; LOG(ERROR) << "Missing texture size for plane " << plane;
return gpu::Mailbox(); return gfx::Size();
} }
return texture_mailboxes_[plane]; return texture_sizes_[plane];
} }
Picture::Picture(int32_t picture_buffer_id, Picture::Picture(int32_t picture_buffer_id,
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "gpu/command_buffer/common/mailbox_holder.h" #include "gpu/command_buffer/common/mailbox_holder.h"
#include "media/base/media_export.h" #include "media/base/media_export.h"
#include "media/base/video_frame.h"
#include "media/base/video_types.h" #include "media/base/video_types.h"
#include "ui/gfx/color_space.h" #include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect.h"
...@@ -25,6 +26,7 @@ namespace media { ...@@ -25,6 +26,7 @@ namespace media {
class MEDIA_EXPORT PictureBuffer { class MEDIA_EXPORT PictureBuffer {
public: public:
using TextureIds = std::vector<uint32_t>; using TextureIds = std::vector<uint32_t>;
using TextureSizes = std::vector<gfx::Size>;
PictureBuffer(int32_t id, const gfx::Size& size); PictureBuffer(int32_t id, const gfx::Size& size);
PictureBuffer(int32_t id, PictureBuffer(int32_t id,
...@@ -42,6 +44,13 @@ class MEDIA_EXPORT PictureBuffer { ...@@ -42,6 +44,13 @@ class MEDIA_EXPORT PictureBuffer {
const std::vector<gpu::Mailbox>& texture_mailboxes, const std::vector<gpu::Mailbox>& texture_mailboxes,
uint32_t texture_target, uint32_t texture_target,
VideoPixelFormat pixel_format); VideoPixelFormat pixel_format);
PictureBuffer(int32_t id,
const gfx::Size& size,
const TextureSizes& texture_sizes,
const TextureIds& client_texture_ids,
const TextureIds& service_texture_ids,
uint32_t texture_target,
VideoPixelFormat pixel_format);
PictureBuffer(const PictureBuffer& other); PictureBuffer(const PictureBuffer& other);
~PictureBuffer(); ~PictureBuffer();
...@@ -64,11 +73,12 @@ class MEDIA_EXPORT PictureBuffer { ...@@ -64,11 +73,12 @@ class MEDIA_EXPORT PictureBuffer {
VideoPixelFormat pixel_format() const { return pixel_format_; } VideoPixelFormat pixel_format() const { return pixel_format_; }
gpu::Mailbox texture_mailbox(size_t plane) const; gfx::Size texture_size(size_t plane) const;
private: private:
int32_t id_; int32_t id_;
gfx::Size size_; gfx::Size size_;
TextureSizes texture_sizes_;
TextureIds client_texture_ids_; TextureIds client_texture_ids_;
TextureIds service_texture_ids_; TextureIds service_texture_ids_;
std::vector<gpu::Mailbox> texture_mailboxes_; std::vector<gpu::Mailbox> texture_mailboxes_;
...@@ -151,11 +161,16 @@ class MEDIA_EXPORT Picture { ...@@ -151,11 +161,16 @@ class MEDIA_EXPORT Picture {
} }
void set_scoped_shared_image( void set_scoped_shared_image(
scoped_refptr<ScopedSharedImage> scoped_shared_image) { scoped_refptr<ScopedSharedImage> scoped_shared_image,
scoped_shared_image_ = scoped_shared_image; uint32_t plane = 0) {
DCHECK(plane < scoped_shared_images_.size());
scoped_shared_images_[plane] = scoped_shared_image;
} }
scoped_refptr<ScopedSharedImage> scoped_shared_image() const {
return scoped_shared_image_; scoped_refptr<ScopedSharedImage> scoped_shared_image(
uint32_t plane = 0) const {
DCHECK(plane < scoped_shared_images_.size());
return scoped_shared_images_[plane];
} }
private: private:
...@@ -168,7 +183,8 @@ class MEDIA_EXPORT Picture { ...@@ -168,7 +183,8 @@ class MEDIA_EXPORT Picture {
bool size_changed_; bool size_changed_;
bool texture_owner_; bool texture_owner_;
bool wants_promotion_hint_; bool wants_promotion_hint_;
scoped_refptr<ScopedSharedImage> scoped_shared_image_; std::array<scoped_refptr<ScopedSharedImage>, VideoFrame::kMaxPlanes>
scoped_shared_images_;
}; };
} // namespace media } // namespace media
......
...@@ -71,6 +71,11 @@ gpu::SharedImageStub* VideoDecodeAccelerator::Client::GetSharedImageStub() ...@@ -71,6 +71,11 @@ gpu::SharedImageStub* VideoDecodeAccelerator::Client::GetSharedImageStub()
return nullptr; return nullptr;
} }
CommandBufferHelper* VideoDecodeAccelerator::Client::GetCommandBufferHelper()
const {
return nullptr;
}
VideoDecodeAccelerator::~VideoDecodeAccelerator() = default; VideoDecodeAccelerator::~VideoDecodeAccelerator() = default;
void VideoDecodeAccelerator::Decode(scoped_refptr<DecoderBuffer> buffer, void VideoDecodeAccelerator::Decode(scoped_refptr<DecoderBuffer> buffer,
......
...@@ -38,6 +38,8 @@ class SharedImageStub; ...@@ -38,6 +38,8 @@ class SharedImageStub;
namespace media { namespace media {
class CommandBufferHelper;
// Video decoder interface. // Video decoder interface.
// This interface is extended by the various components that ultimately // This interface is extended by the various components that ultimately
// implement the backend of PPB_VideoDecoder_Dev. // implement the backend of PPB_VideoDecoder_Dev.
...@@ -262,6 +264,10 @@ class MEDIA_EXPORT VideoDecodeAccelerator { ...@@ -262,6 +264,10 @@ class MEDIA_EXPORT VideoDecodeAccelerator {
// Default implementation returns nullptr. // Default implementation returns nullptr.
virtual gpu::SharedImageStub* GetSharedImageStub() const; virtual gpu::SharedImageStub* GetSharedImageStub() const;
// Return the CommandBufferHelper through which GL passthrough textures may
// be created. Default implementation returns nullptr.
virtual CommandBufferHelper* GetCommandBufferHelper() const;
protected: protected:
virtual ~Client() {} virtual ~Client() {}
}; };
......
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