[vlc-commits] direct3d11: split the DXGI swapchain parts from D3D11 parts
Steve Lhomme
git at videolan.org
Wed Feb 10 11:06:41 UTC 2021
vlc | branch: master | Steve Lhomme <robux4 at ycbcr.xyz> | Fri Jan 22 16:26:56 2021 +0100| [610f928c68a2dc137d3b162e7668b82d56a0c51d] | committer: Steve Lhomme
direct3d11: split the DXGI swapchain parts from D3D11 parts
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=610f928c68a2dc137d3b162e7668b82d56a0c51d
---
modules/video_output/Makefile.am | 1 +
modules/video_output/win32/d3d11_swapchain.c | 514 +++----------------------
modules/video_output/win32/d3d11_swapchain.h | 20 +-
modules/video_output/win32/direct3d11.c | 30 +-
modules/video_output/win32/dxgi_swapchain.c | 541 +++++++++++++++++++++++++++
modules/video_output/win32/dxgi_swapchain.h | 64 ++++
6 files changed, 691 insertions(+), 479 deletions(-)
diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am
index 684bf11d73..36658aa4d7 100644
--- a/modules/video_output/Makefile.am
+++ b/modules/video_output/Makefile.am
@@ -135,6 +135,7 @@ 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/d3d11_swapchain.c video_output/win32/d3d11_swapchain.h \
+ video_output/win32/dxgi_swapchain.c video_output/win32/dxgi_swapchain.h \
video_output/win32/common.c video_output/win32/common.h
libdirect3d11_plugin_la_LIBADD = libchroma_copy.la libd3d11_common.la $(LIBCOM) -luuid
if HAVE_DCOMP
diff --git a/modules/video_output/win32/d3d11_swapchain.c b/modules/video_output/win32/d3d11_swapchain.c
index efeb69b205..d891636504 100644
--- a/modules/video_output/win32/d3d11_swapchain.c
+++ b/modules/video_output/win32/d3d11_swapchain.c
@@ -43,12 +43,8 @@
#define COBJMACROS
#include <initguid.h>
#include <d3d11.h>
-#ifdef HAVE_DXGI1_6_H
-# include <dxgi1_6.h>
-#else
-# include <dxgi1_5.h>
-#endif
+#include "dxgi_swapchain.h"
#include "d3d11_swapchain.h"
#include "d3d11_shaders.h"
@@ -56,350 +52,21 @@
# include "dcomp_wrapper.h"
#endif
-typedef enum video_color_axis {
- COLOR_AXIS_RGB,
- COLOR_AXIS_YCBCR,
-} video_color_axis;
-
-typedef enum swapchain_surface_type {
- SWAPCHAIN_SURFACE_HWND,
- SWAPCHAIN_SURFACE_DCOMP,
-} swapchain_surface_type;
-
-typedef struct {
- DXGI_COLOR_SPACE_TYPE dxgi;
- const char *name;
- video_color_axis axis;
- video_color_primaries_t primaries;
- video_transfer_func_t transfer;
- video_color_space_t color;
- bool b_full_range;
-} dxgi_color_space;
-
struct d3d11_local_swapchain
{
+ struct dxgi_swapchain *sys;
+
vlc_object_t *obj;
d3d11_device_t *d3d_dev;
- const d3d_format_t *pixelFormat;
- const dxgi_color_space *colorspace;
-
- swapchain_surface_type swapchainSurfaceType;
- union {
-#if !VLC_WINSTORE_APP
- HWND hwnd;
-#endif /* !VLC_WINSTORE_APP */
- struct {
- void* device;
- void* visual;
- } dcomp;
- } swapchainSurface;
-
- IDXGISwapChain1 *dxgiswapChain; /* DXGI 1.2 swap chain */
- IDXGISwapChain4 *dxgiswapChain4; /* DXGI 1.5 for HDR metadata */
- bool send_metadata;
- DXGI_HDR_METADATA_HDR10 hdr10;
-
ID3D11RenderTargetView *swapchainTargetView[D3D11_MAX_RENDER_TARGET];
-
- bool logged_capabilities;
};
DEFINE_GUID(GUID_SWAPCHAIN_WIDTH, 0xf1b59347, 0x1643, 0x411a, 0xad, 0x6b, 0xc7, 0x80, 0x17, 0x7a, 0x06, 0xb6);
DEFINE_GUID(GUID_SWAPCHAIN_HEIGHT, 0x6ea976a0, 0x9d60, 0x4bb7, 0xa5, 0xa9, 0x7d, 0xd1, 0x18, 0x7f, 0xc9, 0xbd);
-#define DXGI_COLOR_RANGE_FULL 1 /* 0-255 */
-#define DXGI_COLOR_RANGE_STUDIO 0 /* 16-235 */
-
-#define TRANSFER_FUNC_10 TRANSFER_FUNC_LINEAR
-#define TRANSFER_FUNC_22 TRANSFER_FUNC_SRGB
-#define TRANSFER_FUNC_2084 TRANSFER_FUNC_SMPTE_ST2084
-
-#define COLOR_PRIMARIES_BT601 COLOR_PRIMARIES_BT601_525
-
-static const dxgi_color_space color_spaces[] = {
-#define DXGIMAP(AXIS, RANGE, GAMMA, SITTING, PRIMARIES) \
- { DXGI_COLOR_SPACE_##AXIS##_##RANGE##_G##GAMMA##_##SITTING##_P##PRIMARIES, \
- #AXIS " Rec." #PRIMARIES " gamma:" #GAMMA " range:" #RANGE, \
- COLOR_AXIS_##AXIS, COLOR_PRIMARIES_BT##PRIMARIES, TRANSFER_FUNC_##GAMMA, \
- COLOR_SPACE_BT##PRIMARIES, DXGI_COLOR_RANGE_##RANGE},
-
- DXGIMAP(RGB, FULL, 22, NONE, 709)
- DXGIMAP(YCBCR, STUDIO, 22, LEFT, 601)
- DXGIMAP(YCBCR, FULL, 22, LEFT, 601)
- DXGIMAP(RGB, FULL, 10, NONE, 709)
- DXGIMAP(RGB, STUDIO, 22, NONE, 709)
- DXGIMAP(YCBCR, STUDIO, 22, LEFT, 709)
- DXGIMAP(YCBCR, FULL, 22, LEFT, 709)
- DXGIMAP(RGB, STUDIO, 22, NONE, 2020)
- DXGIMAP(YCBCR, STUDIO, 22, LEFT, 2020)
- DXGIMAP(YCBCR, FULL, 22, LEFT, 2020)
- DXGIMAP(YCBCR, STUDIO, 22, TOPLEFT, 2020)
- DXGIMAP(RGB, FULL, 22, NONE, 2020)
- DXGIMAP(RGB, FULL, 2084, NONE, 2020)
- DXGIMAP(YCBCR, STUDIO, 2084, LEFT, 2020)
- DXGIMAP(RGB, STUDIO, 2084, NONE, 2020)
- DXGIMAP(YCBCR, STUDIO, 2084, TOPLEFT, 2020)
- DXGIMAP(YCBCR, STUDIO, HLG, TOPLEFT, 2020)
- DXGIMAP(YCBCR, FULL, HLG, TOPLEFT, 2020)
- /*DXGIMAP(YCBCR, FULL, 22, NONE, 2020, 601)*/
- {DXGI_COLOR_SPACE_RESERVED, NULL, 0, 0, 0, 0, 0},
-#undef DXGIMAP
-};
-
-#ifdef HAVE_DXGI1_6_H
-static bool canHandleConversion(const dxgi_color_space *src, const dxgi_color_space *dst)
-{
- if (src == dst)
- return true;
- if (src->primaries == COLOR_PRIMARIES_BT2020)
- return true; /* we can convert BT2020 to 2020 or 709 */
- if (dst->transfer == TRANSFER_FUNC_BT709)
- return true; /* we can handle anything to 709 */
- return false; /* let Windows do the rest */
-}
-#endif
-
-static void SelectSwapchainColorspace(struct d3d11_local_swapchain *display, const libvlc_video_render_cfg_t *cfg)
-{
- HRESULT hr;
- int best = 0;
- int score, best_score = 0;
- UINT support;
- IDXGISwapChain3 *dxgiswapChain3 = NULL;
- hr = IDXGISwapChain_QueryInterface( display->dxgiswapChain, &IID_IDXGISwapChain3, (void **)&dxgiswapChain3);
- if (FAILED(hr)) {
- msg_Warn(display->obj, "could not get a IDXGISwapChain3");
- goto done;
- }
-
- /* pick the best output based on color support and transfer */
- /* TODO support YUV output later */
- best = -1;
- for (int i=0; color_spaces[i].name; ++i)
- {
- hr = IDXGISwapChain3_CheckColorSpaceSupport(dxgiswapChain3, color_spaces[i].dxgi, &support);
- if (SUCCEEDED(hr) && support) {
- if (!display->logged_capabilities)
- msg_Dbg(display->obj, "supports colorspace %s", color_spaces[i].name);
- score = 0;
- if (color_spaces[i].primaries == (video_color_primaries_t) cfg->primaries)
- score++;
- if (color_spaces[i].color == (video_color_space_t) cfg->colorspace)
- score += 2; /* we don't want to translate color spaces */
- if (color_spaces[i].transfer == (video_transfer_func_t) cfg->transfer ||
- /* favor 2084 output for HLG source */
- (color_spaces[i].transfer == TRANSFER_FUNC_SMPTE_ST2084 && cfg->transfer == TRANSFER_FUNC_HLG))
- score++;
- if (color_spaces[i].b_full_range == cfg->full_range)
- score++;
- if (score > best_score || (score && best == -1)) {
- best = i;
- best_score = score;
- }
- }
- }
- display->logged_capabilities = true;
-
- if (best == -1)
- {
- best = 0;
- msg_Warn(display->obj, "no matching colorspace found force %s", color_spaces[best].name);
- }
-
- IDXGISwapChain_QueryInterface( display->dxgiswapChain, &IID_IDXGISwapChain4, (void **)&display->dxgiswapChain4);
-
-#ifdef HAVE_DXGI1_6_H
- IDXGIOutput *dxgiOutput = NULL;
-
- if (SUCCEEDED(IDXGISwapChain_GetContainingOutput( display->dxgiswapChain, &dxgiOutput )))
- {
- IDXGIOutput6 *dxgiOutput6 = NULL;
- if (SUCCEEDED(IDXGIOutput_QueryInterface( dxgiOutput, &IID_IDXGIOutput6, (void **)&dxgiOutput6 )))
- {
- DXGI_OUTPUT_DESC1 desc1;
- if (SUCCEEDED(IDXGIOutput6_GetDesc1( dxgiOutput6, &desc1 )))
- {
- const dxgi_color_space *csp = NULL;
- for (int i=0; color_spaces[i].name; ++i)
- {
- if (color_spaces[i].dxgi == desc1.ColorSpace)
- {
- if (!canHandleConversion(&color_spaces[best], &color_spaces[i]))
- msg_Warn(display->obj, "Can't handle conversion to screen format %s", color_spaces[i].name);
- else
- {
- best = i;
- csp = &color_spaces[i];
- }
- break;
- }
- }
-
- msg_Dbg(display->obj, "Output max luminance: %.1f, colorspace %s, bits per pixel %d", desc1.MaxFullFrameLuminance, csp?csp->name:"unknown", desc1.BitsPerColor);
- //sys->display.luminance_peak = desc1.MaxFullFrameLuminance;
- }
- IDXGIOutput6_Release( dxgiOutput6 );
- }
- IDXGIOutput_Release( dxgiOutput );
- }
-#endif
-
- hr = IDXGISwapChain3_SetColorSpace1(dxgiswapChain3, color_spaces[best].dxgi);
- if (SUCCEEDED(hr))
- msg_Dbg(display->obj, "using colorspace %s", color_spaces[best].name);
- else
- msg_Err(display->obj, "Failed to set colorspace %s. (hr=0x%lX)", color_spaces[best].name, hr);
-done:
- display->colorspace = &color_spaces[best];
- display->send_metadata = color_spaces[best].transfer == (video_transfer_func_t) cfg->transfer &&
- color_spaces[best].primaries == (video_color_primaries_t) cfg->primaries &&
- color_spaces[best].color == (video_color_space_t) cfg->colorspace;
- if (dxgiswapChain3)
- IDXGISwapChain3_Release(dxgiswapChain3);
-}
-
-#if !VLC_WINSTORE_APP
-static void FillSwapChainDesc(struct d3d11_local_swapchain *display, UINT width, UINT height, DXGI_SWAP_CHAIN_DESC1 *out)
-{
- ZeroMemory(out, sizeof(*out));
- out->BufferCount = 3;
- out->BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
- out->SampleDesc.Count = 1;
- out->SampleDesc.Quality = 0;
- out->Width = width;
- out->Height = height;
- out->Format = display->pixelFormat->formatTexture;
- //out->Flags = 512; // DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO;
-
- bool isWin10OrGreater = false;
- HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32.dll"));
- if (likely(hKernel32 != NULL))
- isWin10OrGreater = GetProcAddress(hKernel32, "GetSystemCpuSetInformation") != NULL;
- if (isWin10OrGreater)
- out->SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
- else
- {
- bool isWin80OrGreater = false;
- if (likely(hKernel32 != NULL))
- isWin80OrGreater = GetProcAddress(hKernel32, "CheckTokenCapability") != NULL;
- if (isWin80OrGreater)
- out->SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
- else
- {
- out->SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
- out->BufferCount = 1;
- }
- }
-}
-
-static void CreateSwapchainHwnd(struct d3d11_local_swapchain *display, UINT width, UINT height)
-{
- vlc_assert(display->swapchainSurfaceType == SWAPCHAIN_SURFACE_HWND);
- if (display->swapchainSurface.hwnd == NULL)
- {
- msg_Err(display->obj, "missing a HWND to create the swapchain");
- return;
- }
-
- DXGI_SWAP_CHAIN_DESC1 scd;
- FillSwapChainDesc(display, width, height, &scd);
-
- IDXGIAdapter *dxgiadapter = D3D11DeviceAdapter(display->d3d_dev->d3ddevice);
- if (unlikely(dxgiadapter==NULL)) {
- msg_Err(display->obj, "Could not get the DXGI Adapter");
- return;
- }
-
- IDXGIFactory2 *dxgifactory;
- HRESULT hr = IDXGIAdapter_GetParent(dxgiadapter, &IID_IDXGIFactory2, (void **)&dxgifactory);
- IDXGIAdapter_Release(dxgiadapter);
- if (FAILED(hr)) {
- msg_Err(display->obj, "Could not get the DXGI Factory. (hr=0x%lX)", hr);
- return;
- }
-
- hr = IDXGIFactory2_CreateSwapChainForHwnd(dxgifactory, (IUnknown *)display->d3d_dev->d3ddevice,
- display->swapchainSurface.hwnd, &scd,
- NULL, NULL, &display->dxgiswapChain);
-
- if (hr == DXGI_ERROR_INVALID_CALL && scd.Format == DXGI_FORMAT_R10G10B10A2_UNORM)
- {
- msg_Warn(display->obj, "10 bits swapchain failed, try 8 bits");
- scd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
- hr = IDXGIFactory2_CreateSwapChainForHwnd(dxgifactory, (IUnknown *)display->d3d_dev->d3ddevice,
- display->swapchainSurface.hwnd, &scd,
- NULL, NULL, &display->dxgiswapChain);
- }
- IDXGIFactory2_Release(dxgifactory);
- if (FAILED(hr)) {
- msg_Err(display->obj, "Could not create the SwapChain. (hr=0x%lX)", hr);
- }
-}
-
-#ifdef HAVE_DCOMP_H
-static void CreateSwapchainDComp(struct d3d11_local_swapchain *display, UINT width, UINT height)
-{
- vlc_assert(display->swapchainSurfaceType == SWAPCHAIN_SURFACE_DCOMP);
- if (display->swapchainSurface.dcomp.device == NULL || display->swapchainSurface.dcomp.visual == NULL)
- {
- msg_Err(display->obj, "missing a HWND to create the swapchain");
- return;
- }
-
- DXGI_SWAP_CHAIN_DESC1 scd;
- FillSwapChainDesc(display, width, height, &scd);
- ZeroMemory(&scd, sizeof(scd));
- scd.BufferCount = 3;
- scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
- scd.SampleDesc.Count = 1;
- scd.SampleDesc.Quality = 0;
- scd.Width = width;
- scd.Height = height;
- scd.Format = display->pixelFormat->formatTexture;
- scd.Scaling = DXGI_SCALING_STRETCH;
- scd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
- scd.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
-
- IDXGIAdapter *dxgiadapter = D3D11DeviceAdapter(display->d3d_dev->d3ddevice);
- if (unlikely(dxgiadapter==NULL)) {
- msg_Err(display->obj, "Could not get the DXGI Adapter");
- return;
- }
-
- IDXGIFactory2 *dxgifactory;
- HRESULT hr = IDXGIAdapter_GetParent(dxgiadapter, &IID_IDXGIFactory2, (void **)&dxgifactory);
- IDXGIAdapter_Release(dxgiadapter);
- if (FAILED(hr)) {
- msg_Err(display->obj, "Could not get the DXGI Factory. (hr=0x%lX)", hr);
- return;
- }
-
- hr = IDXGIFactory2_CreateSwapChainForComposition(dxgifactory, (IUnknown *)display->d3d_dev->d3ddevice,
- &scd, NULL, &display->dxgiswapChain);
- if (hr == DXGI_ERROR_INVALID_CALL && scd.Format == DXGI_FORMAT_R10G10B10A2_UNORM)
- {
- msg_Warn(display->obj, "10 bits swapchain failed, try 8 bits");
- scd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
- hr = IDXGIFactory2_CreateSwapChainForComposition(dxgifactory, (IUnknown *)display->d3d_dev->d3ddevice,
- &scd, NULL, &display->dxgiswapChain);
- }
- IDXGIFactory2_Release(dxgifactory);
- if (SUCCEEDED(hr)) {
- IDCompositionVisual_SetContent(display->swapchainSurface.dcomp.visual, (IUnknown *)display->dxgiswapChain);
- IDCompositionDevice_Commit(display->swapchainSurface.dcomp.device);
- }
- if (FAILED(hr)) {
- msg_Err(display->obj, "Could not create the SwapChain. (hr=0x%lX)", hr);
- }
-}
-#endif /* HAVE_DCOMP_H */
-
-#endif /* !VLC_WINSTORE_APP */
-
static bool UpdateSwapchain( struct d3d11_local_swapchain *display, const libvlc_video_render_cfg_t *cfg )
{
- ID3D11Texture2D* pBackBuffer;
HRESULT hr;
D3D11_TEXTURE2D_DESC dsc = { 0 };
@@ -413,8 +80,8 @@ static bool UpdateSwapchain( struct d3d11_local_swapchain *display, const libvlc
ID3D11Texture2D_GetDesc( (ID3D11Texture2D*) res, &dsc );
ID3D11Resource_Release( res );
}
- assert(display->pixelFormat->formatTexture == dsc.Format);
- bitsPerChannel = display->pixelFormat->bitsPerChannel;
+ assert(DXGI_GetPixelFormat(display->sys)->formatTexture == dsc.Format);
+ bitsPerChannel = DXGI_GetPixelFormat(display->sys)->bitsPerChannel;
}
if ( dsc.Width == cfg->width && dsc.Height == cfg->height && cfg->bitdepth <= bitsPerChannel )
@@ -431,11 +98,13 @@ static bool UpdateSwapchain( struct d3d11_local_swapchain *display, const libvlc
const d3d_format_t *newPixelFormat = NULL;
#if VLC_WINSTORE_APP
- display->dxgiswapChain = (void*)(uintptr_t)var_InheritInteger(display->obj, "winrt-swapchain");
- if (display->dxgiswapChain != NULL)
+ IDXGISwapChain1 *dxgiswapChain = DXGI_GetSwapChain1(display->sys);
+ if (dxgiswapChain == NULL)
+ dxgiswapChain = (void*)(uintptr_t)var_InheritInteger(display->obj, "winrt-swapchain");
+ if (dxgiswapChain != NULL)
{
DXGI_SWAP_CHAIN_DESC1 scd;
- if (SUCCEEDED(IDXGISwapChain1_GetDesc1(display->dxgiswapChain, &scd)))
+ if (SUCCEEDED(IDXGISwapChain1_GetDesc1(dxgiswapChain, &scd)))
{
for (const d3d_format_t *output_format = GetRenderFormatList();
output_format->name != NULL; ++output_format)
@@ -466,63 +135,46 @@ static bool UpdateSwapchain( struct d3d11_local_swapchain *display, const libvlc
return false;
}
-#if !VLC_WINSTORE_APP
- if (display->dxgiswapChain != NULL && display->pixelFormat != newPixelFormat)
- {
- // the pixel format changed, we need a new swapchain
- IDXGISwapChain_Release(display->dxgiswapChain);
- display->dxgiswapChain = NULL;
- display->logged_capabilities = false;
+ IDXGIDevice *pDXGIDevice = NULL;
+ hr = ID3D11Device_QueryInterface(display->d3d_dev->d3ddevice, &IID_IDXGIDevice, (void **)&pDXGIDevice);
+ if (FAILED(hr)) {
+ return false;
}
-
- if ( display->dxgiswapChain == NULL )
- {
- display->pixelFormat = newPixelFormat;
-
-#ifdef HAVE_DCOMP_H
- if (display->swapchainSurfaceType == SWAPCHAIN_SURFACE_DCOMP)
- CreateSwapchainDComp(display, cfg->width, cfg->height);
- else // SWAPCHAIN_TARGET_HWND
-#endif
- CreateSwapchainHwnd(display, cfg->width, cfg->height);
-
- if (display->dxgiswapChain == NULL)
- return false;
+ IDXGIAdapter *dxgiadapter;
+ hr = IDXGIDevice_GetAdapter(pDXGIDevice, &dxgiadapter);
+ IDXGIDevice_Release(pDXGIDevice);
+ if (FAILED(hr)) {
+ return false;
}
- else
-#endif /* !VLC_WINSTORE_APP */
+
+ if (!DXGI_UpdateSwapChain( display->sys, dxgiadapter, (IUnknown*) display->d3d_dev->d3ddevice, newPixelFormat, cfg ))
{
- /* TODO detect is the size is the same as the output and switch to fullscreen mode */
- hr = IDXGISwapChain_ResizeBuffers( display->dxgiswapChain, 0, cfg->width, cfg->height,
- DXGI_FORMAT_UNKNOWN, 0 );
- if ( FAILED( hr ) ) {
- msg_Err( display->obj, "Failed to resize the backbuffer. (hr=0x%lX)", hr );
- return false;
- }
+ IDXGIAdapter_Release(dxgiadapter);
+ return false;
}
+ IDXGIAdapter_Release(dxgiadapter);
- hr = IDXGISwapChain_GetBuffer( display->dxgiswapChain, 0, &IID_ID3D11Texture2D, (LPVOID *) &pBackBuffer );
+ ID3D11Resource* pBackBuffer;
+ hr = IDXGISwapChain1_GetBuffer( DXGI_GetSwapChain1(display->sys), 0, &IID_ID3D11Resource, (LPVOID *) &pBackBuffer );
if ( FAILED( hr ) ) {
msg_Err( display->obj, "Could not get the backbuffer for the Swapchain. (hr=0x%lX)", hr );
return false;
}
- hr = D3D11_CreateRenderTargets( display->d3d_dev, (ID3D11Resource *) pBackBuffer,
- display->pixelFormat, display->swapchainTargetView );
- ID3D11Texture2D_Release( pBackBuffer );
+ hr = D3D11_CreateRenderTargets( display->d3d_dev, pBackBuffer,
+ DXGI_GetPixelFormat(display->sys), display->swapchainTargetView );
+ ID3D11Resource_Release( pBackBuffer );
if ( FAILED( hr ) ) {
msg_Err( display->obj, "Failed to create the target view. (hr=0x%lX)", hr );
return false;
}
- D3D11_ClearRenderTargets( display->d3d_dev, display->pixelFormat, display->swapchainTargetView );
-
- SelectSwapchainColorspace(display, cfg);
+ D3D11_ClearRenderTargets( display->d3d_dev, DXGI_GetPixelFormat(display->sys), display->swapchainTargetView );
return true;
}
-void LocalSwapchainCleanupDevice( void *opaque )
+void D3D11_LocalSwapchainCleanupDevice( void *opaque )
{
struct d3d11_local_swapchain *display = opaque;
for (size_t i=0; i < ARRAY_SIZE(display->swapchainTargetView); i++)
@@ -532,54 +184,40 @@ void LocalSwapchainCleanupDevice( void *opaque )
display->swapchainTargetView[i] = NULL;
}
}
- if (display->dxgiswapChain4)
- {
- IDXGISwapChain4_Release(display->dxgiswapChain4);
- display->dxgiswapChain4 = NULL;
- }
- if (display->dxgiswapChain)
- {
- IDXGISwapChain_Release(display->dxgiswapChain);
- display->dxgiswapChain = NULL;
- }
+ DXGI_LocalSwapchainCleanupDevice(display->sys);
}
-void LocalSwapchainSwap( void *opaque )
+bool D3D11_LocalSwapchainUpdateOutput( void *opaque, const libvlc_video_render_cfg_t *cfg, libvlc_video_output_cfg_t *out )
{
struct d3d11_local_swapchain *display = opaque;
- DXGI_PRESENT_PARAMETERS presentParams = { 0 };
+ if ( !UpdateSwapchain( display, cfg ) )
+ return false;
+ DXGI_SwapchainUpdateOutput(display->sys, out);
+ return true;
+}
- HRESULT hr = IDXGISwapChain1_Present1( display->dxgiswapChain, 0, 0, &presentParams );
- if ( hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET )
- {
- /* TODO device lost */
- msg_Err( display->obj, "SwapChain Present failed. (hr=0x%lX)", hr );
- }
+void D3D11_LocalSwapchainSwap( void *opaque )
+{
+ struct d3d11_local_swapchain *display = opaque;
+ DXGI_LocalSwapchainSwap( display->sys );
}
-bool LocalSwapchainUpdateOutput( void *opaque, const libvlc_video_render_cfg_t *cfg, libvlc_video_output_cfg_t *out )
+void D3D11_LocalSwapchainSetMetadata( void *opaque, libvlc_video_metadata_type_t type, const void *metadata )
{
struct d3d11_local_swapchain *display = opaque;
- if ( !UpdateSwapchain( display, cfg ) )
- return false;
- out->dxgi_format = display->pixelFormat->formatTexture;
- out->full_range = display->colorspace->b_full_range;
- out->colorspace = (libvlc_video_color_space_t) display->colorspace->color;
- out->primaries = (libvlc_video_color_primaries_t) display->colorspace->primaries;
- out->transfer = (libvlc_video_transfer_func_t) display->colorspace->transfer;
- return true;
+ DXGI_LocalSwapchainSetMetadata( display->sys, type, metadata );
}
-bool LocalSwapchainWinstoreSize( void *opaque, uint32_t *width, uint32_t *height )
+bool D3D11_LocalSwapchainWinstoreSize( void *opaque, uint32_t *width, uint32_t *height )
{
#if VLC_WINSTORE_APP
struct d3d11_local_swapchain *display = opaque;
/* legacy UWP mode, the width/height was set in GUID_SWAPCHAIN_WIDTH/HEIGHT */
UINT dataSize = sizeof(*width);
- HRESULT hr = IDXGISwapChain_GetPrivateData(display->dxgiswapChain, &GUID_SWAPCHAIN_WIDTH, &dataSize, width);
+ HRESULT hr = IDXGISwapChain1_GetPrivateData(DXGI_GetSwapChain1(display->sys), &GUID_SWAPCHAIN_WIDTH, &dataSize, width);
if (SUCCEEDED(hr)) {
dataSize = sizeof(*height);
- hr = IDXGISwapChain_GetPrivateData(display->dxgiswapChain, &GUID_SWAPCHAIN_HEIGHT, &dataSize, height);
+ hr = IDXGISwapChain1_GetPrivateData(DXGI_GetSwapChain1(display->sys), &GUID_SWAPCHAIN_HEIGHT, &dataSize, height);
return SUCCEEDED(hr);
}
#else
@@ -588,48 +226,17 @@ bool LocalSwapchainWinstoreSize( void *opaque, uint32_t *width, uint32_t *height
return false;
}
-bool LocalSwapchainStartEndRendering( void *opaque, bool enter )
+bool D3D11_LocalSwapchainStartEndRendering( void *opaque, bool enter )
{
struct d3d11_local_swapchain *display = opaque;
if ( enter )
- D3D11_ClearRenderTargets( display->d3d_dev, display->pixelFormat, display->swapchainTargetView );
+ D3D11_ClearRenderTargets( display->d3d_dev, DXGI_GetPixelFormat(display->sys), display->swapchainTargetView );
return true;
}
-void LocalSwapchainSetMetadata( void *opaque, libvlc_video_metadata_type_t type, const void *metadata )
-{
- struct d3d11_local_swapchain *display = opaque;
-
- assert(type == libvlc_video_metadata_frame_hdr10);
- if ( type == libvlc_video_metadata_frame_hdr10 && metadata &&
- display->send_metadata && display->dxgiswapChain4 )
- {
- const libvlc_video_frame_hdr10_metadata_t *p_hdr10 = metadata;
- DXGI_HDR_METADATA_HDR10 hdr10 = { 0 };
- hdr10.GreenPrimary[0] = p_hdr10->GreenPrimary[0];
- hdr10.GreenPrimary[1] = p_hdr10->GreenPrimary[1];
- hdr10.BluePrimary[0] = p_hdr10->BluePrimary[0];
- hdr10.BluePrimary[1] = p_hdr10->BluePrimary[1];
- hdr10.RedPrimary[0] = p_hdr10->RedPrimary[0];
- hdr10.RedPrimary[1] = p_hdr10->RedPrimary[1];
- hdr10.WhitePoint[0] = p_hdr10->WhitePoint[0];
- hdr10.WhitePoint[1] = p_hdr10->WhitePoint[1];
- hdr10.MinMasteringLuminance = p_hdr10->MinMasteringLuminance;
- hdr10.MaxMasteringLuminance = p_hdr10->MaxMasteringLuminance;
- hdr10.MaxContentLightLevel = p_hdr10->MaxContentLightLevel;
- hdr10.MaxFrameAverageLightLevel = p_hdr10->MaxFrameAverageLightLevel;
- if (memcmp(&display->hdr10, &hdr10, sizeof(hdr10)))
- {
- memcpy(&display->hdr10, &hdr10, sizeof(hdr10));
- IDXGISwapChain4_SetHDRMetaData( display->dxgiswapChain4, DXGI_HDR_METADATA_TYPE_HDR10,
- sizeof( &display->hdr10 ), &display->hdr10 );
- }
- }
-}
-
-bool LocalSwapchainSelectPlane( void *opaque, size_t plane )
+bool D3D11_LocalSwapchainSelectPlane( void *opaque, size_t plane )
{
struct d3d11_local_swapchain *display = opaque;
if (!display->swapchainTargetView[plane])
@@ -639,35 +246,34 @@ bool LocalSwapchainSelectPlane( void *opaque, size_t plane )
return true;
}
-void *CreateLocalSwapchainHandleHwnd(vlc_object_t *o, HWND hwnd, d3d11_device_t *d3d_dev)
+void *D3D11_CreateLocalSwapchainHandleHwnd(vlc_object_t *o, HWND hwnd, d3d11_device_t *d3d_dev)
{
struct d3d11_local_swapchain *display = vlc_obj_calloc(o, 1, sizeof(*display));
if (unlikely(display == NULL))
return NULL;
+ display->sys = DXGI_CreateLocalSwapchainHandleHwnd(o, hwnd);
+ if (unlikely(display->sys == NULL))
+ return NULL;
+
display->obj = o;
-#if !VLC_WINSTORE_APP
- display->swapchainSurfaceType = SWAPCHAIN_SURFACE_HWND;
- display->swapchainSurface.hwnd = hwnd;
-#else // VLC_WINSTORE_APP
- VLC_UNUSED(hwnd);
-#endif // VLC_WINSTORE_APP
display->d3d_dev = d3d_dev;
return display;
}
#ifdef HAVE_DCOMP_H
-void *CreateLocalSwapchainHandleDComp(vlc_object_t *o, void* dcompDevice, void* dcompVisual, d3d11_device_t *d3d_dev)
+void *D3D11_CreateLocalSwapchainHandleDComp(vlc_object_t *o, void* dcompDevice, void* dcompVisual, d3d11_device_t *d3d_dev)
{
struct d3d11_local_swapchain *display = vlc_obj_calloc(o, 1, sizeof(*display));
if (unlikely(display == NULL))
return NULL;
+ display->sys = DXGI_CreateLocalSwapchainHandleDComp(o, dcompDevice, dcompVisual);
+ if (unlikely(display->sys == NULL))
+ return NULL;
+
display->obj = o;
- display->swapchainSurfaceType = SWAPCHAIN_SURFACE_DCOMP;
- display->swapchainSurface.dcomp.device = dcompDevice;
- display->swapchainSurface.dcomp.visual = dcompVisual;
display->d3d_dev = d3d_dev;
return display;
diff --git a/modules/video_output/win32/d3d11_swapchain.h b/modules/video_output/win32/d3d11_swapchain.h
index 69b2e9a80c..f5dd4c4cf4 100644
--- a/modules/video_output/win32/d3d11_swapchain.h
+++ b/modules/video_output/win32/d3d11_swapchain.h
@@ -25,20 +25,20 @@
#define VLC_D3D11_SWAPCHAIN_H
#include <vlc_common.h>
-#include <vlc_codec.h>
+#include "dxgi_swapchain.h"
#include "../../video_chroma/d3d11_fmt.h"
-void *CreateLocalSwapchainHandleHwnd(vlc_object_t *, HWND, d3d11_device_t *d3d_dev);
+void *D3D11_CreateLocalSwapchainHandleHwnd(vlc_object_t *, HWND, d3d11_device_t *d3d_dev);
#ifdef HAVE_DCOMP_H
-void *CreateLocalSwapchainHandleDComp(vlc_object_t *, void* dcompDevice, void* dcompVisual, d3d11_device_t *d3d_dev);
+void *D3D11_CreateLocalSwapchainHandleDComp(vlc_object_t *, void* dcompDevice, void* dcompVisual, d3d11_device_t *d3d_dev);
#endif
-void LocalSwapchainCleanupDevice( void *opaque );
-void LocalSwapchainSwap( void *opaque );
-bool LocalSwapchainUpdateOutput( void *opaque, const libvlc_video_render_cfg_t *cfg, libvlc_video_output_cfg_t *out );
-bool LocalSwapchainStartEndRendering( void *opaque, bool enter );
-void LocalSwapchainSetMetadata( void *opaque, libvlc_video_metadata_type_t, const void * );
-bool LocalSwapchainSelectPlane( void *opaque, size_t plane );
-bool LocalSwapchainWinstoreSize( void *opaque, uint32_t *, uint32_t * );
+void D3D11_LocalSwapchainCleanupDevice( void *opaque );
+bool D3D11_LocalSwapchainUpdateOutput( void *opaque, const libvlc_video_render_cfg_t *cfg, libvlc_video_output_cfg_t *out );
+bool D3D11_LocalSwapchainStartEndRendering( void *opaque, bool enter );
+bool D3D11_LocalSwapchainSelectPlane( void *opaque, size_t plane );
+bool D3D11_LocalSwapchainWinstoreSize( void *opaque, uint32_t *, uint32_t * );
+void D3D11_LocalSwapchainSwap( void *opaque );
+void D3D11_LocalSwapchainSetMetadata( void *opaque, libvlc_video_metadata_type_t, const void * );
#endif /* VLC_D3D11_SWAPCHAIN_H */
diff --git a/modules/video_output/win32/direct3d11.c b/modules/video_output/win32/direct3d11.c
index 130cbf5f96..94364cf7cd 100644
--- a/modules/video_output/win32/direct3d11.c
+++ b/modules/video_output/win32/direct3d11.c
@@ -399,17 +399,17 @@ static int Open(vout_display_t *vd, const vout_display_cfg_t *cfg,
/* use our internal swapchain callbacks */
#ifdef HAVE_DCOMP_H
if (cfg->window->type == VOUT_WINDOW_TYPE_DCOMP)
- sys->outside_opaque = CreateLocalSwapchainHandleDComp(VLC_OBJECT(vd), cfg->window->display.dcomp_device, cfg->window->handle.dcomp_visual, sys->d3d_dev);
+ sys->outside_opaque = D3D11_CreateLocalSwapchainHandleDComp(VLC_OBJECT(vd), cfg->window->display.dcomp_device, cfg->window->handle.dcomp_visual, sys->d3d_dev);
else
#endif
- sys->outside_opaque = CreateLocalSwapchainHandleHwnd(VLC_OBJECT(vd), sys->sys.hvideownd, sys->d3d_dev);
+ sys->outside_opaque = D3D11_CreateLocalSwapchainHandleHwnd(VLC_OBJECT(vd), sys->sys.hvideownd, sys->d3d_dev);
if (unlikely(sys->outside_opaque == NULL))
goto error;
- sys->updateOutputCb = LocalSwapchainUpdateOutput;
- sys->swapCb = LocalSwapchainSwap;
- sys->startEndRenderingCb = LocalSwapchainStartEndRendering;
- sys->sendMetadataCb = LocalSwapchainSetMetadata;
- sys->selectPlaneCb = LocalSwapchainSelectPlane;
+ sys->updateOutputCb = D3D11_LocalSwapchainUpdateOutput;
+ sys->swapCb = D3D11_LocalSwapchainSwap;
+ sys->startEndRenderingCb = D3D11_LocalSwapchainStartEndRendering;
+ sys->sendMetadataCb = D3D11_LocalSwapchainSetMetadata;
+ sys->selectPlaneCb = D3D11_LocalSwapchainSelectPlane;
}
#if !VLC_WINSTORE_APP
@@ -663,12 +663,12 @@ static void Prepare(vout_display_t *vd, picture_t *picture,
d3d11_device_lock( sys->d3d_dev );
#if VLC_WINSTORE_APP
- if ( sys->swapCb == LocalSwapchainSwap )
+ if ( sys->swapCb == D3D11_LocalSwapchainSwap )
{
/* legacy UWP mode, the width/height was set in GUID_SWAPCHAIN_WIDTH/HEIGHT */
uint32_t i_width;
uint32_t i_height;
- if (LocalSwapchainWinstoreSize( sys->outside_opaque, &i_width, &i_height ))
+ if (D3D11_LocalSwapchainWinstoreSize( sys->outside_opaque, &i_width, &i_height ))
{
if (i_width != vd->cfg->display.width || i_height != vd->cfg->display.height)
vout_display_SetSize(vd, i_width, i_height);
@@ -794,8 +794,8 @@ static int Direct3D11Open(vout_display_t *vd, video_format_t *fmtp, vlc_video_co
}
if (err != VLC_SUCCESS)
{
- if ( sys->swapCb == LocalSwapchainSwap )
- LocalSwapchainCleanupDevice( sys->outside_opaque );
+ if ( sys->swapCb == D3D11_LocalSwapchainSwap )
+ D3D11_LocalSwapchainCleanupDevice( sys->outside_opaque );
return err;
}
}
@@ -820,8 +820,8 @@ static int Direct3D11Open(vout_display_t *vd, video_format_t *fmtp, vlc_video_co
if (Direct3D11CreateGenericResources(vd)) {
msg_Err(vd, "Failed to allocate resources");
- if ( sys->swapCb == LocalSwapchainSwap )
- LocalSwapchainCleanupDevice( sys->outside_opaque );
+ if ( sys->swapCb == D3D11_LocalSwapchainSwap )
+ D3D11_LocalSwapchainCleanupDevice( sys->outside_opaque );
return VLC_EGENERIC;
}
@@ -963,8 +963,8 @@ static void Direct3D11Close(vout_display_t *vd)
Direct3D11DestroyResources(vd);
- if ( sys->swapCb == LocalSwapchainSwap )
- LocalSwapchainCleanupDevice( sys->outside_opaque );
+ if ( sys->swapCb == D3D11_LocalSwapchainSwap )
+ D3D11_LocalSwapchainCleanupDevice( sys->outside_opaque );
if (sys->d3d_dev && sys->d3d_dev == &sys->local_d3d_dev->d3d_dev)
D3D11_ReleaseDevice( sys->local_d3d_dev );
diff --git a/modules/video_output/win32/dxgi_swapchain.c b/modules/video_output/win32/dxgi_swapchain.c
new file mode 100644
index 0000000000..334e6503ae
--- /dev/null
+++ b/modules/video_output/win32/dxgi_swapchain.c
@@ -0,0 +1,541 @@
+/*****************************************************************************
+ * dxgi_swapchain.c: DXGI swapchain handled by the display module
+ *****************************************************************************
+ * Copyright (C) 2014-2021 VLC authors and VideoLAN
+ *
+ * Authors: Martell Malone <martellmalone at gmail.com>
+ * Steve Lhomme <robux4 at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0601 // _WIN32_WINNT_WIN7
+# undef _WIN32_WINNT
+# define _WIN32_WINNT 0x0601 // _WIN32_WINNT_WIN7
+#endif
+
+#include <vlc_es.h>
+
+#define COBJMACROS
+
+#ifdef HAVE_DCOMP_H
+# include "dcomp_wrapper.h"
+#endif
+
+#include <initguid.h>
+#include "dxgi_swapchain.h"
+
+#ifdef HAVE_DXGI1_6_H
+# include <dxgi1_6.h>
+#endif
+
+#include "../../video_chroma/dxgi_fmt.h"
+
+typedef enum video_color_axis {
+ COLOR_AXIS_RGB,
+ COLOR_AXIS_YCBCR,
+} video_color_axis;
+
+typedef enum swapchain_surface_type {
+ SWAPCHAIN_SURFACE_HWND,
+ SWAPCHAIN_SURFACE_DCOMP,
+} swapchain_surface_type;
+
+typedef struct {
+ DXGI_COLOR_SPACE_TYPE dxgi;
+ const char *name;
+ video_color_axis axis;
+ video_color_primaries_t primaries;
+ video_transfer_func_t transfer;
+ video_color_space_t color;
+ bool b_full_range;
+} dxgi_color_space;
+
+struct dxgi_swapchain
+{
+ vlc_object_t *obj;
+
+ const d3d_format_t *pixelFormat;
+ const dxgi_color_space *colorspace;
+
+ swapchain_surface_type swapchainSurfaceType;
+ union {
+#if !VLC_WINSTORE_APP
+ HWND hwnd;
+#endif /* !VLC_WINSTORE_APP */
+#ifdef HAVE_DCOMP_H
+ struct {
+ void* device; // IDCompositionDevice
+ void* visual; // IDCompositionVisual
+ } dcomp;
+#endif // HAVE_DCOMP_H
+ } swapchainSurface;
+
+ IDXGISwapChain1 *dxgiswapChain; /* DXGI 1.2 swap chain */
+ IDXGISwapChain4 *dxgiswapChain4; /* DXGI 1.5 for HDR metadata */
+ bool send_metadata;
+ DXGI_HDR_METADATA_HDR10 hdr10;
+
+ bool logged_capabilities;
+};
+
+DEFINE_GUID(GUID_SWAPCHAIN_WIDTH, 0xf1b59347, 0x1643, 0x411a, 0xad, 0x6b, 0xc7, 0x80, 0x17, 0x7a, 0x06, 0xb6);
+DEFINE_GUID(GUID_SWAPCHAIN_HEIGHT, 0x6ea976a0, 0x9d60, 0x4bb7, 0xa5, 0xa9, 0x7d, 0xd1, 0x18, 0x7f, 0xc9, 0xbd);
+
+#define DXGI_COLOR_RANGE_FULL 1 /* 0-255 */
+#define DXGI_COLOR_RANGE_STUDIO 0 /* 16-235 */
+
+#define TRANSFER_FUNC_10 TRANSFER_FUNC_LINEAR
+#define TRANSFER_FUNC_22 TRANSFER_FUNC_SRGB
+#define TRANSFER_FUNC_2084 TRANSFER_FUNC_SMPTE_ST2084
+
+#define COLOR_PRIMARIES_BT601 COLOR_PRIMARIES_BT601_525
+
+static const dxgi_color_space color_spaces[] = {
+#define DXGIMAP(AXIS, RANGE, GAMMA, SITTING, PRIMARIES) \
+ { DXGI_COLOR_SPACE_##AXIS##_##RANGE##_G##GAMMA##_##SITTING##_P##PRIMARIES, \
+ #AXIS " Rec." #PRIMARIES " gamma:" #GAMMA " range:" #RANGE, \
+ COLOR_AXIS_##AXIS, COLOR_PRIMARIES_BT##PRIMARIES, TRANSFER_FUNC_##GAMMA, \
+ COLOR_SPACE_BT##PRIMARIES, DXGI_COLOR_RANGE_##RANGE},
+
+ DXGIMAP(RGB, FULL, 22, NONE, 709)
+ DXGIMAP(YCBCR, STUDIO, 22, LEFT, 601)
+ DXGIMAP(YCBCR, FULL, 22, LEFT, 601)
+ DXGIMAP(RGB, FULL, 10, NONE, 709)
+ DXGIMAP(RGB, STUDIO, 22, NONE, 709)
+ DXGIMAP(YCBCR, STUDIO, 22, LEFT, 709)
+ DXGIMAP(YCBCR, FULL, 22, LEFT, 709)
+ DXGIMAP(RGB, STUDIO, 22, NONE, 2020)
+ DXGIMAP(YCBCR, STUDIO, 22, LEFT, 2020)
+ DXGIMAP(YCBCR, FULL, 22, LEFT, 2020)
+ DXGIMAP(YCBCR, STUDIO, 22, TOPLEFT, 2020)
+ DXGIMAP(RGB, FULL, 22, NONE, 2020)
+ DXGIMAP(RGB, FULL, 2084, NONE, 2020)
+ DXGIMAP(YCBCR, STUDIO, 2084, LEFT, 2020)
+ DXGIMAP(RGB, STUDIO, 2084, NONE, 2020)
+ DXGIMAP(YCBCR, STUDIO, 2084, TOPLEFT, 2020)
+ DXGIMAP(YCBCR, STUDIO, HLG, TOPLEFT, 2020)
+ DXGIMAP(YCBCR, FULL, HLG, TOPLEFT, 2020)
+ /*DXGIMAP(YCBCR, FULL, 22, NONE, 2020, 601)*/
+ {DXGI_COLOR_SPACE_RESERVED, NULL, 0, 0, 0, 0, 0},
+#undef DXGIMAP
+};
+
+#ifdef HAVE_DXGI1_6_H
+static bool canHandleConversion(const dxgi_color_space *src, const dxgi_color_space *dst)
+{
+ if (src == dst)
+ return true;
+ if (src->primaries == COLOR_PRIMARIES_BT2020)
+ return true; /* we can convert BT2020 to 2020 or 709 */
+ if (dst->transfer == TRANSFER_FUNC_BT709)
+ return true; /* we can handle anything to 709 */
+ return false; /* let Windows do the rest */
+}
+#endif
+
+void DXGI_SelectSwapchainColorspace(struct dxgi_swapchain *display, const libvlc_video_render_cfg_t *cfg)
+{
+ HRESULT hr;
+ int best = 0;
+ int score, best_score = 0;
+ UINT support;
+ IDXGISwapChain3 *dxgiswapChain3 = NULL;
+ hr = IDXGISwapChain_QueryInterface( display->dxgiswapChain, &IID_IDXGISwapChain3, (void **)&dxgiswapChain3);
+ if (FAILED(hr)) {
+ msg_Warn(display->obj, "could not get a IDXGISwapChain3");
+ goto done;
+ }
+
+ /* pick the best output based on color support and transfer */
+ /* TODO support YUV output later */
+ best = -1;
+ for (int i=0; color_spaces[i].name; ++i)
+ {
+ hr = IDXGISwapChain3_CheckColorSpaceSupport(dxgiswapChain3, color_spaces[i].dxgi, &support);
+ if (SUCCEEDED(hr) && support) {
+ if (!display->logged_capabilities)
+ msg_Dbg(display->obj, "supports colorspace %s", color_spaces[i].name);
+ score = 0;
+ if (color_spaces[i].primaries == (video_color_primaries_t) cfg->primaries)
+ score++;
+ if (color_spaces[i].color == (video_color_space_t) cfg->colorspace)
+ score += 2; /* we don't want to translate color spaces */
+ if (color_spaces[i].transfer == (video_transfer_func_t) cfg->transfer ||
+ /* favor 2084 output for HLG source */
+ (color_spaces[i].transfer == TRANSFER_FUNC_SMPTE_ST2084 && cfg->transfer == TRANSFER_FUNC_HLG))
+ score++;
+ if (color_spaces[i].b_full_range == cfg->full_range)
+ score++;
+ if (score > best_score || (score && best == -1)) {
+ best = i;
+ best_score = score;
+ }
+ }
+ }
+ display->logged_capabilities = true;
+
+ if (best == -1)
+ {
+ best = 0;
+ msg_Warn(display->obj, "no matching colorspace found force %s", color_spaces[best].name);
+ }
+
+ IDXGISwapChain_QueryInterface( display->dxgiswapChain, &IID_IDXGISwapChain4, (void **)&display->dxgiswapChain4);
+
+#ifdef HAVE_DXGI1_6_H
+ IDXGIOutput *dxgiOutput = NULL;
+
+ if (SUCCEEDED(IDXGISwapChain_GetContainingOutput( display->dxgiswapChain, &dxgiOutput )))
+ {
+ IDXGIOutput6 *dxgiOutput6 = NULL;
+ if (SUCCEEDED(IDXGIOutput_QueryInterface( dxgiOutput, &IID_IDXGIOutput6, (void **)&dxgiOutput6 )))
+ {
+ DXGI_OUTPUT_DESC1 desc1;
+ if (SUCCEEDED(IDXGIOutput6_GetDesc1( dxgiOutput6, &desc1 )))
+ {
+ const dxgi_color_space *csp = NULL;
+ for (int i=0; color_spaces[i].name; ++i)
+ {
+ if (color_spaces[i].dxgi == desc1.ColorSpace)
+ {
+ if (!canHandleConversion(&color_spaces[best], &color_spaces[i]))
+ msg_Warn(display->obj, "Can't handle conversion to screen format %s", color_spaces[i].name);
+ else
+ {
+ best = i;
+ csp = &color_spaces[i];
+ }
+ break;
+ }
+ }
+
+ msg_Dbg(display->obj, "Output max luminance: %.1f, colorspace %s, bits per pixel %d", desc1.MaxFullFrameLuminance, csp?csp->name:"unknown", desc1.BitsPerColor);
+ //sys->display.luminance_peak = desc1.MaxFullFrameLuminance;
+ }
+ IDXGIOutput6_Release( dxgiOutput6 );
+ }
+ IDXGIOutput_Release( dxgiOutput );
+ }
+#endif
+
+ hr = IDXGISwapChain3_SetColorSpace1(dxgiswapChain3, color_spaces[best].dxgi);
+ if (SUCCEEDED(hr))
+ msg_Dbg(display->obj, "using colorspace %s", color_spaces[best].name);
+ else
+ msg_Err(display->obj, "Failed to set colorspace %s. (hr=0x%lX)", color_spaces[best].name, hr);
+done:
+ display->colorspace = &color_spaces[best];
+ display->send_metadata = color_spaces[best].transfer == (video_transfer_func_t) cfg->transfer &&
+ color_spaces[best].primaries == (video_color_primaries_t) cfg->primaries &&
+ color_spaces[best].color == (video_color_space_t) cfg->colorspace;
+ if (dxgiswapChain3)
+ IDXGISwapChain3_Release(dxgiswapChain3);
+}
+
+#if !VLC_WINSTORE_APP
+static void FillSwapChainDesc(struct dxgi_swapchain *display, UINT width, UINT height, DXGI_SWAP_CHAIN_DESC1 *out)
+{
+ ZeroMemory(out, sizeof(*out));
+ out->BufferCount = DXGI_SWAP_FRAME_COUNT;
+ out->BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ out->SampleDesc.Count = 1;
+ out->SampleDesc.Quality = 0;
+ out->Width = width;
+ out->Height = height;
+ out->Format = display->pixelFormat->formatTexture;
+ //out->Flags = 512; // DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO;
+
+ bool isWin10OrGreater = false;
+ HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32.dll"));
+ if (likely(hKernel32 != NULL))
+ isWin10OrGreater = GetProcAddress(hKernel32, "GetSystemCpuSetInformation") != NULL;
+ if (isWin10OrGreater)
+ out->SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
+ else
+ {
+ bool isWin80OrGreater = false;
+ if (likely(hKernel32 != NULL))
+ isWin80OrGreater = GetProcAddress(hKernel32, "CheckTokenCapability") != NULL;
+ if (isWin80OrGreater)
+ out->SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
+ else
+ {
+ out->SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
+ out->BufferCount = 1;
+ }
+ }
+}
+
+static void DXGI_CreateSwapchainHwnd(struct dxgi_swapchain *display,
+ IDXGIAdapter *dxgiadapter, IUnknown *pFactoryDevice,
+ UINT width, UINT height)
+{
+ vlc_assert(display->swapchainSurfaceType == SWAPCHAIN_SURFACE_HWND);
+ if (display->swapchainSurface.hwnd == NULL)
+ {
+ msg_Err(display->obj, "missing a HWND to create the swapchain");
+ return;
+ }
+
+ DXGI_SWAP_CHAIN_DESC1 scd;
+ FillSwapChainDesc(display, width, height, &scd);
+
+ IDXGIFactory2 *dxgifactory;
+ HRESULT hr = IDXGIAdapter_GetParent(dxgiadapter, &IID_IDXGIFactory2, (void **)&dxgifactory);
+ if (FAILED(hr)) {
+ msg_Err(display->obj, "Could not get the DXGI Factory. (hr=0x%lX)", hr);
+ return;
+ }
+
+ hr = IDXGIFactory2_CreateSwapChainForHwnd(dxgifactory, pFactoryDevice,
+ display->swapchainSurface.hwnd, &scd,
+ NULL, NULL, &display->dxgiswapChain);
+
+ if (hr == DXGI_ERROR_INVALID_CALL && scd.Format == DXGI_FORMAT_R10G10B10A2_UNORM)
+ {
+ msg_Warn(display->obj, "10 bits swapchain failed, try 8 bits");
+ scd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ hr = IDXGIFactory2_CreateSwapChainForHwnd(dxgifactory, pFactoryDevice,
+ display->swapchainSurface.hwnd, &scd,
+ NULL, NULL, &display->dxgiswapChain);
+ }
+ IDXGIFactory2_Release(dxgifactory);
+ if (FAILED(hr)) {
+ msg_Err(display->obj, "Could not create the SwapChain. (hr=0x%lX)", hr);
+ }
+}
+
+#ifdef HAVE_DCOMP_H
+static void DXGI_CreateSwapchainDComp(struct dxgi_swapchain *display,
+ IDXGIAdapter *dxgiadapter, IUnknown *pFactoryDevice,
+ UINT width, UINT height)
+{
+ vlc_assert(display->swapchainSurfaceType == SWAPCHAIN_SURFACE_DCOMP);
+ if (display->swapchainSurface.dcomp.device == NULL || display->swapchainSurface.dcomp.visual == NULL)
+ {
+ msg_Err(display->obj, "missing a HWND to create the swapchain");
+ return;
+ }
+
+ DXGI_SWAP_CHAIN_DESC1 scd;
+ FillSwapChainDesc(display, width, height, &scd);
+ ZeroMemory(&scd, sizeof(scd));
+ scd.BufferCount = 3;
+ scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ scd.SampleDesc.Count = 1;
+ scd.SampleDesc.Quality = 0;
+ scd.Width = width;
+ scd.Height = height;
+ scd.Format = display->pixelFormat->formatTexture;
+ scd.Scaling = DXGI_SCALING_STRETCH;
+ scd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
+ scd.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
+
+ IDXGIFactory2 *dxgifactory;
+ HRESULT hr = IDXGIAdapter_GetParent(dxgiadapter, &IID_IDXGIFactory2, (void **)&dxgifactory);
+ if (FAILED(hr)) {
+ msg_Err(display->obj, "Could not get the DXGI Factory. (hr=0x%lX)", hr);
+ return;
+ }
+
+ hr = IDXGIFactory2_CreateSwapChainForComposition(dxgifactory, pFactoryDevice,
+ &scd, NULL, &display->dxgiswapChain);
+ if (hr == DXGI_ERROR_INVALID_CALL && scd.Format == DXGI_FORMAT_R10G10B10A2_UNORM)
+ {
+ msg_Warn(display->obj, "10 bits swapchain failed, try 8 bits");
+ scd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ hr = IDXGIFactory2_CreateSwapChainForComposition(dxgifactory, pFactoryDevice,
+ &scd, NULL, &display->dxgiswapChain);
+ }
+ IDXGIFactory2_Release(dxgifactory);
+ if (SUCCEEDED(hr)) {
+ IDCompositionVisual_SetContent(display->swapchainSurface.dcomp.visual, (IUnknown *)display->dxgiswapChain);
+ IDCompositionDevice_Commit(display->swapchainSurface.dcomp.device);
+ }
+ if (FAILED(hr)) {
+ msg_Err(display->obj, "Could not create the SwapChain. (hr=0x%lX)", hr);
+ }
+}
+#endif /* HAVE_DCOMP_H */
+
+#endif /* !VLC_WINSTORE_APP */
+
+void DXGI_LocalSwapchainSwap( struct dxgi_swapchain *display )
+{
+ DXGI_PRESENT_PARAMETERS presentParams = { 0 };
+
+ HRESULT hr = IDXGISwapChain1_Present1( display->dxgiswapChain, 0, 0, &presentParams );
+ if ( hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET )
+ {
+ /* TODO device lost */
+ msg_Err( display->obj, "SwapChain Present failed. (hr=0x%lX)", hr );
+ }
+}
+
+void DXGI_LocalSwapchainSetMetadata( struct dxgi_swapchain *display, libvlc_video_metadata_type_t type, const void *metadata )
+{
+ assert(type == libvlc_video_metadata_frame_hdr10);
+ if ( type == libvlc_video_metadata_frame_hdr10 && metadata &&
+ display->send_metadata && display->dxgiswapChain4 )
+ {
+ const libvlc_video_frame_hdr10_metadata_t *p_hdr10 = metadata;
+ DXGI_HDR_METADATA_HDR10 hdr10 = { 0 };
+ hdr10.GreenPrimary[0] = p_hdr10->GreenPrimary[0];
+ hdr10.GreenPrimary[1] = p_hdr10->GreenPrimary[1];
+ hdr10.BluePrimary[0] = p_hdr10->BluePrimary[0];
+ hdr10.BluePrimary[1] = p_hdr10->BluePrimary[1];
+ hdr10.RedPrimary[0] = p_hdr10->RedPrimary[0];
+ hdr10.RedPrimary[1] = p_hdr10->RedPrimary[1];
+ hdr10.WhitePoint[0] = p_hdr10->WhitePoint[0];
+ hdr10.WhitePoint[1] = p_hdr10->WhitePoint[1];
+ hdr10.MinMasteringLuminance = p_hdr10->MinMasteringLuminance;
+ hdr10.MaxMasteringLuminance = p_hdr10->MaxMasteringLuminance;
+ hdr10.MaxContentLightLevel = p_hdr10->MaxContentLightLevel;
+ hdr10.MaxFrameAverageLightLevel = p_hdr10->MaxFrameAverageLightLevel;
+ if (memcmp(&display->hdr10, &hdr10, sizeof(hdr10)))
+ {
+ memcpy(&display->hdr10, &hdr10, sizeof(hdr10));
+ IDXGISwapChain4_SetHDRMetaData( display->dxgiswapChain4, DXGI_HDR_METADATA_TYPE_HDR10,
+ sizeof( &display->hdr10 ), &display->hdr10 );
+ }
+ }
+}
+
+struct dxgi_swapchain *DXGI_CreateLocalSwapchainHandleHwnd(vlc_object_t *o, HWND hwnd)
+{
+ struct dxgi_swapchain *display = vlc_obj_calloc(o, 1, sizeof(*display));
+ if (unlikely(display == NULL))
+ return NULL;
+
+ display->obj = o;
+#if !VLC_WINSTORE_APP
+ display->swapchainSurfaceType = SWAPCHAIN_SURFACE_HWND;
+ display->swapchainSurface.hwnd = hwnd;
+#else // VLC_WINSTORE_APP
+ VLC_UNUSED(hwnd);
+#endif // VLC_WINSTORE_APP
+
+ return display;
+}
+
+#ifdef HAVE_DCOMP_H
+struct dxgi_swapchain *DXGI_CreateLocalSwapchainHandleDComp(vlc_object_t *o, void* dcompDevice, void* dcompVisual)
+{
+ struct dxgi_swapchain *display = vlc_obj_calloc(o, 1, sizeof(*display));
+ if (unlikely(display == NULL))
+ return NULL;
+
+ display->obj = o;
+ display->swapchainSurfaceType = SWAPCHAIN_SURFACE_DCOMP;
+ display->swapchainSurface.dcomp.device = dcompDevice;
+ display->swapchainSurface.dcomp.visual = dcompVisual;
+
+ return display;
+}
+#endif
+
+void DXGI_LocalSwapchainCleanupDevice( struct dxgi_swapchain *display )
+{
+ if (display->dxgiswapChain4)
+ {
+ IDXGISwapChain4_Release(display->dxgiswapChain4);
+ display->dxgiswapChain4 = NULL;
+ }
+ if (display->dxgiswapChain)
+ {
+ IDXGISwapChain_Release(display->dxgiswapChain);
+ display->dxgiswapChain = NULL;
+ }
+}
+
+void DXGI_SwapchainUpdateOutput( struct dxgi_swapchain *display, libvlc_video_output_cfg_t *out )
+{
+ out->dxgi_format = display->pixelFormat->formatTexture;
+ out->full_range = display->colorspace->b_full_range;
+ out->colorspace = (libvlc_video_color_space_t) display->colorspace->color;
+ out->primaries = (libvlc_video_color_primaries_t) display->colorspace->primaries;
+ out->transfer = (libvlc_video_transfer_func_t) display->colorspace->transfer;
+}
+
+bool DXGI_UpdateSwapChain( struct dxgi_swapchain *display, IDXGIAdapter *dxgiadapter,
+ IUnknown *pFactoryDevice,
+ const d3d_format_t *newPixelFormat, const libvlc_video_render_cfg_t *cfg )
+{
+#if !VLC_WINSTORE_APP
+ if (display->dxgiswapChain != NULL && display->pixelFormat != newPixelFormat)
+ {
+ // the pixel format changed, we need a new swapchain
+ IDXGISwapChain_Release(display->dxgiswapChain);
+ display->dxgiswapChain = NULL;
+ display->logged_capabilities = false;
+ }
+
+ if ( display->dxgiswapChain == NULL )
+ {
+ display->pixelFormat = newPixelFormat;
+
+#ifdef HAVE_DCOMP_H
+ if (display->swapchainSurfaceType == SWAPCHAIN_SURFACE_DCOMP)
+ DXGI_CreateSwapchainDComp(display, dxgiadapter, pFactoryDevice,
+ cfg->width, cfg->height);
+ else // SWAPCHAIN_TARGET_HWND
+#endif
+ DXGI_CreateSwapchainHwnd(display, dxgiadapter, pFactoryDevice,
+ cfg->width, cfg->height);
+
+ }
+#else /* VLC_WINSTORE_APP */
+ if ( display->dxgiswapChain == NULL )
+ {
+ display->dxgiswapChain = (void*)(uintptr_t)var_InheritInteger(display->obj, "winrt-swapchain");
+ }
+#endif /* VLC_WINSTORE_APP */
+ if (display->dxgiswapChain == NULL)
+ return false;
+
+ /* TODO detect is the size is the same as the output and switch to fullscreen mode */
+ HRESULT hr;
+ hr = IDXGISwapChain_ResizeBuffers( display->dxgiswapChain, 0, cfg->width, cfg->height,
+ DXGI_FORMAT_UNKNOWN, 0 );
+ if ( FAILED( hr ) ) {
+ msg_Err( display->obj, "Failed to resize the backbuffer. (hr=0x%lX)", hr );
+ return false;
+ }
+
+ DXGI_SelectSwapchainColorspace(display, cfg);
+ return true;
+}
+
+IDXGISwapChain1 *DXGI_GetSwapChain1( struct dxgi_swapchain *display )
+{
+ return display->dxgiswapChain;
+}
+
+IDXGISwapChain4 *DXGI_GetSwapChain4( struct dxgi_swapchain *display )
+{
+ return display->dxgiswapChain4;
+}
+
+const d3d_format_t *DXGI_GetPixelFormat( struct dxgi_swapchain *display )
+{
+ return display->pixelFormat;
+}
diff --git a/modules/video_output/win32/dxgi_swapchain.h b/modules/video_output/win32/dxgi_swapchain.h
new file mode 100644
index 0000000000..77910570ae
--- /dev/null
+++ b/modules/video_output/win32/dxgi_swapchain.h
@@ -0,0 +1,64 @@
+/*****************************************************************************
+ * dxgi_swapchain.h: DXGI swapchain handled by the display module
+ *****************************************************************************
+ * Copyright (C) 2014-2021 VLC authors and VideoLAN
+ *
+ * Authors: Martell Malone <martellmalone at gmail.com>
+ * Steve Lhomme <robux4 at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef VLC_DXGI_SWAPCHAIN_H
+#define VLC_DXGI_SWAPCHAIN_H
+
+#include <vlc_common.h>
+
+#include <vlc/libvlc.h>
+#include <vlc/libvlc_picture.h>
+#include <vlc/libvlc_media.h>
+#include <vlc/libvlc_renderer_discoverer.h>
+#include <vlc/libvlc_media_player.h>
+
+#include <dxgi1_5.h>
+#include "../../video_chroma/dxgi_fmt.h"
+
+#define DXGI_SWAP_FRAME_COUNT 3
+
+struct dxgi_swapchain;
+
+struct dxgi_swapchain *DXGI_CreateLocalSwapchainHandleHwnd(vlc_object_t *, HWND);
+
+#ifdef HAVE_DCOMP_H
+struct dxgi_swapchain *DXGI_CreateLocalSwapchainHandleDComp(vlc_object_t *,
+ void /*IDCompositionDevice*/ * dcompDevice,
+ void /*IDCompositionVisual*/ * dcompVisual);
+#endif
+
+IDXGISwapChain1 *DXGI_GetSwapChain1( struct dxgi_swapchain * );
+IDXGISwapChain4 *DXGI_GetSwapChain4( struct dxgi_swapchain * );
+const d3d_format_t *DXGI_GetPixelFormat( struct dxgi_swapchain * );
+
+void DXGI_SelectSwapchainColorspace( struct dxgi_swapchain *, const libvlc_video_render_cfg_t * );
+void DXGI_LocalSwapchainCleanupDevice( struct dxgi_swapchain * );
+void DXGI_SwapchainUpdateOutput( struct dxgi_swapchain *, libvlc_video_output_cfg_t * );
+bool DXGI_UpdateSwapChain( struct dxgi_swapchain *, IDXGIAdapter *,
+ IUnknown *pFactoryDevice,
+ const d3d_format_t *, const libvlc_video_render_cfg_t * );
+
+void DXGI_LocalSwapchainSwap( struct dxgi_swapchain * );
+void DXGI_LocalSwapchainSetMetadata( struct dxgi_swapchain *, libvlc_video_metadata_type_t, const void * );
+
+#endif /* VLC_D3D11_SWAPCHAIN_H */
More information about the vlc-commits
mailing list