[vlc-commits] [Git][videolan/vlc][master] 6 commits: direct3d11: add an option to select the upscaling quality

Steve Lhomme (@robUx4) gitlab at videolan.org
Tue Apr 18 09:24:16 UTC 2023



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
b86a5787 by Steve Lhomme at 2023-04-18T09:08:05+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.

- - - - -
794d897d by Steve Lhomme at 2023-04-18T09:08:05+00:00
direct3d11: keep the format used with the pic_quad

- - - - -
d4374090 by Steve Lhomme at 2023-04-18T09:08:05+00:00
vout/win32: allow forcing the source size

- - - - -
1f7f849c by Steve Lhomme at 2023-04-18T09:08:05+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>

- - - - -
beac9098 by Chilledheart at 2023-04-18T09:08:05+00:00
direct3d11: use NVIDIA super-resolution upscaler

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

- - - - -
8892ebd6 by Steve Lhomme at 2023-04-18T09:08:05+00:00
direct3d11: add Intel based super resolution

- - - - -


11 changed files:

- 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/d3d11_shaders.h
- modules/video_output/win32/direct3d11.cpp
- modules/video_output/win32/direct3d9.c
- modules/video_output/win32/glwin32.c
- modules/video_output/win32/meson.build
- modules/video_output/win32/wingdi.c


Changes:

=====================================
modules/video_output/Makefile.am
=====================================
@@ -186,6 +186,7 @@ endif
 
 libdirect3d11_plugin_la_SOURCES = video_output/win32/direct3d11.cpp \
  video_output/win32/d3d11_quad.cpp video_output/win32/d3d11_quad.h \
+ video_output/win32/d3d11_scaler.cpp video_output/win32/d3d11_scaler.h \
  video_output/win32/d3d11_shaders.cpp video_output/win32/d3d11_shaders.h \
  video_output/win32/d3d_shaders.c video_output/win32/d3d_shaders.h \
  video_output/win32/d3d_dynamic_shader.c video_output/win32/d3d_dynamic_shader.h \


=====================================
modules/video_output/win32/common.c
=====================================
@@ -41,10 +41,11 @@
 #include "common.h"
 #include "../../video_chroma/copy.h"
 
-void CommonInit(display_win32_area_t *area)
+void CommonInit(display_win32_area_t *area, const video_format_t *src_fmt)
 {
     ZeroMemory(&area->place, sizeof(area->place));
     area->place_changed = false;
+    area->src_fmt = src_fmt;
 }
 
 #ifndef VLC_WINSTORE_APP
@@ -90,7 +91,7 @@ void CommonPlacePicture(vout_display_t *vd, display_win32_area_t *area)
 {
     /* Update the window position and size */
     vout_display_place_t before_place = area->place;
-    vout_display_PlacePicture(&area->place, vd->source, &vd->cfg->display);
+    vout_display_PlacePicture(&area->place, area->src_fmt, &vd->cfg->display);
 
     /* Signal the change in size/position */
     if (!vout_display_PlaceEquals(&before_place, &area->place))
@@ -99,9 +100,9 @@ void CommonPlacePicture(vout_display_t *vd, display_win32_area_t *area)
 
 #ifndef NDEBUG
         msg_Dbg(vd, "UpdateRects source offset: %i,%i visible: %ix%i decoded: %ix%i",
-            vd->source->i_x_offset, vd->source->i_y_offset,
-            vd->source->i_visible_width, vd->source->i_visible_height,
-            vd->source->i_width, vd->source->i_height);
+            area->src_fmt->i_x_offset, area->src_fmt->i_y_offset,
+            area->src_fmt->i_visible_width, area->src_fmt->i_visible_height,
+            area->src_fmt->i_width, area->src_fmt->i_height);
         msg_Dbg(vd, "UpdateRects image_dst coords: %i,%i %ix%i",
             area->place.x, area->place.y, area->place.width, area->place.height);
 #endif


