1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-10 22:31:40 +02:00

Fix crash on closing game during background image upscaling

This commit is contained in:
Ivan Savenko
2025-03-12 14:18:44 +00:00
parent 6855b895a0
commit 96d691b40c
10 changed files with 71 additions and 24 deletions

View File

@@ -10,6 +10,7 @@
#include "StdInc.h"
#include "../../lib/ArtifactUtils.h"
#include "../../lib/AsyncRunner.h"
#include "../../lib/UnlockGuard.h"
#include "../../lib/StartInfo.h"
#include "../../lib/entities/building/CBuilding.h"
@@ -32,8 +33,6 @@
#include "AIGateway.h"
#include "Goals/Goals.h"
static tbb::task_arena executeActionAsyncArena;
namespace NKAI
{
@@ -73,7 +72,7 @@ AIGateway::AIGateway()
destinationTeleport = ObjectInstanceID();
destinationTeleportPos = int3(-1);
nullkiller.reset(new Nullkiller());
asyncTasks = std::make_unique<tbb::task_group>();
asyncTasks = std::make_unique<AsyncRunner>();
}
AIGateway::~AIGateway()
@@ -593,11 +592,11 @@ void AIGateway::yourTurn(QueryID queryID)
nullkiller->makingTurnInterrupption.reset();
executeActionAsyncArena.enqueue(asyncTasks->defer([this]()
asyncTasks->run([this]()
{
ScopedThreadName guard("NKAI::makingTurn");
makeTurn();
}));
});
}
void AIGateway::heroGotLevel(const CGHeroInstance * hero, PrimarySkill pskill, std::vector<SecondarySkill> & skills, QueryID queryID)
@@ -1608,13 +1607,13 @@ void AIGateway::executeActionAsync(const std::string & description, const std::f
if (!asyncTasks)
throw std::runtime_error("Attempt to execute task on shut down AI state!");
executeActionAsyncArena.enqueue(asyncTasks->defer([this, description, whatToDo]()
asyncTasks->run([this, description, whatToDo]()
{
ScopedThreadName guard("NKAI::" + description);
SET_GLOBAL_STATE(this);
std::shared_lock gsLock(CGameState::mutex);
whatToDo();
}));
});
}
void AIGateway::lostHero(HeroPtr h)

View File

@@ -22,8 +22,9 @@
#include "Pathfinding/AIPathfinder.h"
#include "Engine/Nullkiller.h"
#include <tbb/task_group.h>
#include <tbb/task_arena.h>
VCMI_LIB_NAMESPACE_BEGIN
class AsyncRunner;
VCMI_LIB_NAMESPACE_END
namespace NKAI
{
@@ -74,7 +75,7 @@ public:
AIStatus status;
std::string battlename;
std::shared_ptr<CCallback> myCb;
std::unique_ptr<tbb::task_group> asyncTasks;
std::unique_ptr<AsyncRunner> asyncTasks;
public:
ObjectInstanceID selectedObject;

View File

@@ -15,6 +15,7 @@
#include "Goals/Goals.h"
#include "../../lib/ArtifactUtils.h"
#include "../../lib/AsyncRunner.h"
#include "../../lib/CThreadHelper.h"
#include "../../lib/UnlockGuard.h"
#include "../../lib/StartInfo.h"
@@ -37,8 +38,6 @@
#include "AIhelper.h"
static tbb::task_arena executeActionAsyncArena;
extern FuzzyHelper * fh;
const double SAFE_ATTACK_CONSTANT = 1.5;
@@ -78,7 +77,7 @@ struct SetGlobalState
VCAI::VCAI()
{
LOG_TRACE(logAi);
asyncTasks = std::make_unique<tbb::task_group>();
asyncTasks = std::make_unique<AsyncRunner>();
destinationTeleport = ObjectInstanceID();
destinationTeleportPos = int3(-1);
@@ -653,11 +652,11 @@ void VCAI::yourTurn(QueryID queryID)
status.startedTurn();
makingTurnInterrupption.reset();
executeActionAsyncArena.enqueue(asyncTasks->defer([this]()
asyncTasks->run([this]()
{
ScopedThreadName guard("VCAI::makingTurn");
makeTurn();
}));
});
}
void VCAI::heroGotLevel(const CGHeroInstance * hero, PrimarySkill pskill, std::vector<SecondarySkill> & skills, QueryID queryID)
@@ -2510,13 +2509,13 @@ void VCAI::executeActionAsync(const std::string & description, const std::functi
if (!asyncTasks)
throw std::runtime_error("Attempt to execute task on shut down AI state!");
executeActionAsyncArena.enqueue(asyncTasks->defer([this, description, whatToDo]()
asyncTasks->run([this, description, whatToDo]()
{
ScopedThreadName guard("VCAI::" + description);
SET_GLOBAL_STATE(this);
std::shared_lock gsLock(CGameState::mutex);
whatToDo();
}));
});
}
void VCAI::lostHero(HeroPtr h)

