[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