Commit 35c0a1d5 authored by Frank Liberato's avatar Frank Liberato Committed by Commit Bot

Split up TextureSelector, create D3D11DecoderConfigurator.

D3D11DecoderConfiguratorhandles the decoder guid / decoder
output texture.

TextureSelector takes the decoder output texture format as input,
and figures out whether to bind / copy / etc. it.  Produces the
PixelFormat and TextureWrapper as output.

Change-Id: If125572af7a5553fa76ea4dcf40afff9b37e13b7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1999503Reviewed-by: default avatarTed Meyer <tmathmeyer@chromium.org>
Commit-Queue: Frank Liberato <liberato@chromium.org>
Cr-Commit-Position: refs/heads/master@{#740041}
parent ad408dc6
......@@ -164,6 +164,8 @@ component("gpu") {
"windows/d3d11_com_defs.h",
"windows/d3d11_copying_texture_wrapper.cc",
"windows/d3d11_copying_texture_wrapper.h",
"windows/d3d11_decoder_configurator.cc",
"windows/d3d11_decoder_configurator.h",
"windows/d3d11_h264_accelerator.cc",
"windows/d3d11_h264_accelerator.h",
"windows/d3d11_picture_buffer.cc",
......@@ -498,6 +500,7 @@ source_set("unit_tests") {
sources += [
"windows/d3d11_cdm_proxy_unittest.cc",
"windows/d3d11_copying_texture_wrapper_unittest.cc",
"windows/d3d11_decoder_configurator_unittest.cc",
"windows/d3d11_decryptor_unittest.cc",
"windows/d3d11_texture_selector_unittest.cc",
"windows/d3d11_video_decoder_unittest.cc",
......
// Copyright 2019 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/windows/d3d11_decoder_configurator.h"
#include <d3d11.h>
#include "base/feature_list.h"
#include "media/base/media_log.h"
#include "media/base/media_switches.h"
#include "media/gpu/windows/d3d11_copying_texture_wrapper.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gl/direct_composition_surface_win.h"
namespace media {
D3D11DecoderConfigurator::D3D11DecoderConfigurator(
DXGI_FORMAT decoder_output_dxgifmt,
GUID decoder_guid,
gfx::Size coded_size,
bool is_encrypted,
bool supports_swap_chain)
: dxgi_format_(decoder_output_dxgifmt), decoder_guid_(decoder_guid) {
SetUpDecoderDescriptor(coded_size);
SetUpTextureDescriptor(supports_swap_chain, is_encrypted);
}
// static
std::unique_ptr<D3D11DecoderConfigurator> D3D11DecoderConfigurator::Create(
const gpu::GpuPreferences& gpu_preferences,
const gpu::GpuDriverBugWorkarounds& workarounds,
const VideoDecoderConfig& config,
MediaLog* media_log) {
bool supports_nv12_decode_swap_chain =
gl::DirectCompositionSurfaceWin::IsDecodeSwapChainSupported();
DXGI_FORMAT decoder_dxgi_format = DXGI_FORMAT_NV12;
GUID decoder_guid = {};
if (config.codec() == kCodecH264) {
MEDIA_LOG(INFO, media_log) << "D3D11VideoDecoder is using h264 / NV12";
decoder_guid = D3D11_DECODER_PROFILE_H264_VLD_NOFGT;
} else if (config.profile() == VP9PROFILE_PROFILE0) {
MEDIA_LOG(INFO, media_log) << "D3D11VideoDecoder is using vp9p0 / NV12";
decoder_guid = D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0;
} else if (config.profile() == VP9PROFILE_PROFILE2) {
MEDIA_LOG(INFO, media_log) << "D3D11VideoDecoder is using vp9p2 / P010";
decoder_guid = D3D11_DECODER_PROFILE_VP9_VLD_10BIT_PROFILE2;
decoder_dxgi_format = DXGI_FORMAT_P010;
} else {
// TODO(tmathmeyer) support other profiles in the future.
MEDIA_LOG(INFO, media_log)
<< "D3D11VideoDecoder does not support codec " << config.codec();
return nullptr;
}
return std::make_unique<D3D11DecoderConfigurator>(
decoder_dxgi_format, decoder_guid, config.coded_size(),
config.is_encrypted(), supports_nv12_decode_swap_chain);
}
bool D3D11DecoderConfigurator::SupportsDevice(
ComD3D11VideoDevice video_device) {
for (UINT i = video_device->GetVideoDecoderProfileCount(); i--;) {
GUID profile = {};
if (SUCCEEDED(video_device->GetVideoDecoderProfile(i, &profile))) {
if (profile == decoder_guid_)
return true;
}
}
return false;
}
ComD3D11Texture2D D3D11DecoderConfigurator::CreateOutputTexture(
ComD3D11Device device,
gfx::Size size) {
output_texture_desc_.Width = size.width();
output_texture_desc_.Height = size.height();
ComD3D11Texture2D result;
if (!SUCCEEDED(
device->CreateTexture2D(&output_texture_desc_, nullptr, &result)))
return nullptr;
return result;
}
// private
void D3D11DecoderConfigurator::SetUpDecoderDescriptor(
const gfx::Size& coded_size) {
decoder_desc_ = {};
decoder_desc_.Guid = decoder_guid_;
decoder_desc_.SampleWidth = coded_size.width();
decoder_desc_.SampleHeight = coded_size.height();
decoder_desc_.OutputFormat = dxgi_format_;
}
// private
void D3D11DecoderConfigurator::SetUpTextureDescriptor(bool supports_swap_chain,
bool is_encrypted) {
output_texture_desc_ = {};
output_texture_desc_.MipLevels = 1;
output_texture_desc_.ArraySize = D3D11DecoderConfigurator::BUFFER_COUNT;
output_texture_desc_.Format = dxgi_format_;
output_texture_desc_.SampleDesc.Count = 1;
output_texture_desc_.Usage = D3D11_USAGE_DEFAULT;
output_texture_desc_.BindFlags =
D3D11_BIND_DECODER | D3D11_BIND_SHADER_RESOURCE;
// Decode swap chains do not support shared resources.
// TODO(sunnyps): Find a workaround for when the decoder moves to its own
// thread and D3D device. See https://crbug.com/911847
// TODO(liberato): This depends on the configuration of the TextureSelector,
// to some degree. If it's copying, then it can be set up to use our device
// to make the copy, and this can always be unset. If it's binding, then it
// depends on whether we're on the angle device or not.
output_texture_desc_.MiscFlags =
supports_swap_chain ? 0 : D3D11_RESOURCE_MISC_SHARED;
if (is_encrypted)
output_texture_desc_.MiscFlags |= D3D11_RESOURCE_MISC_HW_PROTECTED;
}
} // namespace media
// Copyright 2020 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.
#ifndef MEDIA_GPU_WINDOWS_D3D11_DECODER_CONFIGURATOR_H_
#define MEDIA_GPU_WINDOWS_D3D11_DECODER_CONFIGURATOR_H_
#include <d3d11.h>
#include <wrl.h>
#include <memory>
#include <vector>
#include "media/gpu/media_gpu_export.h"
#include "media/gpu/windows/d3d11_picture_buffer.h"
#include "media/gpu/windows/d3d11_video_processor_proxy.h"
#include "ui/gfx/geometry/size.h"
namespace media {
class MediaLog;
// Stores different pixel formats and DGXI formats, and checks for decoder
// GUID support. Generally provides a centralized place to figure out which
// decoder to use, and how its output texture should be configured.
class MEDIA_GPU_EXPORT D3D11DecoderConfigurator {
public:
D3D11DecoderConfigurator(DXGI_FORMAT decoder_output_dxgifmt,
GUID decoder_guid,
gfx::Size coded_size,
bool is_encrypted,
bool supports_swap_chain);
virtual ~D3D11DecoderConfigurator() = default;
static std::unique_ptr<D3D11DecoderConfigurator> Create(
const gpu::GpuPreferences& gpu_preferences,
const gpu::GpuDriverBugWorkarounds& workarounds,
const VideoDecoderConfig& config,
MediaLog* media_log);
bool SupportsDevice(ComD3D11VideoDevice video_device);
// Create the decoder's output texture.
ComD3D11Texture2D CreateOutputTexture(ComD3D11Device device, gfx::Size size);
const D3D11_VIDEO_DECODER_DESC* DecoderDescriptor() const {
return &decoder_desc_;
}
const GUID DecoderGuid() const { return decoder_guid_; }
DXGI_FORMAT TextureFormat() const { return dxgi_format_; }
static constexpr size_t BUFFER_COUNT = 20;
private:
// Set up instances of the parameter structs for D3D11 Functions
void SetUpDecoderDescriptor(const gfx::Size& coded_size);
void SetUpTextureDescriptor(bool supports_swap_chain, bool is_encrypted);
D3D11_TEXTURE2D_DESC output_texture_desc_;
D3D11_VIDEO_DECODER_DESC decoder_desc_;
const DXGI_FORMAT dxgi_format_;
const GUID decoder_guid_;
};
} // namespace media
#endif // MEDIA_GPU_WINDOWS_D3D11_DECODER_CONFIGURATOR_H_
// Copyright 2020 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 <utility>
#include "media/base/media_util.h"
#include "media/base/win/d3d11_mocks.h"
#include "media/gpu/windows/d3d11_decoder_configurator.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::_;
using ::testing::Combine;
using ::testing::DoAll;
using ::testing::Return;
using ::testing::SetArgPointee;
using ::testing::Values;
namespace media {
class D3D11DecoderConfiguratorUnittest : public ::testing::Test {
public:
VideoDecoderConfig CreateDecoderConfig(VideoCodecProfile profile,
gfx::Size size,
bool encrypted) {
VideoDecoderConfig result;
result.Initialize(
kUnknownVideoCodec, // It doesn't matter because it won't be used.
profile, VideoDecoderConfig::AlphaMode::kIsOpaque, VideoColorSpace(),
kNoTransformation, size, {}, {}, {},
encrypted ? EncryptionScheme::kCenc : EncryptionScheme::kUnencrypted);
return result;
}
std::unique_ptr<D3D11DecoderConfigurator> CreateWithDefaultGPUInfo(
const VideoDecoderConfig& config,
bool zero_copy_enabled = true) {
gpu::GpuPreferences prefs;
prefs.enable_zero_copy_dxgi_video = zero_copy_enabled;
gpu::GpuDriverBugWorkarounds workarounds;
workarounds.disable_dxgi_zero_copy_video = false;
auto media_log = std::make_unique<NullMediaLog>();
return D3D11DecoderConfigurator::Create(prefs, workarounds, config,
media_log.get());
}
};
TEST_F(D3D11DecoderConfiguratorUnittest, VP9Profile0RightFormats) {
auto configurator = CreateWithDefaultGPUInfo(
CreateDecoderConfig(VP9PROFILE_PROFILE0, {0, 0}, false));
EXPECT_EQ(configurator->DecoderGuid(),
D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0);
EXPECT_EQ(configurator->DecoderDescriptor()->OutputFormat, DXGI_FORMAT_NV12);
}
TEST_F(D3D11DecoderConfiguratorUnittest, VP9Profile2RightFormats) {
auto configurator = CreateWithDefaultGPUInfo(
CreateDecoderConfig(VP9PROFILE_PROFILE2, {0, 0}, false), false);
EXPECT_EQ(configurator->DecoderGuid(),
D3D11_DECODER_PROFILE_VP9_VLD_10BIT_PROFILE2);
EXPECT_EQ(configurator->DecoderDescriptor()->OutputFormat, DXGI_FORMAT_P010);
}
TEST_F(D3D11DecoderConfiguratorUnittest, SupportsDeviceNoProfiles) {
auto configurator = CreateWithDefaultGPUInfo(
CreateDecoderConfig(VP9PROFILE_PROFILE0, {0, 0}, false));
auto vd_mock = CreateD3D11Mock<D3D11VideoDeviceMock>();
EXPECT_CALL(*vd_mock.Get(), GetVideoDecoderProfileCount())
.Times(1)
.WillOnce(Return(0));
EXPECT_FALSE(configurator->SupportsDevice(vd_mock));
}
TEST_F(D3D11DecoderConfiguratorUnittest, SupportsDeviceWrongProfiles) {
auto configurator = CreateWithDefaultGPUInfo(
CreateDecoderConfig(VP9PROFILE_PROFILE0, {0, 0}, false));
auto vd_mock = CreateD3D11Mock<D3D11VideoDeviceMock>();
EXPECT_CALL(*vd_mock.Get(), GetVideoDecoderProfileCount())
.Times(1)
.WillOnce(Return(2));
EXPECT_CALL(*vd_mock.Get(), GetVideoDecoderProfile(0, _))
.Times(1)
.WillOnce(DoAll(SetArgPointee<1>(D3D11_DECODER_PROFILE_HEVC_VLD_MAIN),
Return(S_OK)));
EXPECT_CALL(*vd_mock.Get(), GetVideoDecoderProfile(1, _))
.Times(1)
.WillOnce(
DoAll(SetArgPointee<1>(D3D11_DECODER_PROFILE_VC1_VLD), Return(S_OK)));
EXPECT_FALSE(configurator->SupportsDevice(vd_mock));
}
TEST_F(D3D11DecoderConfiguratorUnittest, SupportsDeviceCorrectProfile) {
auto configurator = CreateWithDefaultGPUInfo(
CreateDecoderConfig(VP9PROFILE_PROFILE0, {0, 0}, false));
auto vd_mock = CreateD3D11Mock<D3D11VideoDeviceMock>();
EXPECT_CALL(*vd_mock.Get(), GetVideoDecoderProfileCount())
.Times(1)
.WillOnce(Return(5));
EXPECT_CALL(*vd_mock.Get(), GetVideoDecoderProfile(4, _))
.Times(1)
.WillOnce(DoAll(SetArgPointee<1>(D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0),
Return(S_OK)));
EXPECT_TRUE(configurator->SupportsDevice(vd_mock));
}
} // namespace media
......@@ -16,19 +16,9 @@
namespace media {
TextureSelector::TextureSelector(VideoPixelFormat pixfmt,
DXGI_FORMAT dxgifmt,
GUID decoder_guid,
gfx::Size coded_size,
bool is_encrypted,
bool supports_swap_chain)
: pixel_format_(pixfmt),
dxgi_format_(dxgifmt),
decoder_guid_(decoder_guid),
coded_size_(coded_size),
is_encrypted_(is_encrypted),
supports_swap_chain_(supports_swap_chain) {
SetUpDecoderDescriptor();
SetUpTextureDescriptor();
}
bool SupportsZeroCopy(const gpu::GpuPreferences& preferences,
......@@ -46,125 +36,94 @@ bool SupportsZeroCopy(const gpu::GpuPreferences& preferences,
std::unique_ptr<TextureSelector> TextureSelector::Create(
const gpu::GpuPreferences& gpu_preferences,
const gpu::GpuDriverBugWorkarounds& workarounds,
const VideoDecoderConfig& config,
DXGI_FORMAT decoder_output_format,
MediaLog* media_log) {
bool supports_nv12_decode_swap_chain =
gl::DirectCompositionSurfaceWin::IsDecodeSwapChainSupported();
bool needs_texture_copy = !SupportsZeroCopy(gpu_preferences, workarounds);
DXGI_FORMAT input_dxgi_format = DXGI_FORMAT_NV12;
DXGI_FORMAT output_dxgi_format = DXGI_FORMAT_NV12;
GUID decoder_guid = {};
if (config.codec() == kCodecH264) {
decoder_guid = D3D11_DECODER_PROFILE_H264_VLD_NOFGT;
} else if (config.profile() == VP9PROFILE_PROFILE0) {
decoder_guid = D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0;
} else if (config.profile() == VP9PROFILE_PROFILE2) {
decoder_guid = D3D11_DECODER_PROFILE_VP9_VLD_10BIT_PROFILE2;
input_dxgi_format = DXGI_FORMAT_P010;
output_dxgi_format = DXGI_FORMAT_R16_FLOAT;
needs_texture_copy = true;
} else {
// TODO(tmathmeyer) support other profiles in the future.
return nullptr;
VideoPixelFormat output_pixel_format;
DXGI_FORMAT output_dxgi_format;
// TODO(liberato): add other options here, like "copy to rgb" for NV12.
// However, those require a pbuffer TextureWrapper implementation.
switch (decoder_output_format) {
case DXGI_FORMAT_NV12:
MEDIA_LOG(INFO, media_log) << "D3D11VideoDecoder producing NV12";
output_pixel_format = PIXEL_FORMAT_NV12;
output_dxgi_format = DXGI_FORMAT_NV12;
break;
case DXGI_FORMAT_P010:
MEDIA_LOG(INFO, media_log) << "D3D11VideoDecoder producing FP16";
// Note: this combination isn't actually supported, since we don't support
// pbuffer textures right now.
output_pixel_format = PIXEL_FORMAT_ARGB;
output_dxgi_format = DXGI_FORMAT_R16G16B16A16_FLOAT;
// B8G8R8A8 is also an okay choice, if we don't have fp16 support.
needs_texture_copy = true;
break;
default:
// TODO(tmathmeyer) support other profiles in the future.
MEDIA_LOG(INFO, media_log)
<< "D3D11VideoDecoder does not support " << decoder_output_format;
return nullptr;
}
// Force texture copy on if requested for debugging.
if (base::FeatureList::IsEnabled(kD3D11VideoDecoderAlwaysCopy))
needs_texture_copy = true;
if ((input_dxgi_format != output_dxgi_format) || needs_texture_copy) {
if (needs_texture_copy) {
MEDIA_LOG(INFO, media_log) << "D3D11VideoDecoder is copying textures";
return std::make_unique<CopyTextureSelector>(
PIXEL_FORMAT_NV12, input_dxgi_format, output_dxgi_format, decoder_guid,
config.coded_size(), config.is_encrypted(),
output_pixel_format, decoder_output_format, output_dxgi_format,
supports_nv12_decode_swap_chain); // TODO(tmathmeyer) false always?
} else {
MEDIA_LOG(INFO, media_log) << "D3D11VideoDecoder is binding textures";
return std::make_unique<TextureSelector>(
PIXEL_FORMAT_NV12, output_dxgi_format, decoder_guid,
config.coded_size(), config.is_encrypted(),
supports_nv12_decode_swap_chain);
// We don't support anything except NV12 for binding right now. With
// pbuffer textures, we could support rgb8 and / or fp16.
DCHECK_EQ(output_pixel_format, PIXEL_FORMAT_NV12);
return std::make_unique<TextureSelector>(output_pixel_format,
supports_nv12_decode_swap_chain);
}
}
bool TextureSelector::SupportsDevice(
Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device) {
for (UINT i = video_device->GetVideoDecoderProfileCount(); i--;) {
GUID profile = {};
if (SUCCEEDED(video_device->GetVideoDecoderProfile(i, &profile))) {
if (profile == decoder_guid_)
return true;
}
}
return false;
}
ComD3D11Texture2D TextureSelector::CreateOutputTexture(ComD3D11Device device,
gfx::Size size) {
texture_desc_.Width = size.width();
texture_desc_.Height = size.height();
ComD3D11Texture2D result;
if (!SUCCEEDED(device->CreateTexture2D(&texture_desc_, nullptr, &result)))
return nullptr;
return result;
}
std::unique_ptr<Texture2DWrapper> TextureSelector::CreateTextureWrapper(
ComD3D11Device device,
ComD3D11VideoDevice video_device,
ComD3D11DeviceContext device_context,
ComD3D11Texture2D input_texture,
gfx::Size size) {
// TODO(liberato): If the output format is rgb, then create a pbuffer wrapper.
return std::make_unique<DefaultTexture2DWrapper>(input_texture);
}
// private
void TextureSelector::SetUpDecoderDescriptor() {
decoder_desc_ = {};
decoder_desc_.Guid = decoder_guid_;
decoder_desc_.SampleWidth = coded_size_.width();
decoder_desc_.SampleHeight = coded_size_.height();
decoder_desc_.OutputFormat = dxgi_format_;
}
// private
void TextureSelector::SetUpTextureDescriptor() {
texture_desc_ = {};
texture_desc_.MipLevels = 1;
texture_desc_.ArraySize = TextureSelector::BUFFER_COUNT;
texture_desc_.Format = dxgi_format_;
texture_desc_.SampleDesc.Count = 1;
texture_desc_.Usage = D3D11_USAGE_DEFAULT;
texture_desc_.BindFlags = D3D11_BIND_DECODER | D3D11_BIND_SHADER_RESOURCE;
// Decode swap chains do not support shared resources.
// TODO(sunnyps): Find a workaround for when the decoder moves to its own
// thread and D3D device. See https://crbug.com/911847
texture_desc_.MiscFlags =
supports_swap_chain_ ? 0 : D3D11_RESOURCE_MISC_SHARED;
if (is_encrypted_)
texture_desc_.MiscFlags |= D3D11_RESOURCE_MISC_HW_PROTECTED;
}
std::unique_ptr<Texture2DWrapper> CopyTextureSelector::CreateTextureWrapper(
ComD3D11Device device,
ComD3D11VideoDevice video_device,
ComD3D11DeviceContext device_context,
ComD3D11Texture2D input_texture,
gfx::Size size) {
// Change the texture descriptor flags to make different output textures
texture_desc_.BindFlags =
D3D11_TEXTURE2D_DESC texture_desc = {};
texture_desc.MipLevels = 1;
texture_desc.ArraySize = 1;
texture_desc.CPUAccessFlags = 0;
texture_desc.Format = output_dxgifmt_;
texture_desc.SampleDesc.Count = 1;
texture_desc.Usage = D3D11_USAGE_DEFAULT;
texture_desc.BindFlags =
D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
texture_desc_.ArraySize = 1;
texture_desc_.CPUAccessFlags = 0;
texture_desc_.Format = output_dxgifmt_;
ComD3D11Texture2D out_texture = CreateOutputTexture(device, size);
if (!out_texture)
// Decode swap chains do not support shared resources.
// TODO(sunnyps): Find a workaround for when the decoder moves to its own
// thread and D3D device. See https://crbug.com/911847
texture_desc.MiscFlags =
supports_swap_chain_ ? 0 : D3D11_RESOURCE_MISC_SHARED;
texture_desc.Width = size.width();
texture_desc.Height = size.height();
ComD3D11Texture2D out_texture;
if (!SUCCEEDED(device->CreateTexture2D(&texture_desc, nullptr, &out_texture)))
return nullptr;
return std::make_unique<CopyingTexture2DWrapper>(
......
......@@ -24,21 +24,15 @@ class MediaLog;
class MEDIA_GPU_EXPORT TextureSelector {
public:
TextureSelector(VideoPixelFormat pixfmt,
DXGI_FORMAT dxgifmt,
GUID decoder_guid,
gfx::Size coded_size,
bool is_encrypted,
bool supports_swap_chain);
virtual ~TextureSelector() = default;
static std::unique_ptr<TextureSelector> Create(
const gpu::GpuPreferences& gpu_preferences,
const gpu::GpuDriverBugWorkarounds& workarounds,
const VideoDecoderConfig& config,
DXGI_FORMAT decoder_output_format,
MediaLog* media_log);
bool SupportsDevice(Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device);
ComD3D11Texture2D CreateOutputTexture(ComD3D11Device device, gfx::Size size);
virtual std::unique_ptr<Texture2DWrapper> CreateTextureWrapper(
ComD3D11Device device,
ComD3D11VideoDevice video_device,
......@@ -46,43 +40,23 @@ class MEDIA_GPU_EXPORT TextureSelector {
ComD3D11Texture2D input_texture,
gfx::Size size);
const D3D11_VIDEO_DECODER_DESC* DecoderDescriptor() { return &decoder_desc_; }
const GUID DecoderGuid() { return decoder_guid_; }
VideoPixelFormat PixelFormat() { return pixel_format_; }
static constexpr size_t BUFFER_COUNT = 20;
private:
friend class CopyTextureSelector;
// Set up instances of the parameter structs for D3D11 Functions
void SetUpDecoderDescriptor();
void SetUpTextureDescriptor();
D3D11_TEXTURE2D_DESC texture_desc_;
D3D11_VIDEO_DECODER_DESC decoder_desc_;
const VideoPixelFormat pixel_format_;
const DXGI_FORMAT dxgi_format_;
const GUID decoder_guid_;
const gfx::Size coded_size_;
const bool is_encrypted_;
const bool supports_swap_chain_;
};
class MEDIA_GPU_EXPORT CopyTextureSelector : public TextureSelector {
public:
// TODO(liberato): do we need |input_dxgifmt| here?
CopyTextureSelector(VideoPixelFormat pixfmt,
DXGI_FORMAT input_dxgifmt,
DXGI_FORMAT output_dxgifmt,
GUID decoder_guid,
gfx::Size coded_size,
bool is_encrypted,
bool supports_swap_chain)
: TextureSelector(pixfmt,
input_dxgifmt,
decoder_guid,
coded_size,
is_encrypted,
supports_swap_chain),
output_dxgifmt_(output_dxgifmt) {}
......
......@@ -34,82 +34,30 @@ class D3D11TextureSelectorUnittest : public ::testing::Test {
}
std::unique_ptr<TextureSelector> CreateWithDefaultGPUInfo(
const VideoDecoderConfig& config,
DXGI_FORMAT decoder_output_format,
bool zero_copy_enabled = true) {
gpu::GpuPreferences prefs;
prefs.enable_zero_copy_dxgi_video = zero_copy_enabled;
gpu::GpuDriverBugWorkarounds workarounds;
workarounds.disable_dxgi_zero_copy_video = false;
auto media_log = std::make_unique<NullMediaLog>();
return TextureSelector::Create(prefs, workarounds, config, media_log.get());
return TextureSelector::Create(prefs, workarounds, decoder_output_format,
media_log.get());
}
};
TEST_F(D3D11TextureSelectorUnittest, VP9Profile0RightFormats) {
auto tex_sel = CreateWithDefaultGPUInfo(
CreateDecoderConfig(VP9PROFILE_PROFILE0, {0, 0}, false));
TEST_F(D3D11TextureSelectorUnittest, NV12BindsToNV12) {
auto tex_sel = CreateWithDefaultGPUInfo(DXGI_FORMAT_NV12);
EXPECT_EQ(tex_sel->DecoderGuid(), D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0);
// TODO(liberato): checl "binds", somehow.
EXPECT_EQ(tex_sel->PixelFormat(), PIXEL_FORMAT_NV12);
EXPECT_EQ(tex_sel->DecoderDescriptor()->OutputFormat, DXGI_FORMAT_NV12);
}
TEST_F(D3D11TextureSelectorUnittest, VP9Profile2RightFormats) {
auto tex_sel = CreateWithDefaultGPUInfo(
CreateDecoderConfig(VP9PROFILE_PROFILE2, {0, 0}, false), false);
TEST_F(D3D11TextureSelectorUnittest, P010CopiesToARGB) {
auto tex_sel = CreateWithDefaultGPUInfo(DXGI_FORMAT_P010);
EXPECT_EQ(tex_sel->DecoderGuid(),
D3D11_DECODER_PROFILE_VP9_VLD_10BIT_PROFILE2);
EXPECT_EQ(tex_sel->PixelFormat(), PIXEL_FORMAT_NV12);
EXPECT_EQ(tex_sel->DecoderDescriptor()->OutputFormat, DXGI_FORMAT_P010);
}
TEST_F(D3D11TextureSelectorUnittest, SupportsDeviceNoProfiles) {
auto tex_sel = CreateWithDefaultGPUInfo(
CreateDecoderConfig(VP9PROFILE_PROFILE0, {0, 0}, false));
auto vd_mock = CreateD3D11Mock<D3D11VideoDeviceMock>();
EXPECT_CALL(*vd_mock.Get(), GetVideoDecoderProfileCount())
.Times(1)
.WillOnce(Return(0));
EXPECT_FALSE(tex_sel->SupportsDevice(vd_mock));
}
TEST_F(D3D11TextureSelectorUnittest, SupportsDeviceWrongProfiles) {
auto tex_sel = CreateWithDefaultGPUInfo(
CreateDecoderConfig(VP9PROFILE_PROFILE0, {0, 0}, false));
auto vd_mock = CreateD3D11Mock<D3D11VideoDeviceMock>();
EXPECT_CALL(*vd_mock.Get(), GetVideoDecoderProfileCount())
.Times(1)
.WillOnce(Return(2));
EXPECT_CALL(*vd_mock.Get(), GetVideoDecoderProfile(0, _))
.Times(1)
.WillOnce(DoAll(SetArgPointee<1>(D3D11_DECODER_PROFILE_HEVC_VLD_MAIN),
Return(S_OK)));
EXPECT_CALL(*vd_mock.Get(), GetVideoDecoderProfile(1, _))
.Times(1)
.WillOnce(
DoAll(SetArgPointee<1>(D3D11_DECODER_PROFILE_VC1_VLD), Return(S_OK)));
EXPECT_FALSE(tex_sel->SupportsDevice(vd_mock));
}
TEST_F(D3D11TextureSelectorUnittest, SupportsDeviceCorrectProfile) {
auto tex_sel = CreateWithDefaultGPUInfo(
CreateDecoderConfig(VP9PROFILE_PROFILE0, {0, 0}, false));
auto vd_mock = CreateD3D11Mock<D3D11VideoDeviceMock>();
EXPECT_CALL(*vd_mock.Get(), GetVideoDecoderProfileCount())
.Times(1)
.WillOnce(Return(5));
EXPECT_CALL(*vd_mock.Get(), GetVideoDecoderProfile(4, _))
.Times(1)
.WillOnce(DoAll(SetArgPointee<1>(D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0),
Return(S_OK)));
EXPECT_TRUE(tex_sel->SupportsDevice(vd_mock));
// TODO(liberato): check "copies", somehow.
EXPECT_EQ(tex_sel->PixelFormat(), PIXEL_FORMAT_ARGB);
}
} // namespace media
......@@ -265,18 +265,26 @@ void D3D11VideoDecoder::Initialize(const VideoDecoderConfig& config,
return;
}
texture_selector_ = TextureSelector::Create(
decoder_configurator_ = D3D11DecoderConfigurator::Create(
gpu_preferences_, gpu_workarounds_, config, media_log_.get());
if (!texture_selector_) {
if (!decoder_configurator_) {
NotifyError("D3DD11: Config provided unsupported profile");
return;
}
if (!texture_selector_->SupportsDevice(video_device_)) {
if (!decoder_configurator_->SupportsDevice(video_device_)) {
NotifyError("D3D11: Device does not support decoder GUID");
return;
}
texture_selector_ = TextureSelector::Create(
gpu_preferences_, gpu_workarounds_,
decoder_configurator_->TextureFormat(), media_log_.get());
if (!texture_selector_) {
NotifyError("D3DD11: Cannot get TextureSelector for format");
return;
}
// TODO(liberato): dxva does this. don't know if we need to.
if (!base::FeatureList::IsEnabled(kD3D11VideoDecoderSkipMultithreaded)) {
ComD3D11Multithread multi_threaded;
......@@ -293,7 +301,7 @@ void D3D11VideoDecoder::Initialize(const VideoDecoderConfig& config,
UINT config_count = 0;
hr = video_device_->GetVideoDecoderConfigCount(
texture_selector_->DecoderDescriptor(), &config_count);
decoder_configurator_->DecoderDescriptor(), &config_count);
if (FAILED(hr) || config_count == 0) {
NotifyError("Failed to get video decoder config count");
return;
......@@ -304,7 +312,7 @@ void D3D11VideoDecoder::Initialize(const VideoDecoderConfig& config,
for (UINT i = 0; i < config_count; i++) {
hr = video_device_->GetVideoDecoderConfig(
texture_selector_->DecoderDescriptor(), i, &dec_config);
decoder_configurator_->DecoderDescriptor(), i, &dec_config);
if (FAILED(hr)) {
NotifyError("Failed to get decoder config");
return;
......@@ -334,8 +342,8 @@ void D3D11VideoDecoder::Initialize(const VideoDecoderConfig& config,
}
Microsoft::WRL::ComPtr<ID3D11VideoDecoder> video_decoder;
hr = video_device_->CreateVideoDecoder(texture_selector_->DecoderDescriptor(),
&dec_config, &video_decoder);
hr = video_device_->CreateVideoDecoder(
decoder_configurator_->DecoderDescriptor(), &dec_config, &video_decoder);
if (!video_decoder.Get()) {
NotifyError("Failed to create a video decoder");
return;
......@@ -647,12 +655,13 @@ void D3D11VideoDecoder::CreatePictureBuffers() {
// thread work.
TRACE_EVENT0("gpu", "D3D11VideoDecoder::CreatePictureBuffers");
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(decoder_configurator_);
DCHECK(texture_selector_);
gfx::Size size = accelerated_video_decoder_->GetPicSize();
// Create an input texture array.
ComD3D11Texture2D in_texture =
texture_selector_->CreateOutputTexture(device_, size);
decoder_configurator_->CreateOutputTexture(device_, size);
if (!in_texture) {
NotifyError("Failed to create a Texture2D for PictureBuffers");
return;
......@@ -664,7 +673,7 @@ void D3D11VideoDecoder::CreatePictureBuffers() {
picture_buffers_.clear();
// Create each picture buffer.
for (size_t i = 0; i < TextureSelector::BUFFER_COUNT; i++) {
for (size_t i = 0; i < D3D11DecoderConfigurator::BUFFER_COUNT; i++) {
auto tex_wrapper = texture_selector_->CreateTextureWrapper(
device_, video_device_, device_context_, in_texture, size);
if (!tex_wrapper) {
......@@ -675,7 +684,7 @@ void D3D11VideoDecoder::CreatePictureBuffers() {
picture_buffers_.push_back(
new D3D11PictureBuffer(std::move(tex_wrapper), size, i));
if (!picture_buffers_[i]->Init(get_helper_cb_, video_device_,
texture_selector_->DecoderGuid(),
decoder_configurator_->DecoderGuid(),
media_log_->Clone())) {
NotifyError("Unable to allocate PictureBuffer");
return;
......
......@@ -23,6 +23,7 @@
#include "media/gpu/command_buffer_helper.h"
#include "media/gpu/media_gpu_export.h"
#include "media/gpu/windows/d3d11_com_defs.h"
#include "media/gpu/windows/d3d11_decoder_configurator.h"
#include "media/gpu/windows/d3d11_h264_accelerator.h"
#include "media/gpu/windows/d3d11_texture_selector.h"
#include "media/gpu/windows/d3d11_video_decoder_client.h"
......@@ -254,6 +255,8 @@ class MEDIA_GPU_EXPORT D3D11VideoDecoder : public VideoDecoder,
std::unique_ptr<AcceleratedVideoDecoder> accelerated_video_decoder_;
std::unique_ptr<D3D11DecoderConfigurator> decoder_configurator_;
std::unique_ptr<TextureSelector> texture_selector_;
std::list<std::pair<scoped_refptr<DecoderBuffer>, DecodeCB>>
......
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