mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-03-15 07:00:58 +00:00
Merge pull request #725 from SRSaunders/635-nvrhi3-testing
[Vulkan] Solve multiple Vulkan validation issues, NVRHI game now runs without failures on Linux & macOS
This commit is contained in:
commit
fca592ca73
17 changed files with 351 additions and 1380 deletions
|
@ -852,6 +852,16 @@ file(GLOB RAPIDJSON_INCLUDES libs/rapidjson/include/rapidjson/*.h)
|
|||
file(GLOB SYS_INCLUDES sys/*.h)
|
||||
file(GLOB SYS_SOURCES sys/*.cpp)
|
||||
|
||||
if(NOT USE_DX12)
|
||||
get_filename_component(devicemanager_dx12_cpp_full_path ${CMAKE_CURRENT_SOURCE_DIR}/sys/DeviceManager_DX12.cpp ABSOLUTE)
|
||||
list(REMOVE_ITEM SYS_SOURCES "${devicemanager_dx12_cpp_full_path}")
|
||||
endif()
|
||||
|
||||
if(NOT USE_NVRHI_VULKAN)
|
||||
get_filename_component(devicemanager_vk_cpp_full_path ${CMAKE_CURRENT_SOURCE_DIR}/sys/DeviceManager_VK.cpp ABSOLUTE)
|
||||
list(REMOVE_ITEM SYS_SOURCES "${devicemanager_vk_cpp_full_path}")
|
||||
endif()
|
||||
|
||||
file(GLOB UI_INCLUDES ui/*.h)
|
||||
file(GLOB UI_SOURCES ui/*.cpp)
|
||||
|
||||
|
@ -1104,14 +1114,6 @@ set(WIN32_SOURCES
|
|||
sys/win32/win_taskkeyhook.cpp
|
||||
sys/win32/win_wndproc.cpp)
|
||||
|
||||
if(USE_DX12)
|
||||
list(APPEND WIN32_SOURCES sys/win32/DeviceManager_DX12.cpp)
|
||||
endif()
|
||||
|
||||
if(USE_NVRHI_VULKAN)
|
||||
list(APPEND WIN32_SOURCES sys/win32/DeviceManager_VK.cpp)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
list(APPEND WIN32_SOURCES sys/win32/win_cpu.cpp)
|
||||
endif()
|
||||
|
@ -1206,8 +1208,6 @@ if(UNIX)
|
|||
list(REMOVE_ITEM SYS_INCLUDES "${devicemanager_h_full_path}")
|
||||
get_filename_component(devicemanager_cpp_full_path ${CMAKE_CURRENT_SOURCE_DIR}/sys/DeviceManager.cpp ABSOLUTE)
|
||||
list(REMOVE_ITEM SYS_SOURCES "${devicemanager_cpp_full_path}")
|
||||
get_filename_component(devicemanager_vk_cpp_full_path ${CMAKE_CURRENT_SOURCE_DIR}/sys/sdl/DeviceManager_VK.cpp ABSOLUTE)
|
||||
list(REMOVE_ITEM SDL_SOURCES "${devicemanager_vk_cpp_full_path}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@ -1881,7 +1881,7 @@ else()
|
|||
list(APPEND Vulkan_LIBRARIES glslang-default-resource-limits)
|
||||
endif()
|
||||
endif()
|
||||
elseif(USE_NVRHI)
|
||||
elseif(USE_NVRHI_VULKAN)
|
||||
list(APPEND RBDOOM3_INCLUDES ${RENDERER_NVRHI_INCLUDES})
|
||||
list(APPEND RBDOOM3_SOURCES ${RENDERER_NVRHI_SOURCES})
|
||||
|
||||
|
|
|
@ -220,7 +220,7 @@ extern bool R_UseTemporalAA();
|
|||
#define FPS_FRAMES_HISTORY 90
|
||||
float idConsoleLocal::DrawFPS( float y )
|
||||
{
|
||||
extern idCVar com_smp;
|
||||
extern idCVar r_swapInterval;
|
||||
|
||||
static float previousTimes[FPS_FRAMES];
|
||||
static float previousTimesNormalized[FPS_FRAMES_HISTORY];
|
||||
|
@ -288,8 +288,6 @@ float idConsoleLocal::DrawFPS( float y )
|
|||
|
||||
const uint64 rendererBackEndTime = commonLocal.GetRendererBackEndMicroseconds();
|
||||
const uint64 rendererShadowsTime = commonLocal.GetRendererShadowsMicroseconds();
|
||||
// SRS - GPU idle time calculation depends on whether game is operating in smp mode or not
|
||||
const uint64 rendererGPUIdleTime = commonLocal.GetRendererIdleMicroseconds() - ( com_smp.GetInteger() > 0 && com_editors == 0 ? 0 : gameThreadTotalTime );
|
||||
const uint64 rendererGPUTime = commonLocal.GetRendererGPUMicroseconds();
|
||||
const uint64 rendererGPUEarlyZTime = commonLocal.GetRendererGpuEarlyZMicroseconds();
|
||||
const uint64 rendererGPU_SSAOTime = commonLocal.GetRendererGpuSSAOMicroseconds();
|
||||
|
@ -300,15 +298,20 @@ float idConsoleLocal::DrawFPS( float y )
|
|||
const uint64 rendererGPUShaderPassesTime = commonLocal.GetRendererGpuShaderPassMicroseconds();
|
||||
const uint64 rendererGPU_TAATime = commonLocal.GetRendererGpuTAAMicroseconds();
|
||||
const uint64 rendererGPUPostProcessingTime = commonLocal.GetRendererGpuPostProcessingMicroseconds();
|
||||
const int maxTime = int( 1000 / com_engineHz_latched ) * 1000;
|
||||
|
||||
// SRS - Get GPU sync time at the start of a frame (com_smp = 1 or 0) and at the end of a frame (com_smp = -1)
|
||||
const uint64 rendererStartFrameSyncTime = commonLocal.GetRendererStartFrameSyncMicroseconds();
|
||||
const uint64 rendererEndFrameSyncTime = commonLocal.GetRendererEndFrameSyncMicroseconds();
|
||||
// SRS - Calculate max fps and max frame time based on glConfig.displayFrequency if vsync enabled and lower than engine Hz, otherwise use com_engineHz_latched
|
||||
const int max_FPS = ( r_swapInterval.GetInteger() > 0 && glConfig.displayFrequency > 0 ? std::min( glConfig.displayFrequency, int( com_engineHz_latched ) ) : com_engineHz_latched );
|
||||
const int maxTime = 1000.0 / max_FPS * 1000;
|
||||
|
||||
// SRS - Total CPU and Frame time calculations depend on whether game is operating in smp mode or not
|
||||
const uint64 totalCPUTime = ( com_smp.GetInteger() > 0 && com_editors == 0 ? std::max( gameThreadTotalTime, rendererBackEndTime ) : gameThreadTotalTime + rendererBackEndTime );
|
||||
const uint64 totalFrameTime = ( com_smp.GetInteger() > 0 && com_editors == 0 ? std::max( gameThreadTotalTime, rendererEndFrameSyncTime ) : gameThreadTotalTime + rendererEndFrameSyncTime ) + rendererStartFrameSyncTime;
|
||||
// SRS - Frame idle and busy time calculations are based on direct frame-over-frame measurement relative to finishSyncTime
|
||||
const uint64 frameIdleTime = commonLocal.mainFrameTiming.startGameTime - commonLocal.mainFrameTiming.finishSyncTime;
|
||||
const uint64 frameBusyTime = commonLocal.frameTiming.finishSyncTime - commonLocal.mainFrameTiming.startGameTime;
|
||||
|
||||
// SRS - Frame sync time represents swap buffer synchronization + game thread wait + other time spent outside of rendering
|
||||
const uint64 frameSyncTime = commonLocal.frameTiming.finishSyncTime - commonLocal.mainFrameTiming.finishRenderTime;
|
||||
|
||||
// SRS - GPU idle time is simply the difference between measured frame-over-frame time and GPU busy time (directly from GPU timers)
|
||||
const uint64 rendererGPUIdleTime = frameBusyTime + frameIdleTime - rendererGPUTime;
|
||||
|
||||
#if 1
|
||||
|
||||
|
@ -476,7 +479,7 @@ float idConsoleLocal::DrawFPS( float y )
|
|||
}
|
||||
else
|
||||
{
|
||||
ImGui::TextColored( fps < com_engineHz_latched ? colorRed : colorYellow, "Average FPS %i", fps );
|
||||
ImGui::TextColored( fps < max_FPS ? colorRed : colorYellow, "Average FPS %i", fps );
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
|
@ -486,14 +489,13 @@ float idConsoleLocal::DrawFPS( float y )
|
|||
ImGui::TextColored( gameThreadGameTime > maxTime ? colorRed : colorWhite, "Game: %5llu us SSAO: %5llu us", gameThreadGameTime, rendererGPU_SSAOTime );
|
||||
ImGui::TextColored( gameThreadRenderTime > maxTime ? colorRed : colorWhite, "RF: %5llu us SSR: %5llu us", gameThreadRenderTime, rendererGPU_SSRTime );
|
||||
ImGui::TextColored( rendererBackEndTime > maxTime ? colorRed : colorWhite, "RB: %5llu us Ambient Pass: %5llu us", rendererBackEndTime, rendererGPUAmbientPassTime );
|
||||
ImGui::TextColored( rendererGPUShadowAtlasTime > maxTime ? colorRed : colorWhite, " Shadow Atlas: %5llu us", rendererGPUShadowAtlasTime );
|
||||
ImGui::TextColored( rendererShadowsTime > maxTime ? colorRed : colorWhite, "Shadows: %5llu us Interactions: %5llu us", rendererShadowsTime, rendererGPUInteractionsTime );
|
||||
ImGui::TextColored( rendererGPUShadowAtlasTime > maxTime ? colorRed : colorWhite, "Shadows: %5llu us Shadow Atlas: %5llu us", rendererShadowsTime, rendererGPUShadowAtlasTime );
|
||||
ImGui::TextColored( rendererGPUInteractionsTime > maxTime ? colorRed : colorWhite, "Sync: %5llu us Interactions: %5llu us", frameSyncTime, rendererGPUInteractionsTime );
|
||||
ImGui::TextColored( rendererGPUShaderPassesTime > maxTime ? colorRed : colorWhite, " Shader Pass: %5llu us", rendererGPUShaderPassesTime );
|
||||
ImGui::TextColored( rendererGPU_TAATime > maxTime ? colorRed : colorWhite, " TAA: %5llu us", rendererGPU_TAATime );
|
||||
ImGui::TextColored( rendererGPUPostProcessingTime > maxTime ? colorRed : colorWhite, " PostFX: %5llu us", rendererGPUPostProcessingTime );
|
||||
ImGui::TextColored( totalCPUTime > maxTime || rendererGPUTime > maxTime ? colorRed : colorWhite,
|
||||
"Total: %5llu us Total: %5llu us", totalCPUTime, rendererGPUTime );
|
||||
ImGui::TextColored( totalFrameTime > maxTime ? colorRed : colorWhite, "Frame: %5llu us Idle: %5llu us", totalFrameTime, rendererGPUIdleTime );
|
||||
ImGui::TextColored( frameBusyTime > maxTime || rendererGPUTime > maxTime ? colorRed : colorWhite, "Total: %5llu us Total: %5llu us", frameBusyTime, rendererGPUTime );
|
||||
ImGui::TextColored( colorWhite, "Idle: %5llu us Idle: %5llu us", frameIdleTime, rendererGPUIdleTime );
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
|
|
@ -286,7 +286,15 @@ void idImage::AllocImage()
|
|||
break;
|
||||
|
||||
case FMT_DEPTH_STENCIL:
|
||||
format = nvrhi::Format::D24S8;
|
||||
// SRS - Check if D24S8 is supported, otherwise fall back to D32S8
|
||||
if( deviceManager->deviceParms.enableImageFormatD24S8 )
|
||||
{
|
||||
format = nvrhi::Format::D24S8;
|
||||
}
|
||||
else
|
||||
{
|
||||
format = nvrhi::Format::D32S8;
|
||||
}
|
||||
break;
|
||||
|
||||
case FMT_SHADOW_ARRAY:
|
||||
|
|
|
@ -192,7 +192,6 @@ void idRenderBackend::Init()
|
|||
// RB: FIXME but for now disable it to avoid validation errors
|
||||
if( deviceManager->GetGraphicsAPI() == nvrhi::GraphicsAPI::VULKAN )
|
||||
{
|
||||
glConfig.timerQueryAvailable = false;
|
||||
r_useSSAO.SetBool( false );
|
||||
}
|
||||
}
|
||||
|
@ -1711,6 +1710,13 @@ void idRenderBackend::CheckCVars()
|
|||
R_SetColorMappings();
|
||||
}
|
||||
|
||||
// SRS - support dynamic changes to vsync setting
|
||||
if( r_swapInterval.IsModified() )
|
||||
{
|
||||
r_swapInterval.ClearModified();
|
||||
deviceManager->SetVsyncEnabled( r_swapInterval.GetBool() );
|
||||
}
|
||||
|
||||
// filtering
|
||||
/*if( r_maxAnisotropicFiltering.IsModified() || r_useTrilinearFiltering.IsModified() || r_lodBias.IsModified() )
|
||||
{
|
||||
|
@ -2145,6 +2151,13 @@ idRenderBackend::ResizeImages
|
|||
*/
|
||||
void idRenderBackend::ResizeImages()
|
||||
{
|
||||
glimpParms_t parms;
|
||||
|
||||
parms.width = glConfig.nativeScreenWidth;
|
||||
parms.height = glConfig.nativeScreenHeight;
|
||||
parms.multiSamples = glConfig.multisamples;
|
||||
|
||||
deviceManager->UpdateWindowSize( parms );
|
||||
}
|
||||
|
||||
void idRenderBackend::SetCurrentImage( idImage* image )
|
||||
|
|
|
@ -6664,7 +6664,7 @@ void idRenderBackend::ExecuteBackEndCommands( const emptyCommand_t* cmds )
|
|||
// SRS - Restore timestamp capture state after overlay GUI rendering is finished
|
||||
glConfig.timerQueryAvailable = timerQueryAvailable;
|
||||
renderLog.CloseBlock();
|
||||
renderLog.CloseMainBlock();
|
||||
renderLog.CloseMainBlock( MRB_DRAW_GUI );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -324,7 +324,7 @@ idRenderLog::idRenderLog()
|
|||
void idRenderLog::Init()
|
||||
{
|
||||
#if defined( USE_NVRHI )
|
||||
for( int i = 0; i < MRB_TOTAL_QUERIES; i++ )
|
||||
for( int i = 0; i < MRB_TOTAL * NUM_FRAME_DATA; i++ )
|
||||
{
|
||||
timerQueries.Append( deviceManager->GetDevice()->createTimerQuery() );
|
||||
timerUsed.Append( false );
|
||||
|
@ -335,12 +335,7 @@ void idRenderLog::Init()
|
|||
void idRenderLog::Shutdown()
|
||||
{
|
||||
#if defined( USE_NVRHI )
|
||||
if( commandList )
|
||||
{
|
||||
commandList.Reset();
|
||||
}
|
||||
|
||||
for( int i = 0; i < MRB_TOTAL_QUERIES; i++ )
|
||||
for( int i = 0; i < MRB_TOTAL * NUM_FRAME_DATA; i++ )
|
||||
{
|
||||
timerQueries[i].Reset();
|
||||
}
|
||||
|
@ -356,6 +351,9 @@ void idRenderLog::StartFrame( nvrhi::ICommandList* _commandList )
|
|||
|
||||
void idRenderLog::EndFrame()
|
||||
{
|
||||
#if defined( USE_NVRHI )
|
||||
commandList = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -376,8 +374,11 @@ void idRenderLog::OpenMainBlock( renderLogMainBlock_t block )
|
|||
|
||||
int timerIndex = mainBlock + frameParity * MRB_TOTAL;
|
||||
|
||||
commandList->beginTimerQuery( timerQueries[ timerIndex ] );
|
||||
timerUsed[ timerIndex ] = true;
|
||||
// SRS - Only issue a new start timer query if timer slot unused
|
||||
if( !timerUsed[ timerIndex ] )
|
||||
{
|
||||
commandList->beginTimerQuery( timerQueries[ timerIndex ] );
|
||||
}
|
||||
|
||||
#elif defined( USE_VULKAN )
|
||||
if( vkcontext.queryIndex[ vkcontext.frameParity ] >= ( NUM_TIMESTAMP_QUERIES - 1 ) )
|
||||
|
@ -437,7 +438,12 @@ void idRenderLog::CloseMainBlock( int _block )
|
|||
|
||||
int timerIndex = block + frameParity * MRB_TOTAL;
|
||||
|
||||
commandList->endTimerQuery( timerQueries[ timerIndex ] );
|
||||
// SRS - Only issue a new end timer query if timer slot unused
|
||||
if( !timerUsed[ timerIndex ] )
|
||||
{
|
||||
commandList->endTimerQuery( timerQueries[ timerIndex ] );
|
||||
timerUsed[ timerIndex ] = true;
|
||||
}
|
||||
|
||||
#elif defined( USE_VULKAN )
|
||||
if( vkcontext.queryIndex[ vkcontext.frameParity ] >= ( NUM_TIMESTAMP_QUERIES - 1 ) )
|
||||
|
@ -448,7 +454,7 @@ void idRenderLog::CloseMainBlock( int _block )
|
|||
VkCommandBuffer commandBuffer = vkcontext.commandBuffer[ vkcontext.frameParity ];
|
||||
VkQueryPool queryPool = vkcontext.queryPools[ vkcontext.frameParity ];
|
||||
|
||||
uint32 queryIndex = vkcontext.queryAssignedIndex[ vkcontext.frameParity ][ mainBlock * 2 + 1 ] = vkcontext.queryIndex[ vkcontext.frameParity ]++;
|
||||
uint32 queryIndex = vkcontext.queryAssignedIndex[ vkcontext.frameParity ][ block * 2 + 1 ] = vkcontext.queryIndex[ vkcontext.frameParity ]++;
|
||||
vkCmdWriteTimestamp( commandBuffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, queryIndex );
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
@ -457,12 +463,12 @@ void idRenderLog::CloseMainBlock( int _block )
|
|||
if( !r_useShadowMapping.GetBool() || glConfig.vendor != VENDOR_AMD || r_skipAMDWorkarounds.GetBool() )
|
||||
{
|
||||
glEndQuery( GL_TIME_ELAPSED_EXT );
|
||||
glcontext.renderLogMainBlockTimeQueryIssued[ glcontext.frameParity ][ mainBlock * 2 + 1 ]++;
|
||||
glcontext.renderLogMainBlockTimeQueryIssued[ glcontext.frameParity ][ block * 2 + 1 ]++;
|
||||
}
|
||||
|
||||
#else
|
||||
glQueryCounter( glcontext.renderLogMainBlockTimeQueryIds[ glcontext.frameParity ][ mainBlock * 2 + 1 ], GL_TIMESTAMP );
|
||||
glcontext.renderLogMainBlockTimeQueryIssued[ glcontext.frameParity ][ mainBlock * 2 + 1 ]++;
|
||||
glQueryCounter( glcontext.renderLogMainBlockTimeQueryIds[ glcontext.frameParity ][ block * 2 + 1 ], GL_TIMESTAMP );
|
||||
glcontext.renderLogMainBlockTimeQueryIssued[ glcontext.frameParity ][ block * 2 + 1 ]++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -475,7 +481,7 @@ idRenderLog::FetchGPUTimers
|
|||
void idRenderLog::FetchGPUTimers( backEndCounters_t& pc )
|
||||
{
|
||||
frameCounter++;
|
||||
frameParity ^= 1;
|
||||
frameParity = ( frameParity + 1 ) % NUM_FRAME_DATA;
|
||||
|
||||
#if defined( USE_NVRHI )
|
||||
|
||||
|
|
|
@ -82,8 +82,8 @@ private:
|
|||
uint64 frameCounter;
|
||||
uint32 frameParity;
|
||||
|
||||
idStaticList<nvrhi::TimerQueryHandle, MRB_TOTAL_QUERIES> timerQueries;
|
||||
idStaticList<bool, MRB_TOTAL_QUERIES> timerUsed;
|
||||
idStaticList<nvrhi::TimerQueryHandle, MRB_TOTAL * NUM_FRAME_DATA> timerQueries;
|
||||
idStaticList<bool, MRB_TOTAL * NUM_FRAME_DATA> timerUsed;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
|
|
@ -107,7 +107,7 @@ void idRenderProgManager::Init( nvrhi::IDevice* device )
|
|||
// RB: FIXME this is ugly - DOUBLECHECK this
|
||||
constantBuffer = device->createBuffer(
|
||||
nvrhi::utils::CreateVolatileConstantBufferDesc( uniforms.Allocated(),
|
||||
"RenderParams", 1024 ) );
|
||||
"RenderParams", 4096 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -2245,6 +2245,8 @@ idRenderSystemLocal::Shutdown
|
|||
*/
|
||||
void idRenderSystemLocal::Shutdown()
|
||||
{
|
||||
extern idCVar com_smp;
|
||||
|
||||
common->Printf( "idRenderSystem::Shutdown()\n" );
|
||||
|
||||
fonts.DeleteContents();
|
||||
|
@ -2270,7 +2272,11 @@ void idRenderSystemLocal::Shutdown()
|
|||
UnbindBufferObjects();
|
||||
|
||||
// SRS - wait for fence to hit before freeing any resources the GPU may be using, otherwise get Vulkan validation layer errors on shutdown
|
||||
backend.GL_BlockingSwapBuffers();
|
||||
// SRS - skip this step if we are in Doom 3 mode (com_smp = -1) which has already finished and presented
|
||||
if( com_smp.GetInteger() != -1 )
|
||||
{
|
||||
backend.GL_BlockingSwapBuffers();
|
||||
}
|
||||
|
||||
// free the vertex cache, which should have nothing allocated now
|
||||
vertexCache.Shutdown();
|
||||
|
|
|
@ -96,6 +96,9 @@ struct DeviceCreationParameters
|
|||
std::vector<std::string> optionalVulkanLayers;
|
||||
std::vector<size_t> ignoredVulkanValidationMessageLocations;
|
||||
#endif
|
||||
|
||||
// SRS - Used by idImage::AllocImage() to determine if format D24S8 is supported by device (default = true)
|
||||
bool enableImageFormatD24S8 = true;
|
||||
};
|
||||
|
||||
struct DefaultMessageCallback : public nvrhi::IMessageCallback
|
||||
|
@ -131,6 +134,7 @@ public:
|
|||
|
||||
protected:
|
||||
friend class idRenderBackend;
|
||||
friend class idImage;
|
||||
|
||||
void* windowInstance;
|
||||
void* windowHandle;
|
||||
|
@ -216,4 +220,4 @@ private:
|
|||
std::string m_WindowTitle;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
#include "renderer/RenderCommon.h"
|
||||
#include "renderer/RenderSystem.h"
|
||||
#include "../DeviceManager.h"
|
||||
#include <sys/DeviceManager.h>
|
||||
|
||||
#include <Windows.h>
|
||||
#include <dxgi1_5.h>
|
||||
|
@ -204,15 +204,6 @@ void DeviceManager_DX12::ReportLiveObjects()
|
|||
|
||||
bool DeviceManager_DX12::CreateDeviceAndSwapChain()
|
||||
{
|
||||
UINT windowStyle = deviceParms.startFullscreen
|
||||
? ( WS_POPUP | WS_SYSMENU | WS_VISIBLE )
|
||||
: deviceParms.startMaximized
|
||||
? ( WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_MAXIMIZE )
|
||||
: ( WS_OVERLAPPEDWINDOW | WS_VISIBLE );
|
||||
|
||||
RECT rect = { 0, 0, LONG( deviceParms.backBufferWidth ), LONG( deviceParms.backBufferHeight ) };
|
||||
AdjustWindowRect( &rect, windowStyle, FALSE );
|
||||
|
||||
RefCountPtr<IDXGIAdapter> targetAdapter;
|
||||
|
||||
if( deviceParms.adapter )
|
||||
|
@ -248,12 +239,25 @@ bool DeviceManager_DX12::CreateDeviceAndSwapChain()
|
|||
|
||||
isNvidia = IsNvDeviceID( aDesc.VendorId );
|
||||
}
|
||||
/*
|
||||
// SRS - Don't center window here for DX12 only, instead use portable initialization in CreateWindowDeviceAndSwapChain() within win_glimp.cpp
|
||||
// - Also, calling SetWindowPos() triggers a window mgr event that overwrites r_windowX / r_windowY, which may be undesirable to the user
|
||||
|
||||
UINT windowStyle = deviceParms.startFullscreen
|
||||
? ( WS_POPUP | WS_SYSMENU | WS_VISIBLE )
|
||||
: deviceParms.startMaximized
|
||||
? ( WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_MAXIMIZE )
|
||||
: ( WS_OVERLAPPEDWINDOW | WS_VISIBLE );
|
||||
|
||||
RECT rect = { 0, 0, LONG( deviceParms.backBufferWidth ), LONG( deviceParms.backBufferHeight ) };
|
||||
AdjustWindowRect( &rect, windowStyle, FALSE );
|
||||
|
||||
if( MoveWindowOntoAdapter( targetAdapter, rect ) )
|
||||
{
|
||||
SetWindowPos( ( HWND )windowHandle, deviceParms.startFullscreen ? HWND_TOPMOST : HWND_NOTOPMOST,
|
||||
rect.left, rect.top, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE );
|
||||
}
|
||||
*/
|
||||
HRESULT hr = E_FAIL;
|
||||
|
||||
RECT clientRect;
|
||||
|
@ -539,6 +543,8 @@ void DeviceManager_DX12::ResizeSwapChain()
|
|||
|
||||
void DeviceManager_DX12::BeginFrame()
|
||||
{
|
||||
/* SRS - This code not needed: framebuffer/swapchain resizing & fullscreen are handled by idRenderBackend::ResizeImages() and DeviceManager::UpdateWindowSize()
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC1 newSwapChainDesc;
|
||||
DXGI_SWAP_CHAIN_FULLSCREEN_DESC newFullScreenDesc;
|
||||
if( SUCCEEDED( m_SwapChain->GetDesc1( &newSwapChainDesc ) ) && SUCCEEDED( m_SwapChain->GetFullscreenDesc( &newFullScreenDesc ) ) )
|
||||
|
@ -561,7 +567,7 @@ void DeviceManager_DX12::BeginFrame()
|
|||
BackBufferResized();
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
auto bufferIndex = m_SwapChain->GetCurrentBackBufferIndex();
|
||||
|
||||
WaitForSingleObject( m_FrameFenceEvents[bufferIndex], INFINITE );
|
||||
|
@ -607,21 +613,14 @@ void DeviceManager_DX12::Present()
|
|||
|
||||
UINT presentFlags = 0;
|
||||
|
||||
if( r_swapInterval.GetInteger() == 1 )
|
||||
{
|
||||
SetVsyncEnabled( false );
|
||||
}
|
||||
else if( r_swapInterval.GetInteger() == 2 )
|
||||
{
|
||||
SetVsyncEnabled( true );
|
||||
}
|
||||
|
||||
if( !deviceParms.vsyncEnabled && !glConfig.isFullscreen && m_TearingSupported && r_swapInterval.GetInteger() == 0 )
|
||||
// SRS - DXGI docs say fullscreen must be disabled for unlocked fps/tear, but this does not seem to be true
|
||||
if( !deviceParms.vsyncEnabled && m_TearingSupported ) //&& !glConfig.isFullscreen )
|
||||
{
|
||||
presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
|
||||
}
|
||||
|
||||
m_SwapChain->Present( deviceParms.vsyncEnabled ? 1 : 0, presentFlags );
|
||||
// SRS - Don't change deviceParms.vsyncEnabled here, simply test for vsync mode 2 to set DXGI SyncInterval
|
||||
m_SwapChain->Present( deviceParms.vsyncEnabled && r_swapInterval.GetInteger() == 2 ? 1 : 0, presentFlags );
|
||||
|
||||
m_FrameFence->SetEventOnCompletion( m_FrameCount, m_FrameFenceEvents[bufferIndex] );
|
||||
m_GraphicsQueue->Signal( m_FrameFence, m_FrameCount );
|
||||
|
@ -631,4 +630,4 @@ void DeviceManager_DX12::Present()
|
|||
DeviceManager* DeviceManager::CreateD3D12()
|
||||
{
|
||||
return new DeviceManager_DX12();
|
||||
}
|
||||
}
|
|
@ -164,22 +164,17 @@ private:
|
|||
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME
|
||||
},
|
||||
// layers
|
||||
{
|
||||
#if defined(__APPLE__) && !defined( USE_MoltenVK )
|
||||
//"VK_LAYER_KHRONOS_synchronization2" // sync2 not supported natively on MoltenVK, use layer implementation instead
|
||||
#endif
|
||||
},
|
||||
{ },
|
||||
// device
|
||||
{
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||
VK_KHR_MAINTENANCE1_EXTENSION_NAME,
|
||||
#if defined(__APPLE__)
|
||||
#if defined( VK_KHR_portability_subset )
|
||||
VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME,
|
||||
#endif
|
||||
VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME,
|
||||
VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME,
|
||||
#if !defined( USE_MoltenVK )
|
||||
//VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME
|
||||
#endif
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
@ -197,14 +192,20 @@ private:
|
|||
VK_EXT_DEBUG_UTILS_EXTENSION_NAME
|
||||
},
|
||||
// layers
|
||||
{ },
|
||||
{
|
||||
#if defined(__APPLE__)
|
||||
// SRS - synchronization2 not supported natively on MoltenVK, use layer implementation instead
|
||||
"VK_LAYER_KHRONOS_synchronization2"
|
||||
#endif
|
||||
},
|
||||
// device
|
||||
{
|
||||
VK_EXT_DEBUG_MARKER_EXTENSION_NAME,
|
||||
VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME,
|
||||
VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME,
|
||||
VK_NV_MESH_SHADER_EXTENSION_NAME,
|
||||
VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME
|
||||
VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME,
|
||||
VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -257,6 +258,9 @@ private:
|
|||
std::queue<nvrhi::EventQueryHandle> m_FramesInFlight;
|
||||
std::vector<nvrhi::EventQueryHandle> m_QueryPool;
|
||||
|
||||
// SRS - flag indicating support for eFifoRelaxed surface presentation (r_swapInterval = 1) mode
|
||||
bool enablePModeFifoRelaxed = false;
|
||||
|
||||
|
||||
private:
|
||||
static VKAPI_ATTR VkBool32 VKAPI_CALL vulkanDebugCallback(
|
||||
|
@ -570,6 +574,14 @@ 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() ) )
|
||||
{
|
||||
// can't find the required surface present modes
|
||||
errorStream << std::endl << " - does not support the requested surface present modes";
|
||||
deviceIsGood = false;
|
||||
}
|
||||
|
||||
if( !findQueueFamilies( dev, m_WindowSurface ) )
|
||||
{
|
||||
// device doesn't have all the queue families we need
|
||||
|
@ -706,6 +718,7 @@ bool DeviceManager_VK::createDevice()
|
|||
bool rayQuerySupported = false;
|
||||
bool meshletsSupported = false;
|
||||
bool vrsSupported = false;
|
||||
bool sync2Supported = false;
|
||||
|
||||
common->Printf( "Enabled Vulkan device extensions:\n" );
|
||||
for( const auto& ext : enabledExtensions.device )
|
||||
|
@ -737,6 +750,10 @@ bool DeviceManager_VK::createDevice()
|
|||
{
|
||||
vrsSupported = true;
|
||||
}
|
||||
else if( ext == VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME )
|
||||
{
|
||||
sync2Supported = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_set<int> uniqueQueueFamilies =
|
||||
|
@ -782,7 +799,17 @@ bool DeviceManager_VK::createDevice()
|
|||
.setPrimitiveFragmentShadingRate( true )
|
||||
.setAttachmentFragmentShadingRate( true );
|
||||
|
||||
auto sync2Features = vk::PhysicalDeviceSynchronization2FeaturesKHR()
|
||||
.setSynchronization2( true );
|
||||
|
||||
#if defined(__APPLE__) && defined( VK_KHR_portability_subset )
|
||||
auto portabilityFeatures = vk::PhysicalDevicePortabilitySubsetFeaturesKHR()
|
||||
.setImageViewFormatSwizzle( true );
|
||||
|
||||
void* pNext = &portabilityFeatures;
|
||||
#else
|
||||
void* pNext = nullptr;
|
||||
#endif
|
||||
#define APPEND_EXTENSION(condition, desc) if (condition) { (desc).pNext = pNext; pNext = &(desc); } // NOLINT(cppcoreguidelines-macro-usage)
|
||||
APPEND_EXTENSION( accelStructSupported, accelStructFeatures )
|
||||
APPEND_EXTENSION( bufferAddressSupported, bufferAddressFeatures )
|
||||
|
@ -790,6 +817,7 @@ bool DeviceManager_VK::createDevice()
|
|||
APPEND_EXTENSION( rayQuerySupported, rayQueryFeatures )
|
||||
APPEND_EXTENSION( meshletsSupported, meshletFeatures )
|
||||
APPEND_EXTENSION( vrsSupported, vrsFeatures )
|
||||
APPEND_EXTENSION( sync2Supported, sync2Features )
|
||||
#undef APPEND_EXTENSION
|
||||
|
||||
auto deviceFeatures = vk::PhysicalDeviceFeatures()
|
||||
|
@ -800,6 +828,7 @@ bool DeviceManager_VK::createDevice()
|
|||
#if !defined(__APPLE__)
|
||||
.setGeometryShader( true )
|
||||
#endif
|
||||
.setFillModeNonSolid( true )
|
||||
.setImageCubeArray( true )
|
||||
.setDualSrcBlend( true );
|
||||
|
||||
|
@ -844,7 +873,21 @@ bool DeviceManager_VK::createDevice()
|
|||
m_VulkanDevice.getQueue( m_PresentQueueFamily, 0, &m_PresentQueue );
|
||||
|
||||
VULKAN_HPP_DEFAULT_DISPATCHER.init( m_VulkanDevice );
|
||||
|
||||
// SRS - Determine if preferred image depth/stencil format D24S8 is supported (issue with Vulkan on AMD GPUs)
|
||||
vk::ImageFormatProperties imageFormatProperties;
|
||||
const vk::Result ret = m_VulkanPhysicalDevice.getImageFormatProperties( vk::Format::eD24UnormS8Uint,
|
||||
vk::ImageType::e2D,
|
||||
vk::ImageTiling::eOptimal,
|
||||
vk::ImageUsageFlags( vk::ImageUsageFlagBits::eDepthStencilAttachment ),
|
||||
vk::ImageCreateFlags( 0 ),
|
||||
&imageFormatProperties );
|
||||
deviceParms.enableImageFormatD24S8 = ( ret == vk::Result::eSuccess );
|
||||
|
||||
// SRS - Determine if "smart" (r_swapInterval = 1) vsync mode eFifoRelaxed is supported by device and surface
|
||||
auto surfacePModes = m_VulkanPhysicalDevice.getSurfacePresentModesKHR( m_WindowSurface );
|
||||
enablePModeFifoRelaxed = find( surfacePModes.begin(), surfacePModes.end(), vk::PresentModeKHR::eFifoRelaxed ) != surfacePModes.end();
|
||||
|
||||
// stash the renderer string
|
||||
auto prop = m_VulkanPhysicalDevice.getProperties();
|
||||
m_RendererString = std::string( prop.deviceName.data() );
|
||||
|
@ -896,19 +939,22 @@ void DeviceManager_VK::destroySwapChain()
|
|||
m_VulkanDevice.waitIdle();
|
||||
}
|
||||
|
||||
while( !m_SwapChainImages.empty() )
|
||||
{
|
||||
auto sci = m_SwapChainImages.back();
|
||||
m_SwapChainImages.pop_back();
|
||||
sci.rhiHandle = nullptr;
|
||||
}
|
||||
|
||||
if( m_SwapChain )
|
||||
{
|
||||
m_VulkanDevice.destroySwapchainKHR( m_SwapChain );
|
||||
m_SwapChain = nullptr;
|
||||
}
|
||||
|
||||
m_SwapChainImages.clear();
|
||||
}
|
||||
|
||||
bool DeviceManager_VK::createSwapChain()
|
||||
{
|
||||
destroySwapChain();
|
||||
|
||||
m_SwapChainFormat =
|
||||
{
|
||||
vk::Format( nvrhi::vulkan::convertFormat( deviceParms.swapChainFormat ) ),
|
||||
|
@ -940,7 +986,7 @@ bool DeviceManager_VK::createSwapChain()
|
|||
.setPQueueFamilyIndices( enableSwapChainSharing ? queues.data() : nullptr )
|
||||
.setPreTransform( vk::SurfaceTransformFlagBitsKHR::eIdentity )
|
||||
.setCompositeAlpha( vk::CompositeAlphaFlagBitsKHR::eOpaque )
|
||||
.setPresentMode( deviceParms.vsyncEnabled ? vk::PresentModeKHR::eFifo : vk::PresentModeKHR::eImmediate )
|
||||
.setPresentMode( deviceParms.vsyncEnabled ? ( r_swapInterval.GetInteger() == 2 || !enablePModeFifoRelaxed ? vk::PresentModeKHR::eFifo : vk::PresentModeKHR::eFifoRelaxed ) : vk::PresentModeKHR::eImmediate )
|
||||
.setClipped( true )
|
||||
.setOldSwapchain( nullptr );
|
||||
|
||||
|
@ -1134,7 +1180,7 @@ void DeviceManager_VK::BeginFrame()
|
|||
vk::Fence(),
|
||||
&m_SwapChainIndex );
|
||||
|
||||
assert( res == vk::Result::eSuccess );
|
||||
assert( res == vk::Result::eSuccess || res == vk::Result::eSuboptimalKHR );
|
||||
|
||||
m_NvrhiDevice->queueWaitForSemaphore( nvrhi::CommandQueue::Graphics, m_PresentSemaphore, 0 );
|
||||
}
|
||||
|
@ -1158,7 +1204,7 @@ void DeviceManager_VK::Present()
|
|||
.setPImageIndices( &m_SwapChainIndex );
|
||||
|
||||
const vk::Result res = m_PresentQueue.presentKHR( &info );
|
||||
assert( res == vk::Result::eSuccess || res == vk::Result::eErrorOutOfDateKHR );
|
||||
assert( res == vk::Result::eSuccess || res == vk::Result::eErrorOutOfDateKHR || res == vk::Result::eSuboptimalKHR );
|
||||
|
||||
if( deviceParms.enableDebugRuntime )
|
||||
{
|
|
@ -970,11 +970,19 @@ sysEvent_t Sys_GetEvent()
|
|||
{
|
||||
int w = ev.window.data1;
|
||||
int h = ev.window.data2;
|
||||
r_windowWidth.SetInteger( w );
|
||||
r_windowHeight.SetInteger( h );
|
||||
|
||||
// SRS - Only save window resized events when in windowed modes
|
||||
if( !renderSystem->IsFullScreen() )
|
||||
{
|
||||
r_windowWidth.SetInteger( w );
|
||||
r_windowHeight.SetInteger( h );
|
||||
}
|
||||
|
||||
glConfig.nativeScreenWidth = w;
|
||||
glConfig.nativeScreenHeight = h;
|
||||
|
||||
// SRS - Make sure ImGui gets new window boundaries
|
||||
ImGuiHook::NotifyDisplaySizeChanged( glConfig.nativeScreenWidth, glConfig.nativeScreenHeight );
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -982,8 +990,13 @@ sysEvent_t Sys_GetEvent()
|
|||
{
|
||||
int x = ev.window.data1;
|
||||
int y = ev.window.data2;
|
||||
r_windowX.SetInteger( x );
|
||||
r_windowY.SetInteger( y );
|
||||
|
||||
// SRS - Only save window moved events when in windowed modes
|
||||
if( !renderSystem->IsFullScreen() )
|
||||
{
|
||||
r_windowX.SetInteger( x );
|
||||
r_windowY.SetInteger( y );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1049,7 +1062,7 @@ sysEvent_t Sys_GetEvent()
|
|||
case SDL_KEYDOWN:
|
||||
if( ev.key.keysym.sym == SDLK_RETURN && ( ev.key.keysym.mod & KMOD_ALT ) > 0 )
|
||||
{
|
||||
// DG: go to fullscreen on current display, instead of always first display
|
||||
/* DG: go to fullscreen on current display, instead of always first display
|
||||
int fullscreen = 0;
|
||||
if( ! renderSystem->IsFullScreen() )
|
||||
{
|
||||
|
@ -1058,7 +1071,10 @@ sysEvent_t Sys_GetEvent()
|
|||
fullscreen = -2;
|
||||
}
|
||||
cvarSystem->SetCVarInteger( "r_fullscreen", fullscreen );
|
||||
// DG end
|
||||
// DG end */
|
||||
// SRS - Until Borderless Fullscreen is implemented properly, use same implementation as on Windows
|
||||
cvarSystem->SetCVarBool( "r_fullscreen", !renderSystem->IsFullScreen() );
|
||||
// SRS end
|
||||
PushConsoleEvent( "vid_restart" );
|
||||
continue; // handle next event
|
||||
}
|
||||
|
|
|
@ -135,21 +135,17 @@ bool DeviceManager::CreateWindowDeviceAndSwapChain( const glimpParms_t& parms, c
|
|||
return false;
|
||||
}
|
||||
|
||||
glConfig.isFullscreen = parms.fullScreen;
|
||||
|
||||
UpdateWindowSize( parms );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeviceManager::UpdateWindowSize( const glimpParms_t& params )
|
||||
void DeviceManager::UpdateWindowSize( const glimpParms_t& parms )
|
||||
{
|
||||
windowVisible = true;
|
||||
|
||||
if( int( deviceParms.backBufferWidth ) != params.width ||
|
||||
int( deviceParms.backBufferHeight ) != params.height ||
|
||||
if( int( deviceParms.backBufferWidth ) != parms.width ||
|
||||
int( deviceParms.backBufferHeight ) != parms.height ||
|
||||
#if ID_MSAA
|
||||
int( deviceParms.backBufferSampleCount ) != params.multiSamples ||
|
||||
int( deviceParms.backBufferSampleCount ) != parms.multiSamples ||
|
||||
#endif
|
||||
( deviceParms.vsyncEnabled != requestedVSync && GetGraphicsAPI() == nvrhi::GraphicsAPI::VULKAN ) )
|
||||
{
|
||||
|
@ -157,16 +153,18 @@ void DeviceManager::UpdateWindowSize( const glimpParms_t& params )
|
|||
|
||||
BackBufferResizing();
|
||||
|
||||
deviceParms.backBufferWidth = params.width;
|
||||
deviceParms.backBufferHeight = params.height;
|
||||
deviceParms.backBufferSampleCount = params.multiSamples;
|
||||
deviceParms.backBufferWidth = parms.width;
|
||||
deviceParms.backBufferHeight = parms.height;
|
||||
deviceParms.backBufferSampleCount = parms.multiSamples;
|
||||
deviceParms.vsyncEnabled = requestedVSync;
|
||||
|
||||
ResizeSwapChain();
|
||||
BackBufferResized();
|
||||
}
|
||||
|
||||
deviceParms.vsyncEnabled = requestedVSync;
|
||||
else
|
||||
{
|
||||
deviceParms.vsyncEnabled = requestedVSync;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -190,6 +188,18 @@ void VKimp_PreInit() // DG: added this function for SDL compatibility
|
|||
}
|
||||
}
|
||||
|
||||
// SRS - Function to get display frequency of monitor hosting the current window
|
||||
static int GetDisplayFrequency( glimpParms_t parms )
|
||||
{
|
||||
SDL_DisplayMode m = {0};
|
||||
if( SDL_GetWindowDisplayMode( window, &m ) < 0 )
|
||||
{
|
||||
common->Warning( "Couldn't get display refresh rate, reason: %s", SDL_GetError() );
|
||||
return parms.displayHz;
|
||||
}
|
||||
|
||||
return m.refresh_rate;
|
||||
}
|
||||
|
||||
/* Eric: Is the majority of this function not needed since switching from GL to Vulkan?
|
||||
===================
|
||||
|
@ -346,6 +356,19 @@ bool VKimp_Init( glimpParms_t parms )
|
|||
continue;
|
||||
}
|
||||
|
||||
// SRS - Make sure display is set to requested refresh rate from the start
|
||||
if( parms.displayHz > 0 && parms.displayHz != GetDisplayFrequency( parms ) )
|
||||
{
|
||||
SDL_DisplayMode m = {0};
|
||||
SDL_GetWindowDisplayMode( window, &m );
|
||||
|
||||
m.refresh_rate = parms.displayHz;
|
||||
if( SDL_SetWindowDisplayMode( window, &m ) < 0 )
|
||||
{
|
||||
common->Warning( "Couldn't set display refresh rate to %i Hz", parms.displayHz );
|
||||
}
|
||||
}
|
||||
|
||||
// RB begin
|
||||
SDL_GetWindowSize( window, &glConfig.nativeScreenWidth, &glConfig.nativeScreenHeight );
|
||||
// RB end
|
||||
|
@ -362,7 +385,7 @@ bool VKimp_Init( glimpParms_t parms )
|
|||
#endif
|
||||
|
||||
// RB begin
|
||||
glConfig.displayFrequency = 60;
|
||||
glConfig.displayFrequency = GetDisplayFrequency( parms );
|
||||
glConfig.isStereoPixelFormat = parms.stereo;
|
||||
glConfig.multisamples = parms.multiSamples;
|
||||
|
||||
|
@ -451,7 +474,7 @@ static bool SetScreenParmsFullscreen( glimpParms_t parms )
|
|||
|
||||
// change settings in that display mode according to parms
|
||||
// FIXME: check if refreshrate, width and height are supported?
|
||||
// m.refresh_rate = parms.displayHz;
|
||||
m.refresh_rate = parms.displayHz;
|
||||
m.w = parms.width;
|
||||
m.h = parms.height;
|
||||
|
||||
|
@ -476,8 +499,10 @@ static bool SetScreenParmsFullscreen( glimpParms_t parms )
|
|||
|
||||
static bool SetScreenParmsWindowed( glimpParms_t parms )
|
||||
{
|
||||
SDL_SetWindowSize( window, parms.width, parms.height );
|
||||
// SRS - handle differences in WM behaviour: for macOS set position first, for linux set it last
|
||||
#if defined(__APPLE__)
|
||||
SDL_SetWindowPosition( window, parms.x, parms.y );
|
||||
#endif
|
||||
|
||||
// if we're currently in fullscreen mode, we need to disable that
|
||||
if( SDL_GetWindowFlags( window ) & SDL_WINDOW_FULLSCREEN )
|
||||
|
@ -488,6 +513,17 @@ static bool SetScreenParmsWindowed( glimpParms_t parms )
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_SetWindowSize( window, parms.width, parms.height );
|
||||
|
||||
// SRS - this logic prevents window position drift on linux when coming in and out of fullscreen
|
||||
#if !defined(__APPLE__)
|
||||
SDL_bool borderState = SDL_GetWindowFlags( window ) & SDL_WINDOW_BORDERLESS ? SDL_FALSE : SDL_TRUE;
|
||||
SDL_SetWindowBordered( window, SDL_FALSE );
|
||||
SDL_SetWindowPosition( window, parms.x, parms.y );
|
||||
SDL_SetWindowBordered( window, borderState );
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -524,7 +560,7 @@ bool VKimp_SetScreenParms( glimpParms_t parms )
|
|||
glConfig.isStereoPixelFormat = parms.stereo;
|
||||
glConfig.nativeScreenWidth = parms.width;
|
||||
glConfig.nativeScreenHeight = parms.height;
|
||||
glConfig.displayFrequency = parms.displayHz;
|
||||
glConfig.displayFrequency = GetDisplayFrequency( parms );
|
||||
glConfig.multisamples = parms.multiSamples;
|
||||
|
||||
return true;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -694,6 +694,8 @@ GetDisplayCoordinates
|
|||
*/
|
||||
static bool GetDisplayCoordinates( const int deviceNum, int& x, int& y, int& width, int& height, int& displayHz )
|
||||
{
|
||||
bool verbose = false;
|
||||
|
||||
idStr deviceName = GetDeviceName( deviceNum );
|
||||
if( deviceName.Length() == 0 )
|
||||
{
|
||||
|
@ -729,24 +731,27 @@ static bool GetDisplayCoordinates( const int deviceNum, int& x, int& y, int& wid
|
|||
return false;
|
||||
}
|
||||
|
||||
common->Printf( "display device: %i\n", deviceNum );
|
||||
common->Printf( " DeviceName : %s\n", device.DeviceName );
|
||||
common->Printf( " DeviceString: %s\n", device.DeviceString );
|
||||
common->Printf( " StateFlags : 0x%x\n", device.StateFlags );
|
||||
common->Printf( " DeviceID : %s\n", device.DeviceID );
|
||||
common->Printf( " DeviceKey : %s\n", device.DeviceKey );
|
||||
common->Printf( " DeviceName : %s\n", monitor.DeviceName );
|
||||
common->Printf( " DeviceString: %s\n", monitor.DeviceString );
|
||||
common->Printf( " StateFlags : 0x%x\n", monitor.StateFlags );
|
||||
common->Printf( " DeviceID : %s\n", monitor.DeviceID );
|
||||
common->Printf( " DeviceKey : %s\n", monitor.DeviceKey );
|
||||
common->Printf( " dmPosition.x : %i\n", devmode.dmPosition.x );
|
||||
common->Printf( " dmPosition.y : %i\n", devmode.dmPosition.y );
|
||||
common->Printf( " dmBitsPerPel : %i\n", devmode.dmBitsPerPel );
|
||||
common->Printf( " dmPelsWidth : %i\n", devmode.dmPelsWidth );
|
||||
common->Printf( " dmPelsHeight : %i\n", devmode.dmPelsHeight );
|
||||
common->Printf( " dmDisplayFlags : 0x%x\n", devmode.dmDisplayFlags );
|
||||
common->Printf( " dmDisplayFrequency: %i\n", devmode.dmDisplayFrequency );
|
||||
if( verbose )
|
||||
{
|
||||
common->Printf("display device: %i\n", deviceNum);
|
||||
common->Printf(" DeviceName : %s\n", device.DeviceName);
|
||||
common->Printf(" DeviceString: %s\n", device.DeviceString);
|
||||
common->Printf(" StateFlags : 0x%x\n", device.StateFlags);
|
||||
common->Printf(" DeviceID : %s\n", device.DeviceID);
|
||||
common->Printf(" DeviceKey : %s\n", device.DeviceKey);
|
||||
common->Printf(" DeviceName : %s\n", monitor.DeviceName);
|
||||
common->Printf(" DeviceString: %s\n", monitor.DeviceString);
|
||||
common->Printf(" StateFlags : 0x%x\n", monitor.StateFlags);
|
||||
common->Printf(" DeviceID : %s\n", monitor.DeviceID);
|
||||
common->Printf(" DeviceKey : %s\n", monitor.DeviceKey);
|
||||
common->Printf(" dmPosition.x : %i\n", devmode.dmPosition.x);
|
||||
common->Printf(" dmPosition.y : %i\n", devmode.dmPosition.y);
|
||||
common->Printf(" dmBitsPerPel : %i\n", devmode.dmBitsPerPel);
|
||||
common->Printf(" dmPelsWidth : %i\n", devmode.dmPelsWidth);
|
||||
common->Printf(" dmPelsHeight : %i\n", devmode.dmPelsHeight);
|
||||
common->Printf(" dmDisplayFlags : 0x%x\n", devmode.dmDisplayFlags);
|
||||
common->Printf(" dmDisplayFrequency: %i\n", devmode.dmDisplayFrequency);
|
||||
}
|
||||
|
||||
x = devmode.dmPosition.x;
|
||||
y = devmode.dmPosition.y;
|
||||
|
@ -1065,6 +1070,29 @@ static bool GLW_GetWindowDimensions( const glimpParms_t parms, int& x, int& y, i
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool GetCenteredWindowDimensions( int& x, int& y, int& w, int& h )
|
||||
{
|
||||
// get position and size of default display for windowed mode (parms.fullScreen = 0)
|
||||
int displayX, displayY, displayW, displayH, displayHz = 0;
|
||||
if( !GetDisplayCoordinates( 0, displayX, displayY, displayW, displayH, displayHz ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// find the centered position not exceeding display bounds
|
||||
const int centreX = displayX + displayW / 2;
|
||||
const int centreY = displayY + displayH / 2;
|
||||
const int left = centreX - w / 2;
|
||||
const int right = left + w;
|
||||
const int top = centreY - h / 2;
|
||||
const int bottom = top + h;
|
||||
x = std::max( left, displayX );
|
||||
y = std::max( top, displayY );
|
||||
w = std::min( right - left, displayW );
|
||||
h = std::min( bottom - top, displayH );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceManager::CreateWindowDeviceAndSwapChain( const glimpParms_t& parms, const char* windowTitle )
|
||||
{
|
||||
|
@ -1074,6 +1102,15 @@ bool DeviceManager::CreateWindowDeviceAndSwapChain( const glimpParms_t& parms, c
|
|||
return false;
|
||||
}
|
||||
|
||||
// SRS - if in windowed mode, start with centered windowed on default display, afterwards use r_windowX / r_windowY
|
||||
if( parms.fullScreen == 0 )
|
||||
{
|
||||
if( !GetCenteredWindowDimensions( x, y, w, h ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int stylebits;
|
||||
int exstyle;
|
||||
|
||||
|
@ -1136,21 +1173,17 @@ bool DeviceManager::CreateWindowDeviceAndSwapChain( const glimpParms_t& parms, c
|
|||
SetForegroundWindow( win32.hWnd );
|
||||
SetFocus( win32.hWnd );
|
||||
|
||||
glConfig.isFullscreen = parms.fullScreen;
|
||||
|
||||
UpdateWindowSize( parms );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeviceManager::UpdateWindowSize( const glimpParms_t& params )
|
||||
void DeviceManager::UpdateWindowSize( const glimpParms_t& parms )
|
||||
{
|
||||
windowVisible = true;
|
||||
|
||||
if( int( deviceParms.backBufferWidth ) != params.width ||
|
||||
int( deviceParms.backBufferHeight ) != params.height ||
|
||||
if( int( deviceParms.backBufferWidth ) != parms.width ||
|
||||
int( deviceParms.backBufferHeight ) != parms.height ||
|
||||
#if ID_MSAA
|
||||
int( deviceParms.backBufferSampleCount ) != params.multiSamples ||
|
||||
int( deviceParms.backBufferSampleCount ) != parms.multiSamples ||
|
||||
#endif
|
||||
( deviceParms.vsyncEnabled != requestedVSync && GetGraphicsAPI() == nvrhi::GraphicsAPI::VULKAN ) )
|
||||
{
|
||||
|
@ -1158,16 +1191,18 @@ void DeviceManager::UpdateWindowSize( const glimpParms_t& params )
|
|||
|
||||
BackBufferResizing();
|
||||
|
||||
deviceParms.backBufferWidth = params.width;
|
||||
deviceParms.backBufferHeight = params.height;
|
||||
deviceParms.backBufferSampleCount = params.multiSamples;
|
||||
deviceParms.backBufferWidth = parms.width;
|
||||
deviceParms.backBufferHeight = parms.height;
|
||||
deviceParms.backBufferSampleCount = parms.multiSamples;
|
||||
deviceParms.vsyncEnabled = requestedVSync;
|
||||
|
||||
ResizeSwapChain();
|
||||
BackBufferResized();
|
||||
}
|
||||
|
||||
deviceParms.vsyncEnabled = requestedVSync;
|
||||
else
|
||||
{
|
||||
deviceParms.vsyncEnabled = requestedVSync;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1375,6 +1410,28 @@ void GLimp_PreInit()
|
|||
// DG: not needed on this platform, so just do nothing
|
||||
}
|
||||
|
||||
// SRS - Function to get display frequency of monitor hosting the current window
|
||||
static int GetDisplayFrequency( glimpParms_t parms )
|
||||
{
|
||||
HMONITOR hMonitor = MonitorFromWindow( win32.hWnd, MONITOR_DEFAULTTOPRIMARY );
|
||||
|
||||
MONITORINFOEX minfo;
|
||||
minfo.cbSize = sizeof( minfo );
|
||||
if( !GetMonitorInfo( hMonitor, &minfo ) )
|
||||
{
|
||||
return parms.displayHz;
|
||||
}
|
||||
|
||||
DEVMODE devmode;
|
||||
devmode.dmSize = sizeof( devmode );
|
||||
if( !EnumDisplaySettings( minfo.szDevice, ENUM_CURRENT_SETTINGS, &devmode ) )
|
||||
{
|
||||
return parms.displayHz;
|
||||
}
|
||||
|
||||
return devmode.dmDisplayFrequency;
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
GLimp_Init
|
||||
|
@ -1455,6 +1512,7 @@ bool GLimp_Init( glimpParms_t parms )
|
|||
glConfig.isStereoPixelFormat = parms.stereo;
|
||||
glConfig.nativeScreenWidth = parms.width;
|
||||
glConfig.nativeScreenHeight = parms.height;
|
||||
glConfig.displayFrequency = GetDisplayFrequency( parms );
|
||||
glConfig.multisamples = parms.multiSamples;
|
||||
|
||||
glConfig.pixelAspect = 1.0f; // FIXME: some monitor modes may be distorted
|
||||
|
@ -1538,11 +1596,11 @@ bool GLimp_SetScreenParms( glimpParms_t parms )
|
|||
glConfig.isFullscreen = parms.fullScreen;
|
||||
glConfig.pixelAspect = 1.0f; // FIXME: some monitor modes may be distorted
|
||||
|
||||
glConfig.isFullscreen = parms.fullScreen;
|
||||
glConfig.isStereoPixelFormat = parms.stereo;
|
||||
glConfig.nativeScreenWidth = parms.width;
|
||||
glConfig.nativeScreenHeight = parms.height;
|
||||
|
||||
deviceManager->UpdateWindowSize( parms );
|
||||
glConfig.displayFrequency = GetDisplayFrequency( parms );
|
||||
glConfig.multisamples = parms.multiSamples;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -179,31 +179,32 @@ LONG WINAPI MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
|
|||
switch( uMsg )
|
||||
{
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
// RB: FIXME this messes with with the window size in a really bad way
|
||||
#if 0
|
||||
if( renderSystem->IsInitialized() )//&& win32.hDC != NULL )
|
||||
// SRS - Needed by ResizeImages() to resize before the start of a frame
|
||||
// SRS - Aspect ratio constraints are controlled by WIN_Sizing() above
|
||||
if( renderSystem->IsInitialized() && win32.hDC != NULL )
|
||||
{
|
||||
RECT rect;
|
||||
if( ::GetClientRect( win32.hWnd, &rect ) )
|
||||
{
|
||||
auto originalWidth = glConfig.nativeScreenWidth;
|
||||
auto originalHeight = glConfig.nativeScreenHeight;
|
||||
if( rect.right > rect.left && rect.bottom > rect.top )
|
||||
{
|
||||
glConfig.nativeScreenWidth = rect.right - rect.left;
|
||||
glConfig.nativeScreenHeight = rect.bottom - rect.top;
|
||||
|
||||
// save the window size in cvars if we aren't fullscreen
|
||||
// SRS - also check renderSystem state to make sure WM doesn't fool us when exiting fullscreen
|
||||
int style = GetWindowLong( hWnd, GWL_STYLE );
|
||||
if( ( style & WS_POPUP ) == 0 )
|
||||
if( ( style & WS_POPUP ) == 0 && !renderSystem->IsFullScreen() )
|
||||
{
|
||||
r_windowWidth.SetInteger( glConfig.nativeScreenWidth );
|
||||
r_windowHeight.SetInteger( glConfig.nativeScreenHeight );
|
||||
}
|
||||
|
||||
// SRS - Inform ImGui that the window size has changed
|
||||
ImGuiHook::NotifyDisplaySizeChanged( glConfig.nativeScreenWidth, glConfig.nativeScreenHeight );
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case WM_MOVE:
|
||||
{
|
||||
|
@ -211,8 +212,9 @@ LONG WINAPI MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
|
|||
RECT r;
|
||||
|
||||
// save the window origin in cvars if we aren't fullscreen
|
||||
// SRS - also check renderSystem state to make sure WM doesn't fool us when exiting fullscreen
|
||||
int style = GetWindowLong( hWnd, GWL_STYLE );
|
||||
if( ( style & WS_POPUP ) == 0 )
|
||||
if( ( style & WS_POPUP ) == 0 && !renderSystem->IsFullScreen() )
|
||||
{
|
||||
xPos = ( short ) LOWORD( lParam ); // horizontal position
|
||||
yPos = ( short ) HIWORD( lParam ); // vertical position
|
||||
|
|
Loading…
Reference in a new issue