D3D11_deinterlace: remove debug message
[vlc.git] / modules / hw / d3d11 / d3d11_deinterlace.c
blobc8aaf69c78ea03e086d124f76ebe52b9f7182a38
1 /*****************************************************************************
2 * d3d11_deinterlace.c: D3D11 deinterlacing filter
3 *****************************************************************************
4 * Copyright (C) 2017 Videolabs SAS
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 <stdlib.h>
28 #include <assert.h>
30 #include <vlc_common.h>
31 #include <vlc_filter.h>
32 #include <vlc_picture.h>
34 #define COBJMACROS
35 #include <initguid.h>
36 #include <d3d11.h>
38 #include "d3d11_filters.h"
39 #include "../../video_chroma/d3d11_fmt.h"
40 #include "../../video_filter/deinterlace/common.h"
42 #ifdef __MINGW32__
43 typedef UINT D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS;
44 #define D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_BLEND 0x1
45 #define D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_BOB 0x2
46 #define D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_ADAPTIVE 0x4
47 #define D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_MOTION_COMPENSATION 0x8
48 #define D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_INVERSE_TELECINE 0x10
49 #define D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_FRAME_RATE_CONVERSION 0x20
50 #endif
52 struct filter_sys_t
54 d3d11_device_t d3d_dev;
55 ID3D11VideoDevice *d3dviddev;
56 ID3D11VideoContext *d3dvidctx;
57 ID3D11VideoProcessor *videoProcessor;
58 ID3D11VideoProcessorEnumerator *procEnumerator;
60 HANDLE context_mutex;
61 union {
62 ID3D11Texture2D *outTexture;
63 ID3D11Resource *outResource;
65 ID3D11VideoProcessorOutputView *processorOutput;
67 struct deinterlace_ctx context;
68 picture_t * (*buffer_new)( filter_t * );
71 struct filter_mode_t
73 const char *psz_mode;
74 D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS i_mode;
75 deinterlace_algo settings;
77 static struct filter_mode_t filter_mode [] = {
78 { "blend", D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_BLEND,
79 { false, false, false, false } },
80 { "bob", D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_BOB,
81 { true, false, false, false } },
82 { "x", D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_MOTION_COMPENSATION,
83 { true, true, false, false } },
84 { "ivtc", D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_INVERSE_TELECINE,
85 { false, true, true, false } },
86 { "yadif2x", D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_ADAPTIVE,
87 { true, true, false, false } },
90 static int assert_ProcessorInput(filter_t *p_filter, picture_sys_t *p_sys_src)
92 filter_sys_t *p_sys = p_filter->p_sys;
93 if (!p_sys_src->processorInput)
95 D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inDesc = {
96 .FourCC = 0,
97 .ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D,
98 .Texture2D.MipSlice = 0,
99 .Texture2D.ArraySlice = p_sys_src->slice_index,
101 HRESULT hr;
103 hr = ID3D11VideoDevice_CreateVideoProcessorInputView(p_sys->d3dviddev,
104 p_sys_src->resource[KNOWN_DXGI_INDEX],
105 p_sys->procEnumerator,
106 &inDesc,
107 &p_sys_src->processorInput);
108 if (FAILED(hr))
110 #ifndef NDEBUG
111 msg_Dbg(p_filter,"Failed to create processor input for slice %d. (hr=0x%lX)", p_sys_src->slice_index, hr);
112 #endif
113 return VLC_EGENERIC;
116 return VLC_SUCCESS;
119 static void Flush(filter_t *filter)
121 FlushDeinterlacing(&filter->p_sys->context);
124 static int RenderPic( filter_t *p_filter, picture_t *p_outpic, picture_t *p_pic,
125 int order, int i_field )
127 VLC_UNUSED(order);
128 HRESULT hr;
129 filter_sys_t *p_sys = p_filter->p_sys;
131 picture_t *p_prev = p_sys->context.pp_history[0];
132 picture_t *p_cur = p_sys->context.pp_history[1];
133 picture_t *p_next = p_sys->context.pp_history[2];
135 /* TODO adjust the format if it's the first or second field ? */
136 D3D11_VIDEO_FRAME_FORMAT frameFormat = !i_field ?
137 D3D11_VIDEO_FRAME_FORMAT_INTERLACED_TOP_FIELD_FIRST :
138 D3D11_VIDEO_FRAME_FORMAT_INTERLACED_BOTTOM_FIELD_FIRST;
140 ID3D11VideoContext_VideoProcessorSetStreamFrameFormat(p_sys->d3dvidctx, p_sys->videoProcessor, 0, frameFormat);
142 D3D11_VIDEO_PROCESSOR_STREAM stream = {0};
143 stream.Enable = TRUE;
144 stream.InputFrameOrField = i_field ? 1 : 0;
146 if( p_cur && p_next )
148 picture_sys_t *picsys_next = ActivePictureSys(p_next);
149 if ( assert_ProcessorInput(p_filter, picsys_next) )
150 return VLC_EGENERIC;
152 picture_sys_t *picsys_cur = ActivePictureSys(p_cur);
153 if ( assert_ProcessorInput(p_filter, picsys_cur) )
154 return VLC_EGENERIC;
156 if ( p_prev )
158 picture_sys_t *picsys_prev = ActivePictureSys(p_prev);
159 if ( assert_ProcessorInput(p_filter, picsys_prev) )
160 return VLC_EGENERIC;
162 stream.pInputSurface = picsys_cur->processorInput;
163 stream.ppFutureSurfaces = &picsys_next->processorInput;
164 stream.ppPastSurfaces = &picsys_prev->processorInput;
166 stream.PastFrames = 1;
167 stream.FutureFrames = 1;
169 else
171 /* p_next is the current, p_cur is the previous frame */
172 stream.pInputSurface = picsys_next->processorInput;
173 stream.ppPastSurfaces = &picsys_cur->processorInput;
174 stream.PastFrames = 1;
177 else
179 picture_sys_t *p_sys_src = ActivePictureSys(p_pic);
180 if ( assert_ProcessorInput(p_filter, p_sys_src) )
181 return VLC_EGENERIC;
183 /* first single frame */
184 stream.pInputSurface = p_sys_src->processorInput;
187 RECT srcRect;
188 srcRect.left = 0;
189 srcRect.top = 0;
190 srcRect.right = p_pic->format.i_visible_width;
191 srcRect.bottom = p_pic->format.i_visible_height;
192 ID3D11VideoContext_VideoProcessorSetStreamSourceRect(p_sys->d3dvidctx, p_sys->videoProcessor,
193 0, TRUE, &srcRect);
194 ID3D11VideoContext_VideoProcessorSetStreamDestRect(p_sys->d3dvidctx, p_sys->videoProcessor,
195 0, TRUE, &srcRect);
197 hr = ID3D11VideoContext_VideoProcessorBlt(p_sys->d3dvidctx, p_sys->videoProcessor,
198 p_sys->processorOutput,
199 0, 1, &stream);
200 if (FAILED(hr))
201 return VLC_EGENERIC;
203 D3D11_BOX box = {
204 .top = 0,
205 .bottom = p_outpic->format.i_visible_height,
206 .left = 0,
207 .right = p_outpic->format.i_visible_width,
208 .back = 1,
211 ID3D11DeviceContext_CopySubresourceRegion(p_outpic->p_sys->context,
212 p_outpic->p_sys->resource[KNOWN_DXGI_INDEX],
213 p_outpic->p_sys->slice_index,
214 0, 0, 0,
215 p_sys->outResource,
216 0, &box);
217 return VLC_SUCCESS;
220 static int RenderSinglePic( filter_t *p_filter, picture_t *p_outpic, picture_t *p_pic )
222 return RenderPic( p_filter, p_outpic, p_pic, 0, 0 );
225 static picture_t *Deinterlace(filter_t *p_filter, picture_t *p_pic)
227 filter_sys_t *p_sys = p_filter->p_sys;
229 if( p_sys->context_mutex != INVALID_HANDLE_VALUE )
230 WaitForSingleObjectEx( p_sys->context_mutex, INFINITE, FALSE );
232 picture_t *res = DoDeinterlacing( p_filter, &p_sys->context, p_pic );
234 if( p_sys->context_mutex != INVALID_HANDLE_VALUE )
235 ReleaseMutex( p_sys->context_mutex );
237 return res;
240 static const struct filter_mode_t *GetFilterMode(const char *mode)
242 if ( mode == NULL || !strcmp( mode, "auto" ) )
243 mode = "x";
245 for (size_t i=0; i<ARRAY_SIZE(filter_mode); i++)
247 if( !strcmp( mode, filter_mode[i].psz_mode ) )
248 return &filter_mode[i];
250 return NULL;
253 static void d3d11_pic_context_destroy(struct picture_context_t *opaque)
255 struct va_pic_context *pic_ctx = (struct va_pic_context*)opaque;
256 ReleasePictureSys(&pic_ctx->picsys);
257 free(pic_ctx);
260 static struct picture_context_t *d3d11_pic_context_copy(struct picture_context_t *ctx)
262 struct va_pic_context *src_ctx = (struct va_pic_context*)ctx;
263 struct va_pic_context *pic_ctx = calloc(1, sizeof(*pic_ctx));
264 if (unlikely(pic_ctx==NULL))
265 return NULL;
266 pic_ctx->s.destroy = d3d11_pic_context_destroy;
267 pic_ctx->s.copy = d3d11_pic_context_copy;
268 pic_ctx->picsys = src_ctx->picsys;
269 AcquirePictureSys(&pic_ctx->picsys);
270 return &pic_ctx->s;
273 static picture_t *NewOutputPicture( filter_t *p_filter )
275 picture_t *pic = p_filter->p_sys->buffer_new( p_filter );
276 if ( !pic->context )
278 bool b_local_texture = false;
280 if ( !pic->p_sys )
282 pic->p_sys = calloc(1, sizeof(*pic->p_sys));
283 if (unlikely(pic->p_sys == NULL))
284 return NULL;
286 D3D11_TEXTURE2D_DESC dstDesc;
287 ID3D11Texture2D_GetDesc(p_filter->p_sys->outTexture, &dstDesc);
289 const d3d_format_t *cfg = NULL;
290 for (const d3d_format_t *output_format = GetRenderFormatList();
291 output_format->name != NULL; ++output_format)
293 if (output_format->formatTexture == dstDesc.Format &&
294 is_d3d11_opaque(output_format->fourcc))
296 cfg = output_format;
297 break;
300 if (unlikely(cfg == NULL))
302 free(pic->p_sys);
303 return NULL;
306 /* create the texture that's missing */
307 video_format_t fmt = p_filter->fmt_out.video;
308 fmt.i_width = dstDesc.Width;
309 fmt.i_height = dstDesc.Height;
310 if (AllocateTextures(VLC_OBJECT(p_filter), &p_filter->p_sys->d3d_dev, cfg,
311 &fmt, 1, pic->p_sys->texture) != VLC_SUCCESS)
313 free(pic->p_sys);
314 return NULL;
316 b_local_texture = true;
318 pic->p_sys->context = p_filter->p_sys->d3d_dev.d3dcontext;
319 pic->p_sys->formatTexture = dstDesc.Format;
322 /* the picture might be duplicated for snapshots so it needs a context */
323 struct va_pic_context *pic_ctx = calloc(1, sizeof(*pic_ctx));
324 if (likely(pic_ctx!=NULL))
326 pic_ctx->s.destroy = d3d11_pic_context_destroy;
327 pic_ctx->s.copy = d3d11_pic_context_copy;
328 pic_ctx->picsys = *pic->p_sys;
329 AcquirePictureSys( &pic_ctx->picsys );
330 pic->context = &pic_ctx->s;
332 if (b_local_texture) {
333 for (int i=0; i<D3D11_MAX_SHADER_VIEW; i++) {
334 if (pic->p_sys->texture[i])
335 ID3D11Texture2D_Release(pic->p_sys->texture[i]);
339 return pic;
342 int D3D11OpenDeinterlace(vlc_object_t *obj)
344 filter_t *filter = (filter_t *)obj;
345 HRESULT hr;
346 ID3D11VideoProcessorEnumerator *processorEnumerator = NULL;
348 if (!is_d3d11_opaque(filter->fmt_in.video.i_chroma))
349 return VLC_EGENERIC;
350 if (!video_format_IsSimilar(&filter->fmt_in.video, &filter->fmt_out.video))
351 return VLC_EGENERIC;
353 filter_sys_t *sys = malloc(sizeof (*sys));
354 if (unlikely(sys == NULL))
355 return VLC_ENOMEM;
356 memset(sys, 0, sizeof (*sys));
358 D3D11_TEXTURE2D_DESC dstDesc;
359 D3D11_FilterHoldInstance(filter, &sys->d3d_dev, &dstDesc);
360 if (unlikely(sys->d3d_dev.d3dcontext==NULL))
362 msg_Dbg(filter, "Filter without a context");
363 free(sys);
364 return VLC_ENOOBJ;
367 hr = ID3D11Device_QueryInterface(sys->d3d_dev.d3ddevice, &IID_ID3D11VideoDevice, (void **)&sys->d3dviddev);
368 if (FAILED(hr)) {
369 msg_Err(filter, "Could not Query ID3D11VideoDevice Interface. (hr=0x%lX)", hr);
370 goto error;
373 hr = ID3D11DeviceContext_QueryInterface(sys->d3d_dev.d3dcontext, &IID_ID3D11VideoContext, (void **)&sys->d3dvidctx);
374 if (FAILED(hr)) {
375 msg_Err(filter, "Could not Query ID3D11VideoContext Interface from the picture. (hr=0x%lX)", hr);
376 goto error;
379 HANDLE context_lock = INVALID_HANDLE_VALUE;
380 UINT dataSize = sizeof(context_lock);
381 hr = ID3D11Device_GetPrivateData(sys->d3d_dev.d3ddevice, &GUID_CONTEXT_MUTEX, &dataSize, &context_lock);
382 if (FAILED(hr))
383 msg_Warn(filter, "No mutex found to lock the decoder");
384 sys->context_mutex = context_lock;
386 const video_format_t *fmt = &filter->fmt_out.video;
388 D3D11_VIDEO_PROCESSOR_CONTENT_DESC processorDesc = {
389 .InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_INTERLACED_TOP_FIELD_FIRST,
390 .InputFrameRate = {
391 .Numerator = fmt->i_frame_rate,
392 .Denominator = fmt->i_frame_rate_base,
394 .InputWidth = fmt->i_width,
395 .InputHeight = fmt->i_height,
396 .OutputWidth = dstDesc.Width,
397 .OutputHeight = dstDesc.Height,
398 .OutputFrameRate = {
399 .Numerator = fmt->i_frame_rate,
400 .Denominator = fmt->i_frame_rate_base,
402 .Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL,
404 hr = ID3D11VideoDevice_CreateVideoProcessorEnumerator(sys->d3dviddev, &processorDesc, &processorEnumerator);
405 if ( processorEnumerator == NULL )
407 msg_Dbg(filter, "Can't get a video processor for the video.");
408 goto error;
411 UINT flags;
412 #ifndef NDEBUG
413 D3D11_LogProcessorSupport(filter, processorEnumerator);
414 #endif
415 hr = ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(processorEnumerator, dstDesc.Format, &flags);
416 if (!SUCCEEDED(hr))
418 msg_Dbg(filter, "can't read processor support for %s", DxgiFormatToStr(dstDesc.Format));
419 goto error;
421 if ( !(flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT) ||
422 !(flags & D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT) )
424 msg_Dbg(filter, "deinterlacing %s is not supported", DxgiFormatToStr(dstDesc.Format));
425 goto error;
428 D3D11_VIDEO_PROCESSOR_CAPS processorCaps;
429 hr = ID3D11VideoProcessorEnumerator_GetVideoProcessorCaps(processorEnumerator, &processorCaps);
430 if (FAILED(hr))
431 goto error;
433 char *psz_mode = var_InheritString( filter, "deinterlace-mode" );
434 const struct filter_mode_t *p_mode = GetFilterMode(psz_mode);
435 if (p_mode == NULL)
437 msg_Dbg(filter, "unknown mode %s, trying blend", psz_mode);
438 p_mode = GetFilterMode("blend");
440 if (strcmp(p_mode->psz_mode, psz_mode))
441 msg_Dbg(filter, "using %s deinterlacing mode", p_mode->psz_mode);
443 D3D11_VIDEO_PROCESSOR_RATE_CONVERSION_CAPS rateCaps;
444 for (UINT type = 0; type < processorCaps.RateConversionCapsCount; ++type)
446 ID3D11VideoProcessorEnumerator_GetVideoProcessorRateConversionCaps(processorEnumerator, type, &rateCaps);
447 if (!(rateCaps.ProcessorCaps & p_mode->i_mode))
448 continue;
450 hr = ID3D11VideoDevice_CreateVideoProcessor(sys->d3dviddev,
451 processorEnumerator, type, &sys->videoProcessor);
452 if (SUCCEEDED(hr))
453 break;
454 sys->videoProcessor = NULL;
456 if ( sys->videoProcessor==NULL &&
457 p_mode->i_mode != D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_BOB )
459 msg_Dbg(filter, "mode %s not available, trying bob", psz_mode);
460 p_mode = GetFilterMode("bob");
461 for (UINT type = 0; type < processorCaps.RateConversionCapsCount; ++type)
463 ID3D11VideoProcessorEnumerator_GetVideoProcessorRateConversionCaps(processorEnumerator, type, &rateCaps);
464 if (!(rateCaps.ProcessorCaps & D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_BOB))
465 continue;
467 hr = ID3D11VideoDevice_CreateVideoProcessor(sys->d3dviddev,
468 processorEnumerator, type, &sys->videoProcessor);
469 if (SUCCEEDED(hr))
470 break;
471 sys->videoProcessor = NULL;
475 if (sys->videoProcessor == NULL)
477 msg_Dbg(filter, "couldn't find a deinterlacing filter");
478 goto error;
481 D3D11_TEXTURE2D_DESC texDesc;
482 ZeroMemory(&texDesc, sizeof(texDesc));
483 texDesc.MipLevels = 1;
484 texDesc.SampleDesc.Count = 1;
485 texDesc.MiscFlags = 0; //D3D11_RESOURCE_MISC_SHARED;
486 texDesc.Usage = D3D11_USAGE_DEFAULT;
487 texDesc.CPUAccessFlags = 0;
488 texDesc.Format = dstDesc.Format;
489 texDesc.BindFlags = D3D11_BIND_RENDER_TARGET;
490 texDesc.Usage = D3D11_USAGE_DEFAULT;
491 texDesc.CPUAccessFlags = 0;
492 texDesc.ArraySize = 1;
493 texDesc.Height = dstDesc.Height;
494 texDesc.Width = dstDesc.Width;
496 hr = ID3D11Device_CreateTexture2D( sys->d3d_dev.d3ddevice, &texDesc, NULL, &sys->outTexture );
497 if (FAILED(hr)) {
498 msg_Err(filter, "CreateTexture2D failed. (hr=0x%0lx)", hr);
499 goto error;
502 D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outDesc = {
503 .ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D,
504 .Texture2D.MipSlice = 0,
507 hr = ID3D11VideoDevice_CreateVideoProcessorOutputView(sys->d3dviddev,
508 sys->outResource,
509 processorEnumerator,
510 &outDesc,
511 &sys->processorOutput);
512 if (FAILED(hr))
514 msg_Dbg(filter,"Failed to create processor output. (hr=0x%lX)", hr);
515 goto error;
518 sys->procEnumerator = processorEnumerator;
520 InitDeinterlacingContext( &sys->context );
522 sys->context.settings = p_mode->settings;
523 sys->context.settings.b_use_frame_history = rateCaps.PastFrames != 0 ||
524 rateCaps.FutureFrames != 0;
525 if (sys->context.settings.b_use_frame_history != p_mode->settings.b_use_frame_history)
526 msg_Dbg(filter, "deinterlacing not using frame history as requested");
527 if (sys->context.settings.b_double_rate)
528 sys->context.pf_render_ordered = RenderPic;
529 else
530 sys->context.pf_render_single_pic = RenderSinglePic;
532 video_format_t out_fmt;
533 GetDeinterlacingOutput( &sys->context, &out_fmt, &filter->fmt_in.video );
534 if( !filter->b_allow_fmt_out_change &&
535 out_fmt.i_height != filter->fmt_in.video.i_height )
537 goto error;
540 sys->buffer_new = filter->owner.video.buffer_new;
541 filter->owner.video.buffer_new = NewOutputPicture;
542 filter->fmt_out.video = out_fmt;
543 filter->pf_video_filter = Deinterlace;
544 filter->pf_flush = Flush;
545 filter->p_sys = sys;
547 return VLC_SUCCESS;
548 error:
549 if (sys->outTexture)
550 ID3D11Texture2D_Release(sys->outTexture);
551 if (sys->videoProcessor)
552 ID3D11VideoProcessor_Release(sys->videoProcessor);
553 if (processorEnumerator)
554 ID3D11VideoProcessorEnumerator_Release(processorEnumerator);
555 if (sys->d3dvidctx)
556 ID3D11VideoContext_Release(sys->d3dvidctx);
557 if (sys->d3dviddev)
558 ID3D11VideoDevice_Release(sys->d3dviddev);
559 if (sys->d3d_dev.d3dcontext)
560 D3D11_FilterReleaseInstance(&sys->d3d_dev);
561 free(sys);
563 return VLC_EGENERIC;
566 void D3D11CloseDeinterlace(vlc_object_t *obj)
568 filter_t *filter = (filter_t *)obj;
569 filter_sys_t *sys = filter->p_sys;
571 ID3D11VideoProcessorOutputView_Release(sys->processorOutput);
572 ID3D11Texture2D_Release(sys->outTexture);
573 ID3D11VideoProcessor_Release(sys->videoProcessor);
574 ID3D11VideoProcessorEnumerator_Release(sys->procEnumerator);
575 ID3D11VideoContext_Release(sys->d3dvidctx);
576 ID3D11VideoDevice_Release(sys->d3dviddev);
577 D3D11_FilterReleaseInstance(&sys->d3d_dev);
579 free(sys);