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 /*****************************************************************************
25 *****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_filter.h>
33 #include <vlc_picture.h>
34 #include <vlc_modules.h>
38 #include "../../video_chroma/copy.h"
44 #include "d3d11_filters.h"
45 #include "../../video_chroma/d3d11_fmt.h"
47 #ifdef ID3D11VideoContext_VideoProcessorBlt
48 #define CAN_PROCESSOR 1
50 #define CAN_PROCESSOR 0
56 ID3D11Texture2D
*staging
;
57 ID3D11Resource
*staging_resource
;
59 vlc_mutex_t staging_lock
;
63 ID3D11Texture2D
*procOutTexture
;
64 ID3D11Resource
*procOutResource
;
66 /* 420_OPAQUE processor */
67 ID3D11VideoDevice
*d3dviddev
;
68 ID3D11VideoContext
*d3dvidctx
;
69 ID3D11VideoProcessorOutputView
*processorOutput
;
70 ID3D11VideoProcessorEnumerator
*procEnumerator
;
71 ID3D11VideoProcessor
*videoProcessor
;
73 d3d11_device_t d3d_dev
;
77 picture_t
*staging_pic
;
83 static int SetupProcessor(filter_t
*p_filter
, ID3D11Device
*d3ddevice
,
84 ID3D11DeviceContext
*d3dctx
,
85 DXGI_FORMAT srcFormat
, DXGI_FORMAT dstFormat
)
87 filter_sys_t
*sys
= p_filter
->p_sys
;
89 ID3D11VideoProcessorEnumerator
*processorEnumerator
= NULL
;
91 hr
= ID3D11DeviceContext_QueryInterface(d3dctx
, &IID_ID3D11VideoContext
, (void **)&sys
->d3dvidctx
);
92 if (unlikely(FAILED(hr
)))
95 hr
= ID3D11Device_QueryInterface( d3ddevice
, &IID_ID3D11VideoDevice
, (void **)&sys
->d3dviddev
);
96 if (unlikely(FAILED(hr
)))
99 const video_format_t
*fmt
= &p_filter
->fmt_in
.video
;
100 D3D11_VIDEO_PROCESSOR_CONTENT_DESC processorDesc
= {
101 .InputFrameFormat
= D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE
,
103 .Numerator
= fmt
->i_frame_rate_base
> 0 ? fmt
->i_frame_rate
: 0,
104 .Denominator
= fmt
->i_frame_rate_base
,
106 .InputWidth
= fmt
->i_width
,
107 .InputHeight
= fmt
->i_height
,
108 .OutputWidth
= fmt
->i_width
,
109 .OutputHeight
= fmt
->i_height
,
110 .Usage
= D3D11_VIDEO_USAGE_PLAYBACK_NORMAL
,
112 hr
= ID3D11VideoDevice_CreateVideoProcessorEnumerator(sys
->d3dviddev
, &processorDesc
, &processorEnumerator
);
113 if ( processorEnumerator
== NULL
)
115 msg_Dbg(p_filter
, "Can't get a video processor for the video.");
121 D3D11_LogProcessorSupport(p_filter
, processorEnumerator
);
123 /* shortcut for the rendering output */
124 hr
= ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(processorEnumerator
, srcFormat
, &flags
);
125 if (FAILED(hr
) || !(flags
& D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT
))
127 msg_Dbg(p_filter
, "processor format %s not supported for output", DxgiFormatToStr(srcFormat
));
130 hr
= ID3D11VideoProcessorEnumerator_CheckVideoProcessorFormat(processorEnumerator
, dstFormat
, &flags
);
131 if (FAILED(hr
) || !(flags
& D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT
))
133 msg_Dbg(p_filter
, "processor format %s not supported for input", DxgiFormatToStr(dstFormat
));
137 D3D11_VIDEO_PROCESSOR_CAPS processorCaps
;
138 hr
= ID3D11VideoProcessorEnumerator_GetVideoProcessorCaps(processorEnumerator
, &processorCaps
);
139 for (UINT type
= 0; type
< processorCaps
.RateConversionCapsCount
; ++type
)
141 hr
= ID3D11VideoDevice_CreateVideoProcessor(sys
->d3dviddev
,
142 processorEnumerator
, type
, &sys
->videoProcessor
);
145 D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outDesc
= {
146 .ViewDimension
= D3D11_VPOV_DIMENSION_TEXTURE2D
,
149 hr
= ID3D11VideoDevice_CreateVideoProcessorOutputView(sys
->d3dviddev
,
150 sys
->procOutResource
,
153 &sys
->processorOutput
);
155 msg_Err(p_filter
, "Failed to create the processor output. (hr=0x%lX)", hr
);
158 sys
->procEnumerator
= processorEnumerator
;
162 if (sys
->videoProcessor
)
164 ID3D11VideoProcessor_Release(sys
->videoProcessor
);
165 sys
->videoProcessor
= NULL
;
170 if (processorEnumerator
)
171 ID3D11VideoProcessorEnumerator_Release(processorEnumerator
);
173 ID3D11VideoContext_Release(sys
->d3dvidctx
);
175 ID3D11VideoDevice_Release(sys
->d3dviddev
);
180 static HRESULT
can_map(filter_sys_t
*sys
, ID3D11DeviceContext
*context
)
182 D3D11_MAPPED_SUBRESOURCE lock
;
183 HRESULT hr
= ID3D11DeviceContext_Map(context
, sys
->staging_resource
, 0,
184 D3D11_MAP_READ
, 0, &lock
);
185 ID3D11DeviceContext_Unmap(context
, sys
->staging_resource
, 0);
189 static int assert_staging(filter_t
*p_filter
, picture_sys_t
*p_sys
)
191 filter_sys_t
*sys
= p_filter
->p_sys
;
197 D3D11_TEXTURE2D_DESC texDesc
;
198 ID3D11Texture2D_GetDesc( p_sys
->texture
[KNOWN_DXGI_INDEX
], &texDesc
);
200 texDesc
.MipLevels
= 1;
201 texDesc
.SampleDesc
.Count
= 1;
202 texDesc
.MiscFlags
= 0;
203 texDesc
.ArraySize
= 1;
204 texDesc
.Usage
= D3D11_USAGE_STAGING
;
205 texDesc
.CPUAccessFlags
= D3D11_CPU_ACCESS_READ
;
206 texDesc
.BindFlags
= 0;
208 ID3D11Device
*p_device
;
209 ID3D11DeviceContext_GetDevice(p_sys
->context
, &p_device
);
211 hr
= ID3D11Device_CreateTexture2D( p_device
, &texDesc
, NULL
, &sys
->staging
);
212 /* test if mapping the texture works ref #18746 */
213 if (SUCCEEDED(hr
) && FAILED(hr
= can_map(sys
, p_sys
->context
)))
214 msg_Dbg(p_filter
, "can't map default staging texture (hr=0x%0lx)", hr
);
217 /* failed with the this format, try a different one */
218 UINT supportFlags
= D3D11_FORMAT_SUPPORT_SHADER_LOAD
| D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_OUTPUT
;
219 const d3d_format_t
*new_fmt
=
220 FindD3D11Format( p_device
, 0, false, 0, false, supportFlags
);
221 if (new_fmt
&& texDesc
.Format
!= new_fmt
->formatTexture
)
223 DXGI_FORMAT srcFormat
= texDesc
.Format
;
224 texDesc
.Format
= new_fmt
->formatTexture
;
225 hr
= ID3D11Device_CreateTexture2D( p_device
, &texDesc
, NULL
, &sys
->staging
);
228 texDesc
.Usage
= D3D11_USAGE_DEFAULT
;
229 texDesc
.CPUAccessFlags
= 0;
230 texDesc
.BindFlags
|= D3D11_BIND_RENDER_TARGET
;
231 hr
= ID3D11Device_CreateTexture2D( p_device
, &texDesc
, NULL
, &sys
->procOutTexture
);
232 if (SUCCEEDED(hr
) && SUCCEEDED(hr
= can_map(sys
, p_sys
->context
)))
234 if (SetupProcessor(p_filter
, p_device
, p_sys
->context
, srcFormat
, new_fmt
->formatTexture
))
236 ID3D11Texture2D_Release(sys
->procOutTexture
);
237 ID3D11Texture2D_Release(sys
->staging
);
242 msg_Dbg(p_filter
, "Using shader+processor format %s", new_fmt
->name
);
246 msg_Dbg(p_filter
, "can't create intermediate texture (hr=0x%0lx)", hr
);
247 ID3D11Texture2D_Release(sys
->staging
);
254 ID3D11Device_Release(p_device
);
256 msg_Err(p_filter
, "Failed to create a %s staging texture to extract surface pixels (hr=0x%0lx)", DxgiFormatToStr(texDesc
.Format
), hr
);
263 static void D3D11_YUY2(filter_t
*p_filter
, picture_t
*src
, picture_t
*dst
)
265 if (src
->context
== NULL
)
267 /* the previous stages creating a D3D11 picture should always fill the context */
268 msg_Err(p_filter
, "missing source context");
272 filter_sys_t
*sys
= p_filter
->p_sys
;
273 picture_sys_t
*p_sys
= &((struct va_pic_context
*)src
->context
)->picsys
;
275 D3D11_TEXTURE2D_DESC desc
;
276 D3D11_MAPPED_SUBRESOURCE lock
;
278 vlc_mutex_lock(&sys
->staging_lock
);
279 if (assert_staging(p_filter
, p_sys
) != VLC_SUCCESS
)
281 vlc_mutex_unlock(&sys
->staging_lock
);
286 D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc
;
289 ID3D11VideoDecoderOutputView_GetDesc( p_sys
->decoder
, &viewDesc
);
290 srcSlice
= viewDesc
.Texture2D
.ArraySlice
;
294 ID3D11Resource
*srcResource
= p_sys
->resource
[KNOWN_DXGI_INDEX
];
297 if (sys
->procEnumerator
)
300 if (!p_sys
->processorInput
)
302 D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inDesc
= {
304 .ViewDimension
= D3D11_VPIV_DIMENSION_TEXTURE2D
,
305 .Texture2D
.MipSlice
= 0,
306 .Texture2D
.ArraySlice
= viewDesc
.Texture2D
.ArraySlice
,
309 hr
= ID3D11VideoDevice_CreateVideoProcessorInputView(sys
->d3dviddev
,
310 p_sys
->resource
[KNOWN_DXGI_INDEX
],
313 &p_sys
->processorInput
);
317 msg_Dbg(p_filter
,"Failed to create processor input for slice %d. (hr=0x%lX)", p_sys
->slice_index
, hr
);
322 D3D11_VIDEO_PROCESSOR_STREAM stream
= {
324 .pInputSurface
= p_sys
->processorInput
,
327 hr
= ID3D11VideoContext_VideoProcessorBlt(sys
->d3dvidctx
, sys
->videoProcessor
,
328 sys
->processorOutput
,
332 msg_Err(p_filter
, "Failed to process the video. (hr=0x%lX)", hr
);
333 vlc_mutex_unlock(&sys
->staging_lock
);
337 srcResource
= sys
->procOutResource
;
341 ID3D11DeviceContext_CopySubresourceRegion(p_sys
->context
, sys
->staging_resource
,
347 HRESULT hr
= ID3D11DeviceContext_Map(p_sys
->context
, sys
->staging_resource
,
348 0, D3D11_MAP_READ
, 0, &lock
);
350 msg_Err(p_filter
, "Failed to map source surface. (hr=0x%0lx)", hr
);
351 vlc_mutex_unlock(&sys
->staging_lock
);
355 if (dst
->format
.i_chroma
== VLC_CODEC_I420
)
356 picture_SwapUV( dst
);
358 ID3D11Texture2D_GetDesc(sys
->staging
, &desc
);
360 if (desc
.Format
== DXGI_FORMAT_YUY2
) {
361 size_t chroma_pitch
= (lock
.RowPitch
/ 2);
363 const size_t pitch
[3] = {
369 const uint8_t *plane
[3] = {
370 (uint8_t*)lock
.pData
,
371 (uint8_t*)lock
.pData
+ pitch
[0] * desc
.Height
,
372 (uint8_t*)lock
.pData
+ pitch
[0] * desc
.Height
373 + pitch
[1] * desc
.Height
/ 2,
376 Copy420_P_to_P(dst
, plane
, pitch
,
377 src
->format
.i_visible_height
+ src
->format
.i_y_offset
,
379 } else if (desc
.Format
== DXGI_FORMAT_NV12
) {
380 const uint8_t *plane
[2] = {
382 (uint8_t*)lock
.pData
+ lock
.RowPitch
* desc
.Height
384 const size_t pitch
[2] = {
388 Copy420_SP_to_P(dst
, plane
, pitch
,
389 __MIN(desc
.Height
, src
->format
.i_y_offset
+ src
->format
.i_visible_height
),
393 msg_Err(p_filter
, "Unsupported D3D11VA conversion from 0x%08X to YV12", desc
.Format
);
396 if (dst
->format
.i_chroma
== VLC_CODEC_I420
)
397 picture_SwapUV( dst
);
400 ID3D11DeviceContext_Unmap(p_sys
->context
, sys
->staging_resource
, 0);
401 vlc_mutex_unlock(&sys
->staging_lock
);
404 static void D3D11_NV12(filter_t
*p_filter
, picture_t
*src
, picture_t
*dst
)
406 if (src
->context
== NULL
)
408 /* the previous stages creating a D3D11 picture should always fill the context */
409 msg_Err(p_filter
, "missing source context");
413 filter_sys_t
*sys
= p_filter
->p_sys
;
414 picture_sys_t
*p_sys
= &((struct va_pic_context
*)src
->context
)->picsys
;
416 D3D11_TEXTURE2D_DESC desc
;
417 D3D11_MAPPED_SUBRESOURCE lock
;
419 vlc_mutex_lock(&sys
->staging_lock
);
420 if (assert_staging(p_filter
, p_sys
) != VLC_SUCCESS
)
422 vlc_mutex_unlock(&sys
->staging_lock
);
426 D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc
;
427 ID3D11VideoDecoderOutputView_GetDesc( p_sys
->decoder
, &viewDesc
);
429 ID3D11Resource
*srcResource
= p_sys
->resource
[KNOWN_DXGI_INDEX
];
430 UINT srcSlice
= viewDesc
.Texture2D
.ArraySlice
;
433 if (sys
->procEnumerator
)
436 if (!p_sys
->processorInput
)
438 D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inDesc
= {
440 .ViewDimension
= D3D11_VPIV_DIMENSION_TEXTURE2D
,
441 .Texture2D
.MipSlice
= 0,
442 .Texture2D
.ArraySlice
= viewDesc
.Texture2D
.ArraySlice
,
445 hr
= ID3D11VideoDevice_CreateVideoProcessorInputView(sys
->d3dviddev
,
446 p_sys
->resource
[KNOWN_DXGI_INDEX
],
449 &p_sys
->processorInput
);
453 msg_Dbg(p_filter
,"Failed to create processor input for slice %d. (hr=0x%lX)", p_sys
->slice_index
, hr
);
458 D3D11_VIDEO_PROCESSOR_STREAM stream
= {
460 .pInputSurface
= p_sys
->processorInput
,
463 hr
= ID3D11VideoContext_VideoProcessorBlt(sys
->d3dvidctx
, sys
->videoProcessor
,
464 sys
->processorOutput
,
468 msg_Err(p_filter
, "Failed to process the video. (hr=0x%lX)", hr
);
469 vlc_mutex_unlock(&sys
->staging_lock
);
473 srcResource
= sys
->procOutResource
;
477 ID3D11DeviceContext_CopySubresourceRegion(p_sys
->context
, sys
->staging_resource
,
483 HRESULT hr
= ID3D11DeviceContext_Map(p_sys
->context
, sys
->staging_resource
,
484 0, D3D11_MAP_READ
, 0, &lock
);
486 msg_Err(p_filter
, "Failed to map source surface. (hr=0x%0lx)", hr
);
487 vlc_mutex_unlock(&sys
->staging_lock
);
491 ID3D11Texture2D_GetDesc(sys
->staging
, &desc
);
493 if (desc
.Format
== DXGI_FORMAT_NV12
) {
494 const uint8_t *plane
[2] = {
496 (uint8_t*)lock
.pData
+ lock
.RowPitch
* desc
.Height
502 Copy420_SP_to_SP(dst
, plane
, pitch
,
503 __MIN(desc
.Height
, src
->format
.i_y_offset
+ src
->format
.i_visible_height
),
506 msg_Err(p_filter
, "Unsupported D3D11VA conversion from 0x%08X to NV12", desc
.Format
);
510 ID3D11DeviceContext_Unmap(p_sys
->context
, sys
->staging_resource
, 0);
511 vlc_mutex_unlock(&sys
->staging_lock
);
514 static void D3D11_RGBA(filter_t
*p_filter
, picture_t
*src
, picture_t
*dst
)
516 filter_sys_t
*sys
= p_filter
->p_sys
;
517 assert(src
->context
!= NULL
);
518 picture_sys_t
*p_sys
= &((struct va_pic_context
*)src
->context
)->picsys
;
520 D3D11_TEXTURE2D_DESC desc
;
521 D3D11_MAPPED_SUBRESOURCE lock
;
523 vlc_mutex_lock(&sys
->staging_lock
);
524 if (assert_staging(p_filter
, p_sys
) != VLC_SUCCESS
)
526 vlc_mutex_unlock(&sys
->staging_lock
);
530 ID3D11DeviceContext_CopySubresourceRegion(p_sys
->context
, sys
->staging_resource
,
532 p_sys
->resource
[KNOWN_DXGI_INDEX
],
536 HRESULT hr
= ID3D11DeviceContext_Map(p_sys
->context
, sys
->staging_resource
,
537 0, D3D11_MAP_READ
, 0, &lock
);
539 msg_Err(p_filter
, "Failed to map source surface. (hr=0x%0lx)", hr
);
540 vlc_mutex_unlock(&sys
->staging_lock
);
544 ID3D11Texture2D_GetDesc(sys
->staging
, &desc
);
546 plane_t src_planes
= dst
->p
[0];
547 src_planes
.i_lines
= desc
.Height
;
548 src_planes
.i_pitch
= lock
.RowPitch
;
549 src_planes
.p_pixels
= lock
.pData
;
550 plane_CopyPixels( dst
->p
, &src_planes
);
553 ID3D11DeviceContext_Unmap(p_sys
->context
,
554 p_sys
->resource
[KNOWN_DXGI_INDEX
], p_sys
->slice_index
);
555 vlc_mutex_unlock(&sys
->staging_lock
);
558 static void DestroyPicture(picture_t
*picture
)
560 picture_sys_t
*p_sys
= picture
->p_sys
;
561 ReleasePictureSys( p_sys
);
566 static void DeleteFilter( filter_t
* p_filter
)
568 if( p_filter
->p_module
)
569 module_unneed( p_filter
, p_filter
->p_module
);
571 es_format_Clean( &p_filter
->fmt_in
);
572 es_format_Clean( &p_filter
->fmt_out
);
574 vlc_object_release( p_filter
);
577 static picture_t
*NewBuffer(filter_t
*p_filter
)
579 filter_t
*p_parent
= p_filter
->owner
.sys
;
580 return p_parent
->p_sys
->staging_pic
;
583 static filter_t
*CreateFilter( vlc_object_t
*p_this
, const es_format_t
*p_fmt_in
,
584 vlc_fourcc_t dst_chroma
)
588 p_filter
= vlc_object_create( p_this
, sizeof(filter_t
) );
589 if (unlikely(p_filter
== NULL
))
592 p_filter
->b_allow_fmt_out_change
= false;
593 p_filter
->owner
.video
.buffer_new
= NewBuffer
;
594 p_filter
->owner
.sys
= p_this
;
596 es_format_InitFromVideo( &p_filter
->fmt_in
, &p_fmt_in
->video
);
597 es_format_InitFromVideo( &p_filter
->fmt_out
, &p_fmt_in
->video
);
598 p_filter
->fmt_out
.i_codec
= p_filter
->fmt_out
.video
.i_chroma
= dst_chroma
;
599 p_filter
->p_module
= module_need( p_filter
, "video converter", NULL
, false );
601 if( !p_filter
->p_module
)
603 msg_Dbg( p_filter
, "no video converter found" );
604 DeleteFilter( p_filter
);
611 static void d3d11_pic_context_destroy(struct picture_context_t
*opaque
)
613 struct va_pic_context
*pic_ctx
= (struct va_pic_context
*)opaque
;
614 ReleasePictureSys(&pic_ctx
->picsys
);
618 static struct picture_context_t
*d3d11_pic_context_copy(struct picture_context_t
*ctx
)
620 struct va_pic_context
*src_ctx
= (struct va_pic_context
*)ctx
;
621 struct va_pic_context
*pic_ctx
= calloc(1, sizeof(*pic_ctx
));
622 if (unlikely(pic_ctx
==NULL
))
624 pic_ctx
->s
.destroy
= d3d11_pic_context_destroy
;
625 pic_ctx
->s
.copy
= d3d11_pic_context_copy
;
626 pic_ctx
->picsys
= src_ctx
->picsys
;
627 AcquirePictureSys(&pic_ctx
->picsys
);
631 static void NV12_D3D11(filter_t
*p_filter
, picture_t
*src
, picture_t
*dst
)
633 filter_sys_t
*sys
= p_filter
->p_sys
;
634 picture_sys_t
*p_sys
= dst
->p_sys
;
635 if (unlikely(p_sys
==NULL
))
637 /* the output filter configuration may have changed since the filter
642 D3D11_TEXTURE2D_DESC texDesc
;
643 ID3D11Texture2D_GetDesc( sys
->staging_pic
->p_sys
->texture
[KNOWN_DXGI_INDEX
], &texDesc
);
645 D3D11_MAPPED_SUBRESOURCE lock
;
646 HRESULT hr
= ID3D11DeviceContext_Map(p_sys
->context
, sys
->staging_pic
->p_sys
->resource
[KNOWN_DXGI_INDEX
],
647 0, D3D11_MAP_WRITE
, 0, &lock
);
649 msg_Err(p_filter
, "Failed to map source surface. (hr=0x%0lx)", hr
);
653 picture_UpdatePlanes(sys
->staging_pic
, lock
.pData
, lock
.RowPitch
);
656 sys
->filter
->pf_video_filter(sys
->filter
, src
);
658 ID3D11DeviceContext_Unmap(p_sys
->context
, sys
->staging_pic
->p_sys
->resource
[KNOWN_DXGI_INDEX
], 0);
660 D3D11_BOX copyBox
= {
661 .right
= dst
->format
.i_width
, .bottom
= dst
->format
.i_height
, .back
= 1,
663 ID3D11DeviceContext_CopySubresourceRegion(p_sys
->context
,
664 p_sys
->resource
[KNOWN_DXGI_INDEX
],
667 sys
->staging_pic
->p_sys
->resource
[KNOWN_DXGI_INDEX
], 0,
669 if (dst
->context
== NULL
)
671 struct va_pic_context
*pic_ctx
= calloc(1, sizeof(*pic_ctx
));
674 pic_ctx
->s
.destroy
= d3d11_pic_context_destroy
;
675 pic_ctx
->s
.copy
= d3d11_pic_context_copy
;
676 pic_ctx
->picsys
= *dst
->p_sys
;
677 AcquirePictureSys(&pic_ctx
->picsys
);
678 dst
->context
= &pic_ctx
->s
;
683 VIDEO_FILTER_WRAPPER (D3D11_NV12
)
684 VIDEO_FILTER_WRAPPER (D3D11_YUY2
)
685 VIDEO_FILTER_WRAPPER (D3D11_RGBA
)
686 VIDEO_FILTER_WRAPPER (NV12_D3D11
)
688 int D3D11OpenConverter( vlc_object_t
*obj
)
690 filter_t
*p_filter
= (filter_t
*)obj
;
692 if ( p_filter
->fmt_in
.video
.i_chroma
!= VLC_CODEC_D3D11_OPAQUE
&&
693 p_filter
->fmt_in
.video
.i_chroma
!= VLC_CODEC_D3D11_OPAQUE_RGBA
&&
694 p_filter
->fmt_in
.video
.i_chroma
!= VLC_CODEC_D3D11_OPAQUE_BGRA
)
697 if ( p_filter
->fmt_in
.video
.i_visible_height
!= p_filter
->fmt_out
.video
.i_visible_height
698 || p_filter
->fmt_in
.video
.i_width
!= p_filter
->fmt_out
.video
.i_width
)
701 switch( p_filter
->fmt_out
.video
.i_chroma
) {
704 if (p_filter
->fmt_in
.video
.i_chroma
!= VLC_CODEC_D3D11_OPAQUE
)
706 p_filter
->pf_video_filter
= D3D11_YUY2_Filter
;
709 if (p_filter
->fmt_in
.video
.i_chroma
!= VLC_CODEC_D3D11_OPAQUE
)
711 p_filter
->pf_video_filter
= D3D11_NV12_Filter
;
714 if (p_filter
->fmt_in
.video
.i_chroma
!= VLC_CODEC_D3D11_OPAQUE_RGBA
)
716 p_filter
->pf_video_filter
= D3D11_RGBA_Filter
;
719 if (p_filter
->fmt_in
.video
.i_chroma
!= VLC_CODEC_D3D11_OPAQUE_BGRA
)
721 p_filter
->pf_video_filter
= D3D11_RGBA_Filter
;
727 filter_sys_t
*p_sys
= vlc_obj_calloc(obj
, 1, sizeof(filter_sys_t
));
731 if (D3D11_Create(p_filter
, &p_sys
->hd3d
) != VLC_SUCCESS
)
733 msg_Warn(p_filter
, "cannot load d3d11.dll, aborting");
737 CopyInitCache(&p_sys
->cache
, p_filter
->fmt_in
.video
.i_width
);
738 vlc_mutex_init(&p_sys
->staging_lock
);
739 p_filter
->p_sys
= p_sys
;
743 int D3D11OpenCPUConverter( vlc_object_t
*obj
)
745 filter_t
*p_filter
= (filter_t
*)obj
;
746 int err
= VLC_EGENERIC
;
747 ID3D11Texture2D
*texture
= NULL
;
748 filter_t
*p_cpu_filter
= NULL
;
749 video_format_t fmt_staging
;
750 filter_sys_t
*p_sys
= NULL
;
752 if ( p_filter
->fmt_out
.video
.i_chroma
!= VLC_CODEC_D3D11_OPAQUE
)
755 if ( p_filter
->fmt_in
.video
.i_height
!= p_filter
->fmt_out
.video
.i_height
756 || p_filter
->fmt_in
.video
.i_width
!= p_filter
->fmt_out
.video
.i_width
)
759 switch( p_filter
->fmt_in
.video
.i_chroma
) {
764 p_filter
->pf_video_filter
= NV12_D3D11_Filter
;
770 d3d11_device_t d3d_dev
;
771 D3D11_TEXTURE2D_DESC texDesc
;
772 D3D11_FilterHoldInstance(p_filter
, &d3d_dev
, &texDesc
);
773 if (unlikely(!d3d_dev
.d3dcontext
))
775 msg_Dbg(p_filter
, "D3D11 opaque without a texture");
779 video_format_Init(&fmt_staging
, 0);
781 vlc_fourcc_t d3d_fourcc
= DxgiFormatFourcc(texDesc
.Format
);
785 picture_resource_t res
;
786 res
.pf_destroy
= DestroyPicture
;
787 res
.p_sys
= calloc(1, sizeof(picture_sys_t
));
788 if (res
.p_sys
== NULL
) {
792 res
.p_sys
->context
= d3d_dev
.d3dcontext
;
793 res
.p_sys
->formatTexture
= texDesc
.Format
;
795 video_format_Copy(&fmt_staging
, &p_filter
->fmt_out
.video
);
796 fmt_staging
.i_chroma
= d3d_fourcc
;
797 fmt_staging
.i_height
= texDesc
.Height
;
798 fmt_staging
.i_width
= texDesc
.Width
;
800 picture_t
*p_dst
= picture_NewFromResource(&fmt_staging
, &res
);
802 msg_Err(p_filter
, "Failed to map create the temporary picture.");
805 picture_Setup(p_dst
, &p_dst
->format
);
807 texDesc
.MipLevels
= 1;
808 texDesc
.SampleDesc
.Count
= 1;
809 texDesc
.MiscFlags
= 0;
810 texDesc
.ArraySize
= 1;
811 texDesc
.Usage
= D3D11_USAGE_STAGING
;
812 texDesc
.CPUAccessFlags
= D3D11_CPU_ACCESS_WRITE
;
813 texDesc
.BindFlags
= 0;
814 texDesc
.Height
= p_dst
->format
.i_height
; /* make sure we match picture_Setup() */
816 HRESULT hr
= ID3D11Device_CreateTexture2D( d3d_dev
.d3ddevice
, &texDesc
, NULL
, &texture
);
818 msg_Err(p_filter
, "Failed to create a %s staging texture to extract surface pixels (hr=0x%0lx)", DxgiFormatToStr(texDesc
.Format
), hr
);
822 res
.p_sys
->texture
[KNOWN_DXGI_INDEX
] = texture
;
823 ID3D11DeviceContext_AddRef(p_dst
->p_sys
->context
);
825 if ( p_filter
->fmt_in
.video
.i_chroma
!= d3d_fourcc
)
827 p_cpu_filter
= CreateFilter(VLC_OBJECT(p_filter
), &p_filter
->fmt_in
, p_dst
->format
.i_chroma
);
832 p_sys
= vlc_obj_calloc(obj
, 1, sizeof(filter_sys_t
));
838 if (D3D11_Create(p_filter
, &p_sys
->hd3d
) != VLC_SUCCESS
)
840 msg_Warn(p_filter
, "cannot load d3d11.dll, aborting");
844 p_sys
->filter
= p_cpu_filter
;
845 p_sys
->staging_pic
= p_dst
;
846 p_filter
->p_sys
= p_sys
;
850 video_format_Clean(&fmt_staging
);
851 if (err
!= VLC_SUCCESS
)
854 DeleteFilter( p_cpu_filter
);
856 ID3D11Texture2D_Release(texture
);
857 D3D11_FilterReleaseInstance(&d3d_dev
);
861 p_sys
->d3d_dev
= d3d_dev
;
866 void D3D11CloseConverter( vlc_object_t
*obj
)
868 filter_t
*p_filter
= (filter_t
*)obj
;
869 filter_sys_t
*p_sys
= p_filter
->p_sys
;
871 if (p_sys
->d3dviddev
)
872 ID3D11VideoDevice_Release(p_sys
->d3dviddev
);
873 if (p_sys
->d3dvidctx
)
874 ID3D11VideoContext_Release(p_sys
->d3dvidctx
);
875 if (p_sys
->procEnumerator
)
876 ID3D11VideoProcessorEnumerator_Release(p_sys
->procEnumerator
);
877 if (p_sys
->videoProcessor
)
878 ID3D11VideoProcessor_Release(p_sys
->videoProcessor
);
880 CopyCleanCache(&p_sys
->cache
);
881 vlc_mutex_destroy(&p_sys
->staging_lock
);
883 ID3D11Texture2D_Release(p_sys
->staging
);
884 D3D11_FilterReleaseInstance(&p_sys
->d3d_dev
);
885 D3D11_Destroy(&p_sys
->hd3d
);
888 void D3D11CloseCPUConverter( vlc_object_t
*obj
)
890 filter_t
*p_filter
= (filter_t
*)obj
;
891 filter_sys_t
*p_sys
= p_filter
->p_sys
;
892 DeleteFilter(p_sys
->filter
);
893 picture_Release(p_sys
->staging_pic
);
894 D3D11_Destroy(&p_sys
->hd3d
);