blob: 2644f13272ed2eaf2cf3898633cd2370f25005d5 [file] [log] [blame]
// 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 <d3d9.h>
#include <dxva2api.h>
#include "base/feature_list.h"
#include "media/base/media_log.h"
#include "media/base/media_switches.h"
#include "media/base/status_codes.h"
#include "media/base/win/hresult_status_helper.h"
#include "media/base/win/mf_helpers.h"
#include "media/gpu/windows/av1_guids.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),
supports_swap_chain_(supports_swap_chain),
is_encrypted_(is_encrypted) {
SetUpDecoderDescriptor(coded_size);
SetUpTextureDescriptor();
}
// static
std::unique_ptr<D3D11DecoderConfigurator> D3D11DecoderConfigurator::Create(
const gpu::GpuPreferences& gpu_preferences,
const gpu::GpuDriverBugWorkarounds& workarounds,
const VideoDecoderConfig& config,
uint8_t bit_depth,
MediaLog* media_log,
bool use_shared_handle) {
// Decoder swap chains do not support shared resources. More info in
// https://crbug.com/911847. To enable Kaby Lake+ systems for using shared
// handle, we disable decode swap chain support if shared handle is enabled.
const bool supports_nv12_decode_swap_chain =
gl::DirectCompositionSurfaceWin::IsDecodeSwapChainSupported() &&
!use_shared_handle;
const auto decoder_dxgi_format =
bit_depth == 8 ? DXGI_FORMAT_NV12 : DXGI_FORMAT_P010;
GUID decoder_guid = {};
if (config.codec() == VideoCodec::kH264) {
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;
} else if (config.profile() == AV1PROFILE_PROFILE_MAIN) {
decoder_guid = DXVA_ModeAV1_VLD_Profile0;
} else if (config.profile() == AV1PROFILE_PROFILE_HIGH) {
decoder_guid = DXVA_ModeAV1_VLD_Profile1;
} else if (config.profile() == AV1PROFILE_PROFILE_PRO) {
decoder_guid = DXVA_ModeAV1_VLD_Profile2;
} else {
MEDIA_LOG(INFO, media_log)
<< "D3D11VideoDecoder does not support codec " << config.codec();
return nullptr;
}
MEDIA_LOG(INFO, media_log)
<< "D3D11VideoDecoder is using " << GetProfileName(config.profile())
<< " / " << (decoder_dxgi_format == DXGI_FORMAT_NV12 ? "NV12" : "P010");
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;
}
StatusOr<ComD3D11Texture2D> D3D11DecoderConfigurator::CreateOutputTexture(
ComD3D11Device device,
gfx::Size size,
uint32_t array_size,
bool use_shared_handle) {
output_texture_desc_.Width = size.width();
output_texture_desc_.Height = size.height();
output_texture_desc_.ArraySize = array_size;
if (use_shared_handle) {
// Update the decoder output texture usage to support shared handle and
// keyed_mutex if required. SwapChain should be disabled and the frame
// shouldn't be encrypted.
DCHECK(!supports_swap_chain_);
DCHECK(!is_encrypted_);
output_texture_desc_.MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE |
D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
} else if (supports_swap_chain_) {
// 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. We should unset the flag only if it's binding and the
// decode swap chain is supported, as Intel driver is buggy on Gen9 and
// older devices without the flag. See https://crbug.com/1107403
output_texture_desc_.MiscFlags = 0;
} else {
// Create non-shareable texture for d3d11 video decoder.
output_texture_desc_.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
}
if (is_encrypted_)
output_texture_desc_.MiscFlags |= D3D11_RESOURCE_MISC_HW_PROTECTED;
ComD3D11Texture2D texture;
HRESULT hr =
device->CreateTexture2D(&output_texture_desc_, nullptr, &texture);
if (FAILED(hr)) {
return Status(StatusCode::kCreateDecoderOutputTextureFailed)
.AddCause(HresultToStatus(hr));
}
hr = SetDebugName(texture.Get(), "D3D11Decoder_ConfiguratorOutput");
if (FAILED(hr)) {
return Status(StatusCode::kCreateDecoderOutputTextureFailed)
.AddCause(HresultToStatus(hr));
}
return texture;
}
// 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() {
output_texture_desc_ = {};
output_texture_desc_.MipLevels = 1;
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;
}
} // namespace media