Skip to content

Commit a017743

Browse files
authored
[GEN][ZH] Fix crash when launching the game with an unsupported Display Resolution or when the graphics adapter does not support 800 x 600 (#1055)
1 parent 9862994 commit a017743

File tree

2 files changed

+134
-61
lines changed
  • GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient
  • Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient

2 files changed

+134
-61
lines changed

Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp

Lines changed: 67 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,10 @@ static void drawFramerateBar(void);
115115
#endif
116116

117117
// DEFINE AND ENUMS ///////////////////////////////////////////////////////////
118-
#define W3D_DISPLAY_DEFAULT_BIT_DEPTH 32
118+
#define DEFAULT_DISPLAY_BIT_DEPTH 32
119+
#define MIN_DISPLAY_BIT_DEPTH 16
120+
#define MIN_DISPLAY_RESOLUTION_X 800
121+
#define MIN_DISPLAY_RESOLUTION_Y 600
119122

120123
#define no_SAMPLE_DYNAMIC_LIGHT 1
121124
#ifdef SAMPLE_DYNAMIC_LIGHT
@@ -668,38 +671,73 @@ void W3DDisplay::init( void )
668671
m_2DRender = NEW Render2DClass;
669672
DEBUG_ASSERTCRASH( m_2DRender, ("Cannot create Render2DClass") );
670673

671-
// set our default width and height and bit depth
672-
/// @todo we should set this according to options read from a file
673-
setWidth( TheGlobalData->m_xResolution );
674-
setHeight( TheGlobalData->m_yResolution );
675-
setBitDepth( W3D_DISPLAY_DEFAULT_BIT_DEPTH );
676-
677-
if( WW3D::Set_Render_Device( 0,
678-
getWidth(),
679-
getHeight(),
680-
getBitDepth(),
681-
getWindowed(),
682-
true ) != WW3D_ERROR_OK )
674+
WW3DErrorType renderDeviceError;
675+
Int attempt = 0;
676+
do
683677
{
684-
// Getting the device at the default bit depth (32) didn't work, so try
685-
// getting a 16 bit display. (Voodoo 1-3 only supported 16 bit.) jba.
686-
setBitDepth( 16 );
687-
if( WW3D::Set_Render_Device( 0,
688-
getWidth(),
689-
getHeight(),
690-
getBitDepth(),
691-
getWindowed(),
692-
true ) != WW3D_ERROR_OK )
678+
switch (attempt)
693679
{
694-
695-
WW3D::Shutdown();
696-
WWMath::Shutdown();
697-
throw ERROR_INVALID_D3D; //failed to initialize. User probably doesn't have DX 8.1
698-
DEBUG_ASSERTCRASH( 0, ("Unable to set render device\n") );
699-
return;
680+
case 0:
681+
{
682+
// set our default width and height and bit depth
683+
setWidth( TheGlobalData->m_xResolution );
684+
setHeight( TheGlobalData->m_yResolution );
685+
setBitDepth( DEFAULT_DISPLAY_BIT_DEPTH );
686+
break;
687+
}
688+
case 1:
689+
{
690+
// Getting the device at the default bit depth (32) didn't work, so try
691+
// getting a 16 bit display. (Voodoo 1-3 only supported 16 bit.) jba.
692+
setBitDepth( MIN_DISPLAY_BIT_DEPTH );
693+
break;
694+
}
695+
case 2:
696+
{
697+
// TheSuperHackers @bugfix xezon 11/06/2025 Now tries a safe default resolution
698+
// if the custom resolution did not succeed. This is unlikely to happen but is possible
699+
// if the user writes an unsupported resolution in the Option Preferences or if the
700+
// graphics adapter does not support the minimum display resolution to begin with.
701+
Int xres = MIN_DISPLAY_RESOLUTION_X;
702+
Int yres = MIN_DISPLAY_RESOLUTION_Y;
703+
Int bitDepth = DEFAULT_DISPLAY_BIT_DEPTH;
704+
Int displayModeCount = getDisplayModeCount();
705+
Int displayModeIndex = 0;
706+
for (; displayModeIndex < displayModeCount; ++displayModeIndex)
707+
{
708+
getDisplayModeDescription(displayModeIndex, &xres, &yres, &bitDepth);
709+
if (xres * yres >= MIN_DISPLAY_RESOLUTION_X * MIN_DISPLAY_RESOLUTION_Y)
710+
break; // Is good enough. Use it.
711+
}
712+
TheWritableGlobalData->m_xResolution = xres;
713+
TheWritableGlobalData->m_yResolution = yres;
714+
setWidth( xres );
715+
setHeight( yres );
716+
setBitDepth( bitDepth );
717+
break;
718+
}
700719
}
701720

702-
} // end if
721+
renderDeviceError = WW3D::Set_Render_Device(
722+
0,
723+
getWidth(),
724+
getHeight(),
725+
getBitDepth(),
726+
getWindowed(),
727+
true );
728+
729+
++attempt;
730+
}
731+
while (attempt < 3 && renderDeviceError != WW3D_ERROR_OK);
732+
733+
if (renderDeviceError != WW3D_ERROR_OK)
734+
{
735+
WW3D::Shutdown();
736+
WWMath::Shutdown();
737+
throw ERROR_INVALID_D3D; //failed to initialize. User probably doesn't have DX 8.1
738+
DEBUG_ASSERTCRASH( 0, ("Unable to set render device\n") );
739+
return;
740+
}
703741

704742
//Check if level was never set and default to setting most suitable for system.
705743
if (TheGameLODManager->getStaticLODLevel() == STATIC_GAME_LOD_UNKNOWN)

GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp

