1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-15 20:03:15 +02:00

Run all rendering with pim lock if possible

This commit is contained in:
AlexVinS
2014-07-03 22:05:59 +04:00
parent 30d6eab20b
commit 9b8ad51cd3
7 changed files with 77 additions and 36 deletions

View File

@@ -119,6 +119,7 @@ CPlayerInterface::CPlayerInterface(PlayerColor Player)
duringMovement = false; duringMovement = false;
ignoreEvents = false; ignoreEvents = false;
locked = false;
} }
CPlayerInterface::~CPlayerInterface() CPlayerInterface::~CPlayerInterface()
@@ -1528,31 +1529,11 @@ bool CPlayerInterface::ctrlPressed() const
void CPlayerInterface::update() void CPlayerInterface::update()
{ {
// Updating GUI requires locking pim mutex (that protects screen and GUI state). if (!locked)
// When ending the game, the pim mutex might be hold by other thread,
// that will notify us about the ending game by setting terminate_cond flag.
bool acquiredTheLockOnPim = false; //for tracking whether pim mutex locking succeeded
while(!terminate_cond.get() && !(acquiredTheLockOnPim = pim->try_lock())) //try acquiring long until it succeeds or we are told to terminate
boost::this_thread::sleep(boost::posix_time::milliseconds(15));
if(!acquiredTheLockOnPim)
{ {
// We broke the while loop above and not because of mutex, so we must be terminating. logGlobal->errorStream() << "Non synchronized update of PlayerInterface";
assert(terminate_cond.get());
return; return;
} }
// If we are here, pim mutex has been successfully locked - let's store it in a safe RAII lock.
boost::unique_lock<boost::recursive_mutex> un(*pim, boost::adopt_lock);
// While mutexes were locked away we may be have stopped being the active interface
if(LOCPLINT != this)
return;
// Make sure that gamestate won't change when GUI objects may obtain its parts on event processing or drawing request
boost::shared_lock<boost::shared_mutex> gsLock(cb->getGsMutex());
//if there are any waiting dialogs, show them //if there are any waiting dialogs, show them
if((howManyPeople <= 1 || makingTurn) && !dialogs.empty() && !showingDialog->get()) if((howManyPeople <= 1 || makingTurn) && !dialogs.empty() && !showingDialog->get())
{ {
@@ -1580,6 +1561,38 @@ void CPlayerInterface::update()
GH.drawFPSCounter(); GH.drawFPSCounter();
} }
void CPlayerInterface::runLocked(std::function<void(IUpdateable * )> functor)
{
// Updating GUI requires locking pim mutex (that protects screen and GUI state).
// When ending the game, the pim mutex might be hold by other thread,
// that will notify us about the ending game by setting terminate_cond flag.
bool acquiredTheLockOnPim = false; //for tracking whether pim mutex locking succeeded
while(!terminate_cond.get() && !(acquiredTheLockOnPim = pim->try_lock())) //try acquiring long until it succeeds or we are told to terminate
boost::this_thread::sleep(boost::posix_time::milliseconds(15));
if(!acquiredTheLockOnPim)
{
// We broke the while loop above and not because of mutex, so we must be terminating.
assert(terminate_cond.get());
return;
}
// If we are here, pim mutex has been successfully locked - let's store it in a safe RAII lock.
boost::unique_lock<boost::recursive_mutex> un(*pim, boost::adopt_lock);
// While mutexes were locked away we may be have stopped being the active interface
if(LOCPLINT != this)
return;
// Make sure that gamestate won't change when GUI objects may obtain its parts on event processing or drawing request
boost::shared_lock<boost::shared_mutex> gsLock(cb->getGsMutex());
locked = true;
functor(this);
locked = false;
}
int CPlayerInterface::getLastIndex( std::string namePrefix) int CPlayerInterface::getLastIndex( std::string namePrefix)
{ {
using namespace boost::filesystem; using namespace boost::filesystem;

View File

@@ -129,7 +129,8 @@ public:
} }
} spellbookSettings; } spellbookSettings;
void update(); void update() override;
void runLocked(std::function<void(IUpdateable * )> functor) override;
void initializeHeroTownList(); void initializeHeroTownList();
int getLastIndex(std::string namePrefix); int getLastIndex(std::string namePrefix);
@@ -289,6 +290,8 @@ private:
bool duringMovement; bool duringMovement;
bool ignoreEvents; bool ignoreEvents;
bool locked;
void doMoveHero(const CGHeroInstance *h, CGPath path); void doMoveHero(const CGHeroInstance *h, CGPath path);
}; };

