[vlc-commits] [Git][videolan/vlc][3.0.x] 13 commits: d3d11_fmt: allow build D3D11 modules with C++

Jean-Baptiste Kempf (@jbk) gitlab at videolan.org
Wed Apr 26 16:12:37 UTC 2023



Jean-Baptiste Kempf pushed to branch 3.0.x at VideoLAN / VLC


Commits:
371c0787 by Steve Lhomme at 2023-04-26T14:23:59+00:00
d3d11_fmt: allow build D3D11 modules with C++

as in 6b7a6d86ae30109bed34fec0b5ffc1f013ca4a81

- - - - -
490bcd81 by Steve Lhomme at 2023-04-26T14:23:59+00:00
d3d11_fmt: avoid forcing COBJMACROS on files including the header

(cherry picked from commit 65048467c5f394fcc5c577e69a732bdfd1f1dd70) (edited)

edited:
* FindD3D11Format doesn't use an undef in 4.0

Signed-off-by: Steve Lhomme <robux4 at ycbcr.xyz>

- - - - -
188c5b96 by Steve Lhomme at 2023-04-26T14:23:59+00:00
direct3d11: get source D3D11_TEXTURE2D_DESC early

(cherry picked from commit e4ba931b3d2a6604471f196ddabdedcc9d181f8a) (edited)

edited:
* the direct3d11 code is in C++ in 4.0 (GetDesc called directly)
* the pic_quad is split in generic and D3D11 parts in 4.0

Signed-off-by: Steve Lhomme <robux4 at ycbcr.xyz>

- - - - -
aa52c643 by Steve Lhomme at 2023-04-26T14:23:59+00:00
win32/common: only get the size of the Window

The top/left is always zero.

- - - - -
254d230f by Steve Lhomme at 2023-04-26T14:23:59+00:00
direct3d11: move code to avoid forward declaration

No functional changes.

- - - - -
7ad94cd1 by Steve Lhomme at 2023-04-26T14:23:59+00:00
vout/win32: allow forcing the source size

(cherry picked from commit d4374090ee1ae8a28b46236a89418df3a722871c) (edited)

edited:
* the format is not passed to CommonInit() in 3.0

Signed-off-by: Steve Lhomme <robux4 at ycbcr.xyz>

- - - - -
92e523bd by Steve Lhomme at 2023-04-26T14:23:59+00:00
direct3d11: keep the format used to create the pool

- - - - -
fb2552f0 by Steve Lhomme at 2023-04-26T14:23:59+00:00
direct3d11: add an option to select the upscaling quality

D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT is smoother but a bit slower.
Users may prefer sharper/blockier outputs.

We only force point sampler to the blocky version as SPUs also use this
to make the text smoother.

(cherry picked from commit b86a57876f2cff622be637a66aaf6973ec2018b5)

Signed-off-by: Steve Lhomme <robux4 at ycbcr.xyz>

- - - - -
a6870065 by Steve Lhomme at 2023-04-26T14:23:59+00:00
direct3d11: keep the format used with the pic_quad

(cherry picked from commit 794d897d07ff45b0c60bcbddec1e0705aa157853)

Signed-off-by: Steve Lhomme <robux4 at ycbcr.xyz>

- - - - -
3b520d80 by Steve Lhomme at 2023-04-26T14:23:59+00:00
direct3d11: add video processor based scaler

The VideoProcessor may use some special scaling in hardware that might do a
better job than the linear sampler in the shader.

Co-authored-by: Chilledheart <hukeyue at hotmail.com>

(cherry picked from commit 1f7f849ce18cbdd47c1bdf0a4ffcb0dbdbb6aa6e) (edited)

edited:
* 3.0 doesn't have DXGI_MAX_SHADER_VIEW
* 3.0 doesn't have DXGI_RGB_FORMAT or DXGI_YUV_FORMAT
* 3.0 doesn't have DXGI_CHROMA_GPU
* use a memcmp of the vout_display_place_t instead of vout_display_PlaceEquals()
* pass a vout_display_cfg_t instead of vout_display_placement which does
  not exist in 3.0
* set is_display_filled instead of VLC_VIDEO_FIT_SMALLER
* D3D11_AllocateResourceView is called D3D11_AllocateShaderView in 3.0
* 3.0 uses a picture_sys_t instead of picture_sys_d3d11_t
* 4.0 also has the meson changes

Signed-off-by: Steve Lhomme <robux4 at ycbcr.xyz>

- - - - -
5f10bc7c by Steve Lhomme at 2023-04-26T14:23:59+00:00
direct3d11: use NVIDIA super-resolution upscaler

Co-authored-by: Steve Lhomme <robux4 at ycbcr.xyz>

(cherry picked from commit beac9098dbe49c6e18e842c19dd773c1b395ddef) (edited)

edited:
* the direct3d11 is in C++ in4.0
* 3.0 doesn't have DXGI_RGB_FORMAT or DXGI_YUV_FORMAT
* 3.0 doesn't have DXGI_CHROMA_GPU
* the d3d_dev is a pointer in 4.0

Signed-off-by: Steve Lhomme <robux4 at ycbcr.xyz>

- - - - -
467cd307 by Steve Lhomme at 2023-04-26T14:23:59+00:00
direct3d11: add Intel based super resolution

(cherry picked from commit 8892ebd6f1735fde6433473e7737767733a180ae)

Signed-off-by: Steve Lhomme <robux4 at ycbcr.xyz>

- - - - -
56222b92 by Steve Lhomme at 2023-04-26T14:23:59+00:00
direct3d11: remove unneeded forward declaration

- - - - -


8 changed files:

- modules/video_chroma/d3d11_fmt.c
- modules/video_chroma/d3d11_fmt.h
- modules/video_output/Makefile.am
- modules/video_output/win32/common.c
- modules/video_output/win32/common.h
- + modules/video_output/win32/d3d11_scaler.cpp
- + modules/video_output/win32/d3d11_scaler.h
- modules/video_output/win32/direct3d11.c


Changes:

=====================================
modules/video_chroma/d3d11_fmt.c
=====================================
@@ -503,6 +503,14 @@ done:
     return result;
 }
 
