d3d11_surface: ensure the source picture is correct
[vlc.git] / modules / video_chroma / d3d11_surface.c
blob2e9ab8d5cc207cf4dd870a4629319d20a5e064e2
1 /*****************************************************************************
2 * d3d11_surface.c : D3D11 GPU surface conversion module for vlc
3 *****************************************************************************
4 * Copyright © 2015 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 /*****************************************************************************
24 * Preamble
25 *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_filter.h>
34 #include <vlc_picture.h>
35 #include <vlc_modules.h>
37 #include "copy.h"
40 #include <windows.h>
41 #define COBJMACROS
42 #include <d3d11.h>
43 #include "d3d11_fmt.h"
45 #ifdef ID3D11VideoContext_VideoProcessorBlt
46 #define CAN_PROCESSOR 1
47 #else
48 #define CAN_PROCESSOR 0
49 #endif
51 struct filter_sys_t {
52 copy_cache_t cache;
53 union {
54 ID3D11Texture2D *staging;
55 ID3D11Resource *staging_resource;
57 vlc_mutex_t staging_lock;
59 #if CAN_PROCESSOR
60 union {
61 ID3D11Texture2D *procOutTexture;
62 ID3D11Resource *procOutResource;
64 /* 420_OPAQUE processor */
65 ID3D11VideoDevice *d3dviddev;
66 ID3D11VideoContext *d3dvidctx;
67 ID3D11VideoProcessorOutputView *processorOutput;
68 ID3D11VideoProcessorEnumerator *procEnumerator;
69 ID3D11VideoProcessor *videoProcessor;
70 #endif
72 /* CPU to GPU */
73 filter_t *filter;
74 picture_t *staging_pic;
76 HINSTANCE hd3d_dll;
79 #if CAN_PROCESSOR
80 static int SetupProcessor(filter_t *p_filter, ID3D11Device *d3ddevice,
81 ID3D11DeviceContext *d3dctx,
82 DXGI_FORMAT srcFormat, DXGI_FORMAT dstFormat)
84 filter_sys_t *sys = (filter_sys_t*) p_filter->p_sys;
85 HRESULT hr;
86 ID3D11VideoProcessorEnumerator *processorEnumerator = NULL;
88 hr = ID3D11DeviceContext_QueryInterface(d3dctx, &IID_ID3D11VideoContext, (void **)&sys->d3dvidctx);
89 if (unlikely(FAILED(hr)))
90 goto error;
92 hr = ID3D11Device_QueryInterface( d3ddevice, &IID_ID3D11VideoDevice, (void **)&sys->d3dviddev);
93 if (unlikely(FAILED(hr)))
94 goto error;
96 const video_format_t *fmt = &p_filter->fmt_in.video;
97 D3D11_VIDEO_PROCESSOR_CONTENT_DESC processorDesc = {
98 .InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE,
99 .InputFrameRate = {
100 .Numerator = fmt->i_frame_rate_base > 0 ? fmt->i_frame_rate : 0,
101 .Denominator = fmt->i_frame_rate_base,
103 .InputWidth = fmt->i_width,
104 .InputHeight = fmt->i_height,
105 .OutputWidth = fmt->i_width,
106 .OutputHeight = fmt->i_height,
107 .Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL,
109 hr = ID3D11VideoDevice_CreateVideoProcessorEnumerator(sys->d3dviddev, &processorDesc, &processorEnumerator);
110 if ( processorEnumerator == NULL )
112 msg_Dbg(p_filter, "Can't get a video processor for the video.");
113 goto error;
116 UINT flags;
117 #ifndef NDEBUG
118 for (int format = 0; format < 188; format++) {
119 hr = ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(processorEnumerator, format, &flags);
120 if (SUCCEEDED(hr) && (flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT))
121 msg_Dbg(p_filter, "processor format %s (%d) is supported for input", DxgiFormatToStr(format),format);
122 if (SUCCEEDED(hr) && (flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT))
123 msg_Dbg(p_filter, "processor format %s (%d) is supported for output", DxgiFormatToStr(format),format);
125 #endif
126 /* shortcut for the rendering output */
127 hr = ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(processorEnumerator, srcFormat, &flags);
128 if (FAILED(hr) || !(flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT))
130 msg_Dbg(p_filter, "processor format %s not supported for output", DxgiFormatToStr(srcFormat));
131 goto error;
133 hr = ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(processorEnumerator, dstFormat, &flags);
134 if (FAILED(hr) || !(flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT))
136 msg_Dbg(p_filter, "processor format %s not supported for input", DxgiFormatToStr(dstFormat));
137 goto error;
140 D3D11_VIDEO_PROCESSOR_CAPS processorCaps;
141 hr = ID3D11VideoProcessorEnumerator_GetVideoProcessorCaps(processorEnumerator, &processorCaps);
142 for (UINT type = 0; type < processorCaps.RateConversionCapsCount; ++type)
144 hr = ID3D11VideoDevice_CreateVideoProcessor(sys->d3dviddev,
145 processorEnumerator, type, &sys->videoProcessor);
146 if (SUCCEEDED(hr))
148 D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outDesc = {
149 .ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D,
152 hr = ID3D11VideoDevice_CreateVideoProcessorOutputView(sys->d3dviddev,
153 sys->procOutResource,
154 processorEnumerator,
155 &outDesc,
156 &sys->processorOutput);
157 if (FAILED(hr))
158 msg_Err(p_filter, "Failed to create the processor output. (hr=0x%lX)", hr);
159 else
161 sys->procEnumerator = processorEnumerator;
162 return VLC_SUCCESS;
165 if (sys->videoProcessor)
167 ID3D11VideoProcessor_Release(sys->videoProcessor);
168 sys->videoProcessor = NULL;
172 error:
173 if (processorEnumerator)
174 ID3D11VideoProcessorEnumerator_Release(processorEnumerator);
175 if (sys->d3dvidctx)
176 ID3D11VideoContext_Release(sys->d3dvidctx);
177 if (sys->d3dviddev)
178 ID3D11VideoDevice_Release(sys->d3dviddev);
179 return VLC_EGENERIC;
181 #endif
183 static int assert_staging(filter_t *p_filter, picture_sys_t *p_sys)
185 filter_sys_t *sys = (filter_sys_t*) p_filter->p_sys;
186 HRESULT hr;
188 if (sys->staging)
189 goto ok;
191 D3D11_TEXTURE2D_DESC texDesc;
192 ID3D11Texture2D_GetDesc( p_sys->texture[KNOWN_DXGI_INDEX], &texDesc);
194 texDesc.MipLevels = 1;
195 //texDesc.SampleDesc.Count = 1;
196 texDesc.MiscFlags = 0;
197 texDesc.ArraySize = 1;
198 texDesc.Usage = D3D11_USAGE_STAGING;
199 texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
200 texDesc.BindFlags = 0;
202 ID3D11Device *p_device;
203 ID3D11DeviceContext_GetDevice(p_sys->context, &p_device);
204 sys->staging = NULL;
205 hr = ID3D11Device_CreateTexture2D( p_device, &texDesc, NULL, &sys->staging);
206 #if CAN_PROCESSOR
207 if (FAILED(hr)) {
208 /* failed with the this format, try a different one */
209 UINT supportFlags = D3D11_FORMAT_SUPPORT_SHADER_LOAD | D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_OUTPUT;
210 const d3d_format_t *new_fmt =
211 FindD3D11Format( p_device, 0, 0, false, supportFlags );
212 if (new_fmt && texDesc.Format != new_fmt->formatTexture)
214 DXGI_FORMAT srcFormat = texDesc.Format;
215 texDesc.Format = new_fmt->formatTexture;
216 hr = ID3D11Device_CreateTexture2D( p_device, &texDesc, NULL, &sys->staging);
217 if (SUCCEEDED(hr))
219 texDesc.Usage = D3D11_USAGE_DEFAULT;
220 texDesc.CPUAccessFlags = 0;
221 texDesc.BindFlags |= D3D11_BIND_RENDER_TARGET;
222 hr = ID3D11Device_CreateTexture2D( p_device, &texDesc, NULL, &sys->procOutTexture);
223 if (SUCCEEDED(hr))
225 if (SetupProcessor(p_filter, p_device, p_sys->context, srcFormat, new_fmt->formatTexture))
227 ID3D11Texture2D_Release(sys->procOutTexture);
228 ID3D11Texture2D_Release(sys->staging);
229 sys->staging = NULL;
230 hr = E_FAIL;
233 else
235 ID3D11Texture2D_Release(sys->staging);
236 sys->staging = NULL;
237 hr = E_FAIL;
242 #endif
243 ID3D11Device_Release(p_device);
244 if (FAILED(hr)) {
245 msg_Err(p_filter, "Failed to create a %s staging texture to extract surface pixels (hr=0x%0lx)", DxgiFormatToStr(texDesc.Format), hr );
246 return VLC_EGENERIC;
249 return VLC_SUCCESS;
252 static void D3D11_YUY2(filter_t *p_filter, picture_t *src, picture_t *dst)
254 filter_sys_t *sys = (filter_sys_t*) p_filter->p_sys;
255 assert(src->context != NULL);
256 picture_sys_t *p_sys = &((struct va_pic_context*)src->context)->picsys;
258 D3D11_TEXTURE2D_DESC desc;
259 D3D11_MAPPED_SUBRESOURCE lock;
261 vlc_mutex_lock(&sys->staging_lock);
262 if (assert_staging(p_filter, p_sys) != VLC_SUCCESS)
264 vlc_mutex_unlock(&sys->staging_lock);
265 return;
268 UINT srcSlice;
269 D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc;
270 if (p_sys->decoder)
272 ID3D11VideoDecoderOutputView_GetDesc( p_sys->decoder, &viewDesc );
273 srcSlice = viewDesc.Texture2D.ArraySlice;
275 else
276 srcSlice = 0;
277 ID3D11Resource *srcResource = p_sys->resource[KNOWN_DXGI_INDEX];
279 #if CAN_PROCESSOR
280 if (sys->procEnumerator)
282 HRESULT hr;
283 if (!p_sys->processorInput)
285 D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inDesc = {
286 .FourCC = 0,
287 .ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D,
288 .Texture2D.MipSlice = 0,
289 .Texture2D.ArraySlice = viewDesc.Texture2D.ArraySlice,
292 hr = ID3D11VideoDevice_CreateVideoProcessorInputView(sys->d3dviddev,
293 p_sys->resource[KNOWN_DXGI_INDEX],
294 sys->procEnumerator,
295 &inDesc,
296 &p_sys->processorInput);
297 if (FAILED(hr))
299 #ifndef NDEBUG
300 msg_Dbg(p_filter,"Failed to create processor input for slice %d. (hr=0x%lX)", p_sys->slice_index, hr);
301 #endif
302 return;
305 D3D11_VIDEO_PROCESSOR_STREAM stream = {
306 .Enable = TRUE,
307 .pInputSurface = p_sys->processorInput,
310 hr = ID3D11VideoContext_VideoProcessorBlt(sys->d3dvidctx, sys->videoProcessor,
311 sys->processorOutput,
312 0, 1, &stream);
313 if (FAILED(hr))
315 msg_Err(p_filter, "Failed to process the video. (hr=0x%lX)", hr);
316 vlc_mutex_unlock(&sys->staging_lock);
317 return;
320 srcResource = sys->procOutResource;
321 srcSlice = 0;
323 #endif
324 ID3D11DeviceContext_CopySubresourceRegion(p_sys->context, sys->staging_resource,
325 0, 0, 0, 0,
326 srcResource,
327 srcSlice,
328 NULL);
330 HRESULT hr = ID3D11DeviceContext_Map(p_sys->context, sys->staging_resource,
331 0, D3D11_MAP_READ, 0, &lock);
332 if (FAILED(hr)) {
333 msg_Err(p_filter, "Failed to map source surface. (hr=0x%0lx)", hr);
334 vlc_mutex_unlock(&sys->staging_lock);
335 return;
338 if (dst->format.i_chroma == VLC_CODEC_I420) {
339 uint8_t *tmp = dst->p[1].p_pixels;
340 dst->p[1].p_pixels = dst->p[2].p_pixels;
341 dst->p[2].p_pixels = tmp;
344 ID3D11Texture2D_GetDesc(sys->staging, &desc);
346 if (desc.Format == DXGI_FORMAT_YUY2) {
347 size_t chroma_pitch = (lock.RowPitch / 2);
349 size_t pitch[3] = {
350 lock.RowPitch,
351 chroma_pitch,
352 chroma_pitch,
355 uint8_t *plane[3] = {
356 (uint8_t*)lock.pData,
357 (uint8_t*)lock.pData + pitch[0] * desc.Height,
358 (uint8_t*)lock.pData + pitch[0] * desc.Height
359 + pitch[1] * desc.Height / 2,
362 CopyFromYv12ToYv12(dst, plane, pitch,
363 src->format.i_visible_height + src->format.i_y_offset, &sys->cache);
364 } else if (desc.Format == DXGI_FORMAT_NV12) {
365 uint8_t *plane[2] = {
366 lock.pData,
367 (uint8_t*)lock.pData + lock.RowPitch * desc.Height
369 size_t pitch[2] = {
370 lock.RowPitch,
371 lock.RowPitch,
373 CopyFromNv12ToYv12(dst, plane, pitch,
374 src->format.i_visible_height + src->format.i_y_offset, &sys->cache);
375 } else {
376 msg_Err(p_filter, "Unsupported D3D11VA conversion from 0x%08X to YV12", desc.Format);
379 if (dst->format.i_chroma == VLC_CODEC_I420) {
380 uint8_t *tmp = dst->p[1].p_pixels;
381 dst->p[1].p_pixels = dst->p[2].p_pixels;
382 dst->p[2].p_pixels = tmp;
385 /* */
386 ID3D11DeviceContext_Unmap(p_sys->context, sys->staging_resource, 0);
387 vlc_mutex_unlock(&sys->staging_lock);
390 static void D3D11_NV12(filter_t *p_filter, picture_t *src, picture_t *dst)
392 filter_sys_t *sys = (filter_sys_t*) p_filter->p_sys;
393 assert(src->context != NULL);
394 picture_sys_t *p_sys = &((struct va_pic_context*)src->context)->picsys;
396 D3D11_TEXTURE2D_DESC desc;
397 D3D11_MAPPED_SUBRESOURCE lock;
399 vlc_mutex_lock(&sys->staging_lock);
400 if (assert_staging(p_filter, p_sys) != VLC_SUCCESS)
402 vlc_mutex_unlock(&sys->staging_lock);
403 return;
406 D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc;
407 ID3D11VideoDecoderOutputView_GetDesc( p_sys->decoder, &viewDesc );
409 ID3D11Resource *srcResource = p_sys->resource[KNOWN_DXGI_INDEX];
410 UINT srcSlice = viewDesc.Texture2D.ArraySlice;
412 #if CAN_PROCESSOR
413 if (sys->procEnumerator)
415 HRESULT hr;
416 if (!p_sys->processorInput)
418 D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inDesc = {
419 .FourCC = 0,
420 .ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D,
421 .Texture2D.MipSlice = 0,
422 .Texture2D.ArraySlice = viewDesc.Texture2D.ArraySlice,
425 hr = ID3D11VideoDevice_CreateVideoProcessorInputView(sys->d3dviddev,
426 p_sys->resource[KNOWN_DXGI_INDEX],
427 sys->procEnumerator,
428 &inDesc,
429 &p_sys->processorInput);
430 if (FAILED(hr))
432 #ifndef NDEBUG
433 msg_Dbg(p_filter,"Failed to create processor input for slice %d. (hr=0x%lX)", p_sys->slice_index, hr);
434 #endif
435 return;
438 D3D11_VIDEO_PROCESSOR_STREAM stream = {
439 .Enable = TRUE,
440 .pInputSurface = p_sys->processorInput,
443 hr = ID3D11VideoContext_VideoProcessorBlt(sys->d3dvidctx, sys->videoProcessor,
444 sys->processorOutput,
445 0, 1, &stream);
446 if (FAILED(hr))
448 msg_Err(p_filter, "Failed to process the video. (hr=0x%lX)", hr);
449 vlc_mutex_unlock(&sys->staging_lock);
450 return;
453 srcResource = sys->procOutResource;
454 srcSlice = 0;
456 #endif
457 ID3D11DeviceContext_CopySubresourceRegion(p_sys->context, sys->staging_resource,
458 0, 0, 0, 0,
459 srcResource,
460 srcSlice,
461 NULL);
463 HRESULT hr = ID3D11DeviceContext_Map(p_sys->context, sys->staging_resource,
464 0, D3D11_MAP_READ, 0, &lock);
465 if (FAILED(hr)) {
466 msg_Err(p_filter, "Failed to map source surface. (hr=0x%0lx)", hr);
467 vlc_mutex_unlock(&sys->staging_lock);
468 return;
471 ID3D11Texture2D_GetDesc(sys->staging, &desc);
473 if (desc.Format == DXGI_FORMAT_NV12) {
474 uint8_t *plane[2] = {
475 lock.pData,
476 (uint8_t*)lock.pData + lock.RowPitch * desc.Height
478 size_t pitch[2] = {
479 lock.RowPitch,
480 lock.RowPitch,
482 CopyFromNv12ToNv12(dst, plane, pitch,
483 src->format.i_visible_height + src->format.i_y_offset, &sys->cache);
484 } else {
485 msg_Err(p_filter, "Unsupported D3D11VA conversion from 0x%08X to NV12", desc.Format);
488 /* */
489 ID3D11DeviceContext_Unmap(p_sys->context, sys->staging_resource, 0);
490 vlc_mutex_unlock(&sys->staging_lock);
493 static void DestroyPicture(picture_t *picture)
495 picture_sys_t *p_sys = picture->p_sys;
496 ReleasePictureSys( p_sys );
497 free(p_sys);
498 free(picture);
501 static void DeleteFilter( filter_t * p_filter )
503 if( p_filter->p_module )
504 module_unneed( p_filter, p_filter->p_module );
506 es_format_Clean( &p_filter->fmt_in );
507 es_format_Clean( &p_filter->fmt_out );
509 vlc_object_release( p_filter );
512 static picture_t *NewBuffer(filter_t *p_filter)
514 filter_t *p_parent = p_filter->owner.sys;
515 return p_parent->p_sys->staging_pic;
518 static filter_t *CreateFilter( vlc_object_t *p_this, const es_format_t *p_fmt_in,
519 vlc_fourcc_t dst_chroma )
521 filter_t *p_filter;
523 p_filter = vlc_object_create( p_this, sizeof(filter_t) );
524 if (unlikely(p_filter == NULL))
525 return NULL;
527 p_filter->b_allow_fmt_out_change = false;
528 p_filter->owner.video.buffer_new = NewBuffer;
529 p_filter->owner.sys = p_this;
531 es_format_InitFromVideo( &p_filter->fmt_in, &p_fmt_in->video );
532 es_format_InitFromVideo( &p_filter->fmt_out, &p_fmt_in->video );
533 p_filter->fmt_out.i_codec = p_filter->fmt_out.video.i_chroma = dst_chroma;
534 p_filter->p_module = module_need( p_filter, "video converter", NULL, false );
536 if( !p_filter->p_module )
538 msg_Dbg( p_filter, "no video converter found" );
539 DeleteFilter( p_filter );
540 return NULL;
543 return p_filter;
546 static void d3d11_pic_context_destroy(struct picture_context_t *opaque)
548 struct va_pic_context *pic_ctx = (struct va_pic_context*)opaque;
549 ReleasePictureSys(&pic_ctx->picsys);
550 free(pic_ctx);
553 static struct picture_context_t *d3d11_pic_context_copy(struct picture_context_t *ctx)
555 struct va_pic_context *src_ctx = (struct va_pic_context*)ctx;
556 struct va_pic_context *pic_ctx = calloc(1, sizeof(*pic_ctx));
557 if (unlikely(pic_ctx==NULL))
558 return NULL;
559 pic_ctx->s.destroy = d3d11_pic_context_destroy;
560 pic_ctx->s.copy = d3d11_pic_context_copy;
561 pic_ctx->picsys = src_ctx->picsys;
562 AcquirePictureSys(&pic_ctx->picsys);
563 return &pic_ctx->s;
566 static void NV12_D3D11(filter_t *p_filter, picture_t *src, picture_t *dst)
568 filter_sys_t *sys = (filter_sys_t*) p_filter->p_sys;
569 picture_sys_t *p_sys = dst->p_sys;
571 D3D11_TEXTURE2D_DESC texDesc;
572 ID3D11Texture2D_GetDesc( sys->staging_pic->p_sys->texture[KNOWN_DXGI_INDEX], &texDesc);
574 D3D11_MAPPED_SUBRESOURCE lock;
575 HRESULT hr = ID3D11DeviceContext_Map(p_sys->context, sys->staging_pic->p_sys->resource[KNOWN_DXGI_INDEX],
576 0, D3D11_MAP_WRITE, 0, &lock);
577 if (FAILED(hr)) {
578 msg_Err(p_filter, "Failed to map source surface. (hr=0x%0lx)", hr);
579 return;
582 picture_UpdatePlanes(sys->staging_pic, lock.pData, lock.RowPitch);
584 picture_Hold( src );
585 sys->filter->pf_video_filter(sys->filter, src);
587 ID3D11DeviceContext_Unmap(p_sys->context, sys->staging_pic->p_sys->resource[KNOWN_DXGI_INDEX], 0);
589 D3D11_BOX copyBox = {
590 .right = dst->format.i_width, .bottom = dst->format.i_height, .back = 1,
592 ID3D11DeviceContext_CopySubresourceRegion(p_sys->context,
593 p_sys->resource[KNOWN_DXGI_INDEX],
594 p_sys->slice_index,
595 0, 0, 0,
596 sys->staging_pic->p_sys->resource[KNOWN_DXGI_INDEX], 0,
597 &copyBox);
598 if (dst->context == NULL)
600 struct va_pic_context *pic_ctx = calloc(1, sizeof(*pic_ctx));
601 if (likely(pic_ctx))
603 pic_ctx->s.destroy = d3d11_pic_context_destroy;
604 pic_ctx->s.copy = d3d11_pic_context_copy;
605 pic_ctx->picsys = *dst->p_sys;
606 AcquirePictureSys(&pic_ctx->picsys);
607 dst->context = &pic_ctx->s;
612 VIDEO_FILTER_WRAPPER (D3D11_NV12)
613 VIDEO_FILTER_WRAPPER (D3D11_YUY2)
614 VIDEO_FILTER_WRAPPER (NV12_D3D11)
616 static int OpenConverter( vlc_object_t *obj )
618 filter_t *p_filter = (filter_t *)obj;
619 HINSTANCE hd3d_dll = NULL;
620 int err = VLC_EGENERIC;
622 if ( p_filter->fmt_in.video.i_chroma != VLC_CODEC_D3D11_OPAQUE )
623 return VLC_EGENERIC;
625 if ( p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height
626 || p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width )
627 return VLC_EGENERIC;
629 switch( p_filter->fmt_out.video.i_chroma ) {
630 case VLC_CODEC_I420:
631 case VLC_CODEC_YV12:
632 p_filter->pf_video_filter = D3D11_YUY2_Filter;
633 break;
634 case VLC_CODEC_NV12:
635 p_filter->pf_video_filter = D3D11_NV12_Filter;
636 break;
637 default:
638 return VLC_EGENERIC;
641 hd3d_dll = LoadLibrary(TEXT("D3D11.DLL"));
642 if (unlikely(!hd3d_dll)) {
643 msg_Warn(p_filter, "cannot load d3d11.dll, aborting");
644 goto done;
647 filter_sys_t *p_sys = calloc(1, sizeof(filter_sys_t));
648 if (!p_sys)
649 goto done;
651 CopyInitCache(&p_sys->cache, p_filter->fmt_in.video.i_width );
652 vlc_mutex_init(&p_sys->staging_lock);
653 p_sys->hd3d_dll = hd3d_dll;
654 p_filter->p_sys = p_sys;
655 err = VLC_SUCCESS;
657 done:
658 if (err != VLC_SUCCESS)
660 if (hd3d_dll)
661 FreeLibrary(hd3d_dll);
663 return err;}
665 static int OpenFromCPU( vlc_object_t *obj )
667 filter_t *p_filter = (filter_t *)obj;
668 int err = VLC_EGENERIC;
669 ID3D11Texture2D *texture = NULL;
670 filter_t *p_cpu_filter = NULL;
671 HINSTANCE hd3d_dll = NULL;
672 video_format_t fmt_staging;
674 if ( p_filter->fmt_out.video.i_chroma != VLC_CODEC_D3D11_OPAQUE )
675 return VLC_EGENERIC;
677 if ( p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height
678 || p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width )
679 return VLC_EGENERIC;
681 switch( p_filter->fmt_in.video.i_chroma ) {
682 case VLC_CODEC_I420:
683 case VLC_CODEC_YV12:
684 case VLC_CODEC_NV12:
685 case VLC_CODEC_P010:
686 p_filter->pf_video_filter = NV12_D3D11_Filter;
687 break;
688 default:
689 return VLC_EGENERIC;
692 picture_t *peek = filter_NewPicture(p_filter);
693 if (peek == NULL)
694 return VLC_EGENERIC;
695 if (!peek->p_sys)
697 msg_Dbg(p_filter, "D3D11 opaque without a texture");
698 return VLC_EGENERIC;
701 video_format_Init(&fmt_staging, 0);
703 D3D11_TEXTURE2D_DESC texDesc;
704 ID3D11Texture2D_GetDesc( peek->p_sys->texture[KNOWN_DXGI_INDEX], &texDesc);
705 vlc_fourcc_t d3d_fourcc = DxgiFormatFourcc(texDesc.Format);
706 if (d3d_fourcc == 0)
707 goto done;
709 picture_resource_t res;
710 res.pf_destroy = DestroyPicture;
711 res.p_sys = calloc(1, sizeof(picture_sys_t));
712 if (res.p_sys == NULL) {
713 err = VLC_ENOMEM;
714 goto done;
716 res.p_sys->context = peek->p_sys->context;
717 res.p_sys->formatTexture = texDesc.Format;
719 video_format_Copy(&fmt_staging, &p_filter->fmt_out.video);
720 fmt_staging.i_chroma = d3d_fourcc;
721 fmt_staging.i_height = texDesc.Height;
722 fmt_staging.i_width = texDesc.Width;
724 picture_t *p_dst = picture_NewFromResource(&fmt_staging, &res);
725 if (p_dst == NULL) {
726 msg_Err(p_filter, "Failed to map create the temporary picture.");
727 goto done;
729 picture_Setup(p_dst, &p_dst->format);
731 texDesc.MipLevels = 1;
732 //texDesc.SampleDesc.Count = 1;
733 texDesc.MiscFlags = 0;
734 texDesc.ArraySize = 1;
735 texDesc.Usage = D3D11_USAGE_STAGING;
736 texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
737 texDesc.BindFlags = 0;
738 texDesc.Height = p_dst->format.i_height; /* make sure we match picture_Setup() */
740 ID3D11Device *p_device;
741 ID3D11DeviceContext_GetDevice(peek->p_sys->context, &p_device);
742 HRESULT hr = ID3D11Device_CreateTexture2D( p_device, &texDesc, NULL, &texture);
743 ID3D11Device_Release(p_device);
744 if (FAILED(hr)) {
745 msg_Err(p_filter, "Failed to create a %s staging texture to extract surface pixels (hr=0x%0lx)", DxgiFormatToStr(texDesc.Format), hr );
746 goto done;
749 res.p_sys->texture[KNOWN_DXGI_INDEX] = texture;
750 ID3D11DeviceContext_AddRef(p_dst->p_sys->context);
752 if ( p_filter->fmt_in.video.i_chroma != d3d_fourcc )
754 p_cpu_filter = CreateFilter(VLC_OBJECT(p_filter), &p_filter->fmt_in, p_dst->format.i_chroma);
755 if (!p_cpu_filter)
756 goto done;
759 hd3d_dll = LoadLibrary(TEXT("D3D11.DLL"));
760 if (unlikely(!hd3d_dll)) {
761 msg_Warn(p_filter, "cannot load d3d11.dll, aborting");
762 goto done;
765 filter_sys_t *p_sys = calloc(1, sizeof(filter_sys_t));
766 if (!p_sys) {
767 err = VLC_ENOMEM;
768 goto done;
770 p_sys->filter = p_cpu_filter;
771 p_sys->staging_pic = p_dst;
772 p_sys->hd3d_dll = hd3d_dll;
773 p_filter->p_sys = p_sys;
774 err = VLC_SUCCESS;
776 done:
777 video_format_Clean(&fmt_staging);
778 picture_Release(peek);
779 if (err != VLC_SUCCESS)
781 if (p_cpu_filter)
782 DeleteFilter( p_cpu_filter );
783 if (texture)
784 ID3D11Texture2D_Release(texture);
785 if (hd3d_dll)
786 FreeLibrary(hd3d_dll);
788 return err;
791 static void CloseConverter( vlc_object_t *obj )
793 filter_t *p_filter = (filter_t *)obj;
794 filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys;
795 #if CAN_PROCESSOR
796 if (p_sys->d3dviddev)
797 ID3D11VideoDevice_Release(p_sys->d3dviddev);
798 if (p_sys->d3dvidctx)
799 ID3D11VideoContext_Release(p_sys->d3dvidctx);
800 if (p_sys->procEnumerator)
801 ID3D11VideoProcessorEnumerator_Release(p_sys->procEnumerator);
802 if (p_sys->videoProcessor)
803 ID3D11VideoProcessor_Release(p_sys->videoProcessor);
804 #endif
805 CopyCleanCache(&p_sys->cache);
806 vlc_mutex_destroy(&p_sys->staging_lock);
807 if (p_sys->staging)
808 ID3D11Texture2D_Release(p_sys->staging);
809 FreeLibrary(p_sys->hd3d_dll);
810 free( p_sys );
811 p_filter->p_sys = NULL;
814 static void CloseFromCPU( vlc_object_t *obj )
816 filter_t *p_filter = (filter_t *)obj;
817 filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys;
818 DeleteFilter(p_sys->filter);
819 picture_Release(p_sys->staging_pic);
820 FreeLibrary(p_sys->hd3d_dll);
821 free( p_sys );
822 p_filter->p_sys = NULL;
825 /*****************************************************************************
826 * Module descriptor.
827 *****************************************************************************/
828 vlc_module_begin ()
829 set_description( N_("Conversions from D3D11 to YUV") )
830 set_capability( "video converter", 10 )
831 set_callbacks( OpenConverter, CloseConverter )
832 add_submodule()
833 set_callbacks( OpenFromCPU, CloseFromCPU )
834 set_capability( "video converter", 10 )
835 vlc_module_end ()