1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-20 19:54:19 +01:00

[dxgi] Initial fullscreen support

The implementation is highly experimental and may cause issues.
Tested with DXUT-based Microsoft SDK samples and Nier:Automata.
This commit is contained in:
Philip Rebohle 2018-01-13 18:56:15 +01:00
parent 745ded47e0
commit 10269876e3
4 changed files with 129 additions and 15 deletions

View File

@ -153,6 +153,26 @@ namespace dxvk {
}
HRESULT DxgiAdapter::GetOutputFromMonitor(
HMONITOR Monitor,
IDXGIOutput** ppOutput) {
Com<IDXGIOutput> output;
for (uint32_t i = 0; SUCCEEDED(EnumOutputs(i, &output)); i++) {
DXGI_OUTPUT_DESC outputDesc;
output->GetDesc(&outputDesc);
if (outputDesc.Monitor == Monitor) {
*ppOutput = output.ref();
return S_OK;
}
}
// No such output found
return DXGI_ERROR_NOT_FOUND;
}
void DxgiAdapter::AddColorFormat(
DXGI_FORMAT srcFormat,
VkFormat dstFormat) {

View File

@ -51,6 +51,10 @@ namespace dxvk {
DxgiFormatInfo STDMETHODCALLTYPE LookupFormat(
DXGI_FORMAT format, DxgiFormatMode mode) final;
HRESULT GetOutputFromMonitor(
HMONITOR Monitor,
IDXGIOutput** ppOutput);
private:
using FormatMap = std::unordered_map<DXGI_FORMAT, DxgiFormatInfo>;

View File

@ -1,3 +1,4 @@
#include "dxgi_device.h"
#include "dxgi_factory.h"
#include "dxgi_swapchain.h"
@ -18,17 +19,18 @@ namespace dxvk {
// Retrieve the adapter, which is going
// to be used to enumerate displays.
Com<IDXGIDevice> device;
Com<IDXGIAdapter> adapter;
if (FAILED(pDevice->QueryInterface(__uuidof(IDXGIDevicePrivate),
reinterpret_cast<void**>(&m_device))))
if (FAILED(pDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&device))))
throw DxvkError("DxgiSwapChain::DxgiSwapChain: Invalid device");
if (FAILED(m_device->GetAdapter(&adapter))
|| FAILED(adapter->QueryInterface(__uuidof(IDXGIAdapterPrivate),
reinterpret_cast<void**>(&m_adapter))))
if (FAILED(device->GetAdapter(&adapter)))
throw DxvkError("DxgiSwapChain::DxgiSwapChain: Failed to retrieve adapter");
m_device = static_cast<DxgiDevice*>(device.ptr());
m_adapter = static_cast<DxgiAdapter*>(adapter.ptr());
// Initialize frame statistics
m_stats.PresentCount = 0;
m_stats.PresentRefreshCount = 0;
@ -44,8 +46,8 @@ namespace dxvk {
if (m_desc.BufferDesc.Height == 0) m_desc.BufferDesc.Height = windowSize.height;
// Set initial window mode and fullscreen state
// if (FAILED(this->SetFullscreenState(!pDesc->Windowed, nullptr)))
// throw DxvkError("DxgiSwapChain: Failed to set initial fullscreen state");
if (!pDesc->Windowed && FAILED(EnterFullscreenMode(nullptr)))
throw DxvkError("DxgiSwapChain: Failed to set initial fullscreen state");
if (FAILED(CreatePresenter()) || FAILED(CreateBackBuffer()))
throw DxvkError("DxgiSwapChain: Failed to create presenter or back buffer");
@ -91,11 +93,18 @@ namespace dxvk {
HRESULT STDMETHODCALLTYPE DxgiSwapChain::GetContainingOutput(IDXGIOutput** ppOutput) {
if (ppOutput != nullptr)
if (ppOutput == nullptr)
return DXGI_ERROR_INVALID_CALL;
Logger::err("DxgiSwapChain::GetContainingOutput: Not implemented");
return E_NOTIMPL;
RECT windowRect = { 0, 0, 0, 0 };
::GetWindowRect(m_desc.OutputWindow, &windowRect);
HMONITOR monitor = ::MonitorFromPoint(
{ (windowRect.left + windowRect.right) / 2,
(windowRect.top + windowRect.bottom) / 2 },
MONITOR_DEFAULTTOPRIMARY);
return m_adapter->GetOutputFromMonitor(monitor, ppOutput);
}
@ -232,8 +241,15 @@ namespace dxvk {
IDXGIOutput* pTarget) {
std::lock_guard<std::mutex> lock(m_mutex);
Logger::err("DxgiSwapChain::SetFullscreenState: Not implemented");
return E_NOTIMPL;
if (Fullscreen)
Logger::warn("DxgiSwapChain: Display mode changes not implemented");
if (m_desc.Windowed && Fullscreen)
return this->EnterFullscreenMode(pTarget);
else if (!m_desc.Windowed && !Fullscreen)
return this->LeaveFullscreenMode();
return S_OK;
}
@ -284,6 +300,66 @@ namespace dxvk {
}
HRESULT DxgiSwapChain::EnterFullscreenMode(IDXGIOutput *pTarget) {
Com<IDXGIOutput> output = pTarget;
if (output == nullptr) {
if (FAILED(GetContainingOutput(&output))) {
Logger::err("DxgiSwapChain: Failed to enter fullscreen mode: Cannot query containing output");
return E_FAIL;
}
}
// Change the window flags to remove the decoration etc.
LONG style = ::GetWindowLongW(m_desc.OutputWindow, GWL_STYLE);
LONG exstyle = ::GetWindowLongW(m_desc.OutputWindow, GWL_EXSTYLE);
m_windowState.style = style;
m_windowState.exstyle = exstyle;
::GetWindowRect(m_desc.OutputWindow, &m_windowState.rect);
style |= WS_POPUP | WS_SYSMENU;
style &= ~(WS_CAPTION | WS_THICKFRAME);
exstyle &= ~(WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
::SetWindowLongW(m_desc.OutputWindow, GWL_STYLE, style);
::SetWindowLongW(m_desc.OutputWindow, GWL_EXSTYLE, exstyle);
// Move the window so that it covers the entire output
DXGI_OUTPUT_DESC desc;
output->GetDesc(&desc);
const RECT rect = desc.DesktopCoordinates;
::SetWindowPos(m_desc.OutputWindow, HWND_TOPMOST,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
// Update swap chain description
m_desc.Windowed = FALSE;
return S_OK;
}
HRESULT DxgiSwapChain::LeaveFullscreenMode() {
// FIXME wine only restores window flags if the application
// has not modified them in the meantime. Some applications
// may rely on that behaviour.
const RECT rect = m_windowState.rect;
::SetWindowLongW(m_desc.OutputWindow, GWL_STYLE, m_windowState.style);
::SetWindowLongW(m_desc.OutputWindow, GWL_EXSTYLE, m_windowState.exstyle);
::SetWindowPos(m_desc.OutputWindow, 0,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE);
m_desc.Windowed = TRUE;
return S_OK;
}
HRESULT DxgiSwapChain::GetSampleCount(UINT Count, VkSampleCountFlagBits* pCount) const {
switch (Count) {
case 1: *pCount = VK_SAMPLE_COUNT_1_BIT; return S_OK;

View File

@ -16,6 +16,7 @@
namespace dxvk {
class DxgiDevice;
class DxgiFactory;
class DxgiSwapChain : public DxgiObject<IDXGISwapChain> {
@ -81,11 +82,17 @@ namespace dxvk {
private:
struct WindowState {
uint32_t style = 0;
uint32_t exstyle = 0;
RECT rect = { 0, 0, 0, 0 };
};
std::mutex m_mutex;
Com<DxgiFactory> m_factory;
Com<IDXGIAdapterPrivate> m_adapter;
Com<IDXGIDevicePrivate> m_device;
Com<DxgiAdapter> m_adapter;
Com<DxgiDevice> m_device;
Com<IDXGIPresentDevicePrivate> m_presentDevice;
DXGI_SWAP_CHAIN_DESC m_desc;
@ -94,15 +101,22 @@ namespace dxvk {
Rc<DxgiPresenter> m_presenter;
Com<IDXGIPresentBackBuffer> m_backBuffer;
WindowState m_windowState;
HRESULT CreatePresenter();
HRESULT CreateBackBuffer();
VkExtent2D GetWindowSize() const;
HRESULT EnterFullscreenMode(
IDXGIOutput *pTarget);
HRESULT LeaveFullscreenMode();
HRESULT GetSampleCount(
UINT Count,
VkSampleCountFlagBits* pCount) const;
};
}