+bool DeviceSupportsFormat(ID3D11Device *d3ddevice, DXGI_FORMAT format, UINT supportFlags)
+{
+    UINT i_formatSupport;
+    return SUCCEEDED( ID3D11Device_CheckFormatSupport(d3ddevice, format,
+                                                      &i_formatSupport) )
+            && ( i_formatSupport & supportFlags ) == supportFlags;
+}
+
 #undef FindD3D11Format
 const d3d_format_t *FindD3D11Format(vlc_object_t *o,
                                     d3d11_device_t *d3d_dev,


=====================================
modules/video_chroma/d3d11_fmt.h
=====================================
@@ -28,6 +28,15 @@
 
 #include "dxgi_fmt.h"
 
+#ifdef __cplusplus
+extern "C" {
+
+#ifndef IID_GRAPHICS_PPV_ARGS
+#define IID_GRAPHICS_PPV_ARGS(ppType) IID_PPV_ARGS(ppType)
+#endif
+
+#endif
+
 DEFINE_GUID(GUID_CONTEXT_MUTEX, 0x472e8835, 0x3f8e, 0x4f93, 0xa0, 0xcb, 0x25, 0x79, 0x77, 0x6c, 0xed, 0x86);
 
 /* see https://msdn.microsoft.com/windows/hardware/commercialize/design/compatibility/device-graphics */
@@ -121,14 +130,7 @@ int D3D11CheckDriverVersion(const d3d11_device_t *, UINT vendorId,
 void D3D11_GetDriverVersion(vlc_object_t *, d3d11_device_t *);
 #define D3D11_GetDriverVersion(a,b) D3D11_GetDriverVersion(VLC_OBJECT(a),b)
 
-static inline bool DeviceSupportsFormat(ID3D11Device *d3ddevice,
-                                        DXGI_FORMAT format, UINT supportFlags)
-{
-    UINT i_formatSupport;
-    return SUCCEEDED( ID3D11Device_CheckFormatSupport(d3ddevice, format,
-                                                      &i_formatSupport) )
-            && ( i_formatSupport & supportFlags ) == supportFlags;
-}
+bool DeviceSupportsFormat(ID3D11Device *d3ddevice, DXGI_FORMAT format, UINT supportFlags);
 
 const d3d_format_t *FindD3D11Format(vlc_object_t *,
                                     d3d11_device_t*,
@@ -163,4 +165,8 @@ static inline void d3d11_device_unlock(d3d11_device_t *d3d_dev)
         ReleaseMutex( d3d_dev->context_mutex );
 }
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* include-guard */


=====================================
modules/video_output/Makefile.am
=====================================
@@ -278,7 +278,8 @@ endif
 libdirect3d11_plugin_la_SOURCES = video_output/win32/direct3d11.c \
  video_output/win32/d3d11_quad.c video_output/win32/d3d11_quad.h \
  video_output/win32/d3d11_shaders.c video_output/win32/d3d11_shaders.h \
- video_output/win32/common.c video_output/win32/common.h
+ video_output/win32/common.c video_output/win32/common.h \
+ video_output/win32/d3d11_scaler.cpp video_output/win32/d3d11_scaler.h
 libdirect3d11_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) \
  -DMODULE_NAME_IS_direct3d11
 libdirect3d11_plugin_la_LIBADD = libchroma_copy.la libd3d11_common.la $(LIBCOM) -luuid


=====================================
modules/video_output/win32/common.c
=====================================
@@ -55,9 +55,14 @@ static void CommonChangeThumbnailClip(vout_display_t *, bool show);
 #if !VLC_WINSTORE_APP
 static int  CommonControlSetFullscreen(vout_display_t *, bool is_fullscreen);
 
-static bool GetRect(const vout_display_sys_t *sys, RECT *out)
+static bool GetWindowSize(const vout_display_sys_t *sys, UINT *w, UINT *h)
 {
-    return GetClientRect(sys->hwnd, out);
+    RECT out;
+    if (!GetClientRect(sys->hwnd, &out))
+        return false;
+    *w = out.right;  // out.left is zero
+    *h = out.bottom; // out.top is zero
+    return true;
 }
 #endif
 
@@ -87,7 +92,7 @@ int CommonInit(vout_display_t *vd)
     sys->pf_GetPictureWidth  = GetPictureWidth;
     sys->pf_GetPictureHeight = GetPictureHeight;
 #if !VLC_WINSTORE_APP
-    sys->pf_GetRect = GetRect;
+    sys->pf_GetWindowSize = GetWindowSize;
     SetRectEmpty(&sys->rect_display);
     SetRectEmpty(&sys->rect_parent);
 
@@ -114,6 +119,8 @@ int CommonInit(vout_display_t *vd)
     cfg.width  = vd->cfg->display.width;
     cfg.height = vd->cfg->display.height;
 
+    sys->src_fmt = &vd->source;
+
     event_hwnd_t hwnd;
     if (EventThreadStart(sys->event, &hwnd, &cfg))
         return VLC_EGENERIC;
@@ -156,13 +163,12 @@ void UpdateRects(vout_display_t *vd,
     bool is_forced)
 {
     vout_display_sys_t *sys = vd->sys;
-    const video_format_t *source = &vd->source;
+    const video_format_t *source = sys->src_fmt;
 #define rect_src sys->rect_src
 #define rect_src_clipped sys->rect_src_clipped
 #define rect_dest sys->rect_dest
 #define rect_dest_clipped sys->rect_dest_clipped
 
-    RECT  rect;
     POINT point;
 
     /* */
@@ -170,7 +176,8 @@ void UpdateRects(vout_display_t *vd,
         cfg = vd->cfg;
 
     /* Retrieve the window size */
-    if (!sys->pf_GetRect(sys, &rect))
+    UINT window_width, window_height;
+    if (!sys->pf_GetWindowSize(sys, &window_width, &window_height))
         return;
 
     /* Retrieve the window position */
@@ -186,27 +193,31 @@ void UpdateRects(vout_display_t *vd,
     if (unlikely(!sys->event)) // external rendering
     {
         has_moved = false;
-        is_resized = rect.right != (sys->rect_display.right - sys->rect_display.left) ||
-            rect.bottom != (sys->rect_display.bottom - sys->rect_display.top);
-        sys->rect_display = rect;
+        is_resized =
+            window_width  != (UINT)(sys->rect_display.right - sys->rect_display.left) ||
+            window_height != (UINT)(sys->rect_display.bottom - sys->rect_display.top);
+        sys->rect_display.left = 0;
+        sys->rect_display.top = 0;
+        sys->rect_display.right = window_width;
+        sys->rect_display.bottom = window_height;
     }
 #if !VLC_WINSTORE_APP
     else
     {
         EventThreadUpdateWindowPosition(sys->event, &has_moved, &is_resized,
             point.x, point.y,
-            rect.right, rect.bottom);
+            window_width, window_height);
     }
 #endif
     if (is_resized)
-        vout_display_SendEventDisplaySize(vd, rect.right, rect.bottom);
+        vout_display_SendEventDisplaySize(vd, window_width, window_height);
     if (!is_forced && !has_moved && !is_resized)
         return;
 
     /* Update the window position and size */
     vout_display_cfg_t place_cfg = *cfg;
-    place_cfg.display.width = rect.right;
-    place_cfg.display.height = rect.bottom;
+    place_cfg.display.width = window_width;
+    place_cfg.display.height = window_height;
 
 #if (defined(MODULE_NAME_IS_glwin32))
     /* Reverse vertical alignment as the GL tex are Y inverted */


=====================================
modules/video_output/win32/common.h
=====================================
@@ -67,6 +67,7 @@ typedef struct vout_display_sys_win32_t
     RECT         rect_src_clipped;
     RECT         rect_dest;
     RECT         rect_dest_clipped;
+    const video_format_t *src_fmt;
 
     picture_pool_t *pool;
 
@@ -79,7 +80,7 @@ typedef struct vout_display_sys_win32_t
     int  i_align_dest_boundary;
     int  i_align_dest_size;
 
-    bool (*pf_GetRect)(const struct vout_display_sys_win32_t *p_sys, RECT *out);
+    bool (*pf_GetWindowSize)(const struct vout_display_sys_win32_t *p_sys, UINT *w, UINT *h);
     unsigned int (*pf_GetPictureWidth) (const vout_display_t *);
     unsigned int (*pf_GetPictureHeight)(const vout_display_t *);
 } vout_display_sys_win32_t;


=====================================
modules/video_output/win32/d3d11_scaler.cpp
=====================================
@@ -0,0 +1,442 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*****************************************************************************
+ * d3d11_scaler: Direct3D11 VideoProcessor based output scaling
+ *****************************************************************************
+ * Copyright © 2023 Videolabs, VLC authors and VideoLAN
+ *
+ * Authors: Chilledheart <hukeyue at hotmail.com>
+ *          Steve Lhomme <robux4 at videolabs.io>
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "d3d11_scaler.h"
+
+#include <new>
+#include <wrl/client.h>
+using Microsoft::WRL::ComPtr;
+
+struct d3d11_scaler
+{
+    bool                            usable = false;
+    const d3d_format_t              *d3d_fmt = nullptr;
+    vout_display_place_t            place = {};
+    bool                            super_res = false;
+    bool                            upscaling = false;
+    UINT                            Width  = 0;
+    UINT                            Height = 0;
+    ComPtr<ID3D11VideoDevice>               d3dviddev;
+    ComPtr<ID3D11VideoContext>              d3dvidctx;
+    ComPtr<ID3D11VideoProcessorEnumerator>  enumerator;
+    ComPtr<ID3D11VideoProcessor>            processor;
+    ComPtr<ID3D11VideoProcessorOutputView>  outputView;
+    ID3D11ShaderResourceView                *SRVs[D3D11_MAX_SHADER_VIEW] = {};
+};
+
+static const d3d_format_t *GetDirectRenderingFormat(vlc_object_t *vd, d3d11_device_t *d3d_dev, vlc_fourcc_t i_src_chroma)
+{
+    UINT supportFlags = D3D11_FORMAT_SUPPORT_SHADER_LOAD | D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_INPUT;
+    return (FindD3D11Format)( vd, d3d_dev, i_src_chroma, false, 0, 0, 0, is_d3d11_opaque(i_src_chroma), supportFlags );
+}
+
+d3d11_scaler *D3D11_UpscalerCreate(vlc_object_t *vd, d3d11_device_t *d3d_dev, vlc_fourcc_t i_chroma,
+                                   bool super_res)
+{
+    bool canProcess = !super_res;
+    // NVIDIA 530+ driver
+    if (d3d_dev->adapterDesc.VendorId == GPU_MANUFACTURER_NVIDIA &&
+        (d3d_dev->WDDM.revision * 10000 + d3d_dev->WDDM.build) > 153000)
+    {
+        // TODO refine which GPU can do it
+        canProcess = true;
+    }
+    else if (d3d_dev->adapterDesc.VendorId == GPU_MANUFACTURER_INTEL)
+    {
+        // TODO refine which GPU and drivers can do it
+        canProcess = true;
+    }
+
+    if (!canProcess)
+    {
+        msg_Err(vd, "Super Resolution filter not supported");
+        return nullptr;
+    }
+
+    const d3d_format_t *fmt = GetDirectRenderingFormat(vd, d3d_dev, i_chroma);
+    if (fmt == nullptr || fmt->formatTexture == DXGI_FORMAT_UNKNOWN)
+    {
+        msg_Warn(vd, "chroma upscale of %4.4s not supported", (char*)&i_chroma);
+        return nullptr;
+    }
+
+    d3d11_scaler *scaleProc = new (std::nothrow) d3d11_scaler;
+    if (unlikely(scaleProc == nullptr))
+        return nullptr;
+
+    HRESULT hr;
+    hr = d3d_dev->d3ddevice->QueryInterface(IID_GRAPHICS_PPV_ARGS(&scaleProc->d3dviddev));
+    if (unlikely(FAILED(hr)))
+    {
+        msg_Err(vd, "Could not Query ID3D11VideoDevice Interface. (hr=0x%lX)", hr);
+        goto error;
+    }
+
+    hr = d3d_dev->d3dcontext->QueryInterface(IID_GRAPHICS_PPV_ARGS(&scaleProc->d3dvidctx));
+    if (unlikely(FAILED(hr)))
+    {
+        msg_Err(vd, "Could not Query ID3D11VideoContext Interface. (hr=0x%lX)", hr);
+        goto error;
+    }
+
+    scaleProc->d3d_fmt = fmt;
+    scaleProc->super_res = super_res;
+    return scaleProc;
+error:
+    delete scaleProc;
+    return nullptr;
+}
+
+static void ReleaseSRVs(d3d11_scaler *scaleProc)
+{
+    for (size_t i=0; i<ARRAY_SIZE(scaleProc->SRVs); i++)
+    {
+        if (scaleProc->SRVs[i])
+        {
+            scaleProc->SRVs[i]->Release();
+            scaleProc->SRVs[i] = nullptr;
+        }
+    }
+}
+
+int D3D11_UpscalerUpdate(vlc_object_t *vd, d3d11_scaler *scaleProc, d3d11_device_t*d3d_dev,
+                         const video_format_t *fmt, video_format_t *quad_fmt,
+                         const vout_display_cfg_t *cfg)
+{
+    HRESULT hr;
+    ID3D11Texture2D *_upscaled[D3D11_MAX_SHADER_VIEW];
+    ComPtr<ID3D11Texture2D> upscaled;
+    D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outDesc{ };
+    D3D11_VIDEO_COLOR black{};
+    black.RGBA.A = 1.f;
+    bool upscale = false;
+
+    vout_display_place_t place{};
+    auto display = *cfg;
+    display.is_display_filled = true;
+    vout_display_PlacePicture(&place, fmt, &display, true);
+
+    unsigned out_width, out_height;
+    out_width  = (display.display.width + (scaleProc->d3d_fmt->widthDenominator-1)) & ~(scaleProc->d3d_fmt->widthDenominator-1);
+    out_height = (display.display.height + (scaleProc->d3d_fmt->heightDenominator-1)) & ~(scaleProc->d3d_fmt->heightDenominator-1);
+
+    quad_fmt->i_x_offset = 0;
+    quad_fmt->i_width = quad_fmt->i_visible_width = out_width;
+    quad_fmt->i_y_offset = 0;
+    quad_fmt->i_height = quad_fmt->i_visible_height = out_height;
+
+    if (scaleProc->Width == out_width && scaleProc->Height == out_height &&
+        memcmp(&scaleProc->place, &place, sizeof(place)) == 0)
+        // do nothing
+        return VLC_SUCCESS;
+    scaleProc->place = place;
+
+    scaleProc->usable = false;
+
+    if (scaleProc->enumerator.Get() == nullptr)
+    {
+        d3d11_device_lock(d3d_dev);
+        D3D11_VIDEO_PROCESSOR_CONTENT_DESC processorDesc{};
+        processorDesc.InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE;
+        processorDesc.InputFrameRate = {
+            .Numerator   = fmt->i_frame_rate,
+            .Denominator = fmt->i_frame_rate_base,
+        };
+        processorDesc.InputWidth   = fmt->i_width;
+        processorDesc.InputHeight  = fmt->i_height;
+        processorDesc.OutputWidth  = out_width;
+        processorDesc.OutputHeight = out_height;
+        processorDesc.OutputFrameRate = {
+            .Numerator   = fmt->i_frame_rate,
+            .Denominator = fmt->i_frame_rate_base,
+        };
+        processorDesc.Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL;
+        hr = scaleProc->d3dviddev->CreateVideoProcessorEnumerator(&processorDesc, &scaleProc->enumerator);
+        if (FAILED(hr))
+        {
+            msg_Dbg(vd, "Can't get a video processor for the video (error 0x%lx).", hr);
+            d3d11_device_unlock(d3d_dev);
+            goto done_super;
+        }
+
+        hr = scaleProc->d3dviddev->CreateVideoProcessor(scaleProc->enumerator.Get(), 0,
+                                                        &scaleProc->processor);
+        d3d11_device_unlock(d3d_dev);
+        if (FAILED(hr))
+        {
+            msg_Dbg(vd, "failed to create the processor (error 0x%lx).", hr);
+            goto done_super;
+        }
+    }
+
+    if (scaleProc->Width != out_width || scaleProc->Height != out_height )
+    {
+        scaleProc->Width  = out_width;
+        scaleProc->Height = out_height;
+
+        // we need a texture that will receive the upscale version
+        D3D11_TEXTURE2D_DESC texDesc;
+        ZeroMemory(&texDesc, sizeof(texDesc));
+        texDesc.MipLevels = 1;
+        texDesc.SampleDesc.Count = 1;
+        texDesc.MiscFlags = 0;
+        texDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
+        texDesc.Usage = D3D11_USAGE_DEFAULT;
+        texDesc.CPUAccessFlags = 0;
+        texDesc.ArraySize = 1;
+        texDesc.Format = scaleProc->d3d_fmt->formatTexture;
+        texDesc.Width = scaleProc->Width;
+        texDesc.Height = scaleProc->Height;
+        hr = d3d_dev->d3ddevice->CreateTexture2D(&texDesc, nullptr, upscaled.GetAddressOf());
+        if (FAILED(hr))
+        {
+            msg_Err(vd, "Failed to create the upscale texture. (hr=0x%lX)", hr);
+            goto done_super;
+        }
+        msg_Dbg(vd, "upscale resolution %ux%u", texDesc.Width, texDesc.Height);
+
+        outDesc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D;
+        outDesc.Texture2D.MipSlice = 0;
+
+        hr = scaleProc->d3dviddev->CreateVideoProcessorOutputView(
+                                                                upscaled.Get(),
+                                                                scaleProc->enumerator.Get(),
+                                                                &outDesc,
+                                                                scaleProc->outputView.ReleaseAndGetAddressOf());
+        if (FAILED(hr))
+        {
+            msg_Dbg(vd,"Failed to create processor output. (hr=0x%lX)", hr);
+            goto done_super;
+        }
+
+        ReleaseSRVs(scaleProc);
+        _upscaled[0] = upscaled.Get();
+        _upscaled[1] = upscaled.Get();
+        _upscaled[2] = upscaled.Get();
+        _upscaled[3] = upscaled.Get();
+        if ((D3D11_AllocateShaderView)(vd, d3d_dev->d3ddevice, scaleProc->d3d_fmt,
+                                    _upscaled, 0, scaleProc->SRVs) != VLC_SUCCESS)
+            goto done_super;
+    }
+
+    RECT srcRect;
+    srcRect.left   = fmt->i_x_offset;
+    srcRect.top    = fmt->i_y_offset;
+    srcRect.right  = srcRect.left + fmt->i_visible_width;
+    srcRect.bottom = srcRect.top  + fmt->i_visible_height;
+
+    RECT dstRect;
+    dstRect.left   = place.x;
+    dstRect.top    = place.y;
+    dstRect.right  = dstRect.left + place.width;
+    dstRect.bottom = dstRect.top  + place.height;
+
+    d3d11_device_lock(d3d_dev);
+    scaleProc->d3dvidctx->VideoProcessorSetStreamSourceRect(scaleProc->processor.Get(),
+                                                            0, TRUE, &srcRect);
+
+    scaleProc->d3dvidctx->VideoProcessorSetStreamDestRect(scaleProc->processor.Get(),
+                                                          0, TRUE, &dstRect);
+
+    scaleProc->d3dvidctx->VideoProcessorSetOutputBackgroundColor(scaleProc->processor.Get(),
+                                                                 0, &black);
+
+    if (scaleProc->super_res)
+    {
+        // only use super resolution when source is smaller than display
+        upscale = fmt->i_visible_width < place.width
+               || fmt->i_visible_height < place.height;
+
+        if (d3d_dev->adapterDesc.VendorId == GPU_MANUFACTURER_NVIDIA)
+        {
+            constexpr GUID kNvidiaPPEInterfaceGUID{ 0xd43ce1b3, 0x1f4b, 0x48ac, {0xba, 0xee, 0xc3, 0xc2, 0x53, 0x75, 0xe6, 0xf7} };
+            constexpr UINT kStreamExtensionVersionV1 = 0x1;
+            constexpr UINT kStreamExtensionMethodRTXVSR = 0x2;
+            struct {
+                UINT version;
+                UINT method;
+                UINT enable;
+            } stream_extension_info = {
+                kStreamExtensionVersionV1,
+                kStreamExtensionMethodRTXVSR,
+                upscale ? 1u : 0u,
+            };
+
+            hr = scaleProc->d3dvidctx->VideoProcessorSetStreamExtension(
+                scaleProc->processor.Get(),
+                0, &kNvidiaPPEInterfaceGUID, sizeof(stream_extension_info),
+                &stream_extension_info);
+
+            if (FAILED(hr)) {
+                msg_Err(vd, "Failed to set the NVIDIA video process stream extension. (hr=0x%lX)", hr);
+                d3d11_device_unlock(d3d_dev);
+                goto done_super;
+            }
+        }
+        else if (d3d_dev->adapterDesc.VendorId == GPU_MANUFACTURER_INTEL)
+        {
+            constexpr GUID GUID_INTEL_VPE_INTERFACE{ 0xedd1d4b9, 0x8659, 0x4cbc, {0xa4, 0xd6, 0x98, 0x31, 0xa2, 0x16, 0x3a, 0xc3}};
+
+            constexpr UINT kIntelVpeFnVersion = 0x01;
+            constexpr UINT kIntelVpeFnMode    = 0x20;
+            constexpr UINT kIntelVpeFnScaling = 0x37;
+
+            // values for kIntelVpeFnVersion
+            constexpr UINT kIntelVpeVersion3 = 0x0003;
+
+            // values for kIntelVpeFnMode
+            constexpr UINT kIntelVpeModeNone    = 0x0;
+            constexpr UINT kIntelVpeModePreproc = 0x1;
+
+            // values for kIntelVpeFnScaling
+            constexpr UINT kIntelVpeScalingDefault         = 0x0;
+            constexpr UINT kIntelVpeScalingSuperResolution = 0x2;
+
+            UINT param;
+            struct {
+                UINT function;
+                void *param;
+            } ext = {
+                0,
+                &param,
+            };
+
+            ext.function = kIntelVpeFnVersion;
+            param = kIntelVpeVersion3;
+            hr = scaleProc->d3dvidctx->VideoProcessorSetOutputExtension(
+                scaleProc->processor.Get(),
+                &GUID_INTEL_VPE_INTERFACE, sizeof(ext), &ext);
+
+            if (FAILED(hr)) {
+                msg_Err(vd, "Failed to set the Intel VPE version. (hr=0x%lX)", hr);
+                d3d11_device_unlock(d3d_dev);
+                goto done_super;
+            }
+
+            ext.function = kIntelVpeFnMode;
+            param = upscale ? kIntelVpeModePreproc : kIntelVpeModeNone;
+            hr = scaleProc->d3dvidctx->VideoProcessorSetOutputExtension(
+                scaleProc->processor.Get(),
+                &GUID_INTEL_VPE_INTERFACE, sizeof(ext), &ext);
+            if (FAILED(hr)) {
+                msg_Err(vd, "Failed to set the Intel VPE mode. (hr=0x%lX)", hr);
+                d3d11_device_unlock(d3d_dev);
+                goto done_super;
+            }
+
+            ext.function = kIntelVpeFnScaling;
+            param = upscale ? kIntelVpeScalingSuperResolution : kIntelVpeScalingDefault;
+            hr = scaleProc->d3dvidctx->VideoProcessorSetOutputExtension(
+                scaleProc->processor.Get(),
+                &GUID_INTEL_VPE_INTERFACE, sizeof(ext), &ext);
+            if (FAILED(hr)) {
+                msg_Err(vd, "Failed to set the Intel VPE scaling type. (hr=0x%lX)", hr);
+                d3d11_device_unlock(d3d_dev);
+                goto done_super;
+            }
+        }
+    }
+    d3d11_device_unlock(d3d_dev);
+
+    if (scaleProc->upscaling != upscale)
+    {
+        msg_Dbg(vd, "turning VSR %s", upscale ? "ON" : "OFF");
+        scaleProc->upscaling = upscale;
+    }
+
+    scaleProc->usable = true;
+    return VLC_SUCCESS;
+done_super:
+    ReleaseSRVs(scaleProc);
+    scaleProc->processor.Reset();
+    scaleProc->enumerator.Reset();
+    return VLC_EGENERIC;
+}
+
+void D3D11_UpscalerDestroy(d3d11_scaler *scaleProc)
+{
+    ReleaseSRVs(scaleProc);
+    delete scaleProc;
+}
+
+
+static int assert_ProcessorInput(vlc_object_t *vd, d3d11_scaler *scaleProc, picture_sys_t *p_sys_src)
+{
+    if (!p_sys_src->processorInput)
+    {
+        D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC inDesc{};
+        inDesc.FourCC = 0;
+        inDesc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D;
+        inDesc.Texture2D.MipSlice = 0;
+        inDesc.Texture2D.ArraySlice = p_sys_src->slice_index;
+
+        HRESULT hr;
+
+        hr = scaleProc->d3dviddev->CreateVideoProcessorInputView(
+                                                             p_sys_src->resource[KNOWN_DXGI_INDEX],
+                                                             scaleProc->enumerator.Get(),
+                                                             &inDesc,
+                                                             &p_sys_src->processorInput);
+        if (FAILED(hr))
+        {
+#ifndef NDEBUG
+            msg_Dbg(vd,"Failed to create processor input for slice %d. (hr=0x%lX)", p_sys_src->slice_index, hr);
+#endif
+            return VLC_EGENERIC;
+        }
+    }
+    return VLC_SUCCESS;
+}
+
+int D3D11_UpscalerScale(vlc_object_t *vd, d3d11_scaler *scaleProc, picture_sys_t *p_sys)
+{
+    HRESULT hr;
+
+    if (assert_ProcessorInput(vd, scaleProc, p_sys) != VLC_SUCCESS)
+    {
+        msg_Err(vd, "fail to create upscaler input");
+        return VLC_EGENERIC;
+    }
+
+    D3D11_VIDEO_PROCESSOR_STREAM stream{};
+    stream.Enable = TRUE;
+    stream.pInputSurface = p_sys->processorInput;
+
+    hr = scaleProc->d3dvidctx->VideoProcessorBlt(scaleProc->processor.Get(),
+                                                 scaleProc->outputView.Get(),
+                                                 0, 1, &stream);
+    if (FAILED(hr))
+    {
+        msg_Err(vd, "Failed to render the upscaled texture. (hr=0x%lX)", hr);
+        return VLC_EGENERIC;
+    }
+    return VLC_SUCCESS;
+}
+
+void D3D11_UpscalerGetSize(const d3d11_scaler *scaleProc, unsigned *i_width, unsigned *i_height)
+{
+    *i_width  = scaleProc->Width;
+    *i_height = scaleProc->Height;
+}
+
+bool D3D11_UpscalerUsed(const d3d11_scaler *scaleProc)
+{
+    return scaleProc->usable;
+}
+
+void D3D11_UpscalerGetSRV(const d3d11_scaler *scaleProc, ID3D11ShaderResourceView *SRV[D3D11_MAX_SHADER_VIEW])
+{
+    for (size_t i=0; i<D3D11_MAX_SHADER_VIEW; i++)
+        SRV[i] = scaleProc->SRVs[i];
+}


=====================================
modules/video_output/win32/d3d11_scaler.h
=====================================
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*****************************************************************************
+ * d3d11_scaler: Direct3D11 VideoProcessor based output scaling
+ *****************************************************************************
+ * Copyright © 2023 Videolabs, VLC authors and VideoLAN
+ *
+ * Authors: Chilledheart <hukeyue at hotmail.com>
+ *          Steve Lhomme <robux4 at videolabs.io>
+ *****************************************************************************/
+
+#ifndef VLC_D3D11_SCALER_H
+#define VLC_D3D11_SCALER_H
+
+#include "../../video_chroma/d3d11_fmt.h"
+#include <vlc_vout_display.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct d3d11_scaler;
+
+struct d3d11_scaler *D3D11_UpscalerCreate(vlc_object_t *, d3d11_device_t*, vlc_fourcc_t i_chroma, bool super_res);
+void D3D11_UpscalerDestroy(struct d3d11_scaler *);
+int D3D11_UpscalerUpdate(vlc_object_t *, struct d3d11_scaler *, d3d11_device_t*,
+                         const video_format_t *, video_format_t *,
+                         const vout_display_cfg_t *);
+int D3D11_UpscalerScale(vlc_object_t *, struct d3d11_scaler *, picture_sys_t *);
+bool D3D11_UpscalerUsed(const struct d3d11_scaler *);
+void D3D11_UpscalerGetSRV(const struct d3d11_scaler *, ID3D11ShaderResourceView *SRV[D3D11_MAX_SHADER_VIEW]);
+void D3D11_UpscalerGetSize(const struct d3d11_scaler *, unsigned *i_width, unsigned *i_height);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // VLC_D3D11_SCALER_H


=====================================
modules/video_output/win32/direct3d11.c
=====================================
@@ -55,6 +55,7 @@
 #include "../../video_chroma/d3d11_fmt.h"
 #include "d3d11_quad.h"
 #include "d3d11_shaders.h"
+#include "d3d11_scaler.h"
 
 #include "common.h"
 
@@ -69,6 +70,14 @@ static void Close(vlc_object_t *);
 #define HW_BLENDING_LONGTEXT N_(\
     "Try to use hardware acceleration for subtitle/OSD blending.")
 
+#define UPSCALE_MODE_TEXT N_("Video Upscaling Mode")
+#define UPSCALE_MODE_LONGTEXT N_("Select the upscaling mode for video.")
+
+static const char *const ppsz_upscale_mode[] = {
+    "linear", "point", "processor", "super" };
+static const char *const ppsz_upscale_mode_text[] = {
+    N_("Linear Sampler"), N_("Point Sampler"), N_("Video Processor"), N_("Super Resolution") };
+
 vlc_module_begin ()
     set_shortname("Direct3D11")
     set_description(N_("Direct3D11 video output"))
@@ -83,14 +92,26 @@ vlc_module_begin ()
     add_integer("winrt-swapchain",     0x0, NULL, NULL, true) /* IDXGISwapChain1*     */
         change_volatile()
 
+    add_string("d3d11-upscale-mode", "linear", UPSCALE_MODE_TEXT, UPSCALE_MODE_LONGTEXT, false)
+        change_string_list(ppsz_upscale_mode, ppsz_upscale_mode_text)
+
     set_capability("vout display", 300)
     add_shortcut("direct3d11")
     set_callbacks(Open, Close)
 vlc_module_end ()
 
+enum d3d11_upscale
+{
+    upscale_LinearSampler,
+    upscale_PointSampler,
+    upscale_VideoProcessor,
+    upscale_SuperResolution,
+};
+
 struct vout_display_sys_t
 {
     vout_display_sys_win32_t sys;
+    video_format_t           pool_fmt;
 
     int                      log_level;
 
@@ -102,6 +123,7 @@ struct vout_display_sys_t
     IDXGISwapChain4          *dxgiswapChain4;  /* DXGI 1.5 for HDR */
     d3d11_device_t           d3d_dev;
     d3d_quad_t               picQuad;
+    video_format_t           quad_fmt;
 
 #ifdef HAVE_D3D11_4_H
     ID3D11Fence              *d3dRenderFence;
@@ -129,6 +151,10 @@ struct vout_display_sys_t
     const d3d_format_t       *d3dregion_format;
     int                      d3dregion_count;
     picture_t                **d3dregions;
+
+    // upscaling
+    enum d3d11_upscale       upscaleMode;
+    struct d3d11_scaler      *scaleProc;
 };
 
 #define RECTWidth(r)   (int)((r).right - (r).left)
@@ -149,8 +175,6 @@ static int  Direct3D11CreateFormatResources (vout_display_t *, const video_forma
 static int  Direct3D11CreateGenericResources(vout_display_t *);
 static void Direct3D11DestroyResources(vout_display_t *);
 
-static void Direct3D11DestroyPool(vout_display_t *);
-
 static void DestroyDisplayPoolPicture(picture_t *);
 static void Direct3D11DeleteRegions(int, picture_t **);
 static int Direct3D11MapSubpicture(vout_display_t *, int *, picture_t ***, subpicture_t *);
@@ -192,11 +216,9 @@ static void Direct3D11UnmapPoolTexture(picture_t *picture)
     ID3D11DeviceContext_Unmap(p_sys->context, p_sys->resource[KNOWN_DXGI_INDEX], 0);
 }
 
-static bool GetRect(const vout_display_sys_win32_t *p_sys, RECT *out)
+static bool GetWinRTSize(const vout_display_sys_win32_t *p_sys, UINT *w, UINT *h)
 {
     const vout_display_sys_t *sys = (const vout_display_sys_t *)p_sys;
-    out->left   = 0;
-    out->top    = 0;
     uint32_t i_width;
     uint32_t i_height;
     UINT dataSize = sizeof(i_width);
@@ -209,8 +231,8 @@ static bool GetRect(const vout_display_sys_win32_t *p_sys, RECT *out)
     if (FAILED(hr)) {
         return false;
     }
-    out->right  = i_width;
-    out->bottom = i_height;
+    *w = i_width;
+    *h = i_height;
     return true;
 }
 
@@ -235,7 +257,7 @@ static int OpenCoreW(vout_display_t *vd)
     IDXGISwapChain_AddRef     (sys->dxgiswapChain);
     ID3D11DeviceContext_AddRef(sys->d3d_dev.d3dcontext);
 
-    sys->sys.pf_GetRect = GetRect;
+    sys->sys.pf_GetWindowSize = GetWinRTSize;
 
     return VLC_SUCCESS;
 }
@@ -352,14 +374,10 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
     if (vd->info.is_slow)
         pool_size = 1;
 
-    video_format_t surface_fmt = vd->fmt;
-    surface_fmt.i_width  = sys->picQuad.i_width;
-    surface_fmt.i_height = sys->picQuad.i_height;
-
-    if (D3D11_SetupQuad( vd, &sys->d3d_dev, &surface_fmt, &sys->picQuad, &sys->display, &sys->sys.rect_src_clipped,
+    if (D3D11_SetupQuad( vd, &sys->d3d_dev, &sys->quad_fmt, &sys->picQuad, &sys->display, &sys->sys.rect_src_clipped,
                    vd->fmt.projection_mode == PROJECTION_MODE_RECTANGULAR ? sys->flatVSShader : sys->projectionVSShader,
                    sys->pVertexLayout,
-                   surface_fmt.projection_mode, vd->fmt.orientation ) != VLC_SUCCESS) {
+                   sys->quad_fmt.projection_mode, vd->fmt.orientation ) != VLC_SUCCESS) {
         msg_Err(vd, "Could not Create the main quad picture.");
         return NULL;
     }
@@ -379,7 +397,7 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
     }
 
     if (sys->picQuad.formatInfo->formatTexture == DXGI_FORMAT_UNKNOWN)
-        sys->sys.pool = picture_pool_NewFromFormat( &surface_fmt, pool_size );
+        sys->sys.pool = picture_pool_NewFromFormat( &sys->pool_fmt, pool_size );
     else
     {
         ID3D11Texture2D  *textures[pool_size * D3D11_MAX_SHADER_VIEW];
@@ -389,7 +407,7 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
             /* only provide enough for the filters, we can still do direct rendering */
             slices = __MIN(slices, 6);
 
-        if (AllocateTextures(vd, &sys->d3d_dev, sys->picQuad.formatInfo, &surface_fmt, slices, textures))
+        if (AllocateTextures(vd, &sys->d3d_dev, sys->picQuad.formatInfo, &sys->pool_fmt, slices, textures))
             goto error;
 
         pictures = calloc(pool_size, sizeof(*pictures));
@@ -421,7 +439,7 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
                 .pf_destroy = DestroyDisplayPoolPicture,
             };
 
-            picture = picture_NewFromResource(&surface_fmt, &resource);
+            picture = picture_NewFromResource(&sys->pool_fmt, &resource);
             if (unlikely(picture == NULL)) {
                 free(picsys);
                 msg_Err( vd, "Failed to create picture %d in the pool.", picture_count );
@@ -434,7 +452,7 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
         }
 
 #ifdef HAVE_ID3D11VIDEODECODER
-        if (is_d3d11_opaque(surface_fmt.i_chroma) && !sys->legacy_shader)
+        if (is_d3d11_opaque(sys->pool_fmt.i_chroma) && !sys->legacy_shader)
 #endif
         {
             sys->picQuad.resourceCount = DxgiResourceCount(sys->picQuad.formatInfo);
@@ -452,7 +470,7 @@ static picture_pool_t *Pool(vout_display_t *vd, unsigned pool_size)
             .picture       = pictures,
             .picture_count = pool_size,
         };
-        if (vd->info.is_slow && !is_d3d11_opaque(surface_fmt.i_chroma)) {
+        if (vd->info.is_slow && !is_d3d11_opaque(sys->pool_fmt.i_chroma)) {
             pool_cfg.lock          = Direct3D11MapPoolTexture;
             //pool_cfg.unlock        = Direct3D11UnmapPoolTexture;
         }
@@ -475,7 +493,7 @@ error:
         sys->sys.pool = picture_pool_NewExtended( &pool_cfg );
     } else {
         msg_Dbg(vd, "D3D11 pool succeed with %d surfaces (%dx%d) context 0x%p",
-                pool_size, surface_fmt.i_width, surface_fmt.i_height, sys->d3d_dev.d3dcontext);
+                pool_size, sys->pool_fmt.i_width, sys->pool_fmt.i_height, sys->d3d_dev.d3dcontext);
     }
     return sys->sys.pool;
 }
