mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-03-14 22:50:45 +00:00
Merge remote-tracking branch 'SRSaunders/swapchain-fixes'
This commit is contained in:
commit
330486ecdf
4 changed files with 117 additions and 62 deletions
|
@ -54,7 +54,7 @@ struct DeviceCreationParameters
|
|||
uint32_t backBufferHeight = 720;
|
||||
uint32_t backBufferSampleCount = 1; // optional HDR Framebuffer MSAA
|
||||
uint32_t refreshRate = 0;
|
||||
uint32_t swapChainBufferCount = 3; // SRS - hardcode to 3 for Vsync modes and linux surfaceCaps.minImageCount = 3
|
||||
uint32_t swapChainBufferCount = NUM_FRAME_DATA; // SRS - default matches GPU frames, can be overridden by renderer
|
||||
nvrhi::Format swapChainFormat = nvrhi::Format::RGBA8_UNORM; // RB: don't do the sRGB gamma ramp with the swapchain
|
||||
uint32_t swapChainSampleCount = 1;
|
||||
uint32_t swapChainSampleQuality = 0;
|
||||
|
|
|
@ -54,6 +54,8 @@
|
|||
idCVar r_vmaDeviceLocalMemoryMB( "r_vmaDeviceLocalMemoryMB", "256", CVAR_INTEGER | CVAR_INIT, "Size of VMA allocation block for gpu memory." );
|
||||
#endif
|
||||
|
||||
idCVar r_preferFastSync( "r_preferFastSync", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "Prefer Fast Sync/no-tearing in place of VSync off/tearing (Vulkan only)" );
|
||||
|
||||
// Define the Vulkan dynamic dispatcher - this needs to occur in exactly one cpp file in the program.
|
||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||
|
||||
|
@ -280,8 +282,10 @@ private:
|
|||
|
||||
nvrhi::EventQueryHandle m_FrameWaitQuery;
|
||||
|
||||
// SRS - flag indicating support for eFifoRelaxed surface presentation (r_swapInterval = 1) mode
|
||||
bool enablePModeFifoRelaxed = false;
|
||||
// SRS - flags indicating support for various Vulkan surface presentation modes
|
||||
bool enablePModeMailbox = false; // r_swapInterval = 0 (defaults to eImmediate if not available)
|
||||
bool enablePModeImmediate = false; // r_swapInterval = 0 (defaults to eFifo if not available)
|
||||
bool enablePModeFifoRelaxed = false; // r_swapInterval = 1 (defaults to eFifo if not available)
|
||||
|
||||
|
||||
private:
|
||||
|
@ -559,14 +563,12 @@ bool DeviceManager_VK::pickPhysicalDevice()
|
|||
auto surfaceFmts = dev.getSurfaceFormatsKHR( m_WindowSurface );
|
||||
auto surfacePModes = dev.getSurfacePresentModesKHR( m_WindowSurface );
|
||||
|
||||
if( surfaceCaps.minImageCount > m_DeviceParams.swapChainBufferCount ||
|
||||
( surfaceCaps.maxImageCount < m_DeviceParams.swapChainBufferCount && surfaceCaps.maxImageCount > 0 ) )
|
||||
{
|
||||
errorStream << std::endl << " - cannot support the requested swap chain image count:";
|
||||
errorStream << " requested " << m_DeviceParams.swapChainBufferCount << ", available " << surfaceCaps.minImageCount << " - " << surfaceCaps.maxImageCount;
|
||||
deviceIsGood = false;
|
||||
}
|
||||
// SRS/Ricardo Garcia rg3 - clamp swapChainBufferCount to the min/max capabilities of the surface
|
||||
m_DeviceParams.swapChainBufferCount = Max( surfaceCaps.minImageCount, m_DeviceParams.swapChainBufferCount );
|
||||
m_DeviceParams.swapChainBufferCount = surfaceCaps.maxImageCount > 0 ? Min( m_DeviceParams.swapChainBufferCount, surfaceCaps.maxImageCount ) : m_DeviceParams.swapChainBufferCount;
|
||||
|
||||
/* SRS - Don't check extent here since window manager surfaceCaps may restrict extent to something smaller than requested
|
||||
- Instead, check and clamp extent to window manager surfaceCaps during swap chain creation inside createSwapChain()
|
||||
if( surfaceCaps.minImageExtent.width > requestedExtent.width ||
|
||||
surfaceCaps.minImageExtent.height > requestedExtent.height ||
|
||||
surfaceCaps.maxImageExtent.width < requestedExtent.width ||
|
||||
|
@ -578,6 +580,7 @@ bool DeviceManager_VK::pickPhysicalDevice()
|
|||
errorStream << " - " << surfaceCaps.maxImageExtent.width << "x" << surfaceCaps.maxImageExtent.height;
|
||||
deviceIsGood = false;
|
||||
}
|
||||
*/
|
||||
|
||||
bool surfaceFormatPresent = false;
|
||||
for( const vk::SurfaceFormatKHR& surfaceFmt : surfaceFmts )
|
||||
|
@ -596,11 +599,10 @@ bool DeviceManager_VK::pickPhysicalDevice()
|
|||
deviceIsGood = false;
|
||||
}
|
||||
|
||||
if( ( find( surfacePModes.begin(), surfacePModes.end(), vk::PresentModeKHR::eImmediate ) == surfacePModes.end() ) ||
|
||||
( find( surfacePModes.begin(), surfacePModes.end(), vk::PresentModeKHR::eFifo ) == surfacePModes.end() ) )
|
||||
if( find( surfacePModes.begin(), surfacePModes.end(), vk::PresentModeKHR::eFifo ) == surfacePModes.end() )
|
||||
{
|
||||
// can't find the required surface present modes
|
||||
errorStream << std::endl << " - does not support the requested surface present modes";
|
||||
// this should never happen since eFifo is mandatory according to the Vulkan spec
|
||||
errorStream << std::endl << " - does not support the required surface present modes";
|
||||
deviceIsGood = false;
|
||||
}
|
||||
|
||||
|
@ -908,8 +910,10 @@ bool DeviceManager_VK::createDevice()
|
|||
&imageFormatProperties );
|
||||
m_DeviceParams.enableImageFormatD24S8 = ( ret == vk::Result::eSuccess );
|
||||
|
||||
// SRS - Determine if "smart" (r_swapInterval = 1) vsync mode eFifoRelaxed is supported by device and surface
|
||||
// SRS/rg3 - Determine which Vulkan surface present modes are supported by device and surface
|
||||
auto surfacePModes = m_VulkanPhysicalDevice.getSurfacePresentModesKHR( m_WindowSurface );
|
||||
enablePModeMailbox = find( surfacePModes.begin(), surfacePModes.end(), vk::PresentModeKHR::eMailbox ) != surfacePModes.end();
|
||||
enablePModeImmediate = find( surfacePModes.begin(), surfacePModes.end(), vk::PresentModeKHR::eImmediate ) != surfacePModes.end();
|
||||
enablePModeFifoRelaxed = find( surfacePModes.begin(), surfacePModes.end(), vk::PresentModeKHR::eFifoRelaxed ) != surfacePModes.end();
|
||||
|
||||
// stash the renderer string
|
||||
|
@ -998,6 +1002,11 @@ bool DeviceManager_VK::createSwapChain()
|
|||
vk::ColorSpaceKHR::eSrgbNonlinear
|
||||
};
|
||||
|
||||
// SRS - Clamp swap chain extent within the range supported by the device / window surface
|
||||
auto surfaceCaps = m_VulkanPhysicalDevice.getSurfaceCapabilitiesKHR( m_WindowSurface );
|
||||
m_DeviceParams.backBufferWidth = idMath::ClampInt( surfaceCaps.minImageExtent.width, surfaceCaps.maxImageExtent.width, m_DeviceParams.backBufferWidth );
|
||||
m_DeviceParams.backBufferHeight = idMath::ClampInt( surfaceCaps.minImageExtent.height, surfaceCaps.maxImageExtent.height, m_DeviceParams.backBufferHeight );
|
||||
|
||||
vk::Extent2D extent = vk::Extent2D( m_DeviceParams.backBufferWidth, m_DeviceParams.backBufferHeight );
|
||||
|
||||
std::unordered_set<uint32_t> uniqueQueues =
|
||||
|
@ -1010,6 +1019,22 @@ bool DeviceManager_VK::createSwapChain()
|
|||
|
||||
const bool enableSwapChainSharing = queues.size() > 1;
|
||||
|
||||
// SRS/rg3 - set up Vulkan present mode based on vsync setting and available surface features
|
||||
vk::PresentModeKHR presentMode;
|
||||
switch( m_DeviceParams.vsyncEnabled )
|
||||
{
|
||||
case 0:
|
||||
presentMode = enablePModeMailbox && r_preferFastSync.GetBool() ? vk::PresentModeKHR::eMailbox :
|
||||
( enablePModeImmediate ? vk::PresentModeKHR::eImmediate : vk::PresentModeKHR::eFifo );
|
||||
break;
|
||||
case 1:
|
||||
presentMode = enablePModeFifoRelaxed ? vk::PresentModeKHR::eFifoRelaxed : vk::PresentModeKHR::eFifo;
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
presentMode = vk::PresentModeKHR::eFifo; // eFifo always supported according to Vulkan spec
|
||||
}
|
||||
|
||||
auto desc = vk::SwapchainCreateInfoKHR()
|
||||
.setSurface( m_WindowSurface )
|
||||
.setMinImageCount( m_DeviceParams.swapChainBufferCount )
|
||||
|
@ -1023,7 +1048,7 @@ bool DeviceManager_VK::createSwapChain()
|
|||
.setPQueueFamilyIndices( enableSwapChainSharing ? queues.data() : nullptr )
|
||||
.setPreTransform( vk::SurfaceTransformFlagBitsKHR::eIdentity )
|
||||
.setCompositeAlpha( vk::CompositeAlphaFlagBitsKHR::eOpaque )
|
||||
.setPresentMode( m_DeviceParams.vsyncEnabled > 0 ? ( m_DeviceParams.vsyncEnabled == 2 || !enablePModeFifoRelaxed ? vk::PresentModeKHR::eFifo : vk::PresentModeKHR::eFifoRelaxed ) : vk::PresentModeKHR::eImmediate )
|
||||
.setPresentMode( presentMode )
|
||||
.setClipped( true )
|
||||
.setOldSwapchain( nullptr );
|
||||
|
||||
|
|
|
@ -135,6 +135,10 @@ void DeviceManager::UpdateWindowSize( const glimpParms_t& parms )
|
|||
m_DeviceParams.vsyncEnabled = m_RequestedVSync;
|
||||
|
||||
ResizeSwapChain();
|
||||
|
||||
// SRS - Get actual swapchain dimensions to set new render size
|
||||
deviceManager->GetWindowDimensions( glConfig.nativeScreenWidth, glConfig.nativeScreenHeight );
|
||||
|
||||
BackBufferResized();
|
||||
}
|
||||
else
|
||||
|
@ -195,7 +199,8 @@ static int GetDisplayIndex( glimpParms_t parms )
|
|||
{
|
||||
SDL_Rect rect;
|
||||
SDL_GetDisplayBounds( i, &rect );
|
||||
if( windowPosX >= rect.x && windowPosX < ( rect.x + rect.w ) && windowPosY >= rect.y && windowPosY < ( rect.y + rect.h ) )
|
||||
if( ( windowPosX >= rect.x && windowPosX < ( rect.x + rect.w ) && windowPosY >= rect.y && windowPosY < ( rect.y + rect.h ) ) ||
|
||||
( parms.x == SDL_WINDOWPOS_CENTERED_DISPLAY( i ) && parms.y == SDL_WINDOWPOS_CENTERED_DISPLAY( i ) ) )
|
||||
{
|
||||
displayIdx = i;
|
||||
break;
|
||||
|
@ -206,11 +211,18 @@ static int GetDisplayIndex( glimpParms_t parms )
|
|||
return displayIdx;
|
||||
}
|
||||
|
||||
// SRS - Function to get display frequency of monitor hosting the current window
|
||||
// SRS - Function to get display frequency of monitor corresponding to the window position
|
||||
static int GetDisplayFrequency( glimpParms_t parms )
|
||||
{
|
||||
int displayIndex = GetDisplayIndex( parms );
|
||||
if( displayIndex < 0 )
|
||||
{
|
||||
// SRS - window is out of bounds for desktop, fall back to primary display
|
||||
displayIndex = 0;
|
||||
}
|
||||
|
||||
SDL_DisplayMode m = {0};
|
||||
if( SDL_GetWindowDisplayMode( window, &m ) < 0 )
|
||||
if( SDL_GetCurrentDisplayMode( displayIndex, &m ) )
|
||||
{
|
||||
common->Warning( "Couldn't get display refresh rate, reason: %s", SDL_GetError() );
|
||||
return parms.displayHz;
|
||||
|
@ -255,8 +267,9 @@ bool VKimp_Init( glimpParms_t parms )
|
|||
}
|
||||
else if( GetDisplayIndex( parms ) < 0 ) // verify window position for -1 and -2 borderless modes
|
||||
{
|
||||
// SRS - window is out of bounds for desktop, startup on default display instead
|
||||
createParms.x = createParms.y = SDL_WINDOWPOS_UNDEFINED;
|
||||
// SRS - window is out of bounds for desktop, startup on primary display instead
|
||||
createParms.x = createParms.y = SDL_WINDOWPOS_CENTERED;
|
||||
common->Warning( "Window position out of bounds, falling back to primary display" );
|
||||
}
|
||||
|
||||
if( !deviceManager->CreateWindowDeviceAndSwapChain( createParms, GAME_NAME ) )
|
||||
|
@ -280,7 +293,7 @@ bool VKimp_Init( glimpParms_t parms )
|
|||
}
|
||||
}
|
||||
|
||||
// SRS - Move to fullscreen mode after window creation to avoid SDL platform differences
|
||||
// SRS - Switch into fullscreen mode after window creation to avoid SDL platform differences
|
||||
if( SDL_SetWindowFullscreen( window, SDL_WINDOW_FULLSCREEN ) < 0 )
|
||||
{
|
||||
common->Warning( "Couldn't switch to fullscreen mode, reason: %s", SDL_GetError() );
|
||||
|
@ -288,16 +301,28 @@ bool VKimp_Init( glimpParms_t parms )
|
|||
}
|
||||
else if( parms.fullScreen == -2 )
|
||||
{
|
||||
// SRS - Move to borderless fullscreen mode after window creation
|
||||
// SRS - Switch into borderless fullscreen mode after window creation
|
||||
if( SDL_SetWindowFullscreen( window, SDL_WINDOW_FULLSCREEN_DESKTOP ) < 0 )
|
||||
{
|
||||
common->Warning( "Couldn't switch to borderless fullscreen mode, reason: %s", SDL_GetError() );
|
||||
}
|
||||
}
|
||||
else if( parms.fullScreen == -1 )
|
||||
{
|
||||
// SRS - Make sure custom borderless window is in position after window creation
|
||||
SDL_SetWindowPosition( window, createParms.x, createParms.y );
|
||||
}
|
||||
|
||||
// RB begin
|
||||
SDL_GetWindowSize( window, &glConfig.nativeScreenWidth, &glConfig.nativeScreenHeight );
|
||||
// RB end
|
||||
if( parms.fullScreen )
|
||||
{
|
||||
// SRS - Get window's client area dimensions to set initial render size for fullscreen modes
|
||||
SDL_GetWindowSize( window, &glConfig.nativeScreenWidth, &glConfig.nativeScreenHeight );
|
||||
}
|
||||
else
|
||||
{
|
||||
// SRS - Get actual swapchain dimensions to set initial render size for windowed mode
|
||||
deviceManager->GetWindowDimensions( glConfig.nativeScreenWidth, glConfig.nativeScreenHeight );
|
||||
}
|
||||
|
||||
// SRS - Detect and save actual fullscreen state supporting all modes (-2, -1, 0, 1, ...)
|
||||
glConfig.isFullscreen = ( SDL_GetWindowFlags( window ) & SDL_WINDOW_FULLSCREEN ) || ( parms.fullScreen == -1 ) ? parms.fullScreen : 0;
|
||||
|
@ -371,9 +396,10 @@ static int ScreenParmsHandleDisplayIndex( glimpParms_t parms )
|
|||
int windowPosX = parms.x, windowPosY = parms.y;
|
||||
if( displayIdx < 0 )
|
||||
{
|
||||
// SRS - window is out of bounds for desktop, reposition onto default display
|
||||
windowPosX = windowPosY = SDL_WINDOWPOS_UNDEFINED;
|
||||
// SRS - window is out of bounds for desktop, reposition onto primary display
|
||||
displayIdx = 0;
|
||||
windowPosX = windowPosY = SDL_WINDOWPOS_CENTERED;
|
||||
common->Warning( "Window position out of bounds, falling back to primary display" );
|
||||
}
|
||||
|
||||
// move window to the specified desktop position
|
||||
|
@ -434,8 +460,9 @@ static bool SetScreenParmsWindowed( glimpParms_t parms )
|
|||
int windowPosX = parms.x, windowPosY = parms.y;
|
||||
if( GetDisplayIndex( parms ) < 0 )
|
||||
{
|
||||
// SRS - window is out of bounds for desktop, reposition onto default display
|
||||
windowPosX = windowPosY = SDL_WINDOWPOS_UNDEFINED;
|
||||
// SRS - window is out of bounds for desktop, reposition onto primary display
|
||||
windowPosX = windowPosY = SDL_WINDOWPOS_CENTERED;
|
||||
common->Warning( "Window position out of bounds, falling back to primary display" );
|
||||
}
|
||||
|
||||
// SRS - handle differences in WM behaviour: for macOS set position first, for linux set it last
|
||||
|
@ -496,8 +523,10 @@ bool VKimp_SetScreenParms( glimpParms_t parms )
|
|||
|
||||
glConfig.isFullscreen = parms.fullScreen;
|
||||
glConfig.isStereoPixelFormat = parms.stereo;
|
||||
glConfig.nativeScreenWidth = parms.width;
|
||||
glConfig.nativeScreenHeight = parms.height;
|
||||
|
||||
// SRS - Get window's client area dimensions to set new render size
|
||||
SDL_GetWindowSize( window, &glConfig.nativeScreenWidth, &glConfig.nativeScreenHeight );
|
||||
|
||||
glConfig.displayFrequency = GetDisplayFrequency( parms );
|
||||
glConfig.multisamples = parms.multiSamples;
|
||||
|
||||
|
|
|
@ -659,7 +659,7 @@ static bool GLW_GetWindowDimensions( const glimpParms_t parms, int& x, int& y, i
|
|||
{
|
||||
displayNotFound = true;
|
||||
displayNum = DisplayPrimary();
|
||||
idLib::Printf( "Can't find display for specified window position, falling back to display %i\n", displayNum + 1 );
|
||||
common->Warning( "Window position out of bounds, falling back to primary display" );
|
||||
}
|
||||
|
||||
// get the current monitor position and size on the desktop, assuming
|
||||
|
@ -802,19 +802,17 @@ bool DeviceManager::CreateWindowDeviceAndSwapChain( const glimpParms_t& parms, c
|
|||
return false;
|
||||
}
|
||||
|
||||
// SRS - For fullscreen borderless windowed mode == -2 need to use actual display dimensions
|
||||
if( parms.fullScreen == -2 )
|
||||
// SRS - Get window's client area dimensions to set initial swapchain size
|
||||
RECT rect;
|
||||
if( !GetClientRect( win32.hWnd, &rect ) )
|
||||
{
|
||||
m_DeviceParams.backBufferWidth = w;
|
||||
m_DeviceParams.backBufferHeight = h;
|
||||
}
|
||||
// otherwise use parms
|
||||
else
|
||||
{
|
||||
m_DeviceParams.backBufferWidth = parms.width;
|
||||
m_DeviceParams.backBufferHeight = parms.height;
|
||||
common->Printf( "^3GLW_CreateWindow() - GetClientRect() failed^0\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
m_DeviceParams.backBufferWidth = rect.right - rect.left;
|
||||
m_DeviceParams.backBufferHeight = rect.bottom - rect.top;
|
||||
|
||||
// RB
|
||||
m_DeviceParams.backBufferSampleCount = parms.multiSamples;
|
||||
m_DeviceParams.vsyncEnabled = m_RequestedVSync;
|
||||
|
@ -851,6 +849,10 @@ void DeviceManager::UpdateWindowSize( const glimpParms_t& parms )
|
|||
m_DeviceParams.vsyncEnabled = m_RequestedVSync;
|
||||
|
||||
ResizeSwapChain();
|
||||
|
||||
// SRS - Get actual swapchain dimensions to set new render size
|
||||
deviceManager->GetWindowDimensions( glConfig.nativeScreenWidth, glConfig.nativeScreenHeight );
|
||||
|
||||
BackBufferResized();
|
||||
}
|
||||
else
|
||||
|
@ -1129,22 +1131,23 @@ bool GLimp_Init( glimpParms_t parms )
|
|||
glConfig.isFullscreen = parms.fullScreen;
|
||||
glConfig.isStereoPixelFormat = parms.stereo;
|
||||
|
||||
// SRS - For fullscreen borderless windowed mode == -2 need to use actual display dimensions
|
||||
if( parms.fullScreen == -2 )
|
||||
if( parms.fullScreen )
|
||||
{
|
||||
int x, y, w, h;
|
||||
if( !GLW_GetWindowDimensions( parms, x, y, w, h ) )
|
||||
// SRS - Get window's client area dimensions to set initial render size for fullscreen modes
|
||||
RECT rect;
|
||||
if( !GetClientRect( win32.hWnd, &rect ) )
|
||||
{
|
||||
common->Printf( "^3GLimp_Init() - GetClientRect() failed^0\n" );
|
||||
return false;
|
||||
}
|
||||
glConfig.nativeScreenWidth = w;
|
||||
glConfig.nativeScreenHeight = h;
|
||||
|
||||
glConfig.nativeScreenWidth = rect.right - rect.left;
|
||||
glConfig.nativeScreenHeight = rect.bottom - rect.top;
|
||||
}
|
||||
// otherwise use parms
|
||||
else
|
||||
{
|
||||
glConfig.nativeScreenWidth = parms.width;
|
||||
glConfig.nativeScreenHeight = parms.height;
|
||||
// SRS - Get actual swapchain dimensions to set initial render size for windowed mode
|
||||
deviceManager->GetWindowDimensions( glConfig.nativeScreenWidth, glConfig.nativeScreenHeight );
|
||||
}
|
||||
|
||||
glConfig.displayFrequency = GetDisplayFrequency( parms );
|
||||
|
@ -1219,19 +1222,17 @@ bool GLimp_SetScreenParms( glimpParms_t parms )
|
|||
|
||||
glConfig.isStereoPixelFormat = parms.stereo;
|
||||
|
||||
// SRS - For fullscreen borderless windowed mode == -2 need to use actual display dimensions
|
||||
if( parms.fullScreen == -2 )
|
||||
// SRS - Get window's client area dimensions to set new render size
|
||||
RECT rect;
|
||||
if( !GetClientRect( win32.hWnd, &rect ) )
|
||||
{
|
||||
glConfig.nativeScreenWidth = w;
|
||||
glConfig.nativeScreenHeight = h;
|
||||
}
|
||||
// otherwise use parms
|
||||
else
|
||||
{
|
||||
glConfig.nativeScreenWidth = parms.width;
|
||||
glConfig.nativeScreenHeight = parms.height;
|
||||
common->Printf( "^3GLimp_SetScreenParms() - GetClientRect() failed^0\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
glConfig.nativeScreenWidth = rect.right - rect.left;
|
||||
glConfig.nativeScreenHeight = rect.bottom - rect.top;
|
||||
|
||||
glConfig.displayFrequency = GetDisplayFrequency( parms );
|
||||
glConfig.multisamples = parms.multiSamples;
|
||||
|
||||
|
|
Loading…
Reference in a new issue