Lines changed: 67 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,10 @@ static void drawFramerateBar(void);
116116
#endif
117117

118118
// DEFINE AND ENUMS ///////////////////////////////////////////////////////////
119-
#define W3D_DISPLAY_DEFAULT_BIT_DEPTH 32
119+
#define DEFAULT_DISPLAY_BIT_DEPTH 32
120+
#define MIN_DISPLAY_BIT_DEPTH 16
121+
#define MIN_DISPLAY_RESOLUTION_X 800
122+
#define MIN_DISPLAY_RESOLUTION_Y 600
120123

121124
#define no_SAMPLE_DYNAMIC_LIGHT 1
122125
#ifdef SAMPLE_DYNAMIC_LIGHT
@@ -478,9 +481,6 @@ W3DDisplay::~W3DDisplay()
478481

479482
} // end ~W3DDisplay
480483

481-
#define MIN_DISPLAY_RESOLUTION_X 800
482-
#define MIN_DISPLAY_RESOLUTOIN_Y 600
483-
484484

485485
Bool IS_FOUR_BY_THREE_ASPECT( Real x, Real y )
486486
{
@@ -735,38 +735,73 @@ void W3DDisplay::init( void )
735735
m_2DRender = NEW Render2DClass;
736736
DEBUG_ASSERTCRASH( m_2DRender, ("Cannot create Render2DClass") );
737737

738-
// set our default width and height and bit depth
739-
/// @todo we should set this according to options read from a file
740-
setWidth( TheGlobalData->m_xResolution );
741-
setHeight( TheGlobalData->m_yResolution );
742-
setBitDepth( W3D_DISPLAY_DEFAULT_BIT_DEPTH );
743-
744-
if( WW3D::Set_Render_Device( 0,
745-
getWidth(),
746-
getHeight(),
747-
getBitDepth(),
748-
getWindowed(),
749-
true ) != WW3D_ERROR_OK )
738+
WW3DErrorType renderDeviceError;
739+
Int attempt = 0;
740+
do
750741
{
751-
// Getting the device at the default bit depth (32) didn't work, so try
752-
// getting a 16 bit display. (Voodoo 1-3 only supported 16 bit.) jba.
753-
setBitDepth( 16 );
754-
if( WW3D::Set_Render_Device( 0,
755-
getWidth(),
756-
getHeight(),
757-
getBitDepth(),
758-
getWindowed(),
759-
true ) != WW3D_ERROR_OK )
742+
switch (attempt)
760743
{
761-
762-
WW3D::Shutdown();
763-
WWMath::Shutdown();
764-
throw ERROR_INVALID_D3D; //failed to initialize. User probably doesn't have DX 8.1
765-
DEBUG_ASSERTCRASH( 0, ("Unable to set render device\n") );
766-
return;
744+
case 0:
745+
{
746+
// set our default width and height and bit depth
747+
setWidth( TheGlobalData->m_xResolution );
748+
setHeight( TheGlobalData->m_yResolution );
749+
setBitDepth( DEFAULT_DISPLAY_BIT_DEPTH );
750+
break;
751+
}
752+
case 1:
753+
{
754+
// Getting the device at the default bit depth (32) didn't work, so try
755+
// getting a 16 bit display. (Voodoo 1-3 only supported 16 bit.) jba.
756+
setBitDepth( MIN_DISPLAY_BIT_DEPTH );
757+
break;
758+
}
759+
case 2:
760+
{
761+
// TheSuperHackers @bugfix xezon 11/06/2025 Now tries a safe default resolution
762+
// if the custom resolution did not succeed. This is unlikely to happen but is possible
763+
// if the user writes an unsupported resolution in the Option Preferences or if the
764+
// graphics adapter does not support the minimum display resolution to begin with.
765+
Int xres = MIN_DISPLAY_RESOLUTION_X;
766+
Int yres = MIN_DISPLAY_RESOLUTION_Y;
767+
Int bitDepth = DEFAULT_DISPLAY_BIT_DEPTH;
768+
Int displayModeCount = getDisplayModeCount();
769+
Int displayModeIndex = 0;
770+
for (; displayModeIndex < displayModeCount; ++displayModeIndex)
771+
{
772+
getDisplayModeDescription(displayModeIndex, &xres, &yres, &bitDepth);
773+
if (xres * yres >= MIN_DISPLAY_RESOLUTION_X * MIN_DISPLAY_RESOLUTION_Y)
774+
break; // Is good enough. Use it.
775+
}
776+
TheWritableGlobalData->m_xResolution = xres;
777+
TheWritableGlobalData->m_yResolution = yres;
778+
setWidth( xres );
779+
setHeight( yres );
780+
setBitDepth( bitDepth );
781+
break;
782+
}
767783
}
768784

769-
} // end if
785+
renderDeviceError = WW3D::Set_Render_Device(
786+
0,
787+
getWidth(),
788+
getHeight(),
789+
getBitDepth(),
790+
getWindowed(),
791+
true );
792+
793+
++attempt;
794+
}
795+
while (attempt < 3 && renderDeviceError != WW3D_ERROR_OK);
796+
797+
if (renderDeviceError != WW3D_ERROR_OK)
798+
{
799+
WW3D::Shutdown();
800+
WWMath::Shutdown();
801+
throw ERROR_INVALID_D3D; //failed to initialize. User probably doesn't have DX 8.1
802+
DEBUG_ASSERTCRASH( 0, ("Unable to set render device\n") );
803+
return;
804+
}
770805

771806
//Check if level was never set and default to setting most suitable for system.
772807
if (TheGameLODManager->getStaticLODLevel() == STATIC_GAME_LOD_UNKNOWN)

0 commit comments

Comments
 (0)