@@ -552,7 +570,10 @@ static int UpdateSamplers(vout_display_t *vd)
     d3d11_device_lock(&sys->d3d_dev);
 
     ID3D11SamplerState *d3dsampState[2];
-    sampDesc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
+    if (sys->upscaleMode == upscale_PointSampler)
+        sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
+    else
+        sampDesc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
     hr = ID3D11Device_CreateSamplerState(sys->d3d_dev.d3ddevice, &sampDesc, &d3dsampState[0]);
     if (FAILED(hr)) {
         msg_Err(vd, "Could not Create the D3d11 Sampler State. (hr=0x%lX)", hr);
@@ -583,11 +604,24 @@ static HRESULT UpdateBackBuffer(vout_display_t *vd)
     HRESULT hr;
     ID3D11Texture2D* pDepthStencil;
     ID3D11Texture2D* pBackBuffer;
-    RECT rect;
-    if (sys->sys.pf_GetRect != GetRect || !sys->sys.pf_GetRect(&sys->sys, &rect))
-        rect = sys->sys.rect_dest_clipped;
-    uint32_t i_width = RECTWidth(rect);
-    uint32_t i_height = RECTHeight(rect);
+    UINT window_width, window_height;
+    bool proc_upscale = sys->upscaleMode == upscale_VideoProcessor || sys->upscaleMode == upscale_SuperResolution;
+    if ((sys->sys.pf_GetWindowSize != GetWinRTSize && !proc_upscale)
+    || !sys->sys.pf_GetWindowSize(&sys->sys, &window_width, &window_height))
+    {
+        window_width  = RECTWidth(sys->sys.rect_dest_clipped);
+        window_height = RECTHeight(sys->sys.rect_dest_clipped);
+    }
+
+    if (proc_upscale)
+    {
+        vout_display_cfg_t cfg = *vd->cfg;
+        cfg.display.width = window_width;
+        cfg.display.height = window_height;
+        D3D11_UpscalerUpdate(VLC_OBJECT(vd), sys->scaleProc, &sys->d3d_dev,
+                             &sys->pool_fmt, &sys->quad_fmt, &cfg);
+    }
+
     D3D11_TEXTURE2D_DESC dsc = { 0 };
 
     if (sys->d3drenderTargetView) {
@@ -600,7 +634,7 @@ static HRESULT UpdateBackBuffer(vout_display_t *vd)
         }
     }
 
