[vlc-commits] [Git][videolan/vlc][3.0.x] 9 commits: direct3d11: use a function to select the output format
Felix Paul Kühne (@fkuehne)
gitlab at videolan.org
Sun Mar 17 11:57:25 UTC 2024
Felix Paul Kühne pushed to branch 3.0.x at VideoLAN / VLC
Commits:
8c2c4db1 by Steve Lhomme at 2024-03-14T12:46:39+01:00
direct3d11: use a function to select the output format
This avoids a bit of indentation and makes it clearer what the goal of the code block is.
- - - - -
2192dfbf by Steve Lhomme at 2024-03-14T12:46:39+01:00
direct3d11: use a function to select the closets output format
When decoder ones can't be used.
- - - - -
6da53f38 by Steve Lhomme at 2024-03-14T12:46:39+01:00
direct3d11: add an option to select the HDR output mode
- - - - -
b4f9d49b by Steve Lhomme at 2024-03-14T12:46:39+01:00
direct3d11: fill the pool format directly
No need for an intermediate format that we need to copy.
- - - - -
b6a3a8b1 by Steve Lhomme at 2024-03-14T12:46:39+01:00
direct3d11: allow setting the quad_fmt differently than the decoder format
- - - - -
4d32caff by Steve Lhomme at 2024-03-14T12:46:39+01:00
d3d11_fmt: add a helper to find a hardware/software based d3d_format_t
(cherry picked from commit 230fdf54a20e95a93ba61b7448c256977eb3c42b) (edited)
edited:
- not located in the same place in 3.0
- - - - -
2fca4284 by Steve Lhomme at 2024-03-15T15:17:53+01:00
d3d11: add a VideoProcessor to handle tone mapping
- - - - -
1465e4a9 by Steve Lhomme at 2024-03-15T16:11:08+01:00
direct3d11: add an option to force HDR output from SDR source
- - - - -
6d82c5af by Steve Lhomme at 2024-03-15T16:11:08+01:00
NEWS: add D3D11 forced HDR/SDR option
- - - - -
6 changed files:
- NEWS
- modules/video_chroma/d3d11_fmt.h
- modules/video_output/Makefile.am
- + modules/video_output/win32/d3d11_tonemap.cpp
- + modules/video_output/win32/d3d11_tonemap.h
- modules/video_output/win32/direct3d11.c
Changes:
=====================================
NEWS
=====================================
@@ -6,7 +6,10 @@ Decoders:
- Fix some ASS subtitle rendering issues
Video Output:
- * Super Resolution scaling with AMD GPUs
+ - Super Resolution scaling with AMD GPUs
+ - Add D3D11 option to use NVIDIA TrueHDR to generate HDR from SDR sources
+ - The D3D11 HDR option can also turn on/off HDR for all sources regardless of
+ the display
Audio Output:
- Fix regression on macOS causing crashes when using audio devices
=====================================
modules/video_chroma/d3d11_fmt.h
=====================================
@@ -144,6 +144,20 @@ const d3d_format_t *FindD3D11Format(vlc_object_t *,
#define FindD3D11Format(a,b,c,d,e,f,g,h,i) \
FindD3D11Format(VLC_OBJECT(a),b,c,d,e,f,g,h,i)
+static inline const d3d_format_t *D3D11_RenderFormat(DXGI_FORMAT opaque, bool gpu_based)
+{
+ for (const d3d_format_t *output_format = GetRenderFormatList();
+ output_format->name != NULL; ++output_format)
+ {
+ if (output_format->formatTexture == opaque &&
+ is_d3d11_opaque(output_format->fourcc) == gpu_based)
+ {
+ return output_format;
+ }
+ }
+ return NULL;
+}
+
int AllocateTextures(vlc_object_t *, d3d11_device_t *, const d3d_format_t *,
const video_format_t *, unsigned pool_size, ID3D11Texture2D *textures[]);
#define AllocateTextures(a,b,c,d,e,f) AllocateTextures(VLC_OBJECT(a),b,c,d,e,f)
=====================================
modules/video_output/Makefile.am
=====================================
@@ -284,7 +284,8 @@ 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/d3d11_scaler.cpp video_output/win32/d3d11_scaler.h
+ video_output/win32/d3d11_scaler.cpp video_output/win32/d3d11_scaler.h \
+ video_output/win32/d3d11_tonemap.cpp video_output/win32/d3d11_tonemap.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/d3d11_tonemap.cpp
=====================================
@@ -0,0 +1,267 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*****************************************************************************
+ * d3d11_tonemap: Direct3D11 VideoProcessor to handle tonemapping
+ *****************************************************************************
+ * Copyright © 2024 Videolabs, VLC authors and VideoLAN
+ *
+ * Authors: Steve Lhomme <robux4 at videolabs.io>
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "d3d11_tonemap.h"
+
+#include <cassert>
+
+#include <wrl/client.h>
+using Microsoft::WRL::ComPtr;
+
+struct d3d11_tonemapper
+{
+ ComPtr<ID3D11VideoDevice> d3dviddev;
+ ComPtr<ID3D11VideoContext> d3dvidctx;
+ ComPtr<ID3D11VideoProcessorEnumerator> enumerator;
+ ComPtr<ID3D11VideoProcessor> processor;
+
+ ComPtr<ID3D11VideoProcessorOutputView> outputView;
+ ComPtr<ID3D11ShaderResourceView> SRV;
+ picture_sys_t picsys{};
+};
+
+d3d11_tonemapper *D3D11_TonemapperCreate(vlc_object_t *vd, d3d11_device_t *d3d_dev,
+ const video_format_t *in)
+{
+ if (!is_d3d11_opaque(in->i_chroma))
+ {
+ msg_Dbg(vd, "VideoProcessor tone mapping not supported by CPU formats");
+ return nullptr;
+ }
+
+ if (in->transfer == TRANSFER_FUNC_SMPTE_ST2084 ||
+ in->transfer == TRANSFER_FUNC_HLG)
+ {
+ return nullptr; // the source is already in HDR
+ }
+
+ ComPtr<ID3D11Texture2D> texture;
+ ID3D11Texture2D *_texture[D3D11_MAX_SHADER_VIEW] = {};
+ D3D11_TEXTURE2D_DESC texDesc { };
+ D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outDesc{ };
+ d3d11_tonemapper *tonemapProc = new d3d11_tonemapper();
+ const auto d3d_fmt = D3D11_RenderFormat(DXGI_FORMAT_R10G10B10A2_UNORM, false);
+ assert(d3d_fmt != nullptr);
+
+ HRESULT hr;
+ hr = d3d_dev->d3ddevice->QueryInterface(IID_GRAPHICS_PPV_ARGS(&tonemapProc->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(&tonemapProc->d3dvidctx));
+ if (unlikely(FAILED(hr)))
+ {
+ msg_Err(vd, "Could not Query ID3D11VideoContext Interface. (hr=0x%lX)", hr);
+ goto error;
+ }
+
+ {
+ D3D11_VIDEO_PROCESSOR_CONTENT_DESC processorDesc{};
+ processorDesc.InputFrameFormat = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE;
+ processorDesc.InputFrameRate = {
+ in->i_frame_rate, in->i_frame_rate_base,
+ };
+ processorDesc.InputWidth = in->i_width;
+ processorDesc.InputHeight = in->i_height;
+ processorDesc.OutputWidth = in->i_width;
+ processorDesc.OutputHeight = in->i_height;
+ processorDesc.OutputFrameRate = {
+ in->i_frame_rate, in->i_frame_rate_base,
+ };
+ processorDesc.Usage = D3D11_VIDEO_USAGE_PLAYBACK_NORMAL;
+ hr = tonemapProc->d3dviddev->CreateVideoProcessorEnumerator(&processorDesc, &tonemapProc->enumerator);
+ if (FAILED(hr))
+ {
+ msg_Dbg(vd, "Can't get a video processor for the video (error 0x%lx).", hr);
+ goto error;
+ }
+
+ hr = tonemapProc->d3dviddev->CreateVideoProcessor(tonemapProc->enumerator.Get(), 0,
+ &tonemapProc->processor);
+ if (FAILED(hr))
+ {
+ msg_Dbg(vd, "failed to create the processor (error 0x%lx).", hr);
+ goto error;
+ }
+ }
+
+ // we can only use this filter with the NVIDIA extension as the VideoProcessor
+ // doesn't provide a proper API to set the input and output colorimetry
+
+ // NVIDIA 545+ driver
+ if (d3d_dev->adapterDesc.VendorId != GPU_MANUFACTURER_NVIDIA ||
+ (d3d_dev->WDDM.revision * 10000 + d3d_dev->WDDM.build) < 154500)
+ goto error;
+
+ {
+ constexpr GUID kNvidiaTrueHDRInterfaceGUID{ 0xfdd62bb4, 0x620b, 0x4fd7, {0x9a, 0xb3, 0x1e, 0x59, 0xd0, 0xd5, 0x44, 0xb3} };
+ UINT available = 0;
+ d3d11_device_lock(d3d_dev);
+ hr = tonemapProc->d3dvidctx->VideoProcessorGetStreamExtension(tonemapProc->processor.Get(),
+ 0, &kNvidiaTrueHDRInterfaceGUID, sizeof(available), &available);
+
+ if (!available)
+ {
+ d3d11_device_unlock(d3d_dev);
+ goto error;
+ }
+
+ constexpr UINT kStreamExtensionMethodTrueHDR = 0x3;
+ constexpr UINT TrueHDRVersion4 = 4;
+ struct {
+ UINT version;
+ UINT method;
+ UINT enable : 1;
+ UINT reserved : 31;
+ } stream_extension_info = {TrueHDRVersion4,
+ kStreamExtensionMethodTrueHDR,
+ 1u,
+ 0u};
+ hr = tonemapProc->d3dvidctx->VideoProcessorSetStreamExtension(
+ tonemapProc->processor.Get(),
+ 0, &kNvidiaTrueHDRInterfaceGUID,
+ sizeof(stream_extension_info), &stream_extension_info);
+ if (unlikely(FAILED(hr)))
+ {
+ msg_Warn(vd, "Failed to enable NVIDIA True HDR");
+ }
+ d3d11_device_unlock(d3d_dev);
+ }
+
+ // we need a texture that will receive the upscale version
+ texDesc.MipLevels = 1;
+ texDesc.SampleDesc.Count = 1;
+ texDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
+ texDesc.Usage = D3D11_USAGE_DEFAULT;
+ texDesc.CPUAccessFlags = 0;
+ texDesc.ArraySize = 1;
+ texDesc.Format = d3d_fmt->formatTexture;
+ texDesc.Width = in->i_width;
+ texDesc.Height = in->i_height;
+ texDesc.MiscFlags = 0;
+ hr = d3d_dev->d3ddevice->CreateTexture2D(&texDesc, nullptr, texture.GetAddressOf());
+ if (FAILED(hr))
+ {
+ msg_Err(vd, "Failed to create the tonemap texture. (hr=0x%lX)", hr);
+ goto error;
+ }
+
+ outDesc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D;
+ outDesc.Texture2D.MipSlice = 0;
+
+ hr = tonemapProc->d3dviddev->CreateVideoProcessorOutputView(
+ texture.Get(),
+ tonemapProc->enumerator.Get(),
+ &outDesc,
+ tonemapProc->outputView.ReleaseAndGetAddressOf());
+ if (FAILED(hr))
+ {
+ msg_Dbg(vd,"Failed to create processor output. (hr=0x%lX)", hr);
+ goto error;
+ }
+
+ _texture[0] = texture.Get();
+ _texture[1] = texture.Get();
+ _texture[2] = texture.Get();
+ _texture[3] = texture.Get();
+ if ((D3D11_AllocateShaderView)(vd, d3d_dev->d3ddevice, d3d_fmt,
+ _texture, 0, tonemapProc->SRV.GetAddressOf()) != VLC_SUCCESS)
+ goto error;
+
+ {
+ RECT srcRect;
+ srcRect.left = 0;
+ srcRect.top = 0;
+ srcRect.right = texDesc.Width;
+ srcRect.bottom = texDesc.Height;
+
+ RECT dstRect = srcRect;
+
+ d3d11_device_lock(d3d_dev);
+ tonemapProc->d3dvidctx->VideoProcessorSetStreamSourceRect(tonemapProc->processor.Get(),
+ 0, TRUE, &srcRect);
+
+ tonemapProc->d3dvidctx->VideoProcessorSetStreamDestRect(tonemapProc->processor.Get(),
+ 0, TRUE, &dstRect);
+
+ d3d11_device_unlock(d3d_dev);
+ }
+
+ tonemapProc->picsys.texture[0] = texture.Get();
+ tonemapProc->picsys.resourceView[0] = tonemapProc->SRV.Get();
+ tonemapProc->picsys.formatTexture = texDesc.Format;
+
+ return tonemapProc;
+error:
+ delete tonemapProc;
+ return nullptr;
+}
+
+void D3D11_TonemapperDestroy(d3d11_tonemapper *tonemapProc)
+{
+ delete tonemapProc;
+}
+
+picture_sys_t *D3D11_TonemapperGetOutput(d3d11_tonemapper *tonemapProc)
+{
+ return &tonemapProc->picsys;
+}
+
+static HRESULT assert_ProcessorInput(vlc_object_t *vd, d3d11_tonemapper *tonemapProc, 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 = tonemapProc->d3dviddev->CreateVideoProcessorInputView(
+ p_sys_src->resource[KNOWN_DXGI_INDEX],
+ tonemapProc->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 hr;
+ }
+ }
+ return S_OK;
+}
+
+HRESULT D3D11_TonemapperProcess(vlc_object_t *vd, d3d11_tonemapper *tonemapProc, picture_sys_t *in)
+{
+ HRESULT hr = assert_ProcessorInput(vd, tonemapProc, in);
+ if (FAILED(hr))
+ return hr;
+
+ D3D11_VIDEO_PROCESSOR_STREAM stream{};
+ stream.Enable = TRUE;
+ stream.pInputSurface = in->processorInput;
+
+ hr = tonemapProc->d3dvidctx->VideoProcessorBlt(tonemapProc->processor.Get(),
+ tonemapProc->outputView.Get(),
+ 0, 1, &stream);
+ if (FAILED(hr))
+ msg_Err(vd, "Failed to render the texture. (hr=0x%lX)", hr);
+ return hr;
+}
=====================================
modules/video_output/win32/d3d11_tonemap.h
=====================================
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*****************************************************************************
+ * d3d11_tonemap: Direct3D11 VideoProcessor to handle tonemapping
+ *****************************************************************************
+ * Copyright © 2024 Videolabs, VLC authors and VideoLAN
+ *
+ * Authors: Steve Lhomme <robux4 at videolabs.io>
+ *****************************************************************************/
+
+#ifndef VLC_D3D11_TONEMAP_H
+#define VLC_D3D11_TONEMAP_H
+
+#include "d3d11_quad.h"
+#include "../../video_chroma/d3d11_fmt.h"
+#include <vlc_vout_display.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct d3d11_tonemapper;
+
+struct d3d11_tonemapper *D3D11_TonemapperCreate(vlc_object_t *, d3d11_device_t *,
+ const video_format_t * in);
+void D3D11_TonemapperDestroy(struct d3d11_tonemapper *);
+HRESULT D3D11_TonemapperProcess(vlc_object_t *, struct d3d11_tonemapper *, picture_sys_t *);
+struct picture_sys_t *D3D11_TonemapperGetOutput(struct d3d11_tonemapper *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // VLC_D3D11_TONEMAP_H
=====================================
modules/video_output/win32/direct3d11.c
=====================================
@@ -56,6 +56,7 @@
#include "d3d11_quad.h"
#include "d3d11_shaders.h"
#include "d3d11_scaler.h"
+#include "d3d11_tonemap.h"
#include "common.h"
@@ -78,6 +79,14 @@ static const char *const ppsz_upscale_mode[] = {
static const char *const ppsz_upscale_mode_text[] = {
N_("Linear Sampler"), N_("Point Sampler"), N_("Video Processor"), N_("Super Resolution") };
+#define HDR_MODE_TEXT N_("HDR Output Mode")
+#define HDR_MODE_LONGTEXT N_("Use HDR output even if the source is SDR.")
+
+static const char *const ppsz_hdr_mode[] = {
+ "auto", "never", "always", "generate" };
+static const char *const ppsz_hdr_mode_text[] = {
+ N_("Auto"), N_("Never out HDR"), N_("Always output HDR"), N_("Generate HDR from SDR") };
+
vlc_module_begin ()
set_shortname("Direct3D11")
set_description(N_("Direct3D11 video output"))
@@ -95,6 +104,9 @@ vlc_module_begin ()
add_string("d3d11-upscale-mode", "linear", UPSCALE_MODE_TEXT, UPSCALE_MODE_LONGTEXT, false)
change_string_list(ppsz_upscale_mode, ppsz_upscale_mode_text)
+ add_string("d3d11-hdr-mode", "auto", HDR_MODE_TEXT, HDR_MODE_LONGTEXT, false)
+ change_string_list(ppsz_hdr_mode, ppsz_hdr_mode_text)
+
set_capability("vout display", 300)
add_shortcut("direct3d11")
set_callbacks(Open, Close)
@@ -108,6 +120,14 @@ enum d3d11_upscale
upscale_SuperResolution,
};
+enum d3d11_hdr
+{
+ hdr_Auto,
+ hdr_Never,
+ hdr_Always,
+ hdr_Fake,
+};
+
struct vout_display_sys_t
{
vout_display_sys_win32_t sys;
@@ -157,6 +177,10 @@ struct vout_display_sys_t
// upscaling
enum d3d11_upscale upscaleMode;
struct d3d11_scaler *scaleProc;
+
+ // HDR mode
+ enum d3d11_hdr hdrMode;
+ struct d3d11_tonemapper *tonemapProc;
};
#define RECTWidth(r) (int)((r).right - (r).left)
@@ -172,7 +196,7 @@ static void Direct3D11Destroy(vout_display_t *);
static int Direct3D11Open (vout_display_t *, bool external_device);
static void Direct3D11Close(vout_display_t *);
-static int SetupOutputFormat(vout_display_t *, video_format_t *);
+static int SetupOutputFormat(vout_display_t *, video_format_t *decoder, video_format_t *quad);
static int Direct3D11CreateFormatResources (vout_display_t *, const video_format_t *);
static int Direct3D11CreateGenericResources(vout_display_t *);
static void Direct3D11DestroyResources(vout_display_t *);
@@ -513,6 +537,7 @@ static void DestroyDisplayPoolPicture(picture_t *picture)
#if !VLC_WINSTORE_APP
static void FillSwapChainDesc(vout_display_t *vd, DXGI_SWAP_CHAIN_DESC1 *out)
{
+ vout_display_sys_t *sys = vd->sys;
ZeroMemory(out, sizeof(*out));
out->BufferCount = 3;
out->BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
@@ -520,14 +545,15 @@ static void FillSwapChainDesc(vout_display_t *vd, DXGI_SWAP_CHAIN_DESC1 *out)
out->SampleDesc.Quality = 0;
out->Width = vd->source.i_visible_width;
out->Height = vd->source.i_visible_height;
- switch(vd->source.i_chroma)
- {
- case VLC_CODEC_D3D11_OPAQUE_10B:
+ out->Format = DXGI_FORMAT_R8G8B8A8_UNORM; /* TODO: use DXGI_FORMAT_NV12 */
+ if (sys->hdrMode == hdr_Always || sys->hdrMode == hdr_Fake)
out->Format = DXGI_FORMAT_R10G10B10A2_UNORM;
- break;
- default:
- out->Format = DXGI_FORMAT_R8G8B8A8_UNORM; /* TODO: use DXGI_FORMAT_NV12 */
- break;
+ else if (sys->hdrMode == hdr_Auto)
+ {
+ if ( vd->source.i_chroma == VLC_CODEC_D3D11_OPAQUE_10B ||
+ vd->source.transfer == TRANSFER_FUNC_SMPTE_ST2084 ||
+ vd->source.transfer == TRANSFER_FUNC_HLG)
+ out->Format = DXGI_FORMAT_R10G10B10A2_UNORM;
}
//out->Flags = 512; // DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO;
@@ -1026,7 +1052,13 @@ static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpic
if (is_d3d11_opaque(picture->format.i_chroma))
d3d11_device_lock( &sys->d3d_dev );
- if (sys->scaleProc && D3D11_UpscalerUsed(sys->scaleProc))
+ if (sys->tonemapProc)
+ {
+ if (FAILED(D3D11_TonemapperProcess(VLC_OBJECT(vd), sys->tonemapProc, p_sys)))
+ return;
+ p_sys = D3D11_TonemapperGetOutput(sys->tonemapProc);
+ }
+ else if (sys->scaleProc && D3D11_UpscalerUsed(sys->scaleProc))
{
if (D3D11_UpscalerScale(VLC_OBJECT(vd), sys->scaleProc, p_sys) != VLC_SUCCESS)
return;
@@ -1132,7 +1164,11 @@ static void Prepare(vout_display_t *vd, picture_t *picture, subpicture_t *subpic
}
else
{
- picture_sys_t *p_sys = ActivePictureSys(picture);
+ picture_sys_t *p_sys;
+ if (sys->tonemapProc)
+ p_sys = D3D11_TonemapperGetOutput(sys->tonemapProc);
+ else
+ p_sys = ActivePictureSys(picture);
D3D11_RenderQuad(&sys->d3d_dev, &sys->picQuad, p_sys->resourceView, sys->d3drenderTargetView);
}
@@ -1272,10 +1308,26 @@ static void D3D11SetColorSpace(vout_display_t *vd)
goto done;
}
- bool src_full_range = vd->source.b_color_range_full ||
+ video_format_t match_source = vd->source;
+ if (sys->hdrMode == hdr_Never)
+ {
+ match_source.primaries = COLOR_PRIMARIES_BT709;
+ match_source.transfer = TRANSFER_FUNC_BT709;
+ match_source.space = COLOR_SPACE_BT709;
+ }
+ else if (sys->hdrMode == hdr_Always || sys->hdrMode == hdr_Fake)
+ {
+ match_source.primaries = COLOR_PRIMARIES_BT2020;
+ match_source.transfer = TRANSFER_FUNC_SMPTE_ST2084;
+ match_source.space = COLOR_SPACE_BT2020;
+ if (sys->hdrMode == hdr_Fake) // the video processor keeps the source range
+ match_source.i_chroma = VLC_CODEC_RGBA10;
+ }
+
+ bool src_full_range = match_source.b_color_range_full ||
/* the YUV->RGB conversion already output full range */
- is_d3d11_opaque(vd->source.i_chroma) ||
- vlc_fourcc_IsYUV(vd->source.i_chroma);
+ is_d3d11_opaque(match_source.i_chroma) ||
+ vlc_fourcc_IsYUV(match_source.i_chroma);
/* pick the best output based on color support and transfer */
/* TODO support YUV output later */
@@ -1285,13 +1337,13 @@ static void D3D11SetColorSpace(vout_display_t *vd)
if (SUCCEEDED(hr) && support) {
msg_Dbg(vd, "supports colorspace %s", color_spaces[i].name);
score = 0;
- if (color_spaces[i].primaries == vd->source.primaries)
+ if (color_spaces[i].primaries == match_source.primaries)
score++;
- if (color_spaces[i].color == vd->source.space)
+ if (color_spaces[i].color == match_source.space)
score += 2; /* we don't want to translate color spaces */
- if (color_spaces[i].transfer == vd->source.transfer ||
+ if (color_spaces[i].transfer == match_source.transfer ||
/* favor 2084 output for HLG source */
- (color_spaces[i].transfer == TRANSFER_FUNC_SMPTE_ST2084 && vd->source.transfer == TRANSFER_FUNC_HLG))
+ (color_spaces[i].transfer == TRANSFER_FUNC_SMPTE_ST2084 && match_source.transfer == TRANSFER_FUNC_HLG))
score++;
if (color_spaces[i].b_full_range == src_full_range)
score++;
@@ -1309,6 +1361,7 @@ static void D3D11SetColorSpace(vout_display_t *vd)
}
#ifdef HAVE_DXGI1_6_H
+ if (sys->hdrMode == hdr_Auto) // match the screen
if (SUCCEEDED(IDXGISwapChain_GetContainingOutput( sys->dxgiswapChain, &dxgiOutput )))
{
IDXGIOutput6 *dxgiOutput6 = NULL;
@@ -1457,6 +1510,38 @@ static bool BogusZeroCopy(const vout_display_t *vd)
}
}
+static enum d3d11_hdr HdrModeFromString(vlc_object_t *logger, const char *psz_hdr)
+{
+ if (strcmp("auto", psz_hdr) == 0)
+ return hdr_Auto;
+ if (strcmp("never", psz_hdr) == 0)
+ return hdr_Never;
+ if (strcmp("always", psz_hdr) == 0)
+ return hdr_Always;
+ if (strcmp("generate", psz_hdr) == 0)
+ return hdr_Fake;
+
+ msg_Warn(logger, "unknown HDR mode %s, using auto mode", psz_hdr);
+ return hdr_Auto;
+}
+
+static void InitTonemapProcessor(vout_display_t *vd, const video_format_t *fmt_in)
+{
+ vout_display_sys_t *sys = vd->sys;
+ if (sys->hdrMode != hdr_Fake)
+ return;
+
+ sys->tonemapProc = D3D11_TonemapperCreate(VLC_OBJECT(vd), &sys->d3d_dev, fmt_in);
+ if (sys->tonemapProc == NULL)
+ {
+ sys->hdrMode = hdr_Auto;
+ msg_Dbg(vd, "failed to create the tone mapper, using default HDR mode");
+ return;
+ }
+
+ msg_Dbg(vd, "Using tonemapper");
+}
+
static void InitScaleProcessor(vout_display_t *vd)
{
vout_display_sys_t *sys = vd->sys;
@@ -1477,13 +1562,16 @@ static int Direct3D11Open(vout_display_t *vd, bool external_device)
vout_display_sys_t *sys = vd->sys;
IDXGIFactory2 *dxgifactory;
+ char *psz_hdr = var_InheritString(vd, "d3d11-hdr-mode");
+ sys->hdrMode = HdrModeFromString(VLC_OBJECT(vd), psz_hdr);
+ free(psz_hdr);
+
if (!external_device)
{
#if !VLC_WINSTORE_APP
HRESULT hr = S_OK;
DXGI_SWAP_CHAIN_DESC1 scd;
- FillSwapChainDesc(vd, &scd);
hr = D3D11_CreateDevice(vd, &sys->hd3d,
is_d3d11_opaque(vd->source.i_chroma),
@@ -1499,6 +1587,8 @@ static int Direct3D11Open(vout_display_t *vd, bool external_device)
return VLC_EGENERIC;
}
+ InitTonemapProcessor(vd, &vd->source);
+
hr = IDXGIAdapter_GetParent(dxgiadapter, &IID_IDXGIFactory2, (void **)&dxgifactory);
IDXGIAdapter_Release(dxgiadapter);
if (FAILED(hr)) {
@@ -1506,6 +1596,8 @@ static int Direct3D11Open(vout_display_t *vd, bool external_device)
return VLC_EGENERIC;
}
+ FillSwapChainDesc(vd, &scd);
+
hr = IDXGIFactory2_CreateSwapChainForHwnd(dxgifactory, (IUnknown *)sys->d3d_dev.d3ddevice,
sys->sys.hvideownd, &scd, NULL, NULL, &sys->dxgiswapChain);
if (hr == DXGI_ERROR_INVALID_CALL && scd.Format == DXGI_FORMAT_R10G10B10A2_UNORM)
@@ -1543,9 +1635,9 @@ static int Direct3D11Open(vout_display_t *vd, bool external_device)
}
free(psz_upscale);
- video_format_t fmt;
- video_format_Copy(&fmt, &vd->source);
- int err = SetupOutputFormat(vd, &fmt);
+ video_format_Copy(&sys->pool_fmt, &vd->source);
+ video_format_Copy(&sys->quad_fmt, &vd->source);
+ int err = SetupOutputFormat(vd, &sys->pool_fmt, &sys->quad_fmt);
if (err != VLC_SUCCESS)
{
if (!is_d3d11_opaque(vd->source.i_chroma)
@@ -1558,10 +1650,10 @@ static int Direct3D11Open(vout_display_t *vd, bool external_device)
vlc_fourcc_GetYUVFallback(vd->source.i_chroma) :
vlc_fourcc_GetRGBFallback(vd->source.i_chroma);
for (unsigned i = 0; list[i] != 0; i++) {
- fmt.i_chroma = list[i];
- if (fmt.i_chroma == vd->source.i_chroma)
+ sys->pool_fmt.i_chroma = list[i];
+ if (sys->pool_fmt.i_chroma == vd->source.i_chroma)
continue;
- err = SetupOutputFormat(vd, &fmt);
+ err = SetupOutputFormat(vd, &sys->pool_fmt, &sys->quad_fmt);
if (err == VLC_SUCCESS)
break;
}
@@ -1570,13 +1662,9 @@ static int Direct3D11Open(vout_display_t *vd, bool external_device)
return err;
}
- 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;
- video_format_Copy(&sys->pool_fmt, &fmt);
-
if ( sys->picQuad.formatInfo->formatTexture != DXGI_FORMAT_R8G8B8A8_UNORM &&
sys->picQuad.formatInfo->formatTexture != DXGI_FORMAT_B5G6R5_UNORM )
{
@@ -1590,93 +1678,127 @@ static int Direct3D11Open(vout_display_t *vd, bool external_device)
}
video_format_Clean(&vd->fmt);
- vd->fmt = fmt;
+ vd->fmt = sys->pool_fmt;
sys->log_level = var_InheritInteger(vd, "verbose");
return VLC_SUCCESS;
}
-static int SetupOutputFormat(vout_display_t *vd, video_format_t *fmt)
+static const d3d_format_t *SelectClosestOutput(vout_display_t *vd, vlc_fourcc_t i_chroma,
+ bool from_processor)
{
- vout_display_sys_t *sys = vd->sys;
-
- // look for the requested pixel format first
- sys->picQuad.formatInfo = GetDirectRenderingFormat(vd, fmt->i_chroma);
+ const d3d_format_t *res = NULL;
// look for any pixel format that we can handle with enough pixels per channel
- const d3d_format_t *decoder_format = NULL;
- if ( !sys->picQuad.formatInfo )
+ uint8_t bits_per_channel;
+ uint8_t widthDenominator, heightDenominator;
+ switch (i_chroma)
{
- uint8_t bits_per_channel;
- uint8_t widthDenominator, heightDenominator;
- switch (fmt->i_chroma)
+ case VLC_CODEC_D3D11_OPAQUE:
+ bits_per_channel = 8;
+ widthDenominator = heightDenominator = 2;
+ break;
+ case VLC_CODEC_D3D11_OPAQUE_10B:
+ bits_per_channel = 10;
+ widthDenominator = heightDenominator = 2;
+ break;
+ default:
{
- case VLC_CODEC_D3D11_OPAQUE:
- bits_per_channel = 8;
- widthDenominator = heightDenominator = 2;
- break;
- case VLC_CODEC_D3D11_OPAQUE_10B:
- bits_per_channel = 10;
- widthDenominator = heightDenominator = 2;
- break;
- default:
+ const vlc_chroma_description_t *p_format = vlc_fourcc_GetChromaDescription(i_chroma);
+ if (p_format == NULL)
{
- const vlc_chroma_description_t *p_format = vlc_fourcc_GetChromaDescription(fmt->i_chroma);
- if (p_format == NULL)
- {
- bits_per_channel = 8;
- widthDenominator = heightDenominator = 2;
- }
- else
+ bits_per_channel = 8;
+ widthDenominator = heightDenominator = 2;
+ }
+ else
+ {
+ bits_per_channel = p_format->pixel_bits == 0 ? 8 : p_format->pixel_bits /
+ (p_format->plane_count==1 ? p_format->pixel_size : 1);
+ widthDenominator = heightDenominator = 1;
+ for (size_t i=0; i<p_format->plane_count; i++)
{
- bits_per_channel = p_format->pixel_bits == 0 ? 8 : p_format->pixel_bits /
- (p_format->plane_count==1 ? p_format->pixel_size : 1);
- widthDenominator = heightDenominator = 1;
- for (size_t i=0; i<p_format->plane_count; i++)
- {
- if (widthDenominator < p_format->p[i].w.den)
- widthDenominator = p_format->p[i].w.den;
- if (heightDenominator < p_format->p[i].h.den)
- heightDenominator = p_format->p[1].h.den;
- }
+ if (widthDenominator < p_format->p[i].w.den)
+ widthDenominator = p_format->p[i].w.den;
+ if (heightDenominator < p_format->p[i].h.den)
+ heightDenominator = p_format->p[1].h.den;
}
}
- break;
}
-
- /* look for a decoder format that can be decoded but not used in shaders */
- if ( is_d3d11_opaque(fmt->i_chroma) )
- decoder_format = GetDirectDecoderFormat(vd, fmt->i_chroma);
- else
- decoder_format = sys->picQuad.formatInfo;
-
- bool is_rgb = !vlc_fourcc_IsYUV(fmt->i_chroma);
- sys->picQuad.formatInfo = GetDisplayFormatByDepth(vd, bits_per_channel,
- widthDenominator,
- heightDenominator,
- decoder_format!=NULL, is_rgb);
- if (!sys->picQuad.formatInfo && is_rgb)
- sys->picQuad.formatInfo = GetDisplayFormatByDepth(vd, bits_per_channel,
- widthDenominator,
- heightDenominator,
- decoder_format!=NULL, false);
+ break;
}
+ bool is_rgb = !vlc_fourcc_IsYUV(i_chroma);
+ res = GetDisplayFormatByDepth(vd, bits_per_channel,
+ widthDenominator,
+ heightDenominator,
+ from_processor, is_rgb);
+ if (res != NULL)
+ return res;
+ if (is_rgb)
+ res = GetDisplayFormatByDepth(vd, bits_per_channel,
+ widthDenominator,
+ heightDenominator,
+ from_processor, false);
+ if (res != NULL)
+ return res;
+
// look for any pixel format that we can handle
- if ( !sys->picQuad.formatInfo )
- sys->picQuad.formatInfo = GetDisplayFormatByDepth(vd, 0, 0, 0, false, false);
+ res = GetDisplayFormatByDepth(vd, 0, 0, 0, false, false);
+ return res;
+}
+
+static const d3d_format_t *SelectOutputFormat(vout_display_t *vd, const video_format_t *fmt,
+ const d3d_format_t ** decoder_format)
+{
+ const d3d_format_t *res = NULL;
+ // look for the requested pixel format first
+ res = GetDirectRenderingFormat(vd, fmt->i_chroma);
+ if (res != NULL)
+ return res;
+
+ /* look for a decoder format that can be decoded but not used in shaders */
+ if ( is_d3d11_opaque(fmt->i_chroma) )
+ *decoder_format = GetDirectDecoderFormat(vd, fmt->i_chroma);
+
+ res = SelectClosestOutput(vd, fmt->i_chroma, *decoder_format!=NULL);
+
+ return res;
+}
+
+static int SetupOutputFormat(vout_display_t *vd, video_format_t *fmt, video_format_t *quad_fmt)
+{
+ vout_display_sys_t *sys = vd->sys;
+
+ // look for the requested pixel format first
+ const d3d_format_t *decoder_format = NULL;
+ if (sys->hdrMode == hdr_Fake)
+ {
+ quad_fmt->i_chroma = VLC_CODEC_RGBA10;
+ quad_fmt->primaries = sys->display.colorspace->primaries;
+ quad_fmt->transfer = sys->display.colorspace->transfer;
+ quad_fmt->space = sys->display.colorspace->color;
+ quad_fmt->b_color_range_full = sys->display.colorspace->b_full_range;
+
+ // request an input format that can be input of a VideoProcessor
+ UINT supportFlags = D3D11_FORMAT_SUPPORT_VIDEO_PROCESSOR_INPUT;
+ if (is_d3d11_opaque(fmt->i_chroma))
+ supportFlags |= D3D11_FORMAT_SUPPORT_DECODER_OUTPUT;
+ decoder_format = FindD3D11Format( vd, &sys->d3d_dev, fmt->i_chroma, false, 0, 0, 0,
+ is_d3d11_opaque(fmt->i_chroma), supportFlags );
+ }
+ sys->picQuad.formatInfo = SelectOutputFormat(vd, quad_fmt, &decoder_format);
if ( !sys->picQuad.formatInfo )
{
msg_Err(vd, "Could not get a suitable texture pixel format");
return VLC_EGENERIC;
}
- sys->pool_d3dfmt = sys->picQuad.formatInfo;
+ sys->pool_d3dfmt = decoder_format ? decoder_format : sys->picQuad.formatInfo;
- msg_Dbg( vd, "Using pixel format %s for chroma %4.4s", sys->picQuad.formatInfo->name,
+ msg_Dbg( vd, "Using pixel format %s for chroma %4.4s", sys->pool_d3dfmt->name,
(char *)&fmt->i_chroma );
- fmt->i_chroma = decoder_format ? decoder_format->fourcc : sys->picQuad.formatInfo->fourcc;
+ fmt->i_chroma = sys->pool_d3dfmt->fourcc;
DxgiFormatMask( sys->picQuad.formatInfo->formatTexture, fmt );
/* check the region pixel format */
@@ -1690,10 +1812,11 @@ static int SetupOutputFormat(vout_display_t *vd, video_format_t *fmt)
(sys->scaleProc == NULL && !CanUseTextureArray(vd)) ||
BogusZeroCopy(vd);
- if (Direct3D11CreateFormatResources(vd, fmt)) {
+ if (Direct3D11CreateFormatResources(vd, quad_fmt)) {
msg_Err(vd, "Failed to allocate format resources");
return VLC_EGENERIC;
}
+ vd->info.is_slow = !is_d3d11_opaque(fmt->i_chroma) && sys->picQuad.formatInfo->formatTexture != DXGI_FORMAT_UNKNOWN;
return VLC_SUCCESS;
}
@@ -1788,7 +1911,6 @@ static int Direct3D11CreateFormatResources(vout_display_t *vd, const video_forma
}
#endif
- vd->info.is_slow = !is_d3d11_opaque(fmt->i_chroma) && sys->picQuad.formatInfo->formatTexture != DXGI_FORMAT_UNKNOWN;
return VLC_SUCCESS;
}
@@ -1983,6 +2105,11 @@ static void Direct3D11DestroyResources(vout_display_t *vd)
ReleasePictureSys(&sys->stagingSys);
+ if (sys->tonemapProc != NULL)
+ {
+ D3D11_TonemapperDestroy(sys->tonemapProc);
+ sys->tonemapProc = NULL;
+ }
if (sys->scaleProc != NULL)
{
D3D11_UpscalerDestroy(sys->scaleProc);
@@ -2189,7 +2316,7 @@ static int Direct3D11MapSubpicture(vout_display_t *vd, int *subpicture_region_co
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);
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/10e2808347d49a1862cd7a76d629c2b5d65909e8...6d82c5af389e623c53ef8e9386f9008c1407cea3
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/10e2808347d49a1862cd7a76d629c2b5d65909e8...6d82c5af389e623c53ef8e9386f9008c1407cea3
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