mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-02-20 19:54:19 +01:00
[dxvk] Rework present mode selection for swap chains
This commit is contained in:
parent
1728d9e89d
commit
e6be0cf996
@ -72,7 +72,7 @@ namespace dxvk {
|
||||
CreateHud();
|
||||
|
||||
if (!pDevice->GetOptions()->deferSurfaceCreation)
|
||||
RecreateSwapChain(false);
|
||||
RecreateSwapChain();
|
||||
}
|
||||
|
||||
|
||||
@ -260,17 +260,13 @@ namespace dxvk {
|
||||
if (options->syncInterval >= 0)
|
||||
SyncInterval = options->syncInterval;
|
||||
|
||||
if (!(PresentFlags & DXGI_PRESENT_TEST)) {
|
||||
bool vsync = SyncInterval != 0;
|
||||
|
||||
m_dirty |= vsync != m_vsync;
|
||||
m_vsync = vsync;
|
||||
}
|
||||
if (!(PresentFlags & DXGI_PRESENT_TEST))
|
||||
m_dirty |= m_presenter->setSyncInterval(SyncInterval) != VK_SUCCESS;
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if (!m_presenter->hasSwapChain()) {
|
||||
RecreateSwapChain(m_vsync);
|
||||
RecreateSwapChain();
|
||||
m_dirty = false;
|
||||
}
|
||||
|
||||
@ -284,7 +280,7 @@ namespace dxvk {
|
||||
return hr;
|
||||
|
||||
if (std::exchange(m_dirty, false))
|
||||
RecreateSwapChain(m_vsync);
|
||||
RecreateSwapChain();
|
||||
|
||||
try {
|
||||
PresentImage(SyncInterval);
|
||||
@ -358,7 +354,7 @@ namespace dxvk {
|
||||
VkResult status = m_presenter->acquireNextImage(sync, imageIndex);
|
||||
|
||||
while (status != VK_SUCCESS && status != VK_SUBOPTIMAL_KHR) {
|
||||
RecreateSwapChain(m_vsync);
|
||||
RecreateSwapChain();
|
||||
|
||||
if (!m_presenter->hasSwapChain())
|
||||
return DXGI_STATUS_OCCLUDED;
|
||||
@ -409,6 +405,7 @@ namespace dxvk {
|
||||
cFrameId = FrameId,
|
||||
cSync = Sync,
|
||||
cHud = m_hud,
|
||||
cPresentMode = m_presenter->info().presentMode,
|
||||
cCommandList = m_context->endRecording()
|
||||
] (DxvkContext* ctx) {
|
||||
cCommandList->setWsiSemaphores(cSync);
|
||||
@ -417,7 +414,7 @@ namespace dxvk {
|
||||
if (cHud != nullptr && !cFrameId)
|
||||
cHud->update();
|
||||
|
||||
m_device->presentImage(m_presenter, &m_presentStatus);
|
||||
m_device->presentImage(m_presenter, cPresentMode, &m_presentStatus);
|
||||
});
|
||||
|
||||
pContext->FlushCsChunk();
|
||||
@ -429,11 +426,11 @@ namespace dxvk {
|
||||
VkResult status = m_device->waitForSubmission(&m_presentStatus);
|
||||
|
||||
if (status != VK_SUCCESS)
|
||||
RecreateSwapChain(m_vsync);
|
||||
RecreateSwapChain();
|
||||
}
|
||||
|
||||
|
||||
void D3D11SwapChain::RecreateSwapChain(BOOL Vsync) {
|
||||
void D3D11SwapChain::RecreateSwapChain() {
|
||||
// Ensure that we can safely destroy the swap chain
|
||||
m_device->waitForSubmission(&m_presentStatus);
|
||||
m_device->waitForIdle();
|
||||
@ -445,7 +442,6 @@ namespace dxvk {
|
||||
presenterDesc.imageExtent = { m_desc.Width, m_desc.Height };
|
||||
presenterDesc.imageCount = PickImageCount(m_desc.BufferCount + 1);
|
||||
presenterDesc.numFormats = PickFormats(m_desc.Format, presenterDesc.formats);
|
||||
presenterDesc.numPresentModes = PickPresentModes(Vsync, presenterDesc.presentModes);
|
||||
presenterDesc.fullScreenExclusive = PickFullscreenMode();
|
||||
|
||||
VkResult vr = m_presenter->recreateSwapChain(presenterDesc);
|
||||
@ -481,7 +477,6 @@ namespace dxvk {
|
||||
presenterDesc.imageExtent = { m_desc.Width, m_desc.Height };
|
||||
presenterDesc.imageCount = PickImageCount(m_desc.BufferCount + 1);
|
||||
presenterDesc.numFormats = PickFormats(m_desc.Format, presenterDesc.formats);
|
||||
presenterDesc.numPresentModes = PickPresentModes(false, presenterDesc.presentModes);
|
||||
presenterDesc.fullScreenExclusive = PickFullscreenMode();
|
||||
|
||||
m_presenter = new Presenter(m_device, presenterDesc);
|
||||
@ -702,25 +697,6 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
uint32_t D3D11SwapChain::PickPresentModes(
|
||||
BOOL Vsync,
|
||||
VkPresentModeKHR* pDstModes) {
|
||||
uint32_t n = 0;
|
||||
|
||||
if (Vsync) {
|
||||
if (m_parent->GetOptions()->tearFree == Tristate::False)
|
||||
pDstModes[n++] = VK_PRESENT_MODE_FIFO_RELAXED_KHR;
|
||||
pDstModes[n++] = VK_PRESENT_MODE_FIFO_KHR;
|
||||
} else {
|
||||
if (m_parent->GetOptions()->tearFree != Tristate::True)
|
||||
pDstModes[n++] = VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||
pDstModes[n++] = VK_PRESENT_MODE_MAILBOX_KHR;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
uint32_t D3D11SwapChain::PickImageCount(
|
||||
UINT Preferred) {
|
||||
int32_t option = m_parent->GetOptions()->numBackBuffers;
|
||||
|
@ -119,7 +119,6 @@ namespace dxvk {
|
||||
HANDLE m_processHandle = nullptr;
|
||||
|
||||
bool m_dirty = true;
|
||||
bool m_vsync = true;
|
||||
|
||||
VkColorSpaceKHR m_colorspace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
|
||||
|
||||
@ -135,8 +134,7 @@ namespace dxvk {
|
||||
|
||||
void SynchronizePresent();
|
||||
|
||||
void RecreateSwapChain(
|
||||
BOOL Vsync);
|
||||
void RecreateSwapChain();
|
||||
|
||||
void CreateFrameLatencyEvent();
|
||||
|
||||
@ -162,10 +160,6 @@ namespace dxvk {
|
||||
DXGI_FORMAT Format,
|
||||
VkSurfaceFormatKHR* pDstFormats);
|
||||
|
||||
uint32_t PickPresentModes(
|
||||
BOOL Vsync,
|
||||
VkPresentModeKHR* pDstModes);
|
||||
|
||||
uint32_t PickImageCount(
|
||||
UINT Preferred);
|
||||
|
||||
|
@ -41,7 +41,7 @@ namespace dxvk {
|
||||
CreatePresenter();
|
||||
|
||||
if (!pDevice->GetOptions()->deferSurfaceCreation)
|
||||
RecreateSwapChain(false);
|
||||
RecreateSwapChain();
|
||||
}
|
||||
|
||||
if (FAILED(CreateBackBuffers(m_presentParams.BackBufferCount)))
|
||||
@ -135,8 +135,6 @@ namespace dxvk {
|
||||
if (options->presentInterval >= 0)
|
||||
presentInterval = options->presentInterval;
|
||||
|
||||
bool vsync = presentInterval != 0;
|
||||
|
||||
HWND window = m_presentParams.hDeviceWindow;
|
||||
if (hDestWindowOverride != nullptr)
|
||||
window = hDestWindowOverride;
|
||||
@ -148,13 +146,13 @@ namespace dxvk {
|
||||
|
||||
m_window = window;
|
||||
|
||||
m_dirty |= vsync != m_vsync;
|
||||
if (m_presenter != nullptr) {
|
||||
m_dirty |= m_presenter->setSyncInterval(presentInterval) != VK_SUCCESS;
|
||||
m_dirty |= !m_presenter->hasSwapChain();
|
||||
}
|
||||
|
||||
m_dirty |= UpdatePresentRegion(pSourceRect, pDestRect);
|
||||
m_dirty |= recreate;
|
||||
m_dirty |= m_presenter != nullptr &&
|
||||
!m_presenter->hasSwapChain();
|
||||
|
||||
m_vsync = vsync;
|
||||
|
||||
m_lastDialog = m_dialog;
|
||||
|
||||
@ -169,7 +167,7 @@ namespace dxvk {
|
||||
CreatePresenter();
|
||||
|
||||
if (std::exchange(m_dirty, false))
|
||||
RecreateSwapChain(vsync);
|
||||
RecreateSwapChain();
|
||||
|
||||
// We aren't going to device loss simply because
|
||||
// 99% of D3D9 games don't handle this properly and
|
||||
@ -762,7 +760,7 @@ namespace dxvk {
|
||||
VkResult status = m_presenter->acquireNextImage(sync, imageIndex);
|
||||
|
||||
while (status != VK_SUCCESS && status != VK_SUBOPTIMAL_KHR) {
|
||||
RecreateSwapChain(m_vsync);
|
||||
RecreateSwapChain();
|
||||
|
||||
info = m_presenter->info();
|
||||
status = m_presenter->acquireNextImage(sync, imageIndex);
|
||||
@ -817,6 +815,7 @@ namespace dxvk {
|
||||
cFrameId = FrameId,
|
||||
cSync = Sync,
|
||||
cHud = m_hud,
|
||||
cPresentMode = m_presenter->info().presentMode,
|
||||
cCommandList = m_context->endRecording()
|
||||
] (DxvkContext* ctx) {
|
||||
cCommandList->setWsiSemaphores(cSync);
|
||||
@ -825,7 +824,7 @@ namespace dxvk {
|
||||
if (cHud != nullptr && !cFrameId)
|
||||
cHud->update();
|
||||
|
||||
m_device->presentImage(m_presenter, &m_presentStatus);
|
||||
m_device->presentImage(m_presenter, cPresentMode, &m_presentStatus);
|
||||
});
|
||||
|
||||
m_parent->FlushCsChunk();
|
||||
@ -837,10 +836,10 @@ namespace dxvk {
|
||||
VkResult status = m_device->waitForSubmission(&m_presentStatus);
|
||||
|
||||
if (status != VK_SUCCESS)
|
||||
RecreateSwapChain(m_vsync);
|
||||
RecreateSwapChain();
|
||||
}
|
||||
|
||||
void D3D9SwapChainEx::RecreateSwapChain(BOOL Vsync) {
|
||||
void D3D9SwapChainEx::RecreateSwapChain() {
|
||||
// Ensure that we can safely destroy the swap chain
|
||||
m_device->waitForSubmission(&m_presentStatus);
|
||||
m_device->waitForIdle();
|
||||
@ -851,7 +850,6 @@ namespace dxvk {
|
||||
presenterDesc.imageExtent = GetPresentExtent();
|
||||
presenterDesc.imageCount = PickImageCount(m_presentParams.BackBufferCount + 1);
|
||||
presenterDesc.numFormats = PickFormats(EnumerateFormat(m_presentParams.BackBufferFormat), presenterDesc.formats);
|
||||
presenterDesc.numPresentModes = PickPresentModes(Vsync, presenterDesc.presentModes);
|
||||
presenterDesc.fullScreenExclusive = PickFullscreenMode();
|
||||
|
||||
VkResult vr = m_presenter->recreateSwapChain(presenterDesc);
|
||||
@ -885,7 +883,6 @@ namespace dxvk {
|
||||
presenterDesc.imageExtent = GetPresentExtent();
|
||||
presenterDesc.imageCount = PickImageCount(m_presentParams.BackBufferCount + 1);
|
||||
presenterDesc.numFormats = PickFormats(EnumerateFormat(m_presentParams.BackBufferFormat), presenterDesc.formats);
|
||||
presenterDesc.numPresentModes = PickPresentModes(false, presenterDesc.presentModes);
|
||||
presenterDesc.fullScreenExclusive = PickFullscreenMode();
|
||||
|
||||
m_presenter = new Presenter(m_device, presenterDesc);
|
||||
@ -1121,25 +1118,6 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
uint32_t D3D9SwapChainEx::PickPresentModes(
|
||||
BOOL Vsync,
|
||||
VkPresentModeKHR* pDstModes) {
|
||||
uint32_t n = 0;
|
||||
|
||||
if (Vsync) {
|
||||
if (m_parent->GetOptions()->tearFree == Tristate::False)
|
||||
pDstModes[n++] = VK_PRESENT_MODE_FIFO_RELAXED_KHR;
|
||||
pDstModes[n++] = VK_PRESENT_MODE_FIFO_KHR;
|
||||
} else {
|
||||
if (m_parent->GetOptions()->tearFree != Tristate::True)
|
||||
pDstModes[n++] = VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||
pDstModes[n++] = VK_PRESENT_MODE_MAILBOX_KHR;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
uint32_t D3D9SwapChainEx::PickImageCount(
|
||||
UINT Preferred) {
|
||||
int32_t option = m_parent->GetOptions()->numBackBuffers;
|
||||
|
@ -155,9 +155,7 @@ namespace dxvk {
|
||||
Rc<sync::Fence> m_frameLatencySignal;
|
||||
|
||||
bool m_dirty = true;
|
||||
bool m_vsync = true;
|
||||
|
||||
bool m_dialog;
|
||||
bool m_dialog = false;
|
||||
bool m_lastDialog = false;
|
||||
|
||||
HWND m_window = nullptr;
|
||||
@ -183,8 +181,7 @@ namespace dxvk {
|
||||
|
||||
void SynchronizePresent();
|
||||
|
||||
void RecreateSwapChain(
|
||||
BOOL Vsync);
|
||||
void RecreateSwapChain();
|
||||
|
||||
void CreatePresenter();
|
||||
|
||||
@ -209,10 +206,6 @@ namespace dxvk {
|
||||
D3D9Format Format,
|
||||
VkSurfaceFormatKHR* pDstFormats);
|
||||
|
||||
uint32_t PickPresentModes(
|
||||
BOOL Vsync,
|
||||
VkPresentModeKHR* pDstModes);
|
||||
|
||||
uint32_t PickImageCount(
|
||||
UINT Preferred);
|
||||
|
||||
|
@ -253,11 +253,13 @@ namespace dxvk {
|
||||
|
||||
void DxvkDevice::presentImage(
|
||||
const Rc<Presenter>& presenter,
|
||||
VkPresentModeKHR presentMode,
|
||||
DxvkSubmitStatus* status) {
|
||||
status->result = VK_NOT_READY;
|
||||
|
||||
DxvkPresentInfo presentInfo;
|
||||
DxvkPresentInfo presentInfo = { };
|
||||
presentInfo.presenter = presenter;
|
||||
presentInfo.presentMode = presentMode;
|
||||
m_submissionQueue.present(presentInfo, status);
|
||||
|
||||
std::lock_guard<sync::Spinlock> statLock(m_statLock);
|
||||
|
@ -454,10 +454,12 @@ namespace dxvk {
|
||||
* the submission thread. The status of this operation
|
||||
* can be retrieved with \ref waitForSubmission.
|
||||
* \param [in] presenter The presenter
|
||||
* \param [in] presenteMode Present mode
|
||||
* \param [out] status Present status
|
||||
*/
|
||||
void presentImage(
|
||||
const Rc<Presenter>& presenter,
|
||||
VkPresentModeKHR presentMode,
|
||||
DxvkSubmitStatus* status);
|
||||
|
||||
/**
|
||||
|
@ -49,7 +49,7 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
VkResult Presenter::presentImage() {
|
||||
VkResult Presenter::presentImage(VkPresentModeKHR mode) {
|
||||
PresenterSync sync = m_semaphores.at(m_frameIndex);
|
||||
|
||||
VkPresentInfoKHR info = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
|
||||
@ -76,8 +76,8 @@ namespace dxvk {
|
||||
m_swapchain, std::numeric_limits<uint64_t>::max(),
|
||||
sync.acquire, VK_NULL_HANDLE, &m_imageIndex);
|
||||
|
||||
bool vsync = m_info.presentMode == VK_PRESENT_MODE_FIFO_KHR
|
||||
|| m_info.presentMode == VK_PRESENT_MODE_FIFO_RELAXED_KHR;
|
||||
bool vsync = mode == VK_PRESENT_MODE_FIFO_KHR
|
||||
|| mode == VK_PRESENT_MODE_FIFO_RELAXED_KHR;
|
||||
|
||||
m_fpsLimiter.delay(vsync);
|
||||
return status;
|
||||
@ -124,7 +124,7 @@ namespace dxvk {
|
||||
|
||||
// Select actual swap chain properties and create swap chain
|
||||
m_info.format = pickFormat(formats.size(), formats.data(), desc.numFormats, desc.formats);
|
||||
m_info.presentMode = pickPresentMode(modes.size(), modes.data(), desc.numPresentModes, desc.presentModes);
|
||||
m_info.presentMode = pickPresentMode(modes.size(), modes.data(), m_info.syncInterval);
|
||||
m_info.imageExtent = pickImageExtent(caps, desc.imageExtent);
|
||||
m_info.imageCount = pickImageCount(caps, m_info.presentMode, desc.imageCount);
|
||||
|
||||
@ -234,6 +234,15 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
VkResult Presenter::setSyncInterval(uint32_t syncInterval) {
|
||||
if (syncInterval == m_info.syncInterval)
|
||||
return VK_SUCCESS;
|
||||
|
||||
m_info.syncInterval = syncInterval;
|
||||
return VK_ERROR_OUT_OF_DATE_KHR;
|
||||
}
|
||||
|
||||
|
||||
void Presenter::setFrameRateLimit(double frameRate) {
|
||||
m_fpsLimiter.setTargetFrameRate(frameRate);
|
||||
}
|
||||
@ -381,12 +390,19 @@ namespace dxvk {
|
||||
VkPresentModeKHR Presenter::pickPresentMode(
|
||||
uint32_t numSupported,
|
||||
const VkPresentModeKHR* pSupported,
|
||||
uint32_t numDesired,
|
||||
const VkPresentModeKHR* pDesired) {
|
||||
uint32_t syncInterval) {
|
||||
std::array<VkPresentModeKHR, 2> desired = { };
|
||||
uint32_t numDesired = 0;
|
||||
|
||||
if (!syncInterval) {
|
||||
desired[numDesired++] = VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||
desired[numDesired++] = VK_PRESENT_MODE_MAILBOX_KHR;
|
||||
}
|
||||
|
||||
// Just pick the first desired and supported mode
|
||||
for (uint32_t i = 0; i < numDesired; i++) {
|
||||
for (uint32_t j = 0; j < numSupported; j++) {
|
||||
if (pSupported[j] == pDesired[i])
|
||||
if (pSupported[j] == desired[i])
|
||||
return pSupported[j];
|
||||
}
|
||||
}
|
||||
|
@ -30,8 +30,6 @@ namespace dxvk {
|
||||
uint32_t imageCount;
|
||||
uint32_t numFormats;
|
||||
VkSurfaceFormatKHR formats[4];
|
||||
uint32_t numPresentModes;
|
||||
VkPresentModeKHR presentModes[4];
|
||||
VkFullScreenExclusiveEXT fullScreenExclusive;
|
||||
};
|
||||
|
||||
@ -46,6 +44,7 @@ namespace dxvk {
|
||||
VkPresentModeKHR presentMode;
|
||||
VkExtent2D imageExtent;
|
||||
uint32_t imageCount;
|
||||
uint32_t syncInterval;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -123,9 +122,11 @@ namespace dxvk {
|
||||
* Presents the current image. If this returns
|
||||
* an error, the swap chain must be recreated,
|
||||
* but do not present before acquiring an image.
|
||||
* \param [in] mode Present mode
|
||||
* \returns Status of the operation
|
||||
*/
|
||||
VkResult presentImage();
|
||||
VkResult presentImage(
|
||||
VkPresentModeKHR mode);
|
||||
|
||||
/**
|
||||
* \brief Changes and takes ownership of surface
|
||||
@ -148,6 +149,15 @@ namespace dxvk {
|
||||
VkResult recreateSwapChain(
|
||||
const PresenterDesc& desc);
|
||||
|
||||
/**
|
||||
* \brief Changes sync interval
|
||||
*
|
||||
* If this returns an error, the swap chain must
|
||||
* be recreated.
|
||||
* \param [in] syncInterval New sync interval
|
||||
*/
|
||||
VkResult setSyncInterval(uint32_t syncInterval);
|
||||
|
||||
/**
|
||||
* \brief Changes maximum frame rate
|
||||
*
|
||||
@ -190,7 +200,7 @@ namespace dxvk {
|
||||
Rc<vk::InstanceFn> m_vki;
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
|
||||
PresenterInfo m_info;
|
||||
PresenterInfo m_info = { };
|
||||
|
||||
VkSurfaceKHR m_surface = VK_NULL_HANDLE;
|
||||
VkSwapchainKHR m_swapchain = VK_NULL_HANDLE;
|
||||
@ -228,8 +238,7 @@ namespace dxvk {
|
||||
VkPresentModeKHR pickPresentMode(
|
||||
uint32_t numSupported,
|
||||
const VkPresentModeKHR* pSupported,
|
||||
uint32_t numDesired,
|
||||
const VkPresentModeKHR* pDesired);
|
||||
uint32_t syncInterval);
|
||||
|
||||
VkExtent2D pickImageExtent(
|
||||
const VkSurfaceCapabilitiesKHR& caps,
|
||||
|
@ -118,7 +118,7 @@ namespace dxvk {
|
||||
if (entry.submit.cmdList != nullptr)
|
||||
status = entry.submit.cmdList->submit();
|
||||
else if (entry.present.presenter != nullptr)
|
||||
status = entry.present.presenter->presentImage();
|
||||
status = entry.present.presenter->presentImage(entry.present.presentMode);
|
||||
|
||||
if (m_callback)
|
||||
m_callback(false);
|
||||
|
@ -43,6 +43,7 @@ namespace dxvk {
|
||||
*/
|
||||
struct DxvkPresentInfo {
|
||||
Rc<Presenter> presenter;
|
||||
VkPresentModeKHR presentMode;
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user