chromecast: lower vorbis encoding quality
[vlc.git] / modules / hw / d3d11 / d3d11_surface.c
blobf6b59df86c972a9296f77cdb9b680c2a2612216d
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_filter.h>
33 #include <vlc_picture.h>
34 #include <vlc_modules.h>
36 #include <assert.h>
38 #include "../../video_chroma/copy.h"
40 #include <windows.h>
41 #define COBJMACROS
42 #include <d3d11.h>
44 #include "d3d11_filters.h"
45 #include "../../video_chroma/d3d11_fmt.h"
47 #ifdef ID3D11VideoContext_VideoProcessorBlt
48 #define CAN_PROCESSOR 1
49 #else
50 #define CAN_PROCESSOR 0
51 #endif
53 struct filter_sys_t {
54 copy_cache_t cache;
55 union {
56 ID3D11Texture2D *staging;
57 ID3D11Resource *staging_resource;
59 vlc_mutex_t staging_lock;
61 #if CAN_PROCESSOR
62 union {
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;
72 #endif
73 d3d11_device_t d3d_dev;
75 /* CPU to GPU */
76 filter_t *filter;
77 picture_t *staging_pic;
79 d3d11_handle_t hd3d;
82 #if CAN_PROCESSOR
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;
88 HRESULT hr;
89 ID3D11VideoProcessorEnumerator *processorEnumerator = NULL;
91 hr = ID3D11DeviceContext_QueryInterface(d3dctx, &IID_ID3D11VideoContext, (void **)&sys->d3dvidctx);
92 if (unlikely(FAILED(hr)))
93 goto error;
95 hr = ID3D11Device_QueryInterface( d3ddevice, &IID_ID3D11VideoDevice, (void **)&sys->d3dviddev);
96 if (unlikely(FAILED(hr)))
97 goto error;
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,
102 .InputFrameRate = {
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.");
116 goto error;
119 UINT flags;
120 #ifndef NDEBUG
121 D3D11_LogProcessorSupport(p_filter, processorEnumerator);
122 #endif
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));
128 goto error;
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));
134 goto error;
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);
143 if (SUCCEEDED(hr))
145 D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outDesc = {
146 .ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D,
149 hr = ID3D11VideoDevice_CreateVideoProcessorOutputView(sys->d3dviddev,
150 sys->procOutResource,
151 processorEnumerator,
152 &outDesc,
153 &sys->processorOutput);
154 if (FAILED(hr))
155 msg_Err(p_filter, "Failed to create the processor output. (hr=0x%lX)", hr);
156 else
158 sys->procEnumerator = processorEnumerator;
159 return VLC_SUCCESS;
162 if (sys->videoProcessor)
164 ID3D11VideoProcessor_Release(sys->videoProcessor);
165 sys->videoProcessor = NULL;
169 error:
170 if (processorEnumerator)
171 ID3D11VideoProcessorEnumerator_Release(processorEnumerator);
172 if (sys->d3dvidctx)
173 ID3D11VideoContext_Release(sys->d3dvidctx);
174 if (sys->d3dviddev)
175 ID3D11VideoDevice_Release(sys->d3dviddev);
176 return VLC_EGENERIC;
178 #endif
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);
186 return hr;
189 static int assert_staging(filter_t *p_filter, picture_sys_t *p_sys)
191 filter_sys_t *sys = p_filter->p_sys;
192 HRESULT hr;
194 if (sys->staging)
195 goto ok;
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);
210 sys->staging = NULL;
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);
215 #if CAN_PROCESSOR
216 if (FAILED(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);
226 if (SUCCEEDED(hr))
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);
238 sys->staging = NULL;
239 hr = E_FAIL;
241 else
242 msg_Dbg(p_filter, "Using shader+processor format %s", new_fmt->name);
244 else
246 msg_Dbg(p_filter, "can't create intermediate texture (hr=0x%0lx)", hr);
247 ID3D11Texture2D_Release(sys->staging);
248 sys->staging = NULL;
253 #endif
254 ID3D11Device_Release(p_device);
255 if (FAILED(hr)) {
256 msg_Err(p_filter, "Failed to create a %s staging texture to extract surface pixels (hr=0x%0lx)", DxgiFormatToStr(texDesc.Format), hr );
257 return VLC_EGENERIC;
260 return VLC_SUCCESS;
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");
269 return;
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);
282 return;
285 UINT srcSlice;
286 D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc;
287 if (p_sys->decoder)
289 ID3D11VideoDecoderOutputView_GetDesc( p_sys->decoder, &viewDesc );
290 srcSlice = viewDesc.Texture2D.ArraySlice;
292 else
293 srcSlice = 0;
294 ID3D11Resource *srcResource = p_sys->resource[KNOWN_DXGI_INDEX];
296 #if CAN_PROCESSOR
297 if (sys->procEnumerator)
299 HRESULT hr;
300 if (!p_sys->processorInput)
302 D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inDesc = {
303 .FourCC = 0,
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],
311 sys->procEnumerator,
312 &inDesc,
313 &p_sys->processorInput);
314 if (FAILED(hr))
316 #ifndef NDEBUG
317 msg_Dbg(p_filter,"Failed to create processor input for slice %d. (hr=0x%lX)", p_sys->slice_index, hr);
318 #endif
319 return;
322 D3D11_VIDEO_PROCESSOR_STREAM stream = {
323 .Enable = TRUE,
324 .pInputSurface = p_sys->processorInput,
327 hr = ID3D11VideoContext_VideoProcessorBlt(sys->d3dvidctx, sys->videoProcessor,
328 sys->processorOutput,
329 0, 1, &stream);
330 if (FAILED(hr))
332 msg_Err(p_filter, "Failed to process the video. (hr=0x%lX)", hr);
333 vlc_mutex_unlock(&sys->staging_lock);
334 return;
337 srcResource = sys->procOutResource;
338 srcSlice = 0;
340 #endif
341 ID3D11DeviceContext_CopySubresourceRegion(p_sys->context, sys->staging_resource,
342 0, 0, 0, 0,
343 srcResource,
344 srcSlice,
345 NULL);
347 HRESULT hr = ID3D11DeviceContext_Map(p_sys->context, sys->staging_resource,
348 0, D3D11_MAP_READ, 0, &lock);
349 if (FAILED(hr)) {
350 msg_Err(p_filter, "Failed to map source surface. (hr=0x%0lx)", hr);
351 vlc_mutex_unlock(&sys->staging_lock);
352 return;
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] = {
364 lock.RowPitch,
365 chroma_pitch,
366 chroma_pitch,
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,
378 &sys->cache);
379 } else if (desc.Format == DXGI_FORMAT_NV12) {
380 const uint8_t *plane[2] = {
381 lock.pData,
382 (uint8_t*)lock.pData + lock.RowPitch * desc.Height
384 const size_t pitch[2] = {
385 lock.RowPitch,
386 lock.RowPitch,
388 Copy420_SP_to_P(dst, plane, pitch,
389 __MIN(desc.Height, src->format.i_y_offset + src->format.i_visible_height),
390 &sys->cache);
391 picture_SwapUV(dst);
392 } else {
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 );
399 /* */
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");
410 return;
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);
423 return;
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;
432 #if CAN_PROCESSOR
433 if (sys->procEnumerator)
435 HRESULT hr;
436 if (!p_sys->processorInput)
438 D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inDesc = {
439 .FourCC = 0,
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],
447 sys->procEnumerator,
448 &inDesc,
449 &p_sys->processorInput);
450 if (FAILED(hr))
452 #ifndef NDEBUG
453 msg_Dbg(p_filter,"Failed to create processor input for slice %d. (hr=0x%lX)", p_sys->slice_index, hr);
454 #endif
455 return;
458 D3D11_VIDEO_PROCESSOR_STREAM stream = {
459 .Enable = TRUE,
460 .pInputSurface = p_sys->processorInput,
463 hr = ID3D11VideoContext_VideoProcessorBlt(sys->d3dvidctx, sys->videoProcessor,
464 sys->processorOutput,
465 0, 1, &stream);
466 if (FAILED(hr))
468 msg_Err(p_filter, "Failed to process the video. (hr=0x%lX)", hr);
469 vlc_mutex_unlock(&sys->staging_lock);
470 return;
473 srcResource = sys->procOutResource;
474 srcSlice = 0;
476 #endif
477 ID3D11DeviceContext_CopySubresourceRegion(p_sys->context, sys->staging_resource,
478 0, 0, 0, 0,
479 srcResource,
480 srcSlice,
481 NULL);
483 HRESULT hr = ID3D11DeviceContext_Map(p_sys->context, sys->staging_resource,
484 0, D3D11_MAP_READ, 0, &lock);
485 if (FAILED(hr)) {
486 msg_Err(p_filter, "Failed to map source surface. (hr=0x%0lx)", hr);
487 vlc_mutex_unlock(&sys->staging_lock);
488 return;
491 ID3D11Texture2D_GetDesc(sys->staging, &desc);
493 if (desc.Format == DXGI_FORMAT_NV12) {
494 const uint8_t *plane[2] = {
495 lock.pData,
496 (uint8_t*)lock.pData + lock.RowPitch * desc.Height
498 size_t pitch[2] = {
499 lock.RowPitch,
500 lock.RowPitch,
502 Copy420_SP_to_SP(dst, plane, pitch,
503 __MIN(desc.Height, src->format.i_y_offset + src->format.i_visible_height),
504 &sys->cache);
505 } else {
506 msg_Err(p_filter, "Unsupported D3D11VA conversion from 0x%08X to NV12", desc.Format);
509 /* */
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);
527 return;
530 ID3D11DeviceContext_CopySubresourceRegion(p_sys->context, sys->staging_resource,
531 0, 0, 0, 0,
532 p_sys->resource[KNOWN_DXGI_INDEX],
533 p_sys->slice_index,
534 NULL);
536 HRESULT hr = ID3D11DeviceContext_Map(p_sys->context, sys->staging_resource,
537 0, D3D11_MAP_READ, 0, &lock);
538 if (FAILED(hr)) {
539 msg_Err(p_filter, "Failed to map source surface. (hr=0x%0lx)", hr);
540 vlc_mutex_unlock(&sys->staging_lock);
541 return;
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 );
552 /* */
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 );
562 free(p_sys);
563 free(picture);
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 )
586 filter_t *p_filter;
588 p_filter = vlc_object_create( p_this, sizeof(filter_t) );
589 if (unlikely(p_filter == NULL))
590 return 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 );
605 return NULL;
608 return 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);
615 free(pic_ctx);
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))
623 return 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);
628 return &pic_ctx->s;
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
638 * was opened */
639 return;
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);
648 if (FAILED(hr)) {
649 msg_Err(p_filter, "Failed to map source surface. (hr=0x%0lx)", hr);
650 return;
653 picture_UpdatePlanes(sys->staging_pic, lock.pData, lock.RowPitch);
655 picture_Hold( src );
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],
665 p_sys->slice_index,
666 0, 0, 0,
667 sys->staging_pic->p_sys->resource[KNOWN_DXGI_INDEX], 0,
668 &copyBox);
669 if (dst->context == NULL)
671 struct va_pic_context *pic_ctx = calloc(1, sizeof(*pic_ctx));
672 if (likely(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 )
695 return VLC_EGENERIC;
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 )
699 return VLC_EGENERIC;
701 switch( p_filter->fmt_out.video.i_chroma ) {
702 case VLC_CODEC_I420:
703 case VLC_CODEC_YV12:
704 if (p_filter->fmt_in.video.i_chroma != VLC_CODEC_D3D11_OPAQUE)
705 return VLC_EGENERIC;
706 p_filter->pf_video_filter = D3D11_YUY2_Filter;
707 break;
708 case VLC_CODEC_NV12:
709 if (p_filter->fmt_in.video.i_chroma != VLC_CODEC_D3D11_OPAQUE)
710 return VLC_EGENERIC;
711 p_filter->pf_video_filter = D3D11_NV12_Filter;
712 break;
713 case VLC_CODEC_RGBA:
714 if (p_filter->fmt_in.video.i_chroma != VLC_CODEC_D3D11_OPAQUE_RGBA)
715 return VLC_EGENERIC;
716 p_filter->pf_video_filter = D3D11_RGBA_Filter;
717 break;
718 case VLC_CODEC_BGRA:
719 if (p_filter->fmt_in.video.i_chroma != VLC_CODEC_D3D11_OPAQUE_BGRA)
720 return VLC_EGENERIC;
721 p_filter->pf_video_filter = D3D11_RGBA_Filter;
722 break;
723 default:
724 return VLC_EGENERIC;
727 filter_sys_t *p_sys = vlc_obj_calloc(obj, 1, sizeof(filter_sys_t));
728 if (!p_sys)
729 return VLC_EGENERIC;
731 if (D3D11_Create(p_filter, &p_sys->hd3d) != VLC_SUCCESS)
733 msg_Warn(p_filter, "cannot load d3d11.dll, aborting");
734 return VLC_EGENERIC;
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;
740 return VLC_SUCCESS;
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 )
753 return VLC_EGENERIC;
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 )
757 return VLC_EGENERIC;
759 switch( p_filter->fmt_in.video.i_chroma ) {
760 case VLC_CODEC_I420:
761 case VLC_CODEC_YV12:
762 case VLC_CODEC_NV12:
763 case VLC_CODEC_P010:
764 p_filter->pf_video_filter = NV12_D3D11_Filter;
765 break;
766 default:
767 return VLC_EGENERIC;
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");
776 return VLC_EGENERIC;
779 video_format_Init(&fmt_staging, 0);
781 vlc_fourcc_t d3d_fourcc = DxgiFormatFourcc(texDesc.Format);
782 if (d3d_fourcc == 0)
783 goto done;
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) {
789 err = VLC_ENOMEM;
790 goto done;
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);
801 if (p_dst == NULL) {
802 msg_Err(p_filter, "Failed to map create the temporary picture.");
803 goto done;
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);
817 if (FAILED(hr)) {
818 msg_Err(p_filter, "Failed to create a %s staging texture to extract surface pixels (hr=0x%0lx)", DxgiFormatToStr(texDesc.Format), hr );
819 goto done;
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);
828 if (!p_cpu_filter)
829 goto done;
832 p_sys = vlc_obj_calloc(obj, 1, sizeof(filter_sys_t));
833 if (!p_sys) {
834 err = VLC_ENOMEM;
835 goto done;
838 if (D3D11_Create(p_filter, &p_sys->hd3d) != VLC_SUCCESS)
840 msg_Warn(p_filter, "cannot load d3d11.dll, aborting");
841 goto done;
844 p_sys->filter = p_cpu_filter;
845 p_sys->staging_pic = p_dst;
846 p_filter->p_sys = p_sys;
847 err = VLC_SUCCESS;
849 done:
850 video_format_Clean(&fmt_staging);
851 if (err != VLC_SUCCESS)
853 if (p_cpu_filter)
854 DeleteFilter( p_cpu_filter );
855 if (texture)
856 ID3D11Texture2D_Release(texture);
857 D3D11_FilterReleaseInstance(&d3d_dev);
859 else
861 p_sys->d3d_dev = d3d_dev;
863 return err;
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;
870 #if CAN_PROCESSOR
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);
879 #endif
880 CopyCleanCache(&p_sys->cache);
881 vlc_mutex_destroy(&p_sys->staging_lock);
882 if (p_sys->staging)
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);