lavu/qsv: add log message for libmfx version
[ffmpeg.git] / libavutil / hwcontext_d3d11va.c
index 5432dd8..0a8cc5b 100644 (file)
@@ -16,6 +16,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "config.h"
+
 #include <windows.h>
 
 // Include thread.h before redefining _WIN32_WINNT, to get
 #include <d3d11.h>
 #include <dxgi1_2.h>
 
+#if HAVE_DXGIDEBUG_H
+#include <dxgidebug.h>
+#endif
+
 #include "avassert.h"
 #include "common.h"
 #include "hwcontext.h"
@@ -50,7 +56,7 @@ static PFN_D3D11_CREATE_DEVICE mD3D11CreateDevice;
 
 static av_cold void load_functions(void)
 {
-#if HAVE_LOADLIBRARY
+#if !HAVE_UWP
     // We let these "leak" - this is fine, as unloading has no great benefit, and
     // Windows will mark a DLL as loaded forever if its internal refcount overflows
     // from too many LoadLibrary calls.
@@ -83,8 +89,11 @@ static const struct {
     DXGI_FORMAT d3d_format;
     enum AVPixelFormat pix_fmt;
 } supported_formats[] = {
-    { DXGI_FORMAT_NV12, AV_PIX_FMT_NV12 },
-    { DXGI_FORMAT_P010, AV_PIX_FMT_P010 },
+    { DXGI_FORMAT_NV12,         AV_PIX_FMT_NV12 },
+    { DXGI_FORMAT_P010,         AV_PIX_FMT_P010 },
+    // Special opaque formats. The pix_fmt is merely a place holder, as the
+    // opaque format cannot be accessed directly.
+    { DXGI_FORMAT_420_OPAQUE,   AV_PIX_FMT_YUV420P },
 };
 
 static void d3d11va_default_lock(void *ctx)
@@ -104,9 +113,11 @@ static void d3d11va_frames_uninit(AVHWFramesContext *ctx)
 
     if (frames_hwctx->texture)
         ID3D11Texture2D_Release(frames_hwctx->texture);
+    frames_hwctx->texture = NULL;
 
     if (s->staging_texture)
         ID3D11Texture2D_Release(s->staging_texture);
+    s->staging_texture = NULL;
 }
 
 static void free_texture(void *opaque, uint8_t *data)
@@ -237,17 +248,6 @@ static int d3d11va_frames_init(AVHWFramesContext *ctx)
         }
     }
 
-    texDesc.ArraySize       = 1;
-    texDesc.Usage           = D3D11_USAGE_STAGING;
-    texDesc.BindFlags       = 0;
-    texDesc.CPUAccessFlags  = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
-    texDesc.MiscFlags       = 0;
-    hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &s->staging_texture);
-    if (FAILED(hr)) {
-        av_log(ctx, AV_LOG_ERROR, "Could not create the staging texture (%lx)\n", (long)hr);
-        return AVERROR_UNKNOWN;
-    }
-
     ctx->internal->pool_internal = av_buffer_pool_init2(sizeof(AVD3D11FrameDescriptor),
                                                         ctx, d3d11va_pool_alloc, NULL);
     if (!ctx->internal->pool_internal)
