Implement GLimp_SetScreenParms() for "vid_restart partial"

"vid_restart partial" only changes the window size or its fullscreen
(or windowed) state, without recreating everything.
If that fails (or antialiasing settings have changed), it will fall back
to a full vid_restart (this behavior is different than original
 "vid_restart partial" that probably was implemented in Vanilla Doom3
 but not dhewm3)

This is used for Alt-Enter (which toggles between fullscreen and
windowed state) and when pressing the Apply button in the new Video Menu
This commit is contained in:
Daniel Gibson 2024-06-11 01:56:27 +02:00
parent ac8eec932b
commit 44d19a4175
4 changed files with 136 additions and 40 deletions

View file

@ -1757,9 +1757,7 @@ static void ApplyVideoSettings()
int msaa = ( msaaModeIndex > 0 ) ? ( 1 << msaaModeIndex ) : 0;
r_multiSamples.SetInteger( msaa );
cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "vid_restart\n" );
// TODO: if only fullscreen is changed, the following might suffice
//cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "vid_restart partial windowed\n" );
cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "vid_restart partial\n" );
}
static void InitVideoOptionsMenu()
@ -1859,7 +1857,6 @@ static void DrawVideoOptionsMenu()
if ( !VideoHasApplyableChanges() ) {
ImGui::BeginDisabled();
ImGui::Button( "Apply" );
// TODO: the tooltips backgrounds are transparent (due to this being disabled), which sucks
AddTooltip( "No changes were made, so there's nothing to apply" );
ImGui::SameLine();
ImGui::Button( "Reset" );

View file

@ -1961,12 +1961,6 @@ void R_VidRestart_f( const idCmdArgs &args ) {
return;
}
// DG: notify the game DLL about the reloadImages and vid_restart commands
if(gameCallbacks.reloadImagesCB != NULL)
{
gameCallbacks.reloadImagesCB(gameCallbacks.reloadImagesUserArg, args);
}
bool full = true;
bool forceWindow = false;
for ( int i = 1 ; i < args.Argc() ; i++ ) {
@ -1980,6 +1974,38 @@ void R_VidRestart_f( const idCmdArgs &args ) {
}
}
// DG: in partial mode, try to just resize the window (and make it fullscreen or windowed)
// instead of doing a full vid_restart. Still falls back to a full vid_restart
// in case this doesn't work (for example because MSAA settings have changed)
if ( !full ) {
int wantedWidth=0, wantedHeight=0;
if ( !R_GetModeInfo( &wantedWidth, &wantedHeight, r_mode.GetInteger() ) ) {
common->Warning( "vid_restart: R_GetModeInfo() failed?!\n" );
} else {
glimpParms_t parms;
parms.width = wantedWidth;
parms.height = wantedHeight;
parms.fullScreen = ( forceWindow ) ? false : r_fullscreen.GetBool();
parms.displayHz = r_displayRefresh.GetInteger();
// "vid_restart partial windowed" is used in case of errors to return to windowed mode
// before things explode more. in that case just keep whatever MSAA setting is active
parms.multiSamples = forceWindow ? -1 : r_multiSamples.GetInteger();
parms.stereo = false;
if ( GLimp_SetScreenParms( parms ) ) {
common->Printf( "'vid_restart partial' succeeded in changing resolution and/or fullscreen mode" );
return;
}
}
}
// DG: notify the game DLL about the reloadImages and (non-partial) vid_restart commands
if(gameCallbacks.reloadImagesCB != NULL)
{
gameCallbacks.reloadImagesCB(gameCallbacks.reloadImagesUserArg, args);
}
// this could take a while, so give them the cursor back ASAP
Sys_GrabMouseCursor( false );
@ -1998,37 +2024,24 @@ void R_VidRestart_f( const idCmdArgs &args ) {
// sound and input are tied to the window we are about to destroy
if ( full ) {
// free all of our texture numbers
soundSystem->ShutdownHW();
Sys_ShutdownInput();
globalImages->PurgeAllImages();
// free the context and close the window
GLimp_Shutdown();
glConfig.isInitialized = false;
// free all of our texture numbers
soundSystem->ShutdownHW();
Sys_ShutdownInput();
globalImages->PurgeAllImages();
// free the context and close the window
GLimp_Shutdown();
glConfig.isInitialized = false;
// create the new context and vertex cache
bool latch = cvarSystem->GetCVarBool( "r_fullscreen" );
if ( forceWindow ) {
cvarSystem->SetCVarBool( "r_fullscreen", false );
}
R_InitOpenGL();
cvarSystem->SetCVarBool( "r_fullscreen", latch );
// regenerate all images
globalImages->ReloadAllImages();
} else {
glimpParms_t parms;
parms.width = glConfig.winWidth; // DG: HighDPI adjustment: explicitly use window size
parms.height = glConfig.winHeight;
parms.fullScreen = ( forceWindow ) ? false : r_fullscreen.GetBool();
parms.displayHz = r_displayRefresh.GetInteger();
parms.multiSamples = r_multiSamples.GetInteger();
parms.stereo = false;
GLimp_SetScreenParms( parms );
// create the new context and vertex cache
bool latch = cvarSystem->GetCVarBool( "r_fullscreen" );
if ( forceWindow ) {
cvarSystem->SetCVarBool( "r_fullscreen", false );
}
R_InitOpenGL();
cvarSystem->SetCVarBool( "r_fullscreen", latch );
// regenerate all images
globalImages->ReloadAllImages();
// make sure the regeneration doesn't use anything no longer valid
tr.viewCount++;

View file

@ -1190,7 +1190,7 @@ sysEvent_t Sys_GetEvent() {
case SDL_KEYDOWN:
if (ev.key.keysym.sym == SDLK_RETURN && (ev.key.keysym.mod & KMOD_ALT) > 0) {
cvarSystem->SetCVarBool("r_fullscreen", !renderSystem->IsFullScreen());
PushConsoleEvent("vid_restart");
PushConsoleEvent("vid_restart partial");
return res_none;
}

View file

@ -608,8 +608,94 @@ GLimp_SetScreenParms
===================
*/
bool GLimp_SetScreenParms(glimpParms_t parms) {
common->DPrintf("TODO: GLimp_ActivateContext\n");
#if SDL_VERSION_ATLEAST(2, 0, 0)
int curMultiSamples = 0;
if ( SDL_GL_GetAttribute( SDL_GL_MULTISAMPLEBUFFERS, &curMultiSamples ) == 0 && curMultiSamples > 0 ) {
if ( SDL_GL_GetAttribute( SDL_GL_MULTISAMPLESAMPLES, &curMultiSamples ) != 0 ) {
curMultiSamples = 0; // SDL_GL_GetAttribute() call failed, assume no MSAA
}
} else {
curMultiSamples = 0; // SDL_GL_GetAttribute() call failed, assume no MSAA
}
if( parms.multiSamples != -1 && parms.multiSamples != curMultiSamples ) {
// if MSAA settings have changed, we really need a vid_restart
return false;
}
Uint32 winFlags = SDL_GetWindowFlags( window );
bool isFullscreen = (winFlags & SDL_WINDOW_FULLSCREEN) != 0;
bool isFullscreenDesktop = (winFlags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP;
bool wantFullscreenDesktop = parms.fullScreen && r_fullscreenDesktop.GetBool();
// TODO: parms.displayHz ?
if ( isFullscreenDesktop && wantFullscreenDesktop ) {
return true; // nothing to do (resolution is not configurable in that mode)
}
if ( !parms.fullScreen ) { // we want windowed mode
if ( isFullscreen && SDL_SetWindowFullscreen( window, 0 ) != 0 ) {
common->Warning( "GLimp_SetScreenParms(): Couldn't switch to windowed mode, SDL error: %s\n", SDL_GetError() );
return false;
}
SDL_RestoreWindow( window ); // make sure we're not maximized, then setting the size wouldn't work
SDL_SetWindowSize( window, parms.width, parms.height );
} else { // we want some kind of fullscreen mode
// it's probably safest to first switch to windowed mode
if ( isFullscreen ) {
SDL_SetWindowFullscreen( window, 0 );
}
if ( wantFullscreenDesktop ) {
if ( SDL_SetWindowFullscreen( window, SDL_WINDOW_FULLSCREEN_DESKTOP ) != 0 ) {
common->Warning( "GLimp_SetScreenParms(): Couldn't switch to fullscreen desktop mode, SDL error: %s\n", SDL_GetError() );
return false;
}
} else { // want real fullscreen
SDL_DisplayMode wanted_mode = {};
wanted_mode.w = parms.width;
wanted_mode.h = parms.height;
// TODO: refresh rate? parms.displayHz should probably try to get most similar mode before trying to set it?
if ( SDL_SetWindowDisplayMode( window, &wanted_mode ) != 0 )
{
common->Warning("GLimp_SetScreenParms(): Can't set fullscreen resolution to %ix%i: %s\n", wanted_mode.w, wanted_mode.h, SDL_GetError());
return false;
}
/* The SDL doku says, that SDL_SetWindowSize() shouldn't be
used on fullscreen windows. But at least in my test with
SDL 2.0.9 the subsequent SDL_GetWindowDisplayMode() fails
if I don't call it. */
SDL_SetWindowSize( window, wanted_mode.w, wanted_mode.h );
SDL_DisplayMode real_mode = {};
if ( SDL_GetWindowDisplayMode( window, &real_mode ) != 0 )
{
common->Warning( "GLimp_SetScreenParms(): Can't get display mode: %s\n", SDL_GetError() );
return false; // trying other color depth etc is unlikely to help with this issue
}
if ( (real_mode.w != wanted_mode.w) || (real_mode.h != wanted_mode.h) )
{
common->Warning( "GLimp_SetScreenParms(): Still in wrong display mode: %ix%i instead of %ix%i\n",
real_mode.w, real_mode.h, wanted_mode.w, wanted_mode.h );
return false;
}
}
}
return true;
#else // SDL1.2 - I don't feel like implementing this for old SDL, just do a full vid_restart, like before
return false;
#endif
}
/*