=====================================
modules/video_output/win32/common.h
=====================================
@@ -38,6 +38,8 @@ typedef struct display_win32_area_t
     vout_display_place_t  place;
     bool                  place_changed;
     struct event_thread_t *event; // only use if sys.event is not NULL
+
+    const video_format_t  *src_fmt;
 } display_win32_area_t;
 
 #define RECTWidth(r)   (LONG)((r).right - (r).left)
@@ -56,7 +58,7 @@ void CommonControl(vout_display_t *, display_win32_area_t *, int );
 
 void CommonPlacePicture (vout_display_t *, display_win32_area_t *);
 
-void CommonInit(display_win32_area_t *);
+void CommonInit(display_win32_area_t *, const video_format_t *);
 
 void* HookWindowsSensors(vout_display_t*, HWND);
 void UnhookWindowsSensors(void*);


=====================================
modules/video_output/win32/d3d11_scaler.cpp
=====================================
@@ -0,0 +1,444 @@
+// 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 <vlc_common.h>
+
+#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[DXGI_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, DXGI_RGB_FORMAT|DXGI_YUV_FORMAT, 0, 0, 0, DXGI_CHROMA_GPU, 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_placement *cfg)
+{
+    HRESULT hr;
+    ID3D11Texture2D *_upscaled[DXGI_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.fitting = VLC_VIDEO_FIT_SMALLER;
+    vout_display_PlacePicture(&place, fmt, &display);
+
+    unsigned out_width, out_height;
+    out_width  = (display.width + (scaleProc->d3d_fmt->widthDenominator-1)) & ~(scaleProc->d3d_fmt->widthDenominator-1);
+    out_height = (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 &&
+        vout_display_PlaceEquals(&scaleProc->place, &place))
+        // 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_AllocateResourceView(vlc_object_logger(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_d3d11_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_d3d11_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[DXGI_MAX_SHADER_VIEW])
+{
+    for (size_t i=0; i<DXGI_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_placement *);
+int D3D11_UpscalerScale(vlc_object_t *, struct d3d11_scaler *, picture_sys_d3d11_t *);
+bool D3D11_UpscalerUsed(const struct d3d11_scaler *);
+void D3D11_UpscalerGetSRV(const struct d3d11_scaler *, ID3D11ShaderResourceView *SRV[DXGI_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/d3d11_shaders.h
=====================================
@@ -39,9 +39,15 @@ struct d3d11_vertex_shader_t {
 /* A Quad is texture that can be displayed in a rectangle */
 struct d3d11_quad_t
 {
+    d3d11_quad_t()
+    {
+        video_format_Init(&quad_fmt, 0);
+    }
+
     ~d3d11_quad_t()
     {
         ReleaseD3D11PictureSys(&picSys);
+        video_format_Clean(&quad_fmt);
     }
 
     void Reset();
@@ -49,6 +55,7 @@ struct d3d11_quad_t
 
     picture_sys_d3d11_t       picSys = {};
     d3d_quad_t                generic = {};
+    video_format_t            quad_fmt = {};
     UINT                      resourceCount = 0;
     Microsoft::WRL::ComPtr<ID3D11Buffer> vertexBuffer;
     Microsoft::WRL::ComPtr<ID3D11Buffer> indexBuffer;


=====================================
modules/video_output/win32/direct3d11.cpp
=====================================
@@ -43,6 +43,7 @@
 
 #include "d3d11_quad.h"
 #include "d3d11_shaders.h"
+#include "d3d11_scaler.h"
 #ifndef VLC_WINSTORE_APP
 #include "d3d11_swapchain.h"
 #endif
@@ -61,6 +62,14 @@ static void Close(vout_display_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"))
@@ -69,10 +78,21 @@ vlc_module_begin ()
 
     add_bool("direct3d11-hw-blending", true, HW_BLENDING_TEXT, HW_BLENDING_LONGTEXT)
 
+    add_string("d3d11-upscale-mode", "linear", UPSCALE_MODE_TEXT, UPSCALE_MODE_LONGTEXT)
+        change_string_list(ppsz_upscale_mode, ppsz_upscale_mode_text)
+
     add_shortcut("direct3d11")
     set_callback_display(Open, 300)
 vlc_module_end ()
 
+enum d3d11_upscale
+{
+    upscale_LinearSampler,
+    upscale_PointSampler,
+    upscale_VideoProcessor,
+    upscale_SuperResolution,
+};
+
 typedef struct vout_display_sys_t
 {
     display_win32_area_t     area;
@@ -116,6 +136,10 @@ typedef struct vout_display_sys_t
     libvlc_video_makeCurrent_cb              startEndRenderingCb;
     libvlc_video_frameMetadata_cb            sendMetadataCb;
     libvlc_video_output_select_plane_cb      selectPlaneCb;
+
+    // upscaling
+    enum d3d11_upscale       upscaleMode;
+    d3d11_scaler             *scaleProc;
 } vout_display_sys_t;
 
 static void Prepare(vout_display_t *, picture_t *, subpicture_t *subpicture, vlc_tick_t);
@@ -185,6 +209,12 @@ static int UpdateDisplayFormat(vout_display_t *vd, const video_format_t *fmt)
         return VLC_EGENERIC;
     }
 
+    if (sys->upscaleMode == upscale_VideoProcessor || sys->upscaleMode == upscale_SuperResolution)
+    {
+        D3D11_UpscalerUpdate(VLC_OBJECT(vd), sys->scaleProc, sys->d3d_dev,
+                             vd->source, &sys->picQuad.quad_fmt, &vd->cfg->display);
+    }
+
     display_info_t new_display = { };
 
     new_display.pixelFormat = D3D11_RenderFormat((DXGI_FORMAT)out.dxgi_format, false);
@@ -252,10 +282,10 @@ static void UpdateSize(vout_display_t *vd)
     sys->picQuad.UpdateViewport( &rect_dst, sys->display.pixelFormat );
 
     RECT source_rect;
-    source_rect.left   = vd->source->i_x_offset;
-    source_rect.right  = vd->source->i_x_offset + vd->source->i_visible_width;
-    source_rect.top    = vd->source->i_y_offset;
-    source_rect.bottom = vd->source->i_y_offset + vd->source->i_visible_height;
+    source_rect.left   = sys->picQuad.quad_fmt.i_x_offset;
+    source_rect.right  = sys->picQuad.quad_fmt.i_x_offset + sys->picQuad.quad_fmt.i_visible_width;
+    source_rect.top    = sys->picQuad.quad_fmt.i_y_offset;
+    source_rect.bottom = sys->picQuad.quad_fmt.i_y_offset + sys->picQuad.quad_fmt.i_visible_height;
     d3d11_device_lock( sys->d3d_dev );
 
     D3D11_UpdateQuadPosition(vd, sys->d3d_dev, &sys->picQuad, &source_rect,
@@ -345,7 +375,7 @@ static int Open(vout_display_t *vd,
     if (ret != VLC_SUCCESS)
         goto error;
 
-    CommonInit(&sys->area);
+    CommonInit(&sys->area, &sys->picQuad.quad_fmt);
 
     sys->outside_opaque = var_InheritAddress( vd, "vout-cb-opaque" );
     sys->updateOutputCb      = (libvlc_video_update_output_cb)var_InheritAddress( vd, "vout-cb-update-output" );
@@ -450,6 +480,26 @@ static void Close(vout_display_t *vd)
 static int Control(vout_display_t *vd, int query)
 {
     vout_display_sys_t *sys = static_cast<vout_display_sys_t *>(vd->sys);
+
+    if (sys->upscaleMode == upscale_VideoProcessor || sys->upscaleMode == upscale_SuperResolution)
+    {
+        D3D11_UpscalerUpdate(VLC_OBJECT(vd), sys->scaleProc, sys->d3d_dev,
+                             vd->source, &sys->picQuad.quad_fmt, &vd->cfg->display);
+
+        if (sys->scaleProc && D3D11_UpscalerUsed(sys->scaleProc))
+        {
+            D3D11_UpscalerGetSize(sys->scaleProc, &sys->picQuad.quad_fmt.i_width, &sys->picQuad.quad_fmt.i_height);
+
+            sys->picQuad.quad_fmt.i_x_offset       = 0;
+            sys->picQuad.quad_fmt.i_y_offset       = 0;
+            sys->picQuad.quad_fmt.i_visible_width  = sys->picQuad.quad_fmt.i_width;
+            sys->picQuad.quad_fmt.i_visible_height = sys->picQuad.quad_fmt.i_height;
+
+            sys->picQuad.generic.i_width = sys->picQuad.quad_fmt.i_width;
+            sys->picQuad.generic.i_height = sys->picQuad.quad_fmt.i_height;
+        }
+    }
+
     CommonControl( vd, &sys->area, query );
 
     if ( sys->area.place_changed )
@@ -540,7 +590,17 @@ static void PreparePicture(vout_display_t *vd, picture_t *picture, subpicture_t
         D3D11_TEXTURE2D_DESC srcDesc;
         p_sys->texture[KNOWN_DXGI_INDEX]->GetDesc(&srcDesc);
 
-        if (sys->legacy_shader) {
+        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;
+        }
+        else if (sys->legacy_shader)
+        {
             D3D11_TEXTURE2D_DESC texDesc;
             sys->stagingSys.texture[0]->GetDesc(&texDesc);
             D3D11_BOX box;
@@ -568,8 +628,10 @@ static void PreparePicture(vout_display_t *vd, picture_t *picture, subpicture_t
             {
                 /* the decoder produced different sizes than the vout, we need to
                  * adjust the vertex */
-                sys->picQuad.generic.i_height = srcDesc.Height;
-                sys->picQuad.generic.i_width  = srcDesc.Width;
+                sys->picQuad.quad_fmt.i_width  = srcDesc.Width;
+                sys->picQuad.quad_fmt.i_height = srcDesc.Height;
+                sys->picQuad.generic.i_width  = sys->picQuad.quad_fmt.i_width;
+                sys->picQuad.generic.i_height = sys->picQuad.quad_fmt.i_height;
 
                 CommonPlacePicture(vd, &sys->area);
                 UpdateSize(vd);
@@ -593,7 +655,13 @@ static void PreparePicture(vout_display_t *vd, picture_t *picture, subpicture_t
 
     /* Render the quad */
     ID3D11ShaderResourceView **renderSrc;
-    if (sys->legacy_shader)
+    ID3D11ShaderResourceView *SRV[DXGI_MAX_SHADER_VIEW];
+    if (sys->scaleProc && D3D11_UpscalerUsed(sys->scaleProc))
+    {
+        D3D11_UpscalerGetSRV(sys->scaleProc, SRV);
+        renderSrc = SRV;
+    }
+    else if (sys->legacy_shader)
         renderSrc = sys->stagingSys.renderSrc;
     else {
         picture_sys_d3d11_t *p_sys = ActiveD3D11PictureSys(picture);
@@ -717,6 +785,24 @@ static const d3d_format_t *GetBlendableFormat(vout_display_t *vd, vlc_fourcc_t i
     return FindD3D11Format( vd, sys->d3d_dev, i_src_chroma, DXGI_RGB_FORMAT|DXGI_YUV_FORMAT, 0, 0, 0, DXGI_CHROMA_CPU, supportFlags );
 }
 
+static void InitScaleProcessor(vout_display_t *vd)
+{
+    vout_display_sys_t *sys = static_cast<vout_display_sys_t *>(vd->sys);
+    if (sys->upscaleMode != upscale_VideoProcessor && sys->upscaleMode != upscale_SuperResolution)
+        return;
+
+    sys->scaleProc = D3D11_UpscalerCreate(VLC_OBJECT(vd), sys->d3d_dev, sys->picQuad.quad_fmt.i_chroma,
+                                          sys->upscaleMode == upscale_SuperResolution);
+    if (sys->scaleProc == NULL)
+    {
+        msg_Dbg(vd, "forcing linear sampler");
+        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, video_format_t *fmtp, vlc_video_context *vctx)
 {
     vout_display_sys_t *sys = static_cast<vout_display_sys_t *>(vd->sys);
@@ -753,15 +839,37 @@ static int Direct3D11Open(vout_display_t *vd, video_format_t *fmtp, vlc_video_co
         }
     }
 
+    video_format_Copy(&sys->picQuad.quad_fmt, &fmt);
+    if (!is_d3d11_opaque(fmt.i_chroma))
+        sys->picQuad.quad_fmt.i_chroma = sys->picQuad.generic.textureFormat->fourcc;
+
     /* adjust the decoder sizes to have proper padding */
-    sys->picQuad.generic.i_width  = fmt.i_width;
-    sys->picQuad.generic.i_height = fmt.i_height;
     if ( sys->picQuad.generic.textureFormat->formatTexture != DXGI_FORMAT_R8G8B8A8_UNORM &&
          sys->picQuad.generic.textureFormat->formatTexture != DXGI_FORMAT_B5G6R5_UNORM )
     {
-        sys->picQuad.generic.i_width  = (sys->picQuad.generic.i_width  + 0x01) & ~0x01;
-        sys->picQuad.generic.i_height = (sys->picQuad.generic.i_height + 0x01) & ~0x01;
+        sys->picQuad.quad_fmt.i_width  = (sys->picQuad.quad_fmt.i_width  + 0x01) & ~0x01;
+        sys->picQuad.quad_fmt.i_height = (sys->picQuad.quad_fmt.i_height + 0x01) & ~0x01;
+    }
+    sys->picQuad.generic.i_width  = sys->picQuad.quad_fmt.i_width;
+    sys->picQuad.generic.i_height = sys->picQuad.quad_fmt.i_height;
+
+    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);
+
+    InitScaleProcessor(vd);
 
     CommonPlacePicture(vd, &sys->area);
 
@@ -990,7 +1098,8 @@ static int Direct3D11CreateFormatResources(vout_display_t *vd, const video_forma
     vout_display_sys_t *sys = static_cast<vout_display_sys_t *>(vd->sys);
     HRESULT hr;
 
-    sys->legacy_shader = sys->d3d_dev->feature_level < D3D_FEATURE_LEVEL_10_0 || !CanUseTextureArray(vd) ||
+    sys->legacy_shader = sys->d3d_dev->feature_level < D3D_FEATURE_LEVEL_10_0 ||
+            (sys->scaleProc == nullptr && !CanUseTextureArray(vd)) ||
             BogusZeroCopy(vd) || !is_d3d11_opaque(fmt->i_chroma);
 
     d3d_shader_blob pPSBlob[DXGI_MAX_RENDER_TARGET] = { };
@@ -1003,7 +1112,7 @@ static int Direct3D11CreateFormatResources(vout_display_t *vd, const video_forma
         msg_Err(vd, "Failed to compile the pixel shader. (hr=0x%lX)", hr);
         return VLC_EGENERIC;
     }
-    hr = D3D11_SetQuadPixelShader(VLC_OBJECT(vd), sys->d3d_dev, false,
+    hr = D3D11_SetQuadPixelShader(VLC_OBJECT(vd), sys->d3d_dev, sys->upscaleMode != upscale_LinearSampler,
                                   &sys->picQuad, pPSBlob);
     if (FAILED(hr))
     {
@@ -1011,13 +1120,13 @@ static int Direct3D11CreateFormatResources(vout_display_t *vd, const video_forma
         return VLC_EGENERIC;
     }
 
-    if (D3D11_AllocateQuad(vd, sys->d3d_dev, vd->source->projection_mode, &sys->picQuad) != VLC_SUCCESS)
+    if (D3D11_AllocateQuad(vd, sys->d3d_dev, sys->picQuad.quad_fmt.projection_mode, &sys->picQuad) != VLC_SUCCESS)
     {
         msg_Err(vd, "Could not allocate quad buffers.");
        return VLC_EGENERIC;
     }
 
-    if (D3D11_SetupQuad( vd, sys->d3d_dev, vd->source, &sys->picQuad, &sys->display) != VLC_SUCCESS)
+    if (D3D11_SetupQuad( vd, sys->d3d_dev, &sys->picQuad.quad_fmt, &sys->picQuad, &sys->display) != VLC_SUCCESS)
     {
         msg_Err(vd, "Could not Create the main quad picture.");
         return VLC_EGENERIC;
@@ -1029,7 +1138,7 @@ static int Direct3D11CreateFormatResources(vout_display_t *vd, const video_forma
     source_rect.top    = fmt->i_y_offset;
     source_rect.bottom = fmt->i_y_offset + fmt->i_visible_height;
     if (!D3D11_UpdateQuadPosition(vd, sys->d3d_dev, &sys->picQuad, &source_rect,
-                                  video_format_GetTransform(vd->source->orientation, sys->display.orientation)))
+                                  video_format_GetTransform(sys->picQuad.quad_fmt.orientation, sys->display.orientation)))
     {
         msg_Err(vd, "Could not set quad picture position.");
         return VLC_EGENERIC;
@@ -1163,6 +1272,12 @@ static void Direct3D11DestroyResources(vout_display_t *vd)
 {
     vout_display_sys_t *sys = static_cast<vout_display_sys_t *>(vd->sys);
 
+    if (sys->scaleProc != nullptr)
+    {
+        D3D11_UpscalerDestroy(sys->scaleProc);
+        sys->scaleProc = nullptr;
+    }
+
     sys->picQuad.Reset();
     Direct3D11DeleteRegions(sys->d3dregion_count, sys->d3dregions);
     sys->d3dregion_count = 0;


=====================================
modules/video_output/win32/direct3d9.c
=====================================
@@ -1783,7 +1783,7 @@ static int Open(vout_display_t *vd,
     if (!sys)
         return VLC_ENOMEM;
 
-    CommonInit(&sys->area);
+    CommonInit(&sys->area, vd->source);
 
     sys->outside_opaque = var_InheritAddress( vd, "vout-cb-opaque" );
     sys->updateOutputCb      = var_InheritAddress( vd, "vout-cb-update-output" );


=====================================
modules/video_output/win32/glwin32.c
=====================================
@@ -131,7 +131,7 @@ static int Open(vout_display_t *vd,
         return VLC_ENOMEM;
 
     /* */
-    CommonInit(&sys->area);
+    CommonInit(&sys->area, vd->source);
     if (CommonWindowInit(vd, &sys->area,
                    vd->source->projection_mode != PROJECTION_MODE_RECTANGULAR))
         goto error;


=====================================
modules/video_output/win32/meson.build
=====================================
@@ -3,7 +3,7 @@
 #
 
 # Direct3D11 video output
-d3d11_sources = files('direct3d11.cpp', 'd3d11_quad.cpp', 'd3d11_shaders.cpp', 'd3d_shaders.c', 'd3d_dynamic_shader.c', 'common.c')
+d3d11_sources = files('direct3d11.cpp', 'd3d11_quad.cpp', 'd3d11_scaler.cpp', 'd3d11_shaders.cpp', 'd3d_shaders.c', 'd3d_dynamic_shader.c', 'common.c')
 d3d11_link_with = [ d3d11_common_lib ]
 d3d11_deps = []
 if get_option('winstore_app')


=====================================
modules/video_output/win32/wingdi.c
=====================================
@@ -123,7 +123,7 @@ static int Open(vout_display_t *vd,
     if (!sys)
         return VLC_ENOMEM;
 
-    CommonInit(&sys->area);
+    CommonInit(&sys->area, vd->source);
     if (CommonWindowInit(vd, &sys->area, false))
         goto error;
     CommonPlacePicture(vd, &sys->area);



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/373df52b7eb9c711945eccd5baadd3c7d6c0b5a8...8892ebd6f1735fde6433473e7737767733a180ae

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/373df52b7eb9c711945eccd5baadd3c7d6c0b5a8...8892ebd6f1735fde6433473e7737767733a180ae
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