[d3d9] Add extended swapchain interfaces

Allows for controling colorspace, etc.
This commit is contained in:
Joshua Ashton 2023-05-15 17:45:14 +00:00 committed by Joshie
parent 495dc75ab2
commit f2bb1d4b69
4 changed files with 197 additions and 11 deletions

View File

@ -7359,6 +7359,7 @@ namespace dxvk {
HRESULT D3D9DeviceEx::ResetSwapChain(D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode) {
D3D9Format backBufferFmt = EnumerateFormat(pPresentationParameters->BackBufferFormat);
bool unlockedFormats = m_implicitSwapchain != nullptr && m_implicitSwapchain->HasFormatsUnlocked();
Logger::info(str::format(
"D3D9DeviceEx::ResetSwapChain:\n",
@ -7371,7 +7372,7 @@ namespace dxvk {
" - Windowed: ", pPresentationParameters->Windowed ? "true" : "false", "\n",
" - Swap effect: ", pPresentationParameters->SwapEffect, "\n"));
if (backBufferFmt != D3D9Format::Unknown) {
if (backBufferFmt != D3D9Format::Unknown && !unlockedFormats) {
if (!IsSupportedBackBufferFormat(backBufferFmt)) {
Logger::err(str::format("D3D9DeviceEx::ResetSwapChain: Unsupported backbuffer format: ",
EnumerateFormat(pPresentationParameters->BackBufferFormat)));

View File

@ -196,12 +196,47 @@ ID3D9VkInteropDevice : public IUnknown {
DWORD MapFlags) = 0;
};
/**
* \brief D3D9 current output metadata
*/
struct D3D9VkExtOutputMetadata {
float RedPrimary[2];
float GreenPrimary[2];
float BluePrimary[2];
float WhitePoint[2];
float MinLuminance;
float MaxLuminance;
float MaxFullFrameLuminance;
};
/**
* \brief D3D9 extended swapchain
*/
MIDL_INTERFACE("13776e93-4aa9-430a-a4ec-fe9e281181d5")
ID3D9VkExtSwapchain : public IUnknown {
virtual BOOL STDMETHODCALLTYPE CheckColorSpaceSupport(
VkColorSpaceKHR ColorSpace) = 0;
virtual HRESULT STDMETHODCALLTYPE SetColorSpace(
VkColorSpaceKHR ColorSpace) = 0;
virtual HRESULT STDMETHODCALLTYPE SetHDRMetaData(
const VkHdrMetadataEXT *pHDRMetadata) = 0;
virtual HRESULT STDMETHODCALLTYPE GetCurrentOutputDesc(
D3D9VkExtOutputMetadata *pOutputDesc) = 0;
virtual void STDMETHODCALLTYPE UnlockAdditionalFormats() = 0;
};
#ifdef _MSC_VER
struct __declspec(uuid("3461a81b-ce41-485b-b6b5-fcf08ba6a6bd")) ID3D9VkInteropInterface;
struct __declspec(uuid("d56344f5-8d35-46fd-806d-94c351b472c1")) ID3D9VkInteropTexture;
struct __declspec(uuid("2eaa4b89-0107-4bdb-87f7-0f541c493ce0")) ID3D9VkInteropDevice;
struct __declspec(uuid("13776e93-4aa9-430a-a4ec-fe9e281181d5")) ID3D9VkExtSwapchain;
#else
__CRT_UUID_DECL(ID3D9VkInteropInterface, 0x3461a81b,0xce41,0x485b,0xb6,0xb5,0xfc,0xf0,0x8b,0xa6,0xa6,0xbd);
__CRT_UUID_DECL(ID3D9VkInteropTexture, 0xd56344f5,0x8d35,0x46fd,0x80,0x6d,0x94,0xc3,0x51,0xb4,0x72,0xc1);
__CRT_UUID_DECL(ID3D9VkInteropDevice, 0x2eaa4b89,0x0107,0x4bdb,0x87,0xf7,0x0f,0x54,0x1c,0x49,0x3c,0xe0);
__CRT_UUID_DECL(ID3D9VkExtSwapchain, 0x13776e93,0x4aa9,0x430a,0xa4,0xec,0xfe,0x9e,0x28,0x11,0x81,0xd5);
#endif

View File

@ -29,7 +29,8 @@ namespace dxvk {
, m_context (m_device->createContext(DxvkContextType::Supplementary))
, m_frameLatencyCap (pDevice->GetOptions()->maxFrameLatency)
, m_frameLatencySignal(new sync::Fence(m_frameId))
, m_dialog (pDevice->GetOptions()->enableDialogMode) {
, m_dialog (pDevice->GetOptions()->enableDialogMode)
, m_swapchainExt (this) {
this->NormalizePresentParameters(pPresentParams);
m_presentParams = *pPresentParams;
m_window = m_presentParams.hDeviceWindow;
@ -86,6 +87,11 @@ namespace dxvk {
return S_OK;
}
if (riid == __uuidof(ID3D9VkExtSwapchain)) {
*ppvObject = ref(&m_swapchainExt);
return S_OK;
}
if (logQueryInterfaceError(__uuidof(IDirect3DSwapChain9), riid)) {
Logger::warn("D3D9SwapChainEx::QueryInterface: Unknown interface query");
Logger::warn(str::format(riid));
@ -762,6 +768,11 @@ namespace dxvk {
status = m_presenter->acquireNextImage(sync, imageIndex);
}
if (m_hdrMetadata && m_dirtyHdrMetadata) {
m_presenter->setHdrMetadata(*m_hdrMetadata);
m_dirtyHdrMetadata = false;
}
m_context->beginRecording(
m_device->createCommandList());
@ -1086,27 +1097,36 @@ namespace dxvk {
case D3D9Format::X8R8G8B8:
case D3D9Format::A8B8G8R8:
case D3D9Format::X8B8G8R8: {
pDstFormats[n++] = { VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
pDstFormats[n++] = { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
pDstFormats[n++] = { VK_FORMAT_R8G8B8A8_UNORM, m_colorspace };
pDstFormats[n++] = { VK_FORMAT_B8G8R8A8_UNORM, m_colorspace };
} break;
case D3D9Format::A2R10G10B10:
case D3D9Format::A2B10G10R10: {
pDstFormats[n++] = { VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
pDstFormats[n++] = { VK_FORMAT_A2R10G10B10_UNORM_PACK32, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
pDstFormats[n++] = { VK_FORMAT_A2B10G10R10_UNORM_PACK32, m_colorspace };
pDstFormats[n++] = { VK_FORMAT_A2R10G10B10_UNORM_PACK32, m_colorspace };
} break;
case D3D9Format::X1R5G5B5:
case D3D9Format::A1R5G5B5: {
pDstFormats[n++] = { VK_FORMAT_B5G5R5A1_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
pDstFormats[n++] = { VK_FORMAT_R5G5B5A1_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
pDstFormats[n++] = { VK_FORMAT_A1R5G5B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
pDstFormats[n++] = { VK_FORMAT_B5G5R5A1_UNORM_PACK16, m_colorspace };
pDstFormats[n++] = { VK_FORMAT_R5G5B5A1_UNORM_PACK16, m_colorspace };
pDstFormats[n++] = { VK_FORMAT_A1R5G5B5_UNORM_PACK16, m_colorspace };
} break;
case D3D9Format::R5G6B5: {
pDstFormats[n++] = { VK_FORMAT_B5G6R5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
pDstFormats[n++] = { VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
pDstFormats[n++] = { VK_FORMAT_B5G6R5_UNORM_PACK16, m_colorspace };
pDstFormats[n++] = { VK_FORMAT_R5G6B5_UNORM_PACK16, m_colorspace };
} break;
case D3D9Format::A16B16G16R16F: {
if (m_unlockAdditionalFormats) {
pDstFormats[n++] = { VK_FORMAT_R16G16B16A16_SFLOAT, m_colorspace };
} else {
Logger::warn(str::format("D3D9SwapChainEx: Unexpected format: ", Format));
}
break;
}
}
return n;
@ -1303,4 +1323,91 @@ namespace dxvk {
return this->GetParent()->IsExtended() ? "D3D9Ex" : "D3D9";
}
D3D9VkExtSwapchain::D3D9VkExtSwapchain(D3D9SwapChainEx *pSwapChain)
: m_swapchain(pSwapChain) {
}
ULONG STDMETHODCALLTYPE D3D9VkExtSwapchain::AddRef() {
return m_swapchain->AddRef();
}
ULONG STDMETHODCALLTYPE D3D9VkExtSwapchain::Release() {
return m_swapchain->Release();
}
HRESULT STDMETHODCALLTYPE D3D9VkExtSwapchain::QueryInterface(
REFIID riid,
void** ppvObject) {
return m_swapchain->QueryInterface(riid, ppvObject);
}
BOOL STDMETHODCALLTYPE D3D9VkExtSwapchain::CheckColorSpaceSupport(
VkColorSpaceKHR ColorSpace) {
return m_swapchain->m_presenter->supportsColorSpace(ColorSpace);
}
HRESULT STDMETHODCALLTYPE D3D9VkExtSwapchain::SetColorSpace(
VkColorSpaceKHR ColorSpace) {
if (!CheckColorSpaceSupport(ColorSpace))
return D3DERR_INVALIDCALL;
m_swapchain->m_dirty |= ColorSpace != m_swapchain->m_colorspace;
m_swapchain->m_colorspace = ColorSpace;
return S_OK;
}
HRESULT STDMETHODCALLTYPE D3D9VkExtSwapchain::SetHDRMetaData(
const VkHdrMetadataEXT *pHDRMetadata) {
if (!pHDRMetadata)
return D3DERR_INVALIDCALL;
m_swapchain->m_hdrMetadata = *pHDRMetadata;
m_swapchain->m_dirtyHdrMetadata = true;
return S_OK;
}
HRESULT STDMETHODCALLTYPE D3D9VkExtSwapchain::GetCurrentOutputDesc(
D3D9VkExtOutputMetadata *pOutputDesc) {
HMONITOR monitor = m_swapchain->m_monitor;
if (!monitor)
monitor = wsi::getDefaultMonitor();
// ^ this should be the display we are mostly covering someday.
wsi::WsiEdidData edidData = wsi::getMonitorEdid(monitor);
wsi::WsiDisplayMetadata metadata = {};
{
std::optional<wsi::WsiDisplayMetadata> r_metadata = std::nullopt;
if (!edidData.empty())
r_metadata = wsi::parseColorimetryInfo(edidData);
if (r_metadata)
metadata = *r_metadata;
else
Logger::err("D3D9: Failed to parse display metadata + colorimetry info, using blank.");
}
NormalizeDisplayMetadata(CheckColorSpaceSupport(VK_COLOR_SPACE_HDR10_ST2084_EXT), metadata);
pOutputDesc->RedPrimary[0] = metadata.redPrimary[0];
pOutputDesc->RedPrimary[1] = metadata.redPrimary[1];
pOutputDesc->GreenPrimary[0] = metadata.greenPrimary[0];
pOutputDesc->GreenPrimary[1] = metadata.greenPrimary[1];
pOutputDesc->BluePrimary[0] = metadata.bluePrimary[0];
pOutputDesc->BluePrimary[1] = metadata.bluePrimary[1];
pOutputDesc->WhitePoint[0] = metadata.whitePoint[0];
pOutputDesc->WhitePoint[1] = metadata.whitePoint[1];
pOutputDesc->MinLuminance = metadata.minLuminance;
pOutputDesc->MaxLuminance = metadata.maxLuminance;
pOutputDesc->MaxFullFrameLuminance = metadata.maxFullFrameLuminance;
return S_OK;
}
void STDMETHODCALLTYPE D3D9VkExtSwapchain::UnlockAdditionalFormats() {
m_swapchain->m_unlockAdditionalFormats = true;
}
}

View File

@ -18,10 +18,43 @@
namespace dxvk {
class D3D9Surface;
class D3D9SwapChainEx;
class D3D9VkExtSwapchain final : public ID3D9VkExtSwapchain {
public:
D3D9VkExtSwapchain(D3D9SwapChainEx *pSwapChain);
ULONG STDMETHODCALLTYPE AddRef();
ULONG STDMETHODCALLTYPE Release();
HRESULT STDMETHODCALLTYPE QueryInterface(
REFIID riid,
void** ppvObject);
BOOL STDMETHODCALLTYPE CheckColorSpaceSupport(
VkColorSpaceKHR ColorSpace);
HRESULT STDMETHODCALLTYPE SetColorSpace(
VkColorSpaceKHR ColorSpace);
HRESULT STDMETHODCALLTYPE SetHDRMetaData(
const VkHdrMetadataEXT *pHDRMetadata);
HRESULT STDMETHODCALLTYPE GetCurrentOutputDesc(
D3D9VkExtOutputMetadata *pOutputDesc);
void STDMETHODCALLTYPE UnlockAdditionalFormats();
private:
D3D9SwapChainEx *m_swapchain;
};
using D3D9SwapChainExBase = D3D9DeviceChild<IDirect3DSwapChain9Ex>;
class D3D9SwapChainEx final : public D3D9SwapChainExBase {
static constexpr uint32_t NumControlPoints = 256;
friend class D3D9VkExtSwapchain;
public:
D3D9SwapChainEx(
@ -85,6 +118,8 @@ namespace dxvk {
void SyncFrameLatency();
bool HasFormatsUnlocked() const { return m_unlockAdditionalFormats; }
private:
enum BindingIds : uint32_t {
@ -134,6 +169,14 @@ namespace dxvk {
bool m_warnedAboutGDIFallback = false;
VkColorSpaceKHR m_colorspace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
std::optional<VkHdrMetadataEXT> m_hdrMetadata;
bool m_dirtyHdrMetadata = true;
bool m_unlockAdditionalFormats = false;
D3D9VkExtSwapchain m_swapchainExt;
void PresentImage(UINT PresentInterval);
void SubmitPresent(const vk::PresenterSync& Sync, uint32_t FrameId);