Fixed resolution changing on linux: previously the resolution was

changed (and the old window/device deleted) while the old device was
still actively delivering events, so deleting caused a crash. Now
changing the resolution is only setting a flag, and the resolution
change will be applied during the next update, i.e. while the device is
not busy anymore.


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@6707 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2010-11-23 23:23:40 +00:00
parent fa80d310c5
commit daf2bc5e7e
2 changed files with 56 additions and 34 deletions

View File

@ -52,8 +52,8 @@ const int MIN_SUPPORTED_WIDTH = 800;
IrrDriver::IrrDriver() IrrDriver::IrrDriver()
{ {
m_res_switching = false; m_resolution_changing = RES_CHANGE_NONE;
m_device = NULL; m_device = NULL;
file_manager->dropFileSystem(); file_manager->dropFileSystem();
initDevice(); initDevice();
} // IrrDriver } // IrrDriver
@ -317,19 +317,22 @@ void IrrDriver::changeResolution(const int w, const int h, const bool fullscreen
UserConfigParams::m_height = h; UserConfigParams::m_height = h;
UserConfigParams::m_fullscreen = fullscreen; UserConfigParams::m_fullscreen = fullscreen;
doApplyResSettings(); // Setting this flag will trigger a call to applyResolutionSetting()
// in the next update call. This avoids the problem that changeResolution
new ConfirmResolutionDialog(); // is actually called from the gui, i.e. the event loop, i.e. while the
} // old device is active - so we can't delete this device (which we must
// do in applyResolutionSettings
m_resolution_changing = RES_CHANGE_YES;
} // changeResolution
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void IrrDriver::doApplyResSettings() void IrrDriver::applyResolutionSettings()
{ {
m_res_switching = true; // show black before resolution switch so we don't see OpenGL's buffer
// garbage during switch
// show black before resolution switch so we don't see OpenGL's buffer garbage during switch m_device->getVideoDriver()->beginScene(true, true,
m_device->getVideoDriver()->beginScene(true, true, video::SColor(255,100,101,140)); video::SColor(255,100,101,140));
m_device->getVideoDriver()->draw2DRectangle( SColor(255, 0, 0, 0), m_device->getVideoDriver()->draw2DRectangle( SColor(255, 0, 0, 0),
core::rect<s32>(0, 0, core::rect<s32>(0, 0,
UserConfigParams::m_prev_width, UserConfigParams::m_prev_width,
@ -407,8 +410,17 @@ void IrrDriver::cancelResChange()
UserConfigParams::m_width = UserConfigParams::m_prev_width; UserConfigParams::m_width = UserConfigParams::m_prev_width;
UserConfigParams::m_height = UserConfigParams::m_prev_height; UserConfigParams::m_height = UserConfigParams::m_prev_height;
UserConfigParams::m_fullscreen = UserConfigParams::m_prev_fullscreen; UserConfigParams::m_fullscreen = UserConfigParams::m_prev_fullscreen;
doApplyResSettings(); // This will trigger calling applyResolutionSettings in update(). This is
// necessary to avoid that the old screen is deleted, while it is
// still active (i.e. sending out events which triggered the change
// of resolution // Setting this flag will trigger a call to applyResolutionSetting()
// in the next update call. This avoids the problem that changeResolution
// is actually called from the gui, i.e. the event loop, i.e. while the
// old device is active - so we can't delete this device (which we must
// do in applyResolutionSettings)
m_resolution_changing=RES_CHANGE_CANCEL;
} // cancelResChange } // cancelResChange
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -420,15 +432,15 @@ void IrrDriver::printRenderStats()
{ {
io::IAttributes * attr = m_scene_manager->getParameters(); io::IAttributes * attr = m_scene_manager->getParameters();
printf("[%ls], FPS:%3d Tri:%.03fm Cull %d/%d nodes (%d,%d,%d)\n", printf("[%ls], FPS:%3d Tri:%.03fm Cull %d/%d nodes (%d,%d,%d)\n",
m_video_driver->getName(), m_video_driver->getName(),
m_video_driver->getFPS (), m_video_driver->getFPS (),
(f32) m_video_driver->getPrimitiveCountDrawn( 0 ) * ( 1.f / 1000000.f ), (f32) m_video_driver->getPrimitiveCountDrawn( 0 ) * ( 1.f / 1000000.f ),
attr->getAttributeAsInt ( "culled" ), attr->getAttributeAsInt ( "culled" ),
attr->getAttributeAsInt ( "calls" ), attr->getAttributeAsInt ( "calls" ),
attr->getAttributeAsInt ( "drawn_solid" ), attr->getAttributeAsInt ( "drawn_solid" ),
attr->getAttributeAsInt ( "drawn_transparent" ), attr->getAttributeAsInt ( "drawn_transparent" ),
attr->getAttributeAsInt ( "drawn_transparent_effect" ) attr->getAttributeAsInt ( "drawn_transparent_effect" )
); );
} // printRenderStats } // printRenderStats
@ -818,16 +830,22 @@ void IrrDriver::displayFPS()
*/ */
void IrrDriver::update(float dt) void IrrDriver::update(float dt)
{ {
// If the resolution should be switched, do it now. This will delete the
// old device and create a new one.
if (m_resolution_changing!=RES_CHANGE_NONE)
{
applyResolutionSettings();
if(m_resolution_changing==RES_CHANGE_YES)
new ConfirmResolutionDialog();
m_resolution_changing = RES_CHANGE_NONE;
}
if (!m_device->run()) if (!m_device->run())
{ {
// FIXME: I have NO idea why, after performing resolution switch, the irrlicht device asks once to be deleted main_loop->abort();
if (m_res_switching) m_res_switching = false;
else main_loop->abort();
}
else if (m_res_switching)
{
m_res_switching = false;
} }
World *world = World::getWorld(); World *world = World::getWorld();

View File

@ -60,9 +60,13 @@ private:
/** Irrlicht race font. */ /** Irrlicht race font. */
irr::gui::IGUIFont *m_race_font; irr::gui::IGUIFont *m_race_font;
/** Flag set during resolution switching, so that the game doesn't think it needs /** Flag to indicate if a resolution change is pending (which will be
* to exit because no frame is open */ * acted upon in the next update). None means no change, yes means
bool m_res_switching; * change to new resolution and trigger confirmation dialog.
* Cancel indicates a change of the resolution (back to the original
* one), but no confirmation dialog. */
enum {RES_CHANGE_NONE, RES_CHANGE_YES,
RES_CHANGE_CANCEL} m_resolution_changing;
void setAllMaterialFlags(scene::IAnimatedMesh *mesh) const; void setAllMaterialFlags(scene::IAnimatedMesh *mesh) const;
std::vector<VideoMode> m_modes; std::vector<VideoMode> m_modes;
@ -74,7 +78,7 @@ private:
bool m_pointer_shown; bool m_pointer_shown;
/** Internal method that applies the resolution in user settings. */ /** Internal method that applies the resolution in user settings. */
void doApplyResSettings(); void applyResolutionSettings();
public: public:
IrrDriver(); IrrDriver();
@ -136,7 +140,7 @@ public:
/** Call to change resolution */ /** Call to change resolution */
void changeResolution(const int w, const int h, const bool fullscreen); void changeResolution(const int w, const int h, const bool fullscreen);
/** Call this to roll back to the previous resolution if a resolution switch attempt goes bad */ /** Call this to roll back to the previous resolution if a resolution switch attempt goes bad */
void cancelResChange(); void cancelResChange();
void showPointer(); void showPointer();