@@ -279,6 +279,7 @@ static int d3d11va_transfer_get_formats(AVHWFramesContext *ctx,
                                         enum AVHWFrameTransferDirection dir,
                                         enum AVPixelFormat **formats)
 {
+    D3D11VAFramesContext *s = ctx->internal->priv;
     enum AVPixelFormat *fmts;
 
     fmts = av_malloc_array(2, sizeof(*fmts));
@@ -288,11 +289,40 @@ static int d3d11va_transfer_get_formats(AVHWFramesContext *ctx,
     fmts[0] = ctx->sw_format;
     fmts[1] = AV_PIX_FMT_NONE;
 
+    // Don't signal support for opaque formats. Actual access would fail.
+    if (s->format == DXGI_FORMAT_420_OPAQUE)
+        fmts[0] = AV_PIX_FMT_NONE;
+
     *formats = fmts;
 
     return 0;
 }
 
+static int d3d11va_create_staging_texture(AVHWFramesContext *ctx)
+{
+    AVD3D11VADeviceContext *device_hwctx = ctx->device_ctx->hwctx;
+    D3D11VAFramesContext              *s = ctx->internal->priv;
+    HRESULT hr;
+    D3D11_TEXTURE2D_DESC texDesc = {
+        .Width          = ctx->width,
+        .Height         = ctx->height,
+        .MipLevels      = 1,
+        .Format         = s->format,
+        .SampleDesc     = { .Count = 1 },
+        .ArraySize      = 1,
+        .Usage          = D3D11_USAGE_STAGING,
+        .CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE,
+    };
+
+    hr = ID3D11Device_CreateTexture2D(device_hwctx->device, &texDesc, NULL, &s->staging_texture);
+    if (FAILED(hr)) {
+        av_log(ctx, AV_LOG_ERROR, "Could not create the staging texture (%lx)\n", (long)hr);
+        return AVERROR_UNKNOWN;
+    }
+
+    return 0;
+}
+
 static void fill_texture_ptrs(uint8_t *data[4], int linesize[4],
                               AVHWFramesContext *ctx,
                               D3D11_TEXTURE2D_DESC *desc,
@@ -318,7 +348,7 @@ static int d3d11va_transfer_data(AVHWFramesContext *ctx, AVFrame *dst,
     // (The interface types are compatible.)
     ID3D11Resource *texture = (ID3D11Resource *)(ID3D11Texture2D *)frame->data[0];
     int index = (intptr_t)frame->data[1];
-    ID3D11Resource *staging = (ID3D11Resource *)s->staging_texture;
+    ID3D11Resource *staging;
     int w = FFMIN(dst->width,  src->width);
     int h = FFMIN(dst->height, src->height);
     uint8_t *map_data[4];
@@ -332,6 +362,14 @@ static int d3d11va_transfer_data(AVHWFramesContext *ctx, AVFrame *dst,
 
     device_hwctx->lock(device_hwctx->lock_ctx);
 
+    if (!s->staging_texture) {
+        int res = d3d11va_create_staging_texture(ctx);
+        if (res < 0)
+            return res;
+    }
+
+    staging = (ID3D11Resource *)s->staging_texture;
+
     ID3D11Texture2D_GetDesc(s->staging_texture, &desc);
 
     if (download) {
@@ -444,8 +482,18 @@ static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
     IDXGIAdapter           *pAdapter = NULL;
     ID3D10Multithread      *pMultithread;
     UINT creationFlags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
+    int is_debug       = !!av_dict_get(opts, "debug", NULL, 0);
     int ret;
 
+    // (On UWP we can't check this.)
+#if !HAVE_UWP
+    if (!LoadLibrary("d3d11_1sdklayers.dll"))
+        is_debug = 0;
+#endif
+
+    if (is_debug)
+        creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
+
     if ((ret = ff_thread_once(&functions_loaded, load_functions)) != 0)
         return AVERROR_UNKNOWN;
     if (!mD3D11CreateDevice || !mCreateDXGIFactory) {
@@ -479,6 +527,22 @@ static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device,
         ID3D10Multithread_Release(pMultithread);
     }
 
+#if !HAVE_UWP && HAVE_DXGIDEBUG_H
+    if (is_debug) {
+        HANDLE dxgidebug_dll = LoadLibrary("dxgidebug.dll");
+        if (dxgidebug_dll) {
+            HRESULT (WINAPI  * pf_DXGIGetDebugInterface)(const GUID *riid, void **ppDebug)
+                = (void *)GetProcAddress(dxgidebug_dll, "DXGIGetDebugInterface");
+            if (pf_DXGIGetDebugInterface) {
+                IDXGIDebug *dxgi_debug = NULL;
+                hr = pf_DXGIGetDebugInterface(&IID_IDXGIDebug, (void**)&dxgi_debug);
+                if (SUCCEEDED(hr) && dxgi_debug)
+                    IDXGIDebug_ReportLiveObjects(dxgi_debug, DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_ALL);
+            }
+        }
+    }
+#endif
+
     return 0;
 }