diff --git a/Common/Thread/ThreadManager.cpp b/Common/Thread/ThreadManager.cpp index 514632f1f7..43a658c2ac 100644 --- a/Common/Thread/ThreadManager.cpp +++ b/Common/Thread/ThreadManager.cpp @@ -105,7 +105,7 @@ bool ThreadManager::TeardownTask(Task *task, bool enqueue) { if (task->Cancellable()) { task->Cancel(); - delete task; + task->Release(); return true; } @@ -174,7 +174,7 @@ static void WorkerThreadFunc(GlobalThreadContext *global, ThreadContext *thread) // responsibility of the ThreadManager (although it could be!). if (task) { task->Run(); - delete task; + task->Release(); // Reduce the queue size once complete. thread->queue_size--; diff --git a/Common/Thread/ThreadManager.h b/Common/Thread/ThreadManager.h index bb7b5fd44e..5147ad21cc 100644 --- a/Common/Thread/ThreadManager.h +++ b/Common/Thread/ThreadManager.h @@ -19,6 +19,7 @@ public: virtual bool Cancellable() { return false; } virtual void Cancel() {} virtual uint64_t id() { return 0; } + virtual void Release() { delete this; } }; class Waitable { diff --git a/GPU/Software/BinManager.cpp b/GPU/Software/BinManager.cpp index 093d0acf93..0c44458d11 100644 --- a/GPU/Software/BinManager.cpp +++ b/GPU/Software/BinManager.cpp @@ -105,6 +105,10 @@ public: notify_->Drain(); } + void Release() override { + // Don't delete, this is statically allocated. + } + private: void ProcessItems() { while (!items_.Empty()) { @@ -131,8 +135,11 @@ BinManager::BinManager() { s = false; int maxInitTasks = std::min(g_threadManager.GetNumLooperThreads(), MAX_POSSIBLE_TASKS); - for (int i = 0; i < maxInitTasks; ++i) + for (int i = 0; i < maxInitTasks; ++i) { taskQueues_[i].Setup(); + for (DrawBinItemsTask *&task : taskLists_[i].tasks) + task = new DrawBinItemsTask(waitable_, taskQueues_[i], taskStatus_[i], states_); + } states_.Setup(); cluts_.Setup(); queue_.Setup(); @@ -140,6 +147,11 @@ BinManager::BinManager() { BinManager::~BinManager() { delete waitable_; + + for (int i = 0; i < MAX_POSSIBLE_TASKS; ++i) { + for (DrawBinItemsTask *task : taskLists_[i].tasks) + delete task; + } } void BinManager::UpdateState() { @@ -335,8 +347,7 @@ void BinManager::Drain() { waitable_->Fill(); taskStatus_[i] = true; - DrawBinItemsTask *task = new DrawBinItemsTask(waitable_, taskQueues_[i], taskStatus_[i], states_); - g_threadManager.EnqueueTaskOnThread(i, task, true); + g_threadManager.EnqueueTaskOnThread(i, taskLists_[i].Next(), true); enqueues_++; } diff --git a/GPU/Software/BinManager.h b/GPU/Software/BinManager.h index 9a7e387400..9eeffa8dd0 100644 --- a/GPU/Software/BinManager.h +++ b/GPU/Software/BinManager.h @@ -152,6 +152,19 @@ union BinClut { uint8_t readable[1024]; }; +struct BinTaskList { + // We shouldn't ever need more than two at once, since we use an atomic to run one at a time. + // A second could run due to overlap during teardown. + static constexpr int N = 2; + + DrawBinItemsTask *tasks[N]{}; + int count = 0; + + DrawBinItemsTask *Next() { + return tasks[count % N]; + } +}; + class BinManager { public: BinManager(); @@ -204,6 +217,7 @@ private: bool tasksSplit_ = false; std::vector taskRanges_; BinItemQueue taskQueues_[MAX_POSSIBLE_TASKS]; + BinTaskList taskLists_[MAX_POSSIBLE_TASKS]; std::atomic taskStatus_[MAX_POSSIBLE_TASKS]; BinWaitable *waitable_ = nullptr;