-    if (dsc.Width == i_width && dsc.Height == i_height)
+    if (dsc.Width == window_width && dsc.Height == window_height)
         return S_OK; /* nothing changed */
 
     if (sys->d3drenderTargetView) {
@@ -613,7 +647,7 @@ static HRESULT UpdateBackBuffer(vout_display_t *vd)
     }
 
     /* TODO detect is the size is the same as the output and switch to fullscreen mode */
-    hr = IDXGISwapChain_ResizeBuffers(sys->dxgiswapChain, 0, i_width, i_height,
+    hr = IDXGISwapChain_ResizeBuffers(sys->dxgiswapChain, 0, window_width, window_height,
         DXGI_FORMAT_UNKNOWN, 0);
     if (FAILED(hr)) {
        msg_Err(vd, "Failed to resize the backbuffer. (hr=0x%lX)", hr);
@@ -639,8 +673,8 @@ static HRESULT UpdateBackBuffer(vout_display_t *vd)
     deptTexDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
     deptTexDesc.CPUAccessFlags = 0;
     deptTexDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
-    deptTexDesc.Width = i_width;
-    deptTexDesc.Height = i_height;
+    deptTexDesc.Width = window_width;
+    deptTexDesc.Height = window_height;
     deptTexDesc.MipLevels = 1;
     deptTexDesc.MiscFlags = 0;
     deptTexDesc.SampleDesc.Count = 1;
@@ -851,6 +885,29 @@ static int Control(vout_display_t *vd, int query, va_list args)
     RECT before_dest_clipped = sys->sys.rect_dest_clipped;
     RECT before_dest         = sys->sys.rect_dest;
 
+    if (sys->upscaleMode == upscale_VideoProcessor || sys->upscaleMode == upscale_SuperResolution)
+        switch (query) {
+        case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
+        case VOUT_DISPLAY_CHANGE_ZOOM:
+        case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
+        case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
+            {
+                // update the source cropping
+                UINT window_width, window_height;
+                if (!sys->sys.pf_GetWindowSize(&sys->sys, &window_width, &window_height))
+                {
+                    window_width  = RECTWidth(sys->sys.rect_dest_clipped);
+                    window_height = RECTHeight(sys->sys.rect_dest_clipped);
+                }
+                vout_display_cfg_t cfg = *vd->cfg;
+                cfg.display.width = window_width;
+                cfg.display.height = window_height;
+                D3D11_UpscalerUpdate(VLC_OBJECT(vd), sys->scaleProc, &sys->d3d_dev, &vd->source,
+                                     &sys->quad_fmt, &cfg);
+            }
+            break;
+        }
+
     int res = CommonControl( vd, query, args );
 
     if (query == VOUT_DISPLAY_CHANGE_VIEWPOINT)
@@ -890,6 +947,30 @@ static void Manage(vout_display_t *vd)
     }
 }
 
