1 /*****************************************************************************
2 * d3d11_fmt.c : D3D11 helper calls
3 *****************************************************************************
4 * Copyright © 2017 VLC authors, VideoLAN and VideoLabs
6 * Authors: Steve Lhomme <robux4@gmail.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
27 #include <vlc_common.h>
28 #include <vlc_picture.h>
34 #include "d3d11_fmt.h"
36 #include "../codec/avcodec/va_surface.h"
38 picture_sys_t
*ActivePictureSys(picture_t
*p_pic
)
40 struct va_pic_context
*pic_ctx
= (struct va_pic_context
*)p_pic
->context
;
41 return pic_ctx
? &pic_ctx
->picsys
: p_pic
->p_sys
;
44 void AcquirePictureSys(picture_sys_t
*p_sys
)
46 for (int i
=0; i
<D3D11_MAX_SHADER_VIEW
; i
++) {
47 if (p_sys
->resourceView
[i
])
48 ID3D11ShaderResourceView_AddRef(p_sys
->resourceView
[i
]);
49 if (p_sys
->texture
[i
])
50 ID3D11Texture2D_AddRef(p_sys
->texture
[i
]);
53 ID3D11DeviceContext_AddRef(p_sys
->context
);
55 ID3D11VideoDecoderOutputView_AddRef(p_sys
->decoder
);
56 if (p_sys
->processorInput
)
57 ID3D11VideoProcessorInputView_AddRef(p_sys
->processorInput
);
58 if (p_sys
->processorOutput
)
59 ID3D11VideoProcessorOutputView_AddRef(p_sys
->processorOutput
);
62 void ReleasePictureSys(picture_sys_t
*p_sys
)
64 for (int i
=0; i
<D3D11_MAX_SHADER_VIEW
; i
++) {
65 if (p_sys
->resourceView
[i
])
66 ID3D11ShaderResourceView_Release(p_sys
->resourceView
[i
]);
67 if (p_sys
->texture
[i
])
68 ID3D11Texture2D_Release(p_sys
->texture
[i
]);
71 ID3D11DeviceContext_Release(p_sys
->context
);
73 ID3D11VideoDecoderOutputView_Release(p_sys
->decoder
);
74 if (p_sys
->processorInput
)
75 ID3D11VideoProcessorInputView_Release(p_sys
->processorInput
);
76 if (p_sys
->processorOutput
)
77 ID3D11VideoProcessorOutputView_Release(p_sys
->processorOutput
);
80 /* map texture planes to resource views */
81 int AllocateShaderView(vlc_object_t
*obj
, ID3D11Device
*d3ddevice
,
82 const d3d_format_t
*format
,
83 ID3D11Texture2D
*p_texture
[D3D11_MAX_SHADER_VIEW
], UINT slice_index
,
84 ID3D11ShaderResourceView
*resourceView
[D3D11_MAX_SHADER_VIEW
])
88 D3D11_SHADER_RESOURCE_VIEW_DESC resviewDesc
= { 0 };
89 D3D11_TEXTURE2D_DESC texDesc
;
90 ID3D11Texture2D_GetDesc(p_texture
[0], &texDesc
);
91 assert(texDesc
.BindFlags
& D3D11_BIND_SHADER_RESOURCE
);
93 if (texDesc
.ArraySize
== 1)
95 resviewDesc
.ViewDimension
= D3D11_SRV_DIMENSION_TEXTURE2D
;
96 resviewDesc
.Texture2D
.MipLevels
= 1;
100 resviewDesc
.ViewDimension
= D3D11_SRV_DIMENSION_TEXTURE2DARRAY
;
101 resviewDesc
.Texture2DArray
.MipLevels
= -1;
102 resviewDesc
.Texture2DArray
.ArraySize
= 1;
103 resviewDesc
.Texture2DArray
.FirstArraySlice
= slice_index
;
105 for (i
=0; i
<D3D11_MAX_SHADER_VIEW
; i
++)
107 resviewDesc
.Format
= format
->resourceFormat
[i
];
108 if (resviewDesc
.Format
== DXGI_FORMAT_UNKNOWN
)
109 resourceView
[i
] = NULL
;
112 hr
= ID3D11Device_CreateShaderResourceView(d3ddevice
, (ID3D11Resource
*)p_texture
[i
], &resviewDesc
, &resourceView
[i
]);
114 msg_Err(obj
, "Could not Create the Texture ResourceView %d slice %d. (hr=0x%lX)", i
, slice_index
, hr
);
120 if (i
!= D3D11_MAX_SHADER_VIEW
)
124 ID3D11ShaderResourceView_Release(resourceView
[i
]);
125 resourceView
[i
] = NULL
;
133 HRESULT
D3D11_CreateDevice(vlc_object_t
*obj
, HINSTANCE hdecoder_dll
,
135 d3d11_handle_t
*p_hd3d11
)
137 #if !VLC_WINSTORE_APP
138 # define D3D11CreateDevice(args...) pf_CreateDevice(args)
140 PFN_D3D11_CREATE_DEVICE pf_CreateDevice
;
141 pf_CreateDevice
= (void *)GetProcAddress(hdecoder_dll
, "D3D11CreateDevice");
142 if (!pf_CreateDevice
) {
143 msg_Err(obj
, "Cannot locate reference to D3D11CreateDevice ABI in DLL");
144 return E_NOINTERFACE
;
148 HRESULT hr
= E_NOTIMPL
;
149 UINT creationFlags
= 0;
152 creationFlags
|= D3D11_CREATE_DEVICE_VIDEO_SUPPORT
;
155 # if !VLC_WINSTORE_APP
156 if (IsDebuggerPresent())
159 HINSTANCE sdklayer_dll
= LoadLibrary(TEXT("d3d11_1sdklayers.dll"));
161 creationFlags
|= D3D11_CREATE_DEVICE_DEBUG
;
162 FreeLibrary(sdklayer_dll
);
167 static const D3D_DRIVER_TYPE driverAttempts
[] = {
168 D3D_DRIVER_TYPE_HARDWARE
,
169 #if 0 /* ifndef NDEBUG */
170 D3D_DRIVER_TYPE_REFERENCE
,
174 static D3D_FEATURE_LEVEL D3D11_features
[] = {
175 D3D_FEATURE_LEVEL_11_1
, D3D_FEATURE_LEVEL_11_0
,
176 D3D_FEATURE_LEVEL_10_1
, D3D_FEATURE_LEVEL_10_0
,
177 D3D_FEATURE_LEVEL_9_3
, D3D_FEATURE_LEVEL_9_2
, D3D_FEATURE_LEVEL_9_1
180 for (UINT driver
= 0; driver
< ARRAY_SIZE(driverAttempts
); driver
++) {
181 D3D_FEATURE_LEVEL i_feature_level
;
182 hr
= D3D11CreateDevice(NULL
, driverAttempts
[driver
], NULL
, creationFlags
,
183 D3D11_features
, ARRAY_SIZE(D3D11_features
), D3D11_SDK_VERSION
,
184 &p_hd3d11
->d3ddevice
, &i_feature_level
, &p_hd3d11
->d3dcontext
);
187 msg_Dbg(obj
, "Created the D3D11 device 0x%p ctx 0x%p type %d level %x.",
188 (void *)p_hd3d11
->d3ddevice
, (void *)p_hd3d11
->d3dcontext
,
189 driverAttempts
[driver
], i_feature_level
);
191 /* we can work with legacy levels but only if forced */
192 if ( obj
->obj
.force
|| i_feature_level
>= D3D_FEATURE_LEVEL_11_0
)
194 msg_Dbg(obj
, "Incompatible feature level %x", i_feature_level
);
195 ID3D11DeviceContext_Release(p_hd3d11
->d3dcontext
);
196 ID3D11Device_Release(p_hd3d11
->d3ddevice
);
197 p_hd3d11
->d3dcontext
= NULL
;
198 p_hd3d11
->d3ddevice
= NULL
;
205 IDXGIAdapter
*D3D11DeviceAdapter(ID3D11Device
*d3ddev
)
207 IDXGIDevice
*pDXGIDevice
= NULL
;
208 HRESULT hr
= ID3D11Device_QueryInterface(d3ddev
, &IID_IDXGIDevice
, (void **)&pDXGIDevice
);
213 IDXGIAdapter
*p_adapter
;
214 hr
= IDXGIDevice_GetAdapter(pDXGIDevice
, &p_adapter
);
215 IDXGIDevice_Release(pDXGIDevice
);
222 bool isXboxHardware(ID3D11Device
*d3ddev
)
224 IDXGIAdapter
*p_adapter
= D3D11DeviceAdapter(d3ddev
);
229 DXGI_ADAPTER_DESC adapterDesc
;
230 if (SUCCEEDED(IDXGIAdapter_GetDesc(p_adapter
, &adapterDesc
))) {
231 if (adapterDesc
.VendorId
== 0 &&
232 adapterDesc
.DeviceId
== 0 &&
233 !wcscmp(L
"ROOT\\SraKmd\\0000", adapterDesc
.Description
))
237 IDXGIAdapter_Release(p_adapter
);
241 bool isNvidiaHardware(ID3D11Device
*d3ddev
)
243 IDXGIAdapter
*p_adapter
= D3D11DeviceAdapter(d3ddev
);
248 DXGI_ADAPTER_DESC adapterDesc
;
249 if (SUCCEEDED(IDXGIAdapter_GetDesc(p_adapter
, &adapterDesc
))) {
250 result
= adapterDesc
.VendorId
== 0x10DE;
253 IDXGIAdapter_Release(p_adapter
);
257 const d3d_format_t
*FindD3D11Format(ID3D11Device
*d3ddevice
,
258 vlc_fourcc_t i_src_chroma
,
259 uint8_t bits_per_channel
,
263 supportFlags
|= D3D11_FORMAT_SUPPORT_TEXTURE2D
;
264 for (const d3d_format_t
*output_format
= GetRenderFormatList();
265 output_format
->name
!= NULL
; ++output_format
)
267 if (i_src_chroma
&& i_src_chroma
!= output_format
->fourcc
)
269 if (bits_per_channel
&& bits_per_channel
> output_format
->bitsPerChannel
)
271 if (!allow_opaque
&& (output_format
->fourcc
== VLC_CODEC_D3D11_OPAQUE
||
272 output_format
->fourcc
== VLC_CODEC_D3D11_OPAQUE_10B
))
275 DXGI_FORMAT textureFormat
;
276 if (output_format
->formatTexture
== DXGI_FORMAT_UNKNOWN
)
277 textureFormat
= output_format
->resourceFormat
[0];
279 textureFormat
= output_format
->formatTexture
;
281 if( DeviceSupportsFormat( d3ddevice
, textureFormat
, supportFlags
) )
282 return output_format
;
287 int AllocateTextures( vlc_object_t
*obj
, d3d11_handle_t
*hd3d11
,
288 const d3d_format_t
*cfg
, const video_format_t
*fmt
,
289 unsigned pool_size
, ID3D11Texture2D
*textures
[] )
291 plane_t planes
[PICTURE_PLANE_MAX
];
292 int plane
, plane_count
;
294 ID3D11Texture2D
*slicedTexture
= NULL
;
295 D3D11_TEXTURE2D_DESC texDesc
;
296 ZeroMemory(&texDesc
, sizeof(texDesc
));
297 texDesc
.MipLevels
= 1;
298 texDesc
.SampleDesc
.Count
= 1;
299 texDesc
.MiscFlags
= 0; //D3D11_RESOURCE_MISC_SHARED;
300 texDesc
.BindFlags
= D3D11_BIND_SHADER_RESOURCE
;
301 if (is_d3d11_opaque(fmt
->i_chroma
)) {
302 texDesc
.BindFlags
|= D3D11_BIND_DECODER
;
303 texDesc
.Usage
= D3D11_USAGE_DEFAULT
;
304 texDesc
.CPUAccessFlags
= 0;
306 texDesc
.Usage
= D3D11_USAGE_DYNAMIC
;
307 texDesc
.CPUAccessFlags
= D3D11_CPU_ACCESS_WRITE
;
309 texDesc
.ArraySize
= pool_size
;
311 const vlc_chroma_description_t
*p_chroma_desc
= vlc_fourcc_GetChromaDescription( fmt
->i_chroma
);
315 if (cfg
->formatTexture
== DXGI_FORMAT_UNKNOWN
) {
316 if (p_chroma_desc
->plane_count
== 0)
318 msg_Dbg(obj
, "failed to get the pixel format planes for %4.4s", (char *)&fmt
->i_chroma
);
321 assert(p_chroma_desc
->plane_count
<= D3D11_MAX_SHADER_VIEW
);
322 plane_count
= p_chroma_desc
->plane_count
;
324 texDesc
.Format
= cfg
->resourceFormat
[0];
325 assert(cfg
->resourceFormat
[1] == cfg
->resourceFormat
[0]);
326 assert(cfg
->resourceFormat
[2] == cfg
->resourceFormat
[0]);
328 for( int i
= 0; i
< plane_count
; i
++ )
330 plane_t
*p
= &planes
[i
];
332 p
->i_lines
= fmt
->i_height
* p_chroma_desc
->p
[i
].h
.num
/ p_chroma_desc
->p
[i
].h
.den
;
333 p
->i_visible_lines
= fmt
->i_visible_height
* p_chroma_desc
->p
[i
].h
.num
/ p_chroma_desc
->p
[i
].h
.den
;
334 p
->i_pitch
= fmt
->i_width
* p_chroma_desc
->p
[i
].w
.num
/ p_chroma_desc
->p
[i
].w
.den
* p_chroma_desc
->pixel_size
;
335 p
->i_visible_pitch
= fmt
->i_visible_width
* p_chroma_desc
->p
[i
].w
.num
/ p_chroma_desc
->p
[i
].w
.den
* p_chroma_desc
->pixel_size
;
336 p
->i_pixel_pitch
= p_chroma_desc
->pixel_size
;
340 texDesc
.Format
= cfg
->formatTexture
;
341 texDesc
.Height
= fmt
->i_height
;
342 texDesc
.Width
= fmt
->i_width
;
344 hr
= ID3D11Device_CreateTexture2D( hd3d11
->d3ddevice
, &texDesc
, NULL
, &slicedTexture
);
346 msg_Err(obj
, "CreateTexture2D failed for the %d pool. (hr=0x%0lx)", pool_size
, hr
);
351 for (unsigned picture_count
= 0; picture_count
< pool_size
; picture_count
++) {
352 for (plane
= 0; plane
< plane_count
; plane
++)
355 textures
[picture_count
* D3D11_MAX_SHADER_VIEW
+ plane
] = slicedTexture
;
356 ID3D11Texture2D_AddRef(slicedTexture
);
358 texDesc
.Height
= planes
[plane
].i_lines
;
359 texDesc
.Width
= planes
[plane
].i_pitch
;
360 hr
= ID3D11Device_CreateTexture2D( hd3d11
->d3ddevice
, &texDesc
, NULL
, &textures
[picture_count
* D3D11_MAX_SHADER_VIEW
+ plane
] );
362 msg_Err(obj
, "CreateTexture2D failed for the %d pool. (hr=0x%0lx)", pool_size
, hr
);
367 for (; plane
< D3D11_MAX_SHADER_VIEW
; plane
++) {
368 if (!cfg
->resourceFormat
[plane
])
369 textures
[picture_count
* D3D11_MAX_SHADER_VIEW
+ plane
] = NULL
;
372 textures
[picture_count
* D3D11_MAX_SHADER_VIEW
+ plane
] = textures
[picture_count
* D3D11_MAX_SHADER_VIEW
];
373 ID3D11Texture2D_AddRef(textures
[picture_count
* D3D11_MAX_SHADER_VIEW
+ plane
]);
378 if (!is_d3d11_opaque(fmt
->i_chroma
) && cfg
->formatTexture
!= DXGI_FORMAT_UNKNOWN
) {
379 D3D11_MAPPED_SUBRESOURCE mappedResource
;
380 hr
= ID3D11DeviceContext_Map(hd3d11
->d3dcontext
, (ID3D11Resource
*)textures
[0], 0, D3D11_MAP_WRITE_DISCARD
, 0, &mappedResource
);
382 msg_Err(obj
, "The texture cannot be mapped. (hr=0x%lX)", hr
);
385 ID3D11DeviceContext_Unmap(hd3d11
->d3dcontext
, (ID3D11Resource
*)textures
[0], 0);
386 if (mappedResource
.RowPitch
< p_chroma_desc
->pixel_size
* texDesc
.Width
) {
387 msg_Err( obj
, "The texture row pitch is too small (%d instead of %d)", mappedResource
.RowPitch
,
388 p_chroma_desc
->pixel_size
* texDesc
.Width
);
394 ID3D11Texture2D_Release(slicedTexture
);
398 ID3D11Texture2D_Release(slicedTexture
);