On Fri, 10 Jan 2020 at 10:41, Anton Khirnov <an...@khirnov.net> wrote:
> Quoting Artem Galin (2019-12-23 19:31:04) > > This enables DX11 support for QSV with higher priority than DX9. > > In case of multiple GPUs configuration, DX9 API does not allow to get > > access to QSV device in some cases - headless. > > Implementation based on DX11 resolves that restriction by enumerating > list of available GPUs and finding device with QSV support. > > > > Signed-off-by: Artem Galin <artem.ga...@gmail.com> > > --- > > libavcodec/qsv.c | 13 +++-- > > libavcodec/qsv_internal.h | 1 + > > libavutil/hwcontext_d3d11va.c | 57 +++++++++++++++++++++- > > libavutil/hwcontext_qsv.c | 89 +++++++++++++++++++++++++++++++---- > > libavutil/hwcontext_qsv.h | 1 + > > 5 files changed, 147 insertions(+), 14 deletions(-) > > > > diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c > > index b00e427435..33ac7a3373 100644 > > --- a/libavcodec/qsv.c > > +++ b/libavcodec/qsv.c > > @@ -414,7 +414,7 @@ static int ff_qsv_set_display_handle(AVCodecContext > *avctx, QSVSession *qs) > > int ff_qsv_init_internal_session(AVCodecContext *avctx, QSVSession *qs, > > const char *load_plugins, int gpu_copy) > > { > > - mfxIMPL impl = MFX_IMPL_AUTO_ANY; > > + mfxIMPL impl = MFX_IMPL_AUTO_ANY | MFX_IMPL_VIA_D3D11; > > mfxVersion ver = { { QSV_VERSION_MINOR, QSV_VERSION_MAJOR } > }; > > mfxInitParam init_par = { MFX_IMPL_AUTO_ANY }; > > > > @@ -504,6 +504,7 @@ static AVBufferRef *qsv_create_mids(AVBufferRef > *hw_frames_ref) > > for (i = 0; i < nb_surfaces; i++) { > > QSVMid *mid = &mids[i]; > > mid->handle = frames_hwctx->surfaces[i].Data.MemId; > > + mid->texture = frames_hwctx->texture; > > mid->hw_frames_ref = hw_frames_ref1; > > } > > > > @@ -713,7 +714,13 @@ static mfxStatus qsv_frame_unlock(mfxHDL pthis, > mfxMemId mid, mfxFrameData *ptr) > > static mfxStatus qsv_frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL > *hdl) > > { > > QSVMid *qsv_mid = (QSVMid*)mid; > > - *hdl = qsv_mid->handle; > > + if (qsv_mid->texture) { > > + mfxHDLPair *pair = (mfxHDLPair*)hdl; > > + pair->first = qsv_mid->texture; > > + pair->second = qsv_mid->handle; > > + } else { > > + *hdl = qsv_mid->handle; > > + } > > return MFX_ERR_NONE; > > } > > > > @@ -723,8 +730,8 @@ int ff_qsv_init_session_device(AVCodecContext > *avctx, mfxSession *psession, > > { > > static const mfxHandleType handle_types[] = { > > MFX_HANDLE_VA_DISPLAY, > > - MFX_HANDLE_D3D9_DEVICE_MANAGER, > > MFX_HANDLE_D3D11_DEVICE, > > + MFX_HANDLE_D3D9_DEVICE_MANAGER, > > }; > > AVHWDeviceContext *device_ctx = > (AVHWDeviceContext*)device_ref->data; > > AVQSVDeviceContext *device_hwctx = device_ctx->hwctx; > > diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h > > index 37559270e5..09425fb431 100644 > > --- a/libavcodec/qsv_internal.h > > +++ b/libavcodec/qsv_internal.h > > @@ -60,6 +60,7 @@ > > > > typedef struct QSVMid { > > AVBufferRef *hw_frames_ref; > > + void *texture; > > mfxHDL handle; > > > > AVFrame *locked_frame; > > diff --git a/libavutil/hwcontext_d3d11va.c > b/libavutil/hwcontext_d3d11va.c > > index 6670c47579..a08479fd96 100644 > > --- a/libavutil/hwcontext_d3d11va.c > > +++ b/libavutil/hwcontext_d3d11va.c > > @@ -244,7 +244,7 @@ static int d3d11va_frames_init(AVHWFramesContext > *ctx) > > return AVERROR(EINVAL); > > } > > > > - texDesc = (D3D11_TEXTURE2D_DESC){ > > + texDesc = (D3D11_TEXTURE2D_DESC) { > > .Width = ctx->width, > > .Height = ctx->height, > > .MipLevels = 1, > > @@ -510,6 +510,46 @@ static void d3d11va_device_uninit(AVHWDeviceContext > *hwdev) > > } > > } > > > > +static int d3d11va_device_find_qsv_adapter(AVHWDeviceContext *ctx, UINT > creationFlags) > > +{ > > + HRESULT hr; > > + IDXGIAdapter *adapter = NULL; > > + int adapter_id = 0; > > + int vendor_id = 0x8086; > > + IDXGIFactory2 *factory; > > + hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&factory); > > + while (IDXGIFactory2_EnumAdapters(factory, adapter_id++, &adapter) > != DXGI_ERROR_NOT_FOUND) > > + { > > + ID3D11Device* device = NULL; > > + DXGI_ADAPTER_DESC adapter_desc; > > + > > + hr = mD3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, > creationFlags, NULL, 0, D3D11_SDK_VERSION, &device, NULL, NULL); > > + if (FAILED(hr)) { > > + av_log(ctx, AV_LOG_ERROR, "D3D11CreateDevice returned > error\n"); > > + continue; > > + } > > + > > + hr = IDXGIAdapter2_GetDesc(adapter, &adapter_desc); > > + if (FAILED(hr)) { > > + av_log(ctx, AV_LOG_ERROR, "IDXGIAdapter2_GetDesc returned > error\n"); > > + continue; > > + } > > + > > + if(device) > > + ID3D11Device_Release(device); > > + > > + if (adapter) > > + IDXGIAdapter_Release(adapter); > > + > > + if (adapter_desc.VendorId == vendor_id) { > > + IDXGIFactory2_Release(factory); > > + return adapter_id - 1; > > + } > > + } > > + IDXGIFactory2_Release(factory); > > + return -1; > > +} > > + > > static int d3d11va_device_create(AVHWDeviceContext *ctx, const char > *device, > > AVDictionary *opts, int flags) > > { > > @@ -519,7 +559,9 @@ static int d3d11va_device_create(AVHWDeviceContext > *ctx, const char *device, > > IDXGIAdapter *pAdapter = NULL; > > ID3D10Multithread *pMultithread; > > UINT creationFlags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT; > > + int adapter = -1; > > int is_debug = !!av_dict_get(opts, "debug", NULL, 0); > > + int is_qsv = !!av_dict_get(opts, "d3d11va_qsv", NULL, 0); > > int ret; > > > > // (On UWP we can't check this.) > > @@ -538,11 +580,22 @@ static int d3d11va_device_create(AVHWDeviceContext > *ctx, const char *device, > > return AVERROR_UNKNOWN; > > } > > > > + if (is_qsv) { > > + adapter = d3d11va_device_find_qsv_adapter(ctx, creationFlags); > > + if (adapter < 0) { > > + av_log(ctx, AV_LOG_ERROR, "Failed to find DX11 adapter with > QSV support\n"); > > + return AVERROR_UNKNOWN; > > + } > > + } > > + > > if (device) { > > + adapter = atoi(device); > > + } > > + > > + if (adapter >= 0) { > > IDXGIFactory2 *pDXGIFactory; > > hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void > **)&pDXGIFactory); > > if (SUCCEEDED(hr)) { > > - int adapter = atoi(device); > > if (FAILED(IDXGIFactory2_EnumAdapters(pDXGIFactory, > adapter, &pAdapter))) > > pAdapter = NULL; > > IDXGIFactory2_Release(pDXGIFactory); > > diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c > > index b1b67400de..ae4247abf2 100644 > > --- a/libavutil/hwcontext_qsv.c > > +++ b/libavutil/hwcontext_qsv.c > > @@ -27,9 +27,13 @@ > > #include <pthread.h> > > #endif > > > > +#define COBJMACROS > > #if CONFIG_VAAPI > > #include "hwcontext_vaapi.h" > > #endif > > +#if CONFIG_D3D11VA > > +#include "hwcontext_d3d11va.h" > > +#endif > > #if CONFIG_DXVA2 > > #include "hwcontext_dxva2.h" > > #endif > > @@ -89,6 +93,9 @@ static const struct { > > #if CONFIG_VAAPI > > { MFX_HANDLE_VA_DISPLAY, AV_HWDEVICE_TYPE_VAAPI, > AV_PIX_FMT_VAAPI }, > > #endif > > +#if CONFIG_D3D11VA > > + { MFX_HANDLE_D3D11_DEVICE, AV_HWDEVICE_TYPE_D3D11VA, > AV_PIX_FMT_D3D11 }, > > +#endif > > #if CONFIG_DXVA2 > > { MFX_HANDLE_D3D9_DEVICE_MANAGER, AV_HWDEVICE_TYPE_DXVA2, > AV_PIX_FMT_DXVA2_VLD }, > > #endif > > @@ -229,9 +236,17 @@ static int qsv_init_child_ctx(AVHWFramesContext > *ctx) > > child_device_hwctx->display = (VADisplay)device_priv->handle; > > } > > #endif > > +#if CONFIG_D3D11VA > > + if (child_device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) { > > + AVD3D11VADeviceContext *child_device_hwctx = > child_device_ctx->hwctx; > > + ID3D11Device_AddRef((ID3D11Device*)device_priv->handle); > > + child_device_hwctx->device = (ID3D11Device*)device_priv->handle; > > + } > > +#endif > > #if CONFIG_DXVA2 > > if (child_device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) { > > AVDXVA2DeviceContext *child_device_hwctx = > child_device_ctx->hwctx; > > + > IDirect3DDeviceManager9_AddRef((IDirect3DDeviceManager9*)device_priv->handle); > > child_device_hwctx->devmgr = > (IDirect3DDeviceManager9*)device_priv->handle; > > } > > #endif > > @@ -255,6 +270,16 @@ static int qsv_init_child_ctx(AVHWFramesContext > *ctx) > > child_frames_ctx->width = FFALIGN(ctx->width, 16); > > child_frames_ctx->height = FFALIGN(ctx->height, 16); > > > > +#if CONFIG_D3D11VA > > + if (child_device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) { > > + AVD3D11VAFramesContext *child_frames_hwctx = > child_frames_ctx->hwctx; > > + child_frames_hwctx->MiscFlags |= D3D11_RESOURCE_MISC_SHARED; > > + if (hwctx->frame_type & > MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET) > > + child_frames_hwctx->BindFlags = D3D11_BIND_RENDER_TARGET ; > > + else > > + child_frames_hwctx->BindFlags = D3D11_BIND_DECODER; > > + } > > +#endif > > #if CONFIG_DXVA2 > > if (child_device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) { > > AVDXVA2FramesContext *child_frames_hwctx = > child_frames_ctx->hwctx; > > @@ -279,6 +304,18 @@ static int qsv_init_child_ctx(AVHWFramesContext > *ctx) > > hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET; > > } > > #endif > > +#if CONFIG_D3D11VA > > + if (child_device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) { > > + AVD3D11VAFramesContext *child_frames_hwctx = > child_frames_ctx->hwctx; > > + hwctx->texture = child_frames_hwctx->texture; > > + for (i = 0; i < ctx->initial_pool_size; i++) > > + s->surfaces_internal[i].Data.MemId = (mfxMemId)(int64_t)i; > > + if (child_frames_hwctx->BindFlags == D3D11_BIND_DECODER) > > + hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET; > > + else > > + hwctx->frame_type = > MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET; > > + } > > +#endif > > #if CONFIG_DXVA2 > > if (child_device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) { > > AVDXVA2FramesContext *child_frames_hwctx = > child_frames_ctx->hwctx; > > @@ -421,7 +458,16 @@ static mfxStatus frame_unlock(mfxHDL pthis, > mfxMemId mid, mfxFrameData *ptr) > > > > static mfxStatus frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl) > > { > > - *hdl = mid; > > + AVHWFramesContext *ctx = pthis; > > + AVQSVFramesContext *hwctx = ctx->hwctx; > > + > > + if (hwctx->texture) { > > + mfxHDLPair *pair = (mfxHDLPair*)hdl; > > + pair->first = hwctx->texture; > > + pair->second = mid; > > + } else { > > + *hdl = mid; > > + } > > return MFX_ERR_NONE; > > } > > > > @@ -492,7 +538,7 @@ static int > qsv_init_internal_session(AVHWFramesContext *ctx, > > > > err = MFXVideoVPP_Init(*session, &par); > > if (err != MFX_ERR_NONE) { > > - av_log(ctx, AV_LOG_VERBOSE, "Error opening the internal VPP > session." > > + av_log(ctx, AV_LOG_ERROR, "Error opening the internal VPP > session." > > "Surface upload/download will not be possible\n"); > > MFXClose(*session); > > *session = NULL; > > @@ -1074,7 +1120,7 @@ static void qsv_device_free(AVHWDeviceContext *ctx) > > av_freep(&priv); > > } > > > > -static mfxIMPL choose_implementation(const char *device) > > +static mfxIMPL choose_implementation(const char *device, enum > AVHWDeviceType child_device_type) > > { > > static const struct { > > const char *name; > > @@ -1103,6 +1149,10 @@ static mfxIMPL choose_implementation(const char > *device) > > impl = strtol(device, NULL, 0); > > } > > > > + if ( (child_device_type == AV_HWDEVICE_TYPE_D3D11VA) && (impl != > MFX_IMPL_SOFTWARE) ) { > > + impl |= MFX_IMPL_VIA_D3D11; > > + } > > + > > return impl; > > } > > > > @@ -1129,6 +1179,15 @@ static int > qsv_device_derive_from_child(AVHWDeviceContext *ctx, > > } > > break; > > #endif > > +#if CONFIG_D3D11VA > > + case AV_HWDEVICE_TYPE_D3D11VA: > > + { > > + AVD3D11VADeviceContext *child_device_hwctx = > child_device_ctx->hwctx; > > + handle_type = MFX_HANDLE_D3D11_DEVICE; > > + handle = (mfxHDL)child_device_hwctx->device; > > + } > > + break; > > +#endif > > #if CONFIG_DXVA2 > > case AV_HWDEVICE_TYPE_DXVA2: > > { > > @@ -1226,23 +1285,35 @@ static int qsv_device_create(AVHWDeviceContext > *ctx, const char *device, > > // possible, even when multiple devices and drivers are > available. > > av_dict_set(&child_device_opts, "kernel_driver", "i915", 0); > > av_dict_set(&child_device_opts, "driver", "iHD", 0); > > - } else if (CONFIG_DXVA2) > > + } else if (CONFIG_D3D11VA) { > > + child_device_type = AV_HWDEVICE_TYPE_D3D11VA; > > + av_dict_set(&child_device_opts, "d3d11va_qsv", "enabled", 0); > > + } else if (CONFIG_DXVA2) { > > child_device_type = AV_HWDEVICE_TYPE_DXVA2; > > - else { > > + } else { > > av_log(ctx, AV_LOG_ERROR, "No supported child device type is > enabled\n"); > > return AVERROR(ENOSYS); > > } > > > > ret = av_hwdevice_ctx_create(&priv->child_device_ctx, > child_device_type, > > e ? e->value : NULL, > child_device_opts, 0); > > - > > av_dict_free(&child_device_opts); > > - if (ret < 0) > > - return ret; > > + if (ret < 0) { > > + if (CONFIG_DXVA2 && (child_device_type == > AV_HWDEVICE_TYPE_D3D11VA)) { > > + // in case of d3d11va fail, try one more chance to create > device via dxva2 > > + child_device_type = AV_HWDEVICE_TYPE_DXVA2; > > + child_device_opts = NULL; > > + ret = av_hwdevice_ctx_create(&priv->child_device_ctx, > child_device_type, > > + e ? e->value : NULL, child_device_opts, 0); > > + } > > + if (ret < 0) { > > + return ret; > > + } > > + } > > > > child_device = (AVHWDeviceContext*)priv->child_device_ctx->data; > > > > - impl = choose_implementation(device); > > + impl = choose_implementation(device, child_device_type); > > > > return qsv_device_derive_from_child(ctx, impl, child_device, 0); > > } > > diff --git a/libavutil/hwcontext_qsv.h b/libavutil/hwcontext_qsv.h > > index b98d611cfc..f5a9691949 100644 > > --- a/libavutil/hwcontext_qsv.h > > +++ b/libavutil/hwcontext_qsv.h > > @@ -42,6 +42,7 @@ typedef struct AVQSVDeviceContext { > > typedef struct AVQSVFramesContext { > > mfxFrameSurface1 *surfaces; > > int nb_surfaces; > > + void *texture; > > This is a public struct, so new fields have to be added at the end, > otherwise it's an ABI break. > > Also, API changes require a minor library version bump and an APIchanges > entry. Some documentation would be nice too. > > Done. Sorry for the thread duplication, something wrong with replying to this thread with new patch version. Updated patch is available by link below: https://patchwork.ffmpeg.org/project/ffmpeg/patch/20200123151813.31739-1-artem.ga...@gmail.com/ Thanks, Artem. _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".