diff options
Diffstat (limited to 'src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_swapchain.cpp')
-rw-r--r-- | src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_swapchain.cpp | 747 |
1 files changed, 747 insertions, 0 deletions
diff --git a/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_swapchain.cpp b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_swapchain.cpp new file mode 100644 index 00000000..c49b9355 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/dxgi/dxgi_swapchain.cpp @@ -0,0 +1,747 @@ +#include "dxgi_factory.h" +#include "dxgi_output.h" +#include "dxgi_swapchain.h" + +namespace dxvk { + + DxgiSwapChain::DxgiSwapChain( + IDXGIFactory* pFactory, + IDXGIVkSwapChain* pPresenter, + HWND hWnd, + const DXGI_SWAP_CHAIN_DESC1* pDesc, + const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc) + : m_factory (pFactory), + m_window (hWnd), + m_desc (*pDesc), + m_descFs (*pFullscreenDesc), + m_presentCount(0u), + m_presenter (pPresenter), + m_monitor (nullptr) { + if (FAILED(m_presenter->GetAdapter(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&m_adapter)))) + throw DxvkError("DXGI: Failed to get adapter for present device"); + + // Query monitor info form DXVK's DXGI factory, if available + m_factory->QueryInterface(__uuidof(IDXGIVkMonitorInfo), reinterpret_cast<void**>(&m_monitorInfo)); + + // Apply initial window mode and fullscreen state + if (!m_descFs.Windowed && FAILED(EnterFullscreenMode(nullptr))) + throw DxvkError("DXGI: Failed to set initial fullscreen state"); + } + + + DxgiSwapChain::~DxgiSwapChain() { + wsi::restoreDisplayMode(m_monitor); + + // Decouple swap chain from monitor if necessary + DXGI_VK_MONITOR_DATA* monitorInfo = nullptr; + + if (SUCCEEDED(AcquireMonitorData(m_monitor, &monitorInfo))) { + if (monitorInfo->pSwapChain == this) + monitorInfo->pSwapChain = nullptr; + + ReleaseMonitorData(); + } + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::QueryInterface(REFIID riid, void** ppvObject) { + if (ppvObject == nullptr) + return E_POINTER; + + *ppvObject = nullptr; + + if (riid == __uuidof(IUnknown) + || riid == __uuidof(IDXGIObject) + || riid == __uuidof(IDXGIDeviceSubObject) + || riid == __uuidof(IDXGISwapChain) + || riid == __uuidof(IDXGISwapChain1) + || riid == __uuidof(IDXGISwapChain2) + || riid == __uuidof(IDXGISwapChain3) + || riid == __uuidof(IDXGISwapChain4)) { + *ppvObject = ref(this); + return S_OK; + } + + Logger::warn("DxgiSwapChain::QueryInterface: Unknown interface query"); + Logger::warn(str::format(riid)); + return E_NOINTERFACE; + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetParent(REFIID riid, void** ppParent) { + return m_factory->QueryInterface(riid, ppParent); + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetDevice(REFIID riid, void** ppDevice) { + return m_presenter->GetDevice(riid, ppDevice); + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetBuffer(UINT Buffer, REFIID riid, void** ppSurface) { + return m_presenter->GetImage(Buffer, riid, ppSurface); + } + + + UINT STDMETHODCALLTYPE DxgiSwapChain::GetCurrentBackBufferIndex() { + return m_presenter->GetImageIndex(); + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetContainingOutput(IDXGIOutput** ppOutput) { + InitReturnPtr(ppOutput); + + if (!wsi::isWindow(m_window)) + return DXGI_ERROR_INVALID_CALL; + + if (m_target != nullptr) { + *ppOutput = m_target.ref(); + return S_OK; + } + + return GetOutputFromMonitor(wsi::getWindowMonitor(m_window), ppOutput); + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetDesc(DXGI_SWAP_CHAIN_DESC* pDesc) { + if (!pDesc) + return E_INVALIDARG; + + pDesc->BufferDesc.Width = m_desc.Width; + pDesc->BufferDesc.Height = m_desc.Height; + pDesc->BufferDesc.RefreshRate = m_descFs.RefreshRate; + pDesc->BufferDesc.Format = m_desc.Format; + pDesc->BufferDesc.ScanlineOrdering = m_descFs.ScanlineOrdering; + pDesc->BufferDesc.Scaling = m_descFs.Scaling; + pDesc->SampleDesc = m_desc.SampleDesc; + pDesc->BufferUsage = m_desc.BufferUsage; + pDesc->BufferCount = m_desc.BufferCount; + pDesc->OutputWindow = m_window; + pDesc->Windowed = m_descFs.Windowed; + pDesc->SwapEffect = m_desc.SwapEffect; + pDesc->Flags = m_desc.Flags; + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetDesc1(DXGI_SWAP_CHAIN_DESC1* pDesc) { + if (pDesc == nullptr) + return E_INVALIDARG; + + *pDesc = m_desc; + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetBackgroundColor( + DXGI_RGBA* pColor) { + Logger::err("DxgiSwapChain::GetBackgroundColor: Not implemented"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetRotation( + DXGI_MODE_ROTATION* pRotation) { + Logger::err("DxgiSwapChain::GetRotation: Not implemented"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetRestrictToOutput( + IDXGIOutput** ppRestrictToOutput) { + InitReturnPtr(ppRestrictToOutput); + + Logger::err("DxgiSwapChain::GetRestrictToOutput: Not implemented"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetFrameStatistics(DXGI_FRAME_STATISTICS* pStats) { + std::lock_guard<dxvk::recursive_mutex> lock(m_lockWindow); + + if (!pStats) + return E_INVALIDARG; + + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::warn("DxgiSwapChain::GetFrameStatistics: Semi-stub"); + + // TODO deal with the refresh counts at some point + pStats->PresentCount = m_presentCount; + pStats->PresentRefreshCount = 0; + pStats->SyncRefreshCount = 0; +#ifdef _WIN32 + QueryPerformanceCounter(&pStats->SyncQPCTime); +#endif + pStats->SyncGPUTime.QuadPart = 0; + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetFullscreenState( + BOOL* pFullscreen, + IDXGIOutput** ppTarget) { + if (!wsi::isWindow(m_window)) + return DXGI_ERROR_INVALID_CALL; + + HRESULT hr = S_OK; + + if (pFullscreen != nullptr) + *pFullscreen = !m_descFs.Windowed; + + if (ppTarget != nullptr) + *ppTarget = m_target.ref(); + + return hr; + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetFullscreenDesc( + DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pDesc) { + if (pDesc == nullptr) + return E_INVALIDARG; + + *pDesc = m_descFs; + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetHwnd( + HWND* pHwnd) { + if (pHwnd == nullptr) + return E_INVALIDARG; + + *pHwnd = m_window; + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetCoreWindow( + REFIID refiid, + void** ppUnk) { + InitReturnPtr(ppUnk); + + Logger::err("DxgiSwapChain::GetCoreWindow: Not implemented"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetLastPresentCount(UINT* pLastPresentCount) { + if (pLastPresentCount == nullptr) + return E_INVALIDARG; + + *pLastPresentCount = m_presentCount; + return S_OK; + } + + + BOOL STDMETHODCALLTYPE DxgiSwapChain::IsTemporaryMonoSupported() { + // This seems to be related to stereo 3D display + // modes, which we don't support at the moment + return FALSE; + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::Present(UINT SyncInterval, UINT Flags) { + return Present1(SyncInterval, Flags, nullptr); + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::Present1( + UINT SyncInterval, + UINT PresentFlags, + const DXGI_PRESENT_PARAMETERS* pPresentParameters) { + if (!wsi::isWindow(m_window)) + return S_OK; + + if (SyncInterval > 4) + return DXGI_ERROR_INVALID_CALL; + + std::lock_guard<dxvk::recursive_mutex> lockWin(m_lockWindow); + std::lock_guard<dxvk::mutex> lockBuf(m_lockBuffer); + + try { + HRESULT hr = m_presenter->Present(SyncInterval, PresentFlags, nullptr); + if (hr == S_OK && !(PresentFlags & DXGI_PRESENT_TEST)) + m_presentCount++; + return hr; + } catch (const DxvkError& err) { + Logger::err(err.message()); + return DXGI_ERROR_DRIVER_INTERNAL_ERROR; + } + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::ResizeBuffers( + UINT BufferCount, + UINT Width, + UINT Height, + DXGI_FORMAT NewFormat, + UINT SwapChainFlags) { + if (!wsi::isWindow(m_window)) + return DXGI_ERROR_INVALID_CALL; + + constexpr UINT PreserveFlags = DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; + + if ((m_desc.Flags & PreserveFlags) != (SwapChainFlags & PreserveFlags)) + return DXGI_ERROR_INVALID_CALL; + + std::lock_guard<dxvk::mutex> lock(m_lockBuffer); + m_desc.Width = Width; + m_desc.Height = Height; + + wsi::getWindowSize(m_window, + m_desc.Width ? nullptr : &m_desc.Width, + m_desc.Height ? nullptr : &m_desc.Height); + + if (BufferCount != 0) + m_desc.BufferCount = BufferCount; + + if (NewFormat != DXGI_FORMAT_UNKNOWN) + m_desc.Format = NewFormat; + + return m_presenter->ChangeProperties(&m_desc); + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::ResizeBuffers1( + UINT BufferCount, + UINT Width, + UINT Height, + DXGI_FORMAT Format, + UINT SwapChainFlags, + const UINT* pCreationNodeMask, + IUnknown* const* ppPresentQueue) { + static bool s_errorShown = false; + + if (!std::exchange(s_errorShown, true)) + Logger::warn("DxgiSwapChain::ResizeBuffers1: Stub"); + + return ResizeBuffers(BufferCount, + Width, Height, Format, SwapChainFlags); + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::ResizeTarget(const DXGI_MODE_DESC* pNewTargetParameters) { + std::lock_guard<dxvk::recursive_mutex> lock(m_lockWindow); + + if (pNewTargetParameters == nullptr) + return DXGI_ERROR_INVALID_CALL; + + if (!wsi::isWindow(m_window)) + return DXGI_ERROR_INVALID_CALL; + + // Update the swap chain description + if (pNewTargetParameters->RefreshRate.Numerator != 0) + m_descFs.RefreshRate = pNewTargetParameters->RefreshRate; + + m_descFs.ScanlineOrdering = pNewTargetParameters->ScanlineOrdering; + m_descFs.Scaling = pNewTargetParameters->Scaling; + + if (m_descFs.Windowed) { + wsi::resizeWindow( + m_window, &m_windowState, + pNewTargetParameters->Width, + pNewTargetParameters->Height); + } else { + Com<IDXGIOutput> output; + + if (FAILED(GetOutputFromMonitor(m_monitor, &output))) { + Logger::err("DXGI: ResizeTarget: Failed to query containing output"); + return E_FAIL; + } + + // If the swap chain allows it, change the display mode + if (m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH) { + ChangeDisplayMode(output.ptr(), pNewTargetParameters, false); + NotifyModeChange(m_monitor, FALSE); + } + } + + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetFullscreenState( + BOOL Fullscreen, + IDXGIOutput* pTarget) { + std::lock_guard<dxvk::recursive_mutex> lock(m_lockWindow); + + if (!Fullscreen && pTarget) + return DXGI_ERROR_INVALID_CALL; + + if (m_descFs.Windowed && Fullscreen) + return this->EnterFullscreenMode(pTarget); + else if (!m_descFs.Windowed && !Fullscreen) + return this->LeaveFullscreenMode(); + + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetBackgroundColor( + const DXGI_RGBA* pColor) { + Logger::err("DxgiSwapChain::SetBackgroundColor: Not implemented"); + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetRotation( + DXGI_MODE_ROTATION Rotation) { + Logger::err("DxgiSwapChain::SetRotation: Not implemented"); + return E_NOTIMPL; + } + + + HANDLE STDMETHODCALLTYPE DxgiSwapChain::GetFrameLatencyWaitableObject() { + if (!(m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT)) + return nullptr; + + return m_presenter->GetFrameLatencyEvent(); + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetMatrixTransform( + DXGI_MATRIX_3X2_F* pMatrix) { + // We don't support composition swap chains + Logger::err("DxgiSwapChain::GetMatrixTransform: Not supported"); + return DXGI_ERROR_INVALID_CALL; + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetMaximumFrameLatency( + UINT* pMaxLatency) { + if (!(m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT)) + return DXGI_ERROR_INVALID_CALL; + + std::lock_guard<dxvk::recursive_mutex> lock(m_lockWindow); + *pMaxLatency = m_presenter->GetFrameLatency(); + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetSourceSize( + UINT* pWidth, + UINT* pHeight) { + // TODO implement properly once supported + if (pWidth) *pWidth = m_desc.Width; + if (pHeight) *pHeight = m_desc.Height; + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetMatrixTransform( + const DXGI_MATRIX_3X2_F* pMatrix) { + // We don't support composition swap chains + Logger::err("DxgiSwapChain::SetMatrixTransform: Not supported"); + return DXGI_ERROR_INVALID_CALL; + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetMaximumFrameLatency( + UINT MaxLatency) { + if (!(m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT)) + return DXGI_ERROR_INVALID_CALL; + + std::lock_guard<dxvk::recursive_mutex> lock(m_lockWindow); + return m_presenter->SetFrameLatency(MaxLatency); + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetSourceSize( + UINT Width, + UINT Height) { + if (Width == 0 || Width > m_desc.Width + || Height == 0 || Height > m_desc.Height) + return E_INVALIDARG; + + RECT region; + region.left = 0; + region.top = 0; + region.right = Width; + region.bottom = Height; + return m_presenter->SetPresentRegion(®ion); + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::CheckColorSpaceSupport( + DXGI_COLOR_SPACE_TYPE ColorSpace, + UINT* pColorSpaceSupport) { + if (!pColorSpaceSupport) + return E_INVALIDARG; + + UINT supportFlags = 0; + + if (ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709) + supportFlags |= DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT; + + *pColorSpaceSupport = supportFlags; + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetColorSpace1(DXGI_COLOR_SPACE_TYPE ColorSpace) { + UINT support = 0; + + HRESULT hr = CheckColorSpaceSupport(ColorSpace, &support); + + if (FAILED(hr)) + return hr; + + if (!support) + return E_INVALIDARG; + + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetHDRMetaData( + DXGI_HDR_METADATA_TYPE Type, + UINT Size, + void* pMetaData) { + if (Size && !pMetaData) + return E_INVALIDARG; + + switch (Type) { + case DXGI_HDR_METADATA_TYPE_NONE: + return S_OK; + + case DXGI_HDR_METADATA_TYPE_HDR10: + if (Size != sizeof(DXGI_HDR_METADATA_HDR10)) + return E_INVALIDARG; + + // For some reason this always seems to succeed on Windows + Logger::warn("DXGI: HDR not supported"); + return S_OK; + + default: + Logger::err(str::format("DXGI: Invalid HDR metadata type: ", Type)); + return E_INVALIDARG; + } + } + + + HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetGammaControl( + UINT NumPoints, + const DXGI_RGB* pGammaCurve) { + std::lock_guard<dxvk::mutex> lockBuf(m_lockBuffer); + return m_presenter->SetGammaControl(NumPoints, pGammaCurve); + } + + + HRESULT DxgiSwapChain::EnterFullscreenMode(IDXGIOutput* pTarget) { + Com<IDXGIOutput> output = pTarget; + + if (!wsi::isWindow(m_window)) + return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE; + + if (output == nullptr) { + if (FAILED(GetContainingOutput(&output))) { + Logger::err("DXGI: EnterFullscreenMode: Cannot query containing output"); + return E_FAIL; + } + } + + const bool modeSwitch = m_desc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; + + if (modeSwitch) { + DXGI_MODE_DESC displayMode; + displayMode.Width = m_desc.Width; + displayMode.Height = m_desc.Height; + displayMode.RefreshRate = m_descFs.RefreshRate; + displayMode.Format = m_desc.Format; + // Ignore these two, games usually use them wrong and we don't + // support any scaling modes except UNSPECIFIED anyway. + displayMode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + displayMode.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + + if (FAILED(ChangeDisplayMode(output.ptr(), &displayMode, true))) { + Logger::err("DXGI: EnterFullscreenMode: Failed to change display mode"); + return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE; + } + } + + // Update swap chain description + m_descFs.Windowed = FALSE; + + // Move the window so that it covers the entire output + DXGI_OUTPUT_DESC desc; + output->GetDesc(&desc); + + if (!wsi::enterFullscreenMode(desc.Monitor, m_window, &m_windowState, modeSwitch)) { + Logger::err("DXGI: EnterFullscreenMode: Failed to enter fullscreen mode"); + return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE; + } + + m_monitor = desc.Monitor; + m_target = std::move(output); + + // Apply current gamma curve of the output + DXGI_VK_MONITOR_DATA* monitorInfo = nullptr; + + if (SUCCEEDED(AcquireMonitorData(m_monitor, &monitorInfo))) { + if (!monitorInfo->pSwapChain) + monitorInfo->pSwapChain = this; + + SetGammaControl(DXGI_VK_GAMMA_CP_COUNT, monitorInfo->GammaCurve.GammaCurve); + ReleaseMonitorData(); + } + + NotifyModeChange(m_monitor, FALSE); + return S_OK; + } + + + HRESULT DxgiSwapChain::LeaveFullscreenMode() { + if (!wsi::restoreDisplayMode(m_monitor)) + Logger::warn("DXGI: LeaveFullscreenMode: Failed to restore display mode"); + + // Reset gamma control and decouple swap chain from monitor + DXGI_VK_MONITOR_DATA* monitorInfo = nullptr; + + if (SUCCEEDED(AcquireMonitorData(m_monitor, &monitorInfo))) { + if (monitorInfo->pSwapChain == this) + monitorInfo->pSwapChain = nullptr; + + SetGammaControl(0, nullptr); + ReleaseMonitorData(); + } + + // Restore internal state + HMONITOR monitor = m_monitor; + + m_descFs.Windowed = TRUE; + m_monitor = nullptr; + m_target = nullptr; + + if (!wsi::isWindow(m_window)) + return S_OK; + + if (!wsi::leaveFullscreenMode(m_window, &m_windowState)) { + Logger::err("DXGI: LeaveFullscreenMode: Failed to exit fullscreen mode"); + return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE; + } + + NotifyModeChange(monitor, TRUE); + return S_OK; + } + + + HRESULT DxgiSwapChain::ChangeDisplayMode( + IDXGIOutput* pOutput, + const DXGI_MODE_DESC* pDisplayMode, + BOOL EnteringFullscreen) { + if (!pOutput) + return DXGI_ERROR_INVALID_CALL; + + // Find a mode that the output supports + DXGI_OUTPUT_DESC outputDesc; + pOutput->GetDesc(&outputDesc); + + DXGI_MODE_DESC preferredMode = *pDisplayMode; + DXGI_MODE_DESC selectedMode; + + if (preferredMode.Format == DXGI_FORMAT_UNKNOWN) + preferredMode.Format = m_desc.Format; + + HRESULT hr = pOutput->FindClosestMatchingMode( + &preferredMode, &selectedMode, nullptr); + + if (FAILED(hr)) { + Logger::err(str::format( + "DXGI: Failed to query closest mode:", + "\n Format: ", preferredMode.Format, + "\n Mode: ", preferredMode.Width, "x", preferredMode.Height, + "@", preferredMode.RefreshRate.Numerator / preferredMode.RefreshRate.Denominator)); + return hr; + } + + DXGI_MODE_DESC1 selectedMode1; + selectedMode1.Width = selectedMode.Width; + selectedMode1.Height = selectedMode.Height; + selectedMode1.RefreshRate = selectedMode.RefreshRate; + selectedMode1.Format = selectedMode.Format; + selectedMode1.ScanlineOrdering = selectedMode.ScanlineOrdering; + selectedMode1.Scaling = selectedMode.Scaling; + selectedMode1.Stereo = false; + + wsi::WsiMode wsiMode = { }; + ConvertDisplayMode(selectedMode1, &wsiMode); + + return wsi::setWindowMode(outputDesc.Monitor, m_window, &wsiMode, EnteringFullscreen) + ? S_OK + : DXGI_ERROR_NOT_CURRENTLY_AVAILABLE; + } + + + HRESULT DxgiSwapChain::GetSampleCount(UINT Count, VkSampleCountFlagBits* pCount) const { + switch (Count) { + case 1: *pCount = VK_SAMPLE_COUNT_1_BIT; return S_OK; + case 2: *pCount = VK_SAMPLE_COUNT_2_BIT; return S_OK; + case 4: *pCount = VK_SAMPLE_COUNT_4_BIT; return S_OK; + case 8: *pCount = VK_SAMPLE_COUNT_8_BIT; return S_OK; + case 16: *pCount = VK_SAMPLE_COUNT_16_BIT; return S_OK; + } + + return E_INVALIDARG; + } + + + HRESULT DxgiSwapChain::GetOutputFromMonitor( + HMONITOR Monitor, + IDXGIOutput** ppOutput) { + if (!ppOutput) + return DXGI_ERROR_INVALID_CALL; + + for (uint32_t i = 0; SUCCEEDED(m_adapter->EnumOutputs(i, ppOutput)); i++) { + DXGI_OUTPUT_DESC outputDesc; + (*ppOutput)->GetDesc(&outputDesc); + + if (outputDesc.Monitor == Monitor) + return S_OK; + + (*ppOutput)->Release(); + (*ppOutput) = nullptr; + } + + return DXGI_ERROR_NOT_FOUND; + } + + + HRESULT DxgiSwapChain::AcquireMonitorData( + HMONITOR hMonitor, + DXGI_VK_MONITOR_DATA** ppData) { + return m_monitorInfo != nullptr + ? m_monitorInfo->AcquireMonitorData(hMonitor, ppData) + : E_NOINTERFACE; + } + + + void DxgiSwapChain::ReleaseMonitorData() { + if (m_monitorInfo != nullptr) + m_monitorInfo->ReleaseMonitorData(); + } + + + void DxgiSwapChain::NotifyModeChange( + HMONITOR hMonitor, + BOOL Windowed) { + wsi::WsiMode mode; + + if (wsi::getCurrentDisplayMode(hMonitor, &mode)) { + DXGI_MODE_DESC displayMode = { }; + displayMode.Width = mode.width; + displayMode.Height = mode.height; + displayMode.RefreshRate = { mode.refreshRate.numerator, mode.refreshRate.denominator }; + displayMode.Format = m_desc.Format; + displayMode.ScanlineOrdering = m_descFs.ScanlineOrdering; + displayMode.Scaling = m_descFs.Scaling; + m_presenter->NotifyModeChange(Windowed, &displayMode); + } else { + Logger::warn("Failed to query current display mode"); + m_presenter->NotifyModeChange(Windowed, nullptr); + } + } + +} |