vlc | branch: master | Steve Lhomme <[email protected]> | Tue Jun 6 16:27:08 2017 +0200| [2139237836a60bafded97e5ebfeef5cf02743267] | committer: Jean-Baptiste Kempf
video_chroma:d3d11: add a module to convert from CPU to GPU textures Signed-off-by: Jean-Baptiste Kempf <[email protected]> > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=2139237836a60bafded97e5ebfeef5cf02743267 --- modules/video_chroma/Makefile.am | 2 +- modules/video_chroma/d3d11_surface.c | 320 +++++++++++++++++++++++++++++++++-- 2 files changed, 305 insertions(+), 17 deletions(-) diff --git a/modules/video_chroma/Makefile.am b/modules/video_chroma/Makefile.am index cbd8e8a1e7..fd95f7a719 100644 --- a/modules/video_chroma/Makefile.am +++ b/modules/video_chroma/Makefile.am @@ -125,7 +125,7 @@ endif # D3D11VA libd3d11_surface_plugin_la_SOURCES = video_chroma/d3d11_surface.c \ video_chroma/d3d11_fmt.h video_chroma/dxgi_fmt.c video_chroma/dxgi_fmt.h \ - video_chroma/copy.c video_chroma/copy.h + video_chroma/copy.c video_chroma/copy.h if HAVE_AVCODEC_D3D11VA chroma_LTLIBRARIES += \ diff --git a/modules/video_chroma/d3d11_surface.c b/modules/video_chroma/d3d11_surface.c index f626df6f31..d8fe4c5993 100644 --- a/modules/video_chroma/d3d11_surface.c +++ b/modules/video_chroma/d3d11_surface.c @@ -32,20 +32,10 @@ #include <vlc_plugin.h> #include <vlc_filter.h> #include <vlc_picture.h> +#include <vlc_modules.h> #include "copy.h" -static int OpenConverter( vlc_object_t * ); -static void CloseConverter( vlc_object_t * ); - -/***************************************************************************** - * Module descriptor. - *****************************************************************************/ -vlc_module_begin () - set_description( N_("Conversions from D3D11 to YUV") ) - set_capability( "video converter", 10 ) - set_callbacks( OpenConverter, CloseConverter ) -vlc_module_end () #include <windows.h> #define COBJMACROS @@ -78,6 +68,12 @@ struct filter_sys_t { ID3D11VideoProcessorEnumerator *procEnumerator; ID3D11VideoProcessor *videoProcessor; #endif + + /* CPU to GPU */ + filter_t *filter; + picture_t *staging_pic; + + HINSTANCE hd3d_dll; }; #if CAN_PROCESSOR @@ -268,11 +264,16 @@ static void D3D11_YUY2(filter_t *p_filter, picture_t *src, picture_t *dst) return; } + UINT srcSlice; D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC viewDesc; - ID3D11VideoDecoderOutputView_GetDesc( p_sys->decoder, &viewDesc ); - + if (p_sys->decoder) + { + ID3D11VideoDecoderOutputView_GetDesc( p_sys->decoder, &viewDesc ); + srcSlice = viewDesc.Texture2D.ArraySlice; + } + else + srcSlice = 0; ID3D11Resource *srcResource = p_sys->resource[KNOWN_DXGI_INDEX]; - UINT srcSlice = viewDesc.Texture2D.ArraySlice; #if CAN_PROCESSOR if (sys->procEnumerator) @@ -487,12 +488,135 @@ static void D3D11_NV12(filter_t *p_filter, picture_t *src, picture_t *dst) vlc_mutex_unlock(&sys->staging_lock); } +static void DestroyPicture(picture_t *picture) +{ + picture_sys_t *p_sys = picture->p_sys; + ReleasePictureSys( p_sys ); + free(p_sys); + free(picture); +} + +static void DeleteFilter( filter_t * p_filter ) +{ + if( p_filter->p_module ) + module_unneed( p_filter, p_filter->p_module ); + + es_format_Clean( &p_filter->fmt_in ); + es_format_Clean( &p_filter->fmt_out ); + + vlc_object_release( p_filter ); +} + +static picture_t *NewBuffer(filter_t *p_filter) +{ + filter_t *p_parent = p_filter->owner.sys; + return p_parent->p_sys->staging_pic; +} + +static filter_t *CreateFilter( vlc_object_t *p_this, const es_format_t *p_fmt_in, + vlc_fourcc_t dst_chroma ) +{ + filter_t *p_filter; + + p_filter = vlc_object_create( p_this, sizeof(filter_t) ); + if (unlikely(p_filter == NULL)) + return NULL; + + p_filter->b_allow_fmt_out_change = false; + p_filter->owner.video.buffer_new = NewBuffer; + p_filter->owner.sys = p_this; + + es_format_InitFromVideo( &p_filter->fmt_in, &p_fmt_in->video ); + es_format_InitFromVideo( &p_filter->fmt_out, &p_fmt_in->video ); + p_filter->fmt_out.i_codec = p_filter->fmt_out.video.i_chroma = dst_chroma; + p_filter->p_module = module_need( p_filter, "video converter", NULL, false ); + + if( !p_filter->p_module ) + { + msg_Dbg( p_filter, "no video converter found" ); + DeleteFilter( p_filter ); + return NULL; + } + + return p_filter; +} + +static void d3d11_pic_context_destroy(struct picture_context_t *opaque) +{ + struct va_pic_context *pic_ctx = (struct va_pic_context*)opaque; + ReleasePictureSys(&pic_ctx->picsys); + free(pic_ctx); +} + +static struct picture_context_t *d3d11_pic_context_copy(struct picture_context_t *ctx) +{ + struct va_pic_context *src_ctx = (struct va_pic_context*)ctx; + struct va_pic_context *pic_ctx = calloc(1, sizeof(*pic_ctx)); + if (unlikely(pic_ctx==NULL)) + return NULL; + pic_ctx->s.destroy = d3d11_pic_context_destroy; + pic_ctx->s.copy = d3d11_pic_context_copy; + pic_ctx->picsys = src_ctx->picsys; + AcquirePictureSys(&pic_ctx->picsys); + return &pic_ctx->s; +} + +static void NV12_D3D11(filter_t *p_filter, picture_t *src, picture_t *dst) +{ + filter_sys_t *sys = (filter_sys_t*) p_filter->p_sys; + picture_sys_t *p_sys = dst->p_sys; + + D3D11_TEXTURE2D_DESC texDesc; + ID3D11Texture2D_GetDesc( sys->staging_pic->p_sys->texture[KNOWN_DXGI_INDEX], &texDesc); + + D3D11_MAPPED_SUBRESOURCE lock; + HRESULT hr = ID3D11DeviceContext_Map(p_sys->context, sys->staging_pic->p_sys->resource[KNOWN_DXGI_INDEX], + 0, D3D11_MAP_WRITE, 0, &lock); + if (FAILED(hr)) { + msg_Err(p_filter, "Failed to map source surface. (hr=0x%0lx)", hr); + return; + } + + picture_UpdatePlanes(sys->staging_pic, lock.pData, lock.RowPitch); + + picture_Hold( src ); + sys->filter->pf_video_filter(sys->filter, src); + + ID3D11DeviceContext_Unmap(p_sys->context, sys->staging_pic->p_sys->resource[KNOWN_DXGI_INDEX], 0); + + D3D11_BOX copyBox = { + .right = dst->format.i_width, .bottom = dst->format.i_height, .back = 1, + }; + ID3D11DeviceContext_CopySubresourceRegion(p_sys->context, + p_sys->resource[KNOWN_DXGI_INDEX], + p_sys->slice_index, + 0, 0, 0, + sys->staging_pic->p_sys->resource[KNOWN_DXGI_INDEX], 0, + ©Box); + if (dst->context == NULL) + { + struct va_pic_context *pic_ctx = calloc(1, sizeof(*pic_ctx)); + if (likely(pic_ctx)) + { + pic_ctx->s.destroy = d3d11_pic_context_destroy; + pic_ctx->s.copy = d3d11_pic_context_copy; + pic_ctx->picsys = *dst->p_sys; + AcquirePictureSys(&pic_ctx->picsys); + dst->context = &pic_ctx->s; + } + } +} + VIDEO_FILTER_WRAPPER (D3D11_NV12) VIDEO_FILTER_WRAPPER (D3D11_YUY2) +VIDEO_FILTER_WRAPPER (NV12_D3D11) static int OpenConverter( vlc_object_t *obj ) { filter_t *p_filter = (filter_t *)obj; + HINSTANCE hd3d_dll = NULL; + int err = VLC_EGENERIC; + if ( p_filter->fmt_in.video.i_chroma != VLC_CODEC_D3D11_OPAQUE ) return VLC_EGENERIC; @@ -512,14 +636,154 @@ static int OpenConverter( vlc_object_t *obj ) return VLC_EGENERIC; } + hd3d_dll = LoadLibrary(TEXT("D3D11.DLL")); + if (unlikely(!hd3d_dll)) { + msg_Warn(p_filter, "cannot load d3d11.dll, aborting"); + goto done; + } + filter_sys_t *p_sys = calloc(1, sizeof(filter_sys_t)); if (!p_sys) - return VLC_ENOMEM; + goto done; + CopyInitCache(&p_sys->cache, p_filter->fmt_in.video.i_width ); vlc_mutex_init(&p_sys->staging_lock); + p_sys->hd3d_dll = hd3d_dll; p_filter->p_sys = p_sys; + err = VLC_SUCCESS; - return VLC_SUCCESS; +done: + if (err != VLC_SUCCESS) + { + if (hd3d_dll) + FreeLibrary(hd3d_dll); + } + return err;} + +static int OpenFromCPU( vlc_object_t *obj ) +{ + filter_t *p_filter = (filter_t *)obj; + int err = VLC_EGENERIC; + ID3D11Texture2D *texture = NULL; + filter_t *p_cpu_filter = NULL; + HINSTANCE hd3d_dll = NULL; + video_format_t fmt_staging; + + if ( p_filter->fmt_out.video.i_chroma != VLC_CODEC_D3D11_OPAQUE ) + return VLC_EGENERIC; + + if ( p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height + || p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width ) + return VLC_EGENERIC; + + switch( p_filter->fmt_in.video.i_chroma ) { + case VLC_CODEC_I420: + case VLC_CODEC_YV12: + case VLC_CODEC_NV12: + case VLC_CODEC_P010: + p_filter->pf_video_filter = NV12_D3D11_Filter; + break; + default: + return VLC_EGENERIC; + } + + picture_t *peek = filter_NewPicture(p_filter); + if (peek == NULL) + return VLC_EGENERIC; + if (!peek->p_sys) + { + msg_Dbg(p_filter, "D3D11 opaque without a texture"); + return VLC_EGENERIC; + } + + video_format_Init(&fmt_staging, 0); + + D3D11_TEXTURE2D_DESC texDesc; + ID3D11Texture2D_GetDesc( peek->p_sys->texture[KNOWN_DXGI_INDEX], &texDesc); + vlc_fourcc_t d3d_fourcc = DxgiFormatFourcc(texDesc.Format); + if (d3d_fourcc == 0) + goto done; + + picture_resource_t res; + res.pf_destroy = DestroyPicture; + res.p_sys = calloc(1, sizeof(picture_sys_t)); + if (res.p_sys == NULL) { + err = VLC_ENOMEM; + goto done; + } + res.p_sys->context = peek->p_sys->context; + res.p_sys->formatTexture = texDesc.Format; + + video_format_Copy(&fmt_staging, &p_filter->fmt_out.video); + fmt_staging.i_chroma = d3d_fourcc; + fmt_staging.i_height = texDesc.Height; + fmt_staging.i_width = texDesc.Width; + + picture_t *p_dst = picture_NewFromResource(&fmt_staging, &res); + if (p_dst == NULL) { + msg_Err(p_filter, "Failed to map create the temporary picture."); + goto done; + } + picture_Setup(p_dst, &p_dst->format); + + texDesc.MipLevels = 1; + //texDesc.SampleDesc.Count = 1; + texDesc.MiscFlags = 0; + texDesc.ArraySize = 1; + texDesc.Usage = D3D11_USAGE_STAGING; + texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + texDesc.BindFlags = 0; + texDesc.Height = p_dst->format.i_height; /* make sure we match picture_Setup() */ + + ID3D11Device *p_device; + ID3D11DeviceContext_GetDevice(peek->p_sys->context, &p_device); + HRESULT hr = ID3D11Device_CreateTexture2D( p_device, &texDesc, NULL, &texture); + ID3D11Device_Release(p_device); + if (FAILED(hr)) { + msg_Err(p_filter, "Failed to create a %s staging texture to extract surface pixels (hr=0x%0lx)", DxgiFormatToStr(texDesc.Format), hr ); + goto done; + } + + res.p_sys->texture[KNOWN_DXGI_INDEX] = texture; + ID3D11DeviceContext_AddRef(p_dst->p_sys->context); + + if ( p_filter->fmt_in.video.i_chroma != d3d_fourcc ) + { + p_cpu_filter = CreateFilter(VLC_OBJECT(p_filter), &p_filter->fmt_in, p_dst->format.i_chroma); + if (!p_cpu_filter) + goto done; + } + + hd3d_dll = LoadLibrary(TEXT("D3D11.DLL")); + if (unlikely(!hd3d_dll)) { + msg_Warn(p_filter, "cannot load d3d11.dll, aborting"); + goto done; + } + + filter_sys_t *p_sys = calloc(1, sizeof(filter_sys_t)); + if (!p_sys) { + err = VLC_ENOMEM; + goto done; + } + p_sys->filter = p_cpu_filter; + p_sys->staging_pic = p_dst; + p_sys->hd3d_dll = hd3d_dll; + p_filter->p_sys = p_sys; + err = VLC_SUCCESS; + +done: + video_format_Clean(&fmt_staging); + picture_Release(peek); + if (err != VLC_SUCCESS) + { + if (p_cpu_filter) + DeleteFilter( p_cpu_filter ); + if (texture) + ID3D11Texture2D_Release(texture); + if (hd3d_dll) + FreeLibrary(hd3d_dll); + } + return err; } static void CloseConverter( vlc_object_t *obj ) @@ -540,6 +804,30 @@ static void CloseConverter( vlc_object_t *obj ) vlc_mutex_destroy(&p_sys->staging_lock); if (p_sys->staging) ID3D11Texture2D_Release(p_sys->staging); + FreeLibrary(p_sys->hd3d_dll); free( p_sys ); p_filter->p_sys = NULL; } + +static void CloseFromCPU( vlc_object_t *obj ) +{ + filter_t *p_filter = (filter_t *)obj; + filter_sys_t *p_sys = (filter_sys_t*) p_filter->p_sys; + DeleteFilter(p_sys->filter); + picture_Release(p_sys->staging_pic); + FreeLibrary(p_sys->hd3d_dll); + free( p_sys ); + p_filter->p_sys = NULL; +} + +/***************************************************************************** + * Module descriptor. + *****************************************************************************/ +vlc_module_begin () + set_description( N_("Conversions from D3D11 to YUV") ) + set_capability( "video converter", 10 ) + set_callbacks( OpenConverter, CloseConverter ) + add_submodule() + set_callbacks( OpenFromCPU, CloseFromCPU ) + set_capability( "video converter", 10 ) +vlc_module_end () _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
