direct3d11: move is_d3d11_opaque() and AllocateTextures() in d3d11_fmt
[vlc.git] / modules / video_chroma / d3d11_fmt.c
blobe3b5e4e0cd8c2c220c648643e305e19bc0b05276
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 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 #include <vlc_common.h>
28 #include <vlc_picture.h>
30 #define COBJMACROS
31 #include <d3d11.h>
32 #include <assert.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]);
52 if (p_sys->context)
53 ID3D11DeviceContext_AddRef(p_sys->context);
54 if (p_sys->decoder)
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]);
70 if (p_sys->context)
71 ID3D11DeviceContext_Release(p_sys->context);
72 if (p_sys->decoder)
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])
86 HRESULT hr;
87 int i;
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;
98 else
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;
110 else
112 hr = ID3D11Device_CreateShaderResourceView(d3ddevice, (ID3D11Resource*)p_texture[i], &resviewDesc, &resourceView[i]);
113 if (FAILED(hr)) {
114 msg_Err(obj, "Could not Create the Texture ResourceView %d slice %d. (hr=0x%lX)", i, slice_index, hr);
115 break;
120 if (i != D3D11_MAX_SHADER_VIEW)
122 while (--i >= 0)
124 ID3D11ShaderResourceView_Release(resourceView[i]);
125 resourceView[i] = NULL;
127 return VLC_EGENERIC;
130 return VLC_SUCCESS;
133 HRESULT D3D11_CreateDevice(vlc_object_t *obj, HINSTANCE hdecoder_dll,
134 bool hw_decoding,
135 d3d11_handle_t *p_hd3d11)
137 #if !VLC_WINSTORE_APP
138 # define D3D11CreateDevice(args...) pf_CreateDevice(args)
139 /* */
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;
146 #endif
148 HRESULT hr = E_NOTIMPL;
149 UINT creationFlags = 0;
151 if (hw_decoding)
152 creationFlags |= D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
154 #if !defined(NDEBUG)
155 # if !VLC_WINSTORE_APP
156 if (IsDebuggerPresent())
157 # endif
159 HINSTANCE sdklayer_dll = LoadLibrary(TEXT("d3d11_1sdklayers.dll"));
160 if (sdklayer_dll) {
161 creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
162 FreeLibrary(sdklayer_dll);
165 #endif
167 static const D3D_DRIVER_TYPE driverAttempts[] = {
168 D3D_DRIVER_TYPE_HARDWARE,
169 #if 0 /* ifndef NDEBUG */
170 D3D_DRIVER_TYPE_REFERENCE,
171 #endif
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);
185 if (SUCCEEDED(hr)) {
186 #ifndef NDEBUG
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);
190 #endif
191 /* we can work with legacy levels but only if forced */
192 if ( obj->obj.force || i_feature_level >= D3D_FEATURE_LEVEL_11_0 )
193 break;
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;
199 hr = E_NOTIMPL;
202 return hr;
205 IDXGIAdapter *D3D11DeviceAdapter(ID3D11Device *d3ddev)
207 IDXGIDevice *pDXGIDevice = NULL;
208 HRESULT hr = ID3D11Device_QueryInterface(d3ddev, &IID_IDXGIDevice, (void **)&pDXGIDevice);
209 if (FAILED(hr)) {
210 return NULL;
213 IDXGIAdapter *p_adapter;
214 hr = IDXGIDevice_GetAdapter(pDXGIDevice, &p_adapter);
215 IDXGIDevice_Release(pDXGIDevice);
216 if (FAILED(hr)) {
217 return NULL;
219 return p_adapter;
222 bool isXboxHardware(ID3D11Device *d3ddev)
224 IDXGIAdapter *p_adapter = D3D11DeviceAdapter(d3ddev);
225 if (!p_adapter)
226 return NULL;
228 bool result = false;
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))
234 result = true;
237 IDXGIAdapter_Release(p_adapter);
238 return result;
241 bool isNvidiaHardware(ID3D11Device *d3ddev)
243 IDXGIAdapter *p_adapter = D3D11DeviceAdapter(d3ddev);
244 if (!p_adapter)
245 return NULL;
247 bool result = false;
248 DXGI_ADAPTER_DESC adapterDesc;
249 if (SUCCEEDED(IDXGIAdapter_GetDesc(p_adapter, &adapterDesc))) {
250 result = adapterDesc.VendorId == 0x10DE;
253 IDXGIAdapter_Release(p_adapter);
254 return result;
257 const d3d_format_t *FindD3D11Format(ID3D11Device *d3ddevice,
258 vlc_fourcc_t i_src_chroma,
259 uint8_t bits_per_channel,
260 bool allow_opaque,
261 UINT supportFlags)
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)
268 continue;
269 if (bits_per_channel && bits_per_channel > output_format->bitsPerChannel)
270 continue;
271 if (!allow_opaque && (output_format->fourcc == VLC_CODEC_D3D11_OPAQUE ||
272 output_format->fourcc == VLC_CODEC_D3D11_OPAQUE_10B))
273 continue;
275 DXGI_FORMAT textureFormat;
276 if (output_format->formatTexture == DXGI_FORMAT_UNKNOWN)
277 textureFormat = output_format->resourceFormat[0];
278 else
279 textureFormat = output_format->formatTexture;
281 if( DeviceSupportsFormat( d3ddevice, textureFormat, supportFlags ) )
282 return output_format;
284 return NULL;
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;
293 HRESULT hr;
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;
305 } else {
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 );
312 if( !p_chroma_desc )
313 return VLC_EGENERIC;
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);
319 return VLC_EGENERIC;
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;
338 } else {
339 plane_count = 1;
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 );
345 if (FAILED(hr)) {
346 msg_Err(obj, "CreateTexture2D failed for the %d pool. (hr=0x%0lx)", pool_size, hr);
347 goto error;
351 for (unsigned picture_count = 0; picture_count < pool_size; picture_count++) {
352 for (plane = 0; plane < plane_count; plane++)
354 if (slicedTexture) {
355 textures[picture_count * D3D11_MAX_SHADER_VIEW + plane] = slicedTexture;
356 ID3D11Texture2D_AddRef(slicedTexture);
357 } else {
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] );
361 if (FAILED(hr)) {
362 msg_Err(obj, "CreateTexture2D failed for the %d pool. (hr=0x%0lx)", pool_size, hr);
363 goto error;
367 for (; plane < D3D11_MAX_SHADER_VIEW; plane++) {
368 if (!cfg->resourceFormat[plane])
369 textures[picture_count * D3D11_MAX_SHADER_VIEW + plane] = NULL;
370 else
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);
381 if( FAILED(hr) ) {
382 msg_Err(obj, "The texture cannot be mapped. (hr=0x%lX)", hr);
383 goto error;
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 );
389 goto error;
393 if (slicedTexture)
394 ID3D11Texture2D_Release(slicedTexture);
395 return VLC_SUCCESS;
396 error:
397 if (slicedTexture)
398 ID3D11Texture2D_Release(slicedTexture);
399 return VLC_EGENERIC;