View File

@@ -538,6 +538,12 @@ void CGPreGame::update()
GH.drawFPSCounter(); GH.drawFPSCounter();
} }
void CGPreGame::runLocked(std::function<void(IUpdateable * )> cb)
{
boost::unique_lock<boost::recursive_mutex> lock(*CPlayerInterface::pim);
cb(this);
}
void CGPreGame::openCampaignScreen(std::string name) void CGPreGame::openCampaignScreen(std::string name)
{ {
if (vstd::contains(CGPreGameConfig::get().getCampaigns().Struct(), name)) if (vstd::contains(CGPreGameConfig::get().getCampaigns().Struct(), name))

View File

@@ -603,6 +603,7 @@ public:
~CGPreGame(); ~CGPreGame();
void update(); void update();
void runLocked(std::function<void(IUpdateable * )> cb) override;
void openSel(CMenuScreen::EState type, CMenuScreen::EMultiMode multi = CMenuScreen::SINGLE_PLAYER); void openSel(CMenuScreen::EState type, CMenuScreen::EMultiMode multi = CMenuScreen::SINGLE_PLAYER);
void openCampaignScreen(std::string name); void openCampaignScreen(std::string name);

View File

@@ -409,21 +409,28 @@ void CGuiHandler::fakeMouseMove()
void CGuiHandler::renderFrame() void CGuiHandler::renderFrame()
{ {
auto doUpdate = [](IUpdateable * target)
{
if(nullptr != target)
target -> update();
// draw the mouse cursor and update the screen
CCS->curh->render();
#ifndef VCMI_SDL1
if(0 != SDL_RenderCopy(mainRenderer, screenTexture, nullptr, nullptr))
logGlobal->errorStream() << __FUNCTION__ << " SDL_RenderCopy " << SDL_GetError();
SDL_RenderPresent(mainRenderer);
#endif
};
if(curInt) if(curInt)
curInt->update(); // calls a update and drawing process of the loaded game interface object at the moment curInt->runLocked(doUpdate);
else
// draw the mouse cursor and update the screen doUpdate(nullptr);
CCS->curh->render();
#ifndef VCMI_SDL1
if(0 != SDL_RenderCopy(mainRenderer, screenTexture, nullptr, nullptr))
logGlobal->errorStream() << __FUNCTION__ << " SDL_RenderCopy " << SDL_GetError();
SDL_RenderPresent(mainRenderer);
#endif
mainFPSmng->framerateDelay(); // holds a constant FPS
mainFPSmng->framerateDelay(); // holds a constant FPS
} }

View File

@@ -4,6 +4,14 @@
#include "SDL_Extensions.h" #include "SDL_Extensions.h"
#include "../CMessage.h" #include "../CMessage.h"
void IUpdateable::runLocked(std::function<void(IUpdateable*)> cb)
{
boost::unique_lock<boost::recursive_mutex> lock(updateGuard);
cb(this);
}
CIntObject::CIntObject(int used_, Point pos_): CIntObject::CIntObject(int used_, Point pos_):
parent_m(nullptr), parent_m(nullptr),
active_m(0), active_m(0),

View File

@@ -31,7 +31,10 @@ public:
class IUpdateable class IUpdateable
{ {
boost::recursive_mutex updateGuard;
public: public:
virtual void runLocked(std::function<void(IUpdateable * )> cb);
virtual void update()=0; virtual void update()=0;
virtual ~IUpdateable(){}; //d-tor virtual ~IUpdateable(){}; //d-tor
}; };