View File

@@ -23,13 +23,11 @@
#include "../../lib/spells/CSpellHandler.h"
#include "Pathfinding/AIPathfinder.h"
#include <tbb/task_group.h>
#include <tbb/task_arena.h>
VCMI_LIB_NAMESPACE_BEGIN
struct QuestInfo;
class PathfinderCache;
class AsyncRunner;
VCMI_LIB_NAMESPACE_END
@@ -108,7 +106,7 @@ public:
std::shared_ptr<CCallback> myCb;
std::unique_ptr<tbb::task_group> asyncTasks;
std::unique_ptr<AsyncRunner> asyncTasks;
ThreadInterruption makingTurnInterrupption;
public:

View File

@@ -36,6 +36,7 @@
#include "GameEngineUser.h"
#include "battle/BattleInterface.h"
#include "../lib/AsyncRunner.h"
#include "../lib/CThreadHelper.h"
#include "../lib/CConfigHandler.h"
@@ -86,6 +87,8 @@ GameEngine::GameEngine()
sound().setVolume((ui32)settings["general"]["sound"].Float());
music().setVolume((ui32)settings["general"]["music"].Float());
cursorHandlerInstance = std::make_unique<CursorHandler>();
asyncTasks = std::make_unique<AsyncRunner>();
}
void GameEngine::handleEvents()

View File

@@ -11,6 +11,7 @@
VCMI_LIB_NAMESPACE_BEGIN
class Point;
class AsyncRunner;
class Rect;
VCMI_LIB_NAMESPACE_END
@@ -52,6 +53,7 @@ private:
std::unique_ptr<IMusicPlayer> musicPlayerInstance;
std::unique_ptr<CursorHandler> cursorHandlerInstance;
std::unique_ptr<IVideoPlayer> videoPlayerInstance;
std::unique_ptr<AsyncRunner> asyncTasks;
IGameEngineUser *engineUser = nullptr;
@@ -68,6 +70,7 @@ public:
EventDispatcher & events();
InputHandler & input();
AsyncRunner & async() { return *asyncTasks; }
IGameEngineUser & user() { return *engineUser; }
ISoundPlayer & sound() { return *soundPlayerInstance; }
IMusicPlayer & music() { return *musicPlayerInstance; }

View File

@@ -20,6 +20,7 @@
#include "../GameEngine.h"
#include "../render/IScreenHandler.h"
#include "../../lib/AsyncRunner.h"
#include "../../lib/CConfigHandler.h"
#include <tbb/parallel_for.h>
@@ -256,8 +257,6 @@ std::shared_ptr<const ISharedImage> SDLImageShared::scaleInteger(int factor, SDL
SDLImageShared::SDLImageShared(const SDLImageShared * from, int integerScaleFactor, EScalingAlgorithm algorithm)
{
static tbb::task_arena upscalingArena;
upscalingInProgress = true;
auto scaler = std::make_shared<SDLImageScaler>(from->surf, Rect(from->margins, from->fullSize), true);
@@ -273,7 +272,7 @@ SDLImageShared::SDLImageShared(const SDLImageShared * from, int integerScaleFact
};
if(settings["video"]["asyncUpscaling"].Bool())
upscalingArena.enqueue(scalingTask);
ENGINE->async().run(scalingTask);
else
scalingTask();
}

View File

@@ -27,6 +27,7 @@
#include "../client/windows/CMessage.h"
#include "../client/windows/InfoWindows.h"
#include "../lib/AsyncRunner.h"
#include "../lib/CConsoleHandler.h"
#include "../lib/CConfigHandler.h"
#include "../lib/CThreadHelper.h"
@@ -417,6 +418,9 @@ int main(int argc, char * argv[])
vstd::clear_pointer(graphics);
}
// must be executed before reset - since unique_ptr resets pointer to null before calling destructor
ENGINE->async().wait();
ENGINE.reset();
vstd::clear_pointer(LIBRARY);

40
lib/AsyncRunner.h Normal file
View File

@@ -0,0 +1,40 @@
/*
* AsyncRunner.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <tbb/task_group.h>
#include <tbb/task_arena.h>
VCMI_LIB_NAMESPACE_BEGIN
class AsyncRunner : boost::noncopyable
{
tbb::task_arena arena;
tbb::task_group taskGroup;
public:
template <typename Functor>
void run(Functor && f)
{
arena.enqueue(taskGroup.defer(std::forward<Functor>(f)));
}
void wait()
{
taskGroup.wait();
}
~AsyncRunner()
{
wait();
}
};
VCMI_LIB_NAMESPACE_END

View File

@@ -693,6 +693,7 @@ set(lib_MAIN_HEADERS
AI_Base.h
ArtifactUtils.h
AsyncRunner.h
BattleFieldHandler.h
CAndroidVMHelper.h
CArtHandler.h