[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,
+ ¶m,
+ };
+
+ 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