+static void CallUpdateRects(vout_display_t *vd)
+{
+    vout_display_sys_t *sys = vd->sys;
+    if (sys->scaleProc && D3D11_UpscalerUsed(sys->scaleProc))
+    {
+        D3D11_UpscalerGetSize(sys->scaleProc, &sys->quad_fmt.i_width, &sys->quad_fmt.i_height);
+
+        sys->quad_fmt.i_x_offset       = 0;
+        sys->quad_fmt.i_y_offset       = 0;
+        sys->quad_fmt.i_visible_width  = sys->quad_fmt.i_width;
+        sys->quad_fmt.i_visible_height = sys->quad_fmt.i_height;
+
+        sys->picQuad.i_width = sys->quad_fmt.i_width;
+        sys->picQuad.i_height = sys->quad_fmt.i_height;
+
+        UpdateRects(vd, NULL, true);
+        UpdateSize(vd);
+    }
+    else
+    {
+        UpdateRects(vd, NULL, true);
+    }
+}
+
 static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
 {
     vout_display_sys_t *sys = vd->sys;
@@ -935,14 +1016,26 @@ static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpic
     {
         picture_sys_t *p_sys = ActivePictureSys(picture);
 
+        D3D11_TEXTURE2D_DESC srcDesc;
+        ID3D11Texture2D_GetDesc(p_sys->texture[KNOWN_DXGI_INDEX], &srcDesc);
+
         if (is_d3d11_opaque(picture->format.i_chroma))
             d3d11_device_lock( &sys->d3d_dev );
 
+        if (sys->scaleProc && D3D11_UpscalerUsed(sys->scaleProc))
+        {
+            if (D3D11_UpscalerScale(VLC_OBJECT(vd), sys->scaleProc, p_sys) != VLC_SUCCESS)
+                return;
+            uint32_t witdh, height;
+            D3D11_UpscalerGetSize(sys->scaleProc, &witdh, &height);
+            srcDesc.Width  = witdh;
+            srcDesc.Height = height;
+        }
+
         if (!is_d3d11_opaque(picture->format.i_chroma) || sys->legacy_shader) {
-            D3D11_TEXTURE2D_DESC srcDesc,texDesc;
+            D3D11_TEXTURE2D_DESC texDesc;
             if (!is_d3d11_opaque(picture->format.i_chroma))
                 Direct3D11UnmapPoolTexture(picture);
-            ID3D11Texture2D_GetDesc(p_sys->texture[KNOWN_DXGI_INDEX], &srcDesc);
             ID3D11Texture2D_GetDesc(sys->stagingSys.texture[0], &texDesc);
             D3D11_BOX box = {
                 .top = 0,
@@ -959,23 +1052,23 @@ static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpic
         }
         else
         {
-            D3D11_TEXTURE2D_DESC texDesc;
-            ID3D11Texture2D_GetDesc(p_sys->texture[0], &texDesc);
-            if (texDesc.BindFlags & D3D11_BIND_SHADER_RESOURCE)
+            if (srcDesc.BindFlags & D3D11_BIND_SHADER_RESOURCE)
             {
                 /* for performance reason we don't want to allocate this during
                  * display, do it preferrably when creating the texture */
                 assert(p_sys->resourceView[0]!=NULL);
             }
-            if ( sys->picQuad.i_height != texDesc.Height ||
-                 sys->picQuad.i_width != texDesc.Width )
+            if ( sys->picQuad.i_height != srcDesc.Height ||
+                 sys->picQuad.i_width != srcDesc.Width )
             {
                 /* the decoder produced different sizes than the vout, we need to
                  * adjust the vertex */
-                sys->picQuad.i_height = texDesc.Height;
-                sys->picQuad.i_width = texDesc.Width;
+                sys->quad_fmt.i_width = srcDesc.Width;
+                sys->quad_fmt.i_height = srcDesc.Height;
+                sys->picQuad.i_width = sys->quad_fmt.i_width;
+                sys->picQuad.i_height = sys->quad_fmt.i_height;
 
-                UpdateRects(vd, NULL, true);
+                CallUpdateRects(vd);
                 UpdateSize(vd);
             }
         }
@@ -1023,7 +1116,14 @@ static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpic
     /* Render the quad */
     if (!is_d3d11_opaque(picture->format.i_chroma) || sys->legacy_shader)
         D3D11_RenderQuad(&sys->d3d_dev, &sys->picQuad, sys->stagingSys.resourceView, sys->d3drenderTargetView);
-    else {
+    else if (sys->scaleProc && D3D11_UpscalerUsed(sys->scaleProc))
+    {
+        ID3D11ShaderResourceView *SRV[D3D11_MAX_SHADER_VIEW];
+        D3D11_UpscalerGetSRV(sys->scaleProc, SRV);
+        D3D11_RenderQuad(&sys->d3d_dev, &sys->picQuad, SRV, sys->d3drenderTargetView);
+    }
+    else
+    {
         picture_sys_t *p_sys = ActivePictureSys(picture);
         D3D11_RenderQuad(&sys->d3d_dev, &sys->picQuad, p_sys->resourceView, sys->d3drenderTargetView);
     }
@@ -1296,6 +1396,74 @@ static const d3d_format_t *GetBlendableFormat(vout_display_t *vd, vlc_fourcc_t i
     return FindD3D11Format( vd, &vd->sys->d3d_dev, i_src_chroma, false, 0, 0, 0, false, supportFlags );
 }
 
+static bool CanUseTextureArray(vout_display_t *vd)
+{
+#ifndef HAVE_ID3D11VIDEODECODER
+    (void) vd;
+    return false;
+#else
+    // 15.200.1062.1004 is wrong - 2015/08/03 - 15.7.1 WHQL
+    // 21.19.144.1281 is wrong   -
+    // 22.19.165.3 is good       - 2017/05/04 - ReLive Edition 17.5.1
+    struct wddm_version WDDM_os = {
+        .wddm         = 21,  // starting with drivers designed for W10 Anniversary Update
+    };
+    if (D3D11CheckDriverVersion(&vd->sys->d3d_dev, GPU_MANUFACTURER_AMD, &WDDM_os) != VLC_SUCCESS)
+    {
+        msg_Dbg(vd, "AMD driver too old, fallback to legacy shader mode");
+        return false;
+    }
+
+    // xx.xx.1000.xxx drivers can't happen here for WDDM > 2.0
+    struct wddm_version WDDM_build = {
+        .revision     = 162,
+    };
+    if (D3D11CheckDriverVersion(&vd->sys->d3d_dev, GPU_MANUFACTURER_AMD, &WDDM_build) != VLC_SUCCESS)
+    {
+        msg_Dbg(vd, "Bogus AMD driver detected, fallback to legacy shader mode");
+        return false;
+    }
+
+    return true;
+#endif
+}
+
+static bool BogusZeroCopy(const vout_display_t *vd)
+{
+    if (vd->sys->d3d_dev.adapterDesc.VendorId != GPU_MANUFACTURER_AMD)
+        return false;
+
+    switch (vd->sys->d3d_dev.adapterDesc.DeviceId)
+    {
+    case 0x687F: // RX Vega 56/64
+    case 0x6863: // RX Vega Frontier Edition
+    case 0x15DD: // RX Vega 8/11 (Ryzen iGPU)
+    {
+        struct wddm_version WDDM = {
+            .revision     = 14011, // 18.10.2 - 2018/06/11
+        };
+        return D3D11CheckDriverVersion(&vd->sys->d3d_dev, GPU_MANUFACTURER_AMD, &WDDM) != VLC_SUCCESS;
+    }
+    default:
+        return false;
+    }
+}
+
+static void InitScaleProcessor(vout_display_t *vd)
+{
+    vout_display_sys_t *sys = vd->sys;
+    if (sys->upscaleMode != upscale_VideoProcessor && sys->upscaleMode != upscale_SuperResolution)
+        return;
+
+    sys->scaleProc = D3D11_UpscalerCreate(VLC_OBJECT(vd), &sys->d3d_dev, sys->quad_fmt.i_chroma,
+                                          sys->upscaleMode == upscale_SuperResolution);
+    if (sys->scaleProc == NULL)
+        sys->upscaleMode = upscale_LinearSampler;
+
+    msg_Dbg(vd, "Using %s scaler", sys->upscaleMode != upscale_SuperResolution ?
+            "Video Processor": "Super Resolution");
+}
+
 static int Direct3D11Open(vout_display_t *vd, bool external_device)
 {
     vout_display_sys_t *sys = vd->sys;
@@ -1378,6 +1546,47 @@ static int Direct3D11Open(vout_display_t *vd, bool external_device)
             return err;
     }
 
+    char *psz_upscale = var_InheritString(vd, "d3d11-upscale-mode");
+    if (strcmp("linear", psz_upscale) == 0)
+        sys->upscaleMode = upscale_LinearSampler;
+    else if (strcmp("point", psz_upscale) == 0)
+        sys->upscaleMode = upscale_PointSampler;
+    else if (strcmp("processor", psz_upscale) == 0)
+        sys->upscaleMode = upscale_VideoProcessor;
+    else if (strcmp("super", psz_upscale) == 0)
+        sys->upscaleMode = upscale_SuperResolution;
+    else
+    {
+        msg_Warn(vd, "unknown upscale mode %s, using linear sampler", psz_upscale);
+        sys->upscaleMode = upscale_LinearSampler;
+    }
+    free(psz_upscale);
+
+    video_format_Init(&sys->quad_fmt, vd->source.i_chroma);
+    video_format_Copy(&sys->quad_fmt, &vd->source);
+    if (sys->upscaleMode == upscale_VideoProcessor || sys->upscaleMode == upscale_SuperResolution)
+        sys->sys.src_fmt = &sys->quad_fmt;
+    InitScaleProcessor(vd);
+
+    video_format_Copy(&sys->pool_fmt, &fmt);
+
+    sys->legacy_shader = sys->d3d_dev.feature_level < D3D_FEATURE_LEVEL_10_0 ||
+            (sys->scaleProc == NULL && !CanUseTextureArray(vd)) ||
+            BogusZeroCopy(vd);
+
+    if (!sys->legacy_shader && is_d3d11_opaque(sys->pool_fmt.i_chroma))
+    {
+        sys->pool_fmt.i_width  = (sys->pool_fmt.i_width  + 0x7F) & ~0x7F;
+        sys->pool_fmt.i_height = (sys->pool_fmt.i_height + 0x7F) & ~0x7F;
+    }
+    else
+    if ( sys->picQuad.formatInfo->formatTexture != DXGI_FORMAT_R8G8B8A8_UNORM &&
+         sys->picQuad.formatInfo->formatTexture != DXGI_FORMAT_B5G6R5_UNORM )
+    {
+        sys->pool_fmt.i_width  = (sys->pool_fmt.i_width  + 0x01) & ~0x01;
+        sys->pool_fmt.i_height = (sys->pool_fmt.i_height + 0x01) & ~0x01;
+    }
+
     if (Direct3D11CreateGenericResources(vd)) {
         msg_Err(vd, "Failed to allocate resources");
         return VLC_EGENERIC;
@@ -1525,59 +1734,6 @@ static void UpdatePicQuadPosition(vout_display_t *vd)
 #endif
 }
 
-static bool CanUseTextureArray(vout_display_t *vd)
-{
-#ifndef HAVE_ID3D11VIDEODECODER
-    (void) vd;
-    return false;
-#else
-    // 15.200.1062.1004 is wrong - 2015/08/03 - 15.7.1 WHQL
-    // 21.19.144.1281 is wrong   -
-    // 22.19.165.3 is good       - 2017/05/04 - ReLive Edition 17.5.1
-    struct wddm_version WDDM_os = {
-        .wddm         = 21,  // starting with drivers designed for W10 Anniversary Update
-    };
-    if (D3D11CheckDriverVersion(&vd->sys->d3d_dev, GPU_MANUFACTURER_AMD, &WDDM_os) != VLC_SUCCESS)
-    {
-        msg_Dbg(vd, "AMD driver too old, fallback to legacy shader mode");
-        return false;
-    }
-
-    // xx.xx.1000.xxx drivers can't happen here for WDDM > 2.0
-    struct wddm_version WDDM_build = {
-        .revision     = 162,
-    };
-    if (D3D11CheckDriverVersion(&vd->sys->d3d_dev, GPU_MANUFACTURER_AMD, &WDDM_build) != VLC_SUCCESS)
-    {
-        msg_Dbg(vd, "Bogus AMD driver detected, fallback to legacy shader mode");
-        return false;
-    }
-
-    return true;
-#endif
-}
-
-static bool BogusZeroCopy(const vout_display_t *vd)
-{
-    if (vd->sys->d3d_dev.adapterDesc.VendorId != GPU_MANUFACTURER_AMD)
-        return false;
-
-    switch (vd->sys->d3d_dev.adapterDesc.DeviceId)
-    {
-    case 0x687F: // RX Vega 56/64
-    case 0x6863: // RX Vega Frontier Edition
-    case 0x15DD: // RX Vega 8/11 (Ryzen iGPU)
-    {
-        struct wddm_version WDDM = {
-            .revision     = 14011, // 18.10.2 - 2018/06/11
-        };
-        return D3D11CheckDriverVersion(&vd->sys->d3d_dev, GPU_MANUFACTURER_AMD, &WDDM) != VLC_SUCCESS;
-    }
-    default:
-        return false;
-    }
-}
-
 /* TODO : handle errors better
    TODO : seperate out into smaller functions like createshaders */
 static int Direct3D11CreateFormatResources(vout_display_t *vd, const video_format_t *fmt)
@@ -1585,9 +1741,6 @@ static int Direct3D11CreateFormatResources(vout_display_t *vd, const video_forma
     vout_display_sys_t *sys = vd->sys;
     HRESULT hr;
 
-    sys->legacy_shader = sys->d3d_dev.feature_level < D3D_FEATURE_LEVEL_10_0 || !CanUseTextureArray(vd) ||
-            BogusZeroCopy(vd);
-
     hr = D3D11_CompilePixelShader(vd, &sys->hd3d, sys->legacy_shader, &sys->d3d_dev,
                                   sys->picQuad.formatInfo, &sys->display, fmt->transfer, fmt->primaries,
                                   fmt->b_color_range_full,
@@ -1600,20 +1753,8 @@ static int Direct3D11CreateFormatResources(vout_display_t *vd, const video_forma
 
     sys->picQuad.i_width  = fmt->i_width;
     sys->picQuad.i_height = fmt->i_height;
-    if (!sys->legacy_shader && is_d3d11_opaque(fmt->i_chroma))
-    {
-        sys->picQuad.i_width  = (sys->picQuad.i_width  + 0x7F) & ~0x7F;
-        sys->picQuad.i_height = (sys->picQuad.i_height + 0x7F) & ~0x7F;
-    }
-    else
-    if ( sys->picQuad.formatInfo->formatTexture != DXGI_FORMAT_R8G8B8A8_UNORM &&
-         sys->picQuad.formatInfo->formatTexture != DXGI_FORMAT_B5G6R5_UNORM )
-    {
-        sys->picQuad.i_width  = (sys->picQuad.i_width  + 0x01) & ~0x01;
-        sys->picQuad.i_height = (sys->picQuad.i_height + 0x01) & ~0x01;
-    }
 
-    UpdateRects(vd, NULL, true);
+    CallUpdateRects(vd);
 
 #ifdef HAVE_ID3D11VIDEODECODER
     if (!is_d3d11_opaque(fmt->i_chroma) || sys->legacy_shader)
@@ -1742,14 +1883,14 @@ static int Direct3D11CreateGenericResources(vout_display_t *vd)
         ID3D11DepthStencilState_Release(pDepthStencilState);
     }
 
-    UpdateRects(vd, NULL, true);
-
     hr = UpdateBackBuffer(vd);
     if (FAILED(hr)) {
        msg_Err(vd, "Could not update the backbuffer. (hr=0x%lX)", hr);
        return VLC_EGENERIC;
     }
 
+    CallUpdateRects(vd);
+
     if (sys->d3dregion_format != NULL)
     {
         hr = D3D11_CompilePixelShader(vd, &sys->hd3d, sys->legacy_shader, &sys->d3d_dev,
@@ -1823,6 +1964,7 @@ static void Direct3D11DestroyPool(vout_display_t *vd)
     if (sys->sys.pool)
         picture_pool_Release(sys->sys.pool);
     sys->sys.pool = NULL;
+    video_format_Clean(&sys->pool_fmt);
 }
 
 static void Direct3D11DestroyResources(vout_display_t *vd)
@@ -1837,6 +1979,13 @@ static void Direct3D11DestroyResources(vout_display_t *vd)
 
     ReleasePictureSys(&sys->stagingSys);
 
+    if (sys->scaleProc != NULL)
+    {
+        D3D11_UpscalerDestroy(sys->scaleProc);
+        sys->scaleProc = NULL;
+    }
+    video_format_Clean(&sys->quad_fmt);
+
     if (sys->pVertexLayout)
     {
         ID3D11InputLayout_Release(sys->pVertexLayout);
@@ -2027,12 +2176,18 @@ static int Direct3D11MapSubpicture(vout_display_t *vd, int *subpicture_region_co
 
         d3d_quad_t *quad = (d3d_quad_t *) quad_picture->p_sys;
 
-        quad->cropViewport.Width =  (FLOAT) r->fmt.i_visible_width  * RECTWidth(sys->sys.rect_dest)  / subpicture->i_original_picture_width;
-        quad->cropViewport.Height = (FLOAT) r->fmt.i_visible_height * RECTHeight(sys->sys.rect_dest) / subpicture->i_original_picture_height;
+        vout_display_cfg_t place_cfg = *vd->cfg;
+        place_cfg.display.width  = RECTWidth(sys->sys.rect_dest_clipped);
+        place_cfg.display.height = RECTHeight(sys->sys.rect_dest_clipped);
+        vout_display_place_t place;
+        vout_display_PlacePicture(&place, &vd->source, &place_cfg, false);
+
+        quad->cropViewport.Width =  (FLOAT) r->fmt.i_visible_width  * place.width  / subpicture->i_original_picture_width;
+        quad->cropViewport.Height = (FLOAT) r->fmt.i_visible_height * place.height / subpicture->i_original_picture_height;
         quad->cropViewport.MinDepth = 0.0f;
         quad->cropViewport.MaxDepth = 1.0f;
-        quad->cropViewport.TopLeftX = sys->sys.rect_dest.left + (FLOAT) r->i_x * RECTWidth(sys->sys.rect_dest) / subpicture->i_original_picture_width;
-        quad->cropViewport.TopLeftY = sys->sys.rect_dest.top  + (FLOAT) r->i_y * RECTHeight(sys->sys.rect_dest) / subpicture->i_original_picture_height;
+        quad->cropViewport.TopLeftX = place.x + (FLOAT) r->i_x * place.width  / subpicture->i_original_picture_width;
+        quad->cropViewport.TopLeftY = place.y + (FLOAT) r->i_y * place.height / subpicture->i_original_picture_height;
 
         D3D11_UpdateQuadOpacity(vd, &sys->d3d_dev, quad, r->i_alpha / 255.0f );
     }



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/70de1313be8e1d4bc90aeea6ea67a57db1924b05...56222b9290dd9bf08e02b10b1e9ee13d68931fc2

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/70de1313be8e1d4bc90aeea6ea67a57db1924b05...56222b9290dd9bf08e02b10b1e9ee13d68931fc2
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list