1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/gpu/windows/d3d11_decoder_configurator.h"
6
7 #include <d3d11.h>
8
9 #include "base/feature_list.h"
10 #include "media/base/media_log.h"
11 #include "media/base/media_switches.h"
12 #include "media/base/status_codes.h"
13 #include "media/base/win/hresult_status_helper.h"
14 #include "media/gpu/windows/d3d11_copying_texture_wrapper.h"
15 #include "ui/gfx/geometry/size.h"
16 #include "ui/gl/direct_composition_surface_win.h"
17
18 namespace media {
19
D3D11DecoderConfigurator(DXGI_FORMAT decoder_output_dxgifmt,GUID decoder_guid,gfx::Size coded_size,bool is_encrypted,bool supports_swap_chain)20 D3D11DecoderConfigurator::D3D11DecoderConfigurator(
21 DXGI_FORMAT decoder_output_dxgifmt,
22 GUID decoder_guid,
23 gfx::Size coded_size,
24 bool is_encrypted,
25 bool supports_swap_chain)
26 : dxgi_format_(decoder_output_dxgifmt), decoder_guid_(decoder_guid) {
27 SetUpDecoderDescriptor(coded_size);
28 SetUpTextureDescriptor(supports_swap_chain, is_encrypted);
29 }
30
31 // static
Create(const gpu::GpuPreferences & gpu_preferences,const gpu::GpuDriverBugWorkarounds & workarounds,const VideoDecoderConfig & config,MediaLog * media_log)32 std::unique_ptr<D3D11DecoderConfigurator> D3D11DecoderConfigurator::Create(
33 const gpu::GpuPreferences& gpu_preferences,
34 const gpu::GpuDriverBugWorkarounds& workarounds,
35 const VideoDecoderConfig& config,
36 MediaLog* media_log) {
37 bool supports_nv12_decode_swap_chain =
38 gl::DirectCompositionSurfaceWin::IsDecodeSwapChainSupported();
39
40 DXGI_FORMAT decoder_dxgi_format = DXGI_FORMAT_NV12;
41 GUID decoder_guid = {};
42 if (config.codec() == kCodecH264) {
43 MEDIA_LOG(INFO, media_log) << "D3D11VideoDecoder is using h264 / NV12";
44 decoder_guid = D3D11_DECODER_PROFILE_H264_VLD_NOFGT;
45 } else if (config.profile() == VP9PROFILE_PROFILE0) {
46 MEDIA_LOG(INFO, media_log) << "D3D11VideoDecoder is using vp9p0 / NV12";
47 decoder_guid = D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0;
48 } else if (config.profile() == VP9PROFILE_PROFILE2) {
49 MEDIA_LOG(INFO, media_log) << "D3D11VideoDecoder is using vp9p2 / P010";
50 decoder_guid = D3D11_DECODER_PROFILE_VP9_VLD_10BIT_PROFILE2;
51 decoder_dxgi_format = DXGI_FORMAT_P010;
52 } else {
53 // TODO(tmathmeyer) support other profiles in the future.
54 MEDIA_LOG(INFO, media_log)
55 << "D3D11VideoDecoder does not support codec " << config.codec();
56 return nullptr;
57 }
58
59 return std::make_unique<D3D11DecoderConfigurator>(
60 decoder_dxgi_format, decoder_guid, config.coded_size(),
61 config.is_encrypted(), supports_nv12_decode_swap_chain);
62 }
63
SupportsDevice(ComD3D11VideoDevice video_device)64 bool D3D11DecoderConfigurator::SupportsDevice(
65 ComD3D11VideoDevice video_device) {
66 for (UINT i = video_device->GetVideoDecoderProfileCount(); i--;) {
67 GUID profile = {};
68 if (SUCCEEDED(video_device->GetVideoDecoderProfile(i, &profile))) {
69 if (profile == decoder_guid_)
70 return true;
71 }
72 }
73 return false;
74 }
75
CreateOutputTexture(ComD3D11Device device,gfx::Size size,uint32_t array_size)76 StatusOr<ComD3D11Texture2D> D3D11DecoderConfigurator::CreateOutputTexture(
77 ComD3D11Device device,
78 gfx::Size size,
79 uint32_t array_size) {
80 output_texture_desc_.Width = size.width();
81 output_texture_desc_.Height = size.height();
82 output_texture_desc_.ArraySize = array_size;
83
84 ComD3D11Texture2D texture;
85 HRESULT hr =
86 device->CreateTexture2D(&output_texture_desc_, nullptr, &texture);
87 if (!SUCCEEDED(hr)) {
88 return Status(StatusCode::kCreateDecoderOutputTextureFailed)
89 .AddCause(HresultToStatus(hr));
90 }
91
92 return texture;
93 }
94
95 // private
SetUpDecoderDescriptor(const gfx::Size & coded_size)96 void D3D11DecoderConfigurator::SetUpDecoderDescriptor(
97 const gfx::Size& coded_size) {
98 decoder_desc_ = {};
99 decoder_desc_.Guid = decoder_guid_;
100 decoder_desc_.SampleWidth = coded_size.width();
101 decoder_desc_.SampleHeight = coded_size.height();
102 decoder_desc_.OutputFormat = dxgi_format_;
103 }
104
105 // private
SetUpTextureDescriptor(bool supports_swap_chain,bool is_encrypted)106 void D3D11DecoderConfigurator::SetUpTextureDescriptor(bool supports_swap_chain,
107 bool is_encrypted) {
108 output_texture_desc_ = {};
109 output_texture_desc_.MipLevels = 1;
110 output_texture_desc_.Format = dxgi_format_;
111 output_texture_desc_.SampleDesc.Count = 1;
112 output_texture_desc_.Usage = D3D11_USAGE_DEFAULT;
113 output_texture_desc_.BindFlags =
114 D3D11_BIND_DECODER | D3D11_BIND_SHADER_RESOURCE;
115
116 // Decode swap chains do not support shared resources.
117 // TODO(sunnyps): Find a workaround for when the decoder moves to its own
118 // thread and D3D device. See https://crbug.com/911847
119 // TODO(liberato): This depends on the configuration of the TextureSelector,
120 // to some degree. We should unset the flag only if it's binding and the
121 // decode swap chain is supported, as Intel driver is buggy on Gen9 and older
122 // devices without the flag. See https://crbug.com/1107403
123 output_texture_desc_.MiscFlags =
124 supports_swap_chain ? 0 : D3D11_RESOURCE_MISC_SHARED;
125
126 if (is_encrypted)
127 output_texture_desc_.MiscFlags |= D3D11_RESOURCE_MISC_HW_PROTECTED;
128 }
129
130 } // namespace media
131