Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix various crashes when loading/unloading images #9941

Merged
merged 1 commit into from
Mar 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions source/Engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,9 @@ void Engine::Step(bool isActive)
events.swap(eventQueue);
eventQueue.clear();

// Process any outstanding sprites that need to be uploaded to the GPU.
queue.ProcessSyncTasks();

// The calculation thread was paused by MainPanel before calling this function, so it is safe to access things.
const shared_ptr<Ship> flagship = player.FlagshipPtr();
const StellarObject *object = player.GetStellarObject();
Expand Down
4 changes: 2 additions & 2 deletions source/GameData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,14 +329,14 @@ void GameData::Preload(TaskQueue &queue, const Sprite *sprite)
// This sprite is not currently preloaded. Check to see whether we already
// have the maximum number of sprites loaded, in which case the oldest one
// must be unloaded to make room for this one.
const string &name = sprite->Name();
pit = preloaded.begin();
while(pit != preloaded.end())
{
++pit->second;
if(pit->second >= 20)
{
SpriteSet::Modify(name)->Unload();
// Unloading needs to be queued on the main thread.
queue.Run({}, [name = pit->first->Name()] { SpriteSet::Modify(name)->Unload(); });
pit = preloaded.erase(pit);
}
else
Expand Down
2 changes: 2 additions & 0 deletions source/PlanetPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ PlanetPanel::PlanetPanel(PlayerInfo &player, function<void()> callback)
// landscapes for this system are loaded before showing the planet panel.
TaskQueue queue;
GameData::Preload(queue, planet.Landscape());
queue.Wait();
queue.ProcessSyncTasks();
}


Expand Down
27 changes: 10 additions & 17 deletions source/TaskQueue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,28 +105,20 @@ void TaskQueue::ProcessSyncTasks()



// Whether there are any outstanding tasks left in this queue, including any outstanding tasks
// that need to be executed on the main thread.
bool TaskQueue::IsDone() const
// Waits for all of this queue's task to finish. Ignores any sync tasks to be processed.
void TaskQueue::Wait()
{
{
lock_guard<mutex> lock(asyncMutex);
if(!futures.empty())
return false;
}

lock_guard lock(syncMutex);
return syncTasks.empty();
while(!IsDone())
this_thread::yield();
}



// Waits for all of this queue's task to finish while properly processing any outstanding main thread tasks.
void TaskQueue::Wait()
// Whether there are any outstanding async tasks left in this queue.
bool TaskQueue::IsDone() const
{
// Process tasks while any task is still being executed.
while(!IsDone())
ProcessSyncTasks();
lock_guard<mutex> lock(asyncMutex);
return futures.empty();
}


Expand Down Expand Up @@ -155,7 +147,8 @@ void TaskQueue::ThreadLoop() noexcept

// Execute the task.
try {
task.async();
if(task.async)
task.async();
}
catch(...)
{
Expand Down
11 changes: 6 additions & 5 deletions source/TaskQueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,15 @@ class TaskQueue {
// Process any tasks to be scheduled to be executed on the main thread.
void ProcessSyncTasks();

// Whether there are any outstanding tasks left in this queue, including any outstanding tasks
// that need to be executed on the main thread.
bool IsDone() const;

// Waits for all of this queue's task to finish while properly processing any outstanding main thread tasks.
// Waits for all of this queue's task to finish. Ignores any sync tasks to be processed.
void Wait();


private:
// Whether there are any outstanding async tasks left in this queue.
bool IsDone() const;


public:
// Thread entry point.
static void ThreadLoop() noexcept;
Expand Down
3 changes: 2 additions & 1 deletion source/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ int main(int argc, char *argv[])

// Begin loading the game data.
bool isConsoleOnly = loadOnly || printTests || printData;
auto dataFuture = GameData::BeginLoad(queue, isConsoleOnly, debugMode, isTesting && !debugMode);
auto dataFuture = GameData::BeginLoad(queue, isConsoleOnly, debugMode,
isConsoleOnly || (isTesting && !debugMode));

// If we are not using the UI, or performing some automated task, we should load
// all data now.
Expand Down
Loading