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