feat: simulation tasks can now be subdivided into separate workloads for separate threads
This commit is contained in:
		
							parent
							
								
									e1bb3beeed
								
							
						
					
					
						commit
						df31dea9c7
					
				| 
						 | 
					@ -11,20 +11,31 @@
 | 
				
			||||||
#include <set>
 | 
					#include <set>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace simulation {
 | 
					 | 
				
			||||||
bool drawDebugInfo{ true };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static std::set<Cell> living{};
 | 
					 | 
				
			||||||
static std::vector<Cell> overpopulated{};
 | 
					 | 
				
			||||||
static std::vector<Cell> underpopulated{};
 | 
					 | 
				
			||||||
static std::vector<Cell> born{};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef __glibc_likely
 | 
					#ifdef __glibc_likely
 | 
				
			||||||
#define likely(cond_) __glibc_likely(cond_)
 | 
					#define likely(cond_) __glibc_likely(cond_)
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#define likely(cond_) (cond_)
 | 
					#define likely(cond_) (cond_)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SIM_MULTITHREADING 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace simulation {
 | 
				
			||||||
 | 
					bool drawDebugInfo{ true };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ThreadWorkload {
 | 
				
			||||||
 | 
						size_t seg_idx{0}, seg_len{1};
 | 
				
			||||||
 | 
						std::mutex mtx{};
 | 
				
			||||||
 | 
						std::vector<Cell> changes{};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static std::set<Cell> living{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static std::vector<std::shared_ptr<ThreadWorkload>> overpopulated{};
 | 
				
			||||||
 | 
					static std::vector<std::shared_ptr<ThreadWorkload>> underpopulated{};
 | 
				
			||||||
 | 
					static std::vector<std::shared_ptr<ThreadWorkload>> born{};
 | 
				
			||||||
 | 
					static uint64_t generationStartTime{ 0 };
 | 
				
			||||||
 | 
					static unsigned tasks{ 0 }; std::mutex tasksMutex{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CellIterator::CellIterator(Cell begin, Cell end)
 | 
					CellIterator::CellIterator(Cell begin, Cell end)
 | 
				
			||||||
: state{ begin } , begin{ begin }, end{ end } {}
 | 
					: state{ begin } , begin{ begin }, end{ end } {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,16 +67,6 @@ bool CellIterator::at_end() const {
 | 
				
			||||||
	return this->state.y == this->end.y;
 | 
						return this->state.y == this->end.y;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static std::vector<Cell> NeighborSet(Cell cell) {
 | 
					 | 
				
			||||||
	std::vector<Cell> out{};
 | 
					 | 
				
			||||||
	for (Cell const &c : CellRange{ { cell.x - 1, cell.y - 1 }, { cell.x + 2, cell.y + 2 } }) {
 | 
					 | 
				
			||||||
		if (likely(c != cell)) {
 | 
					 | 
				
			||||||
			out.push_back(c);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return out;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static size_t CountNeighbors(Cell const &cell) {
 | 
					static size_t CountNeighbors(Cell const &cell) {
 | 
				
			||||||
	size_t count{ 0 };
 | 
						size_t count{ 0 };
 | 
				
			||||||
	for (Cell const &c : CellRange{ {cell.x - 1, cell.y - 1}, { cell.x + 2, cell.y + 2} }) {
 | 
						for (Cell const &c : CellRange{ {cell.x - 1, cell.y - 1}, { cell.x + 2, cell.y + 2} }) {
 | 
				
			||||||
| 
						 | 
					@ -76,100 +77,125 @@ static size_t CountNeighbors(Cell const &cell) {
 | 
				
			||||||
	return count;
 | 
						return count;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static std::mutex underpopulatedMutex, overpopulatedMutex, bornMutex;
 | 
					static void TaskComplete() {
 | 
				
			||||||
 | 
						std::scoped_lock lock{ tasksMutex };
 | 
				
			||||||
static void FindOverpopulated(size_t segment, size_t length) {
 | 
						if (--tasks == 0) {
 | 
				
			||||||
	overpopulatedMutex.lock();
 | 
							SDL_Log("Generation Complete %lfs", (double)(SDL_GetTicksNS() - generationStartTime) * 0.0000000001);
 | 
				
			||||||
	std::set<Cell>::iterator begin{ living.begin() };
 | 
					 | 
				
			||||||
	std::set<Cell>::iterator end{ living.begin() };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::advance(begin, segment * length);
 | 
					 | 
				
			||||||
	std::advance(end, segment * length + length);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::copy_if(begin, end, std::back_inserter(overpopulated),
 | 
					 | 
				
			||||||
	[&](Cell const &c) -> bool {
 | 
					 | 
				
			||||||
		size_t const neighbors{ CountNeighbors(c) };
 | 
					 | 
				
			||||||
		return neighbors > 3;
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
	overpopulatedMutex.unlock();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void FindUnderpopulated(size_t segment, size_t length) {
 | 
					 | 
				
			||||||
	uint64_t ns{ SDL_GetTicksNS() };
 | 
					 | 
				
			||||||
	underpopulatedMutex.lock();
 | 
					 | 
				
			||||||
	std::set<Cell>::iterator begin{ living.begin() };
 | 
					 | 
				
			||||||
	std::set<Cell>::iterator end{ living.begin() };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::advance(begin, segment * length);
 | 
					 | 
				
			||||||
	std::advance(end, segment * length + length);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::copy_if(begin, end, std::back_inserter(underpopulated),
 | 
					 | 
				
			||||||
	[&](Cell const &c) -> bool {
 | 
					 | 
				
			||||||
		size_t const neighbors{ CountNeighbors(c) };
 | 
					 | 
				
			||||||
		return neighbors < 2;
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
	underpopulatedMutex.unlock();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void FindBorn(size_t segment, size_t length) {
 | 
					 | 
				
			||||||
	uint64_t ns{ SDL_GetTicksNS() };
 | 
					 | 
				
			||||||
	bornMutex.lock();
 | 
					 | 
				
			||||||
	std::set<Cell>::iterator itr{ living.begin() };
 | 
					 | 
				
			||||||
	std::set<Cell>::iterator end{ living.begin() };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	std::advance(itr, segment * length);
 | 
					 | 
				
			||||||
	std::advance(end, segment * length + length);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (;itr != end; ++itr) {
 | 
					 | 
				
			||||||
		std::vector<Cell> neighbors{ NeighborSet(*itr) };
 | 
					 | 
				
			||||||
		std::ranges::copy_if(neighbors, std::back_inserter(born),
 | 
					 | 
				
			||||||
		[&](Cell const &c) -> bool {
 | 
					 | 
				
			||||||
			size_t const neighbors{ CountNeighbors(c) };
 | 
					 | 
				
			||||||
			return !living.contains(c) && neighbors == 3;
 | 
					 | 
				
			||||||
		});
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	bornMutex.unlock();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MULTITHREADING 1
 | 
					static void FindOverpopulated(std::shared_ptr<ThreadWorkload> wl) {
 | 
				
			||||||
static uint64_t generationStartTime{ 0 };
 | 
						std::scoped_lock lock{ wl->mtx };
 | 
				
			||||||
static bool logGenerationTime{ false };
 | 
						wl->changes.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::set<Cell>::iterator begin{ living.begin() };
 | 
				
			||||||
 | 
						std::set<Cell>::iterator end{ living.begin() };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::advance(begin, wl->seg_idx * wl->seg_len);
 | 
				
			||||||
 | 
						std::advance(end, wl->seg_idx * wl->seg_len + wl->seg_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::copy_if(begin, end, std::back_inserter(wl->changes),
 | 
				
			||||||
 | 
						[&](Cell const &c) -> bool {
 | 
				
			||||||
 | 
							return CountNeighbors(c) > 3;
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						TaskComplete();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void FindUnderpopulated(std::shared_ptr<ThreadWorkload> wl) {
 | 
				
			||||||
 | 
						std::scoped_lock lock{ wl->mtx };
 | 
				
			||||||
 | 
						wl->changes.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::set<Cell>::iterator begin{ living.begin() };
 | 
				
			||||||
 | 
						std::set<Cell>::iterator end{ living.begin() };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::advance(begin, wl->seg_idx * wl->seg_len);
 | 
				
			||||||
 | 
						std::advance(end, wl->seg_idx * wl->seg_len + wl->seg_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::copy_if(begin, end, std::back_inserter(wl->changes),
 | 
				
			||||||
 | 
						[&](Cell const &c) -> bool {
 | 
				
			||||||
 | 
							return CountNeighbors(c) < 2;
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						TaskComplete();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void FindBorn(std::shared_ptr<ThreadWorkload> wl) {
 | 
				
			||||||
 | 
						std::scoped_lock lock{ wl->mtx };
 | 
				
			||||||
 | 
						wl->changes.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::set<Cell>::iterator itr{ living.begin() };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::advance(itr, wl->seg_idx * wl->seg_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::for_each_n(itr, wl->seg_len, [&wl](Cell const ¢er){
 | 
				
			||||||
 | 
							CellRange range{{ center.x - 1, center.y - 1 }, {center.x + 2, center.y + 2 }};
 | 
				
			||||||
 | 
							std::copy_if(range.begin(), range.end(), std::back_inserter(wl->changes),
 | 
				
			||||||
 | 
							[&](Cell const &c) -> bool {
 | 
				
			||||||
 | 
								return !living.contains(c) && CountNeighbors(c) == 3;
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
						TaskComplete();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void PopulateChanges() {
 | 
					static void PopulateChanges() {
 | 
				
			||||||
#if MULTITHREADING
 | 
						static bool first_run{ true };
 | 
				
			||||||
	constexpr size_t split{ 1 };
 | 
					#if SIM_MULTITHREADING
 | 
				
			||||||
 | 
						constexpr size_t split{ 4 };
 | 
				
			||||||
 | 
						if (first_run) {
 | 
				
			||||||
 | 
							first_run = false;
 | 
				
			||||||
 | 
							born.resize(split);
 | 
				
			||||||
 | 
							underpopulated.resize(split);
 | 
				
			||||||
 | 
							overpopulated.resize(split);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SDL_Log("Multithreading ON");
 | 
						SDL_Log("Multithreading ON");
 | 
				
			||||||
	logGenerationTime = true;
 | 
						{ std::scoped_lock lock{ tasksMutex };
 | 
				
			||||||
 | 
							tasks = 3 * split; }
 | 
				
			||||||
	generationStartTime = SDL_GetTicksNS();
 | 
						generationStartTime = SDL_GetTicksNS();
 | 
				
			||||||
	size_t const seg_length{ living.size() / split };
 | 
						size_t const seg_length{ living.size() / split };
 | 
				
			||||||
	for (size_t i{ 0 }; i < split; ++i) {
 | 
						for (size_t i{ 0 }; i < split; ++i) {
 | 
				
			||||||
		threading::tasks.ScheduleTask(std::bind(FindOverpopulated, i, seg_length));
 | 
							if (overpopulated[i] == nullptr)
 | 
				
			||||||
		threading::tasks.ScheduleTask(std::bind(FindUnderpopulated, i, seg_length));
 | 
								overpopulated[i] = std::make_shared<ThreadWorkload>();
 | 
				
			||||||
		threading::tasks.ScheduleTask(std::bind(FindBorn, i, seg_length));
 | 
							{ std::scoped_lock lock{ overpopulated[i]->mtx };
 | 
				
			||||||
 | 
								overpopulated[i]->seg_idx = i; overpopulated[i]->seg_len = seg_length;
 | 
				
			||||||
 | 
								threading::tasks.ScheduleTask(std::bind(FindOverpopulated, overpopulated[i]));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (underpopulated[i] == nullptr)
 | 
				
			||||||
 | 
								underpopulated[i] = std::make_shared<ThreadWorkload>();
 | 
				
			||||||
 | 
							{ std::scoped_lock lock{ underpopulated[i]->mtx };
 | 
				
			||||||
 | 
								underpopulated[i]->seg_idx = i; underpopulated[i]->seg_len = seg_length;
 | 
				
			||||||
 | 
								threading::tasks.ScheduleTask(std::bind(FindUnderpopulated, underpopulated[i]));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (born[i] == nullptr)
 | 
				
			||||||
 | 
								born[i] = std::make_shared<ThreadWorkload>();
 | 
				
			||||||
 | 
							{ std::scoped_lock lock{ born[i]->mtx };
 | 
				
			||||||
 | 
								born[i]->seg_idx = i; born[i]->seg_len = seg_length;
 | 
				
			||||||
 | 
								threading::tasks.ScheduleTask(std::bind(FindBorn, born[i]));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
 | 
						if (first_run) {
 | 
				
			||||||
 | 
							first_run = false;
 | 
				
			||||||
 | 
							overpopulated.emplace_back(std::make_shared<ThreadWorkload>());
 | 
				
			||||||
 | 
							overpopulated[0]->seg_idx = 0;
 | 
				
			||||||
 | 
							overpopulated[0]->seg_len = living.size();
 | 
				
			||||||
 | 
							underpopulated.emplace_back(std::make_shared<ThreadWorkload>());
 | 
				
			||||||
 | 
							underpopulated[0]->seg_idx = 0;
 | 
				
			||||||
 | 
							underpopulated[0]->seg_len = living.size();
 | 
				
			||||||
 | 
							born.emplace_back(std::make_shared<ThreadWorkload>());
 | 
				
			||||||
 | 
							born[0]->seg_idx = 0;
 | 
				
			||||||
 | 
							born[0]->seg_len = living.size();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	SDL_Log("Multithreading OFF");
 | 
						SDL_Log("Multithreading OFF");
 | 
				
			||||||
	logGenerationTime = true;
 | 
						{ std::scoped_lock lock{ tasksMutex };
 | 
				
			||||||
 | 
							tasks = 3; }
 | 
				
			||||||
	generationStartTime = SDL_GetTicksNS();
 | 
						generationStartTime = SDL_GetTicksNS();
 | 
				
			||||||
	FindOverpopulated(0, living.size());
 | 
						FindOverpopulated(overpopulated[0]);
 | 
				
			||||||
	FindUnderpopulated(0, living.size());
 | 
						FindUnderpopulated(underpopulated[0]);
 | 
				
			||||||
	FindBorn(0, living.size());
 | 
						FindBorn(born[0]);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void InitializeRandom(size_t livingChance, int64_t fillArea) {
 | 
					void InitializeRandom(size_t livingChance, int64_t fillArea) {
 | 
				
			||||||
	underpopulatedMutex.lock();
 | 
					 | 
				
			||||||
	underpopulated.clear();
 | 
					 | 
				
			||||||
	underpopulatedMutex.unlock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	overpopulatedMutex.lock();
 | 
					 | 
				
			||||||
	overpopulated.clear();
 | 
					 | 
				
			||||||
	overpopulatedMutex.unlock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	bornMutex.lock();
 | 
					 | 
				
			||||||
	born.clear();
 | 
					 | 
				
			||||||
	bornMutex.unlock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	living.clear();
 | 
						living.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Cell itr{ 0, 0 };
 | 
						Cell itr{ 0, 0 };
 | 
				
			||||||
| 
						 | 
					@ -187,28 +213,24 @@ void InitializeRandom(size_t livingChance, int64_t fillArea) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Step() {
 | 
					void Step() {
 | 
				
			||||||
	underpopulatedMutex.lock();
 | 
						for (std::shared_ptr<ThreadWorkload> wl : underpopulated) {
 | 
				
			||||||
	overpopulatedMutex.lock();
 | 
							if (wl == nullptr) continue;
 | 
				
			||||||
	bornMutex.lock();
 | 
							std::scoped_lock l{ wl->mtx };
 | 
				
			||||||
 | 
							for (Cell const &cell : wl->changes)
 | 
				
			||||||
	for (Cell const &cell : underpopulated) {
 | 
								living.erase(cell);
 | 
				
			||||||
		living.erase(cell);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	underpopulated.clear();
 | 
						for (std::shared_ptr<ThreadWorkload> wl : overpopulated) {
 | 
				
			||||||
 | 
							if (wl == nullptr) continue;
 | 
				
			||||||
	for (Cell const &cell : overpopulated) {
 | 
							std::scoped_lock l{ wl->mtx };
 | 
				
			||||||
		living.erase(cell);
 | 
							for (Cell const &cell : wl->changes)
 | 
				
			||||||
 | 
								living.erase(cell);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	overpopulated.clear();
 | 
						for (std::shared_ptr<ThreadWorkload> wl : born) {
 | 
				
			||||||
 | 
							if (wl == nullptr) continue;
 | 
				
			||||||
	for (Cell const &cell : born) {
 | 
							std::scoped_lock l{ wl->mtx };
 | 
				
			||||||
		living.insert(cell);
 | 
							for (Cell const &cell : wl->changes)
 | 
				
			||||||
 | 
								living.insert(cell);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	born.clear();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	underpopulatedMutex.unlock();
 | 
					 | 
				
			||||||
	overpopulatedMutex.unlock();
 | 
					 | 
				
			||||||
	bornMutex.unlock();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	PopulateChanges();
 | 
						PopulateChanges();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -236,34 +258,32 @@ void Draw(SDL_Renderer *renderer, double cellSizePercent) {
 | 
				
			||||||
	if (!drawDebugInfo) {
 | 
						if (!drawDebugInfo) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	overpopulatedMutex.lock();
 | 
						for (std::shared_ptr<ThreadWorkload> wl : overpopulated) {
 | 
				
			||||||
	SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
 | 
							std::scoped_lock l{ wl->mtx };
 | 
				
			||||||
	for (Cell const &cell : overpopulated) {
 | 
							SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
 | 
				
			||||||
		cellRect.x = (viewOffset.x + cell.x) * cellRect.w;
 | 
							for (Cell const &cell : wl->changes) {
 | 
				
			||||||
		cellRect.y = (viewOffset.y + cell.y) * cellRect.h;
 | 
								cellRect.x = (viewOffset.x + cell.x) * cellRect.w;
 | 
				
			||||||
		SDL_RenderRect(renderer, &cellRect);
 | 
								cellRect.y = (viewOffset.y + cell.y) * cellRect.h;
 | 
				
			||||||
 | 
								SDL_RenderRect(renderer, &cellRect);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	overpopulatedMutex.unlock();
 | 
						for (std::shared_ptr<ThreadWorkload> wl : underpopulated) {
 | 
				
			||||||
	underpopulatedMutex.lock();
 | 
							std::scoped_lock l{ wl->mtx };
 | 
				
			||||||
	SDL_SetRenderDrawColor(renderer, 255, 0, 255, 255);
 | 
							SDL_SetRenderDrawColor(renderer, 255, 0, 255, 255);
 | 
				
			||||||
	for (Cell const &cell : underpopulated) {
 | 
							for (Cell const &cell : wl->changes) {
 | 
				
			||||||
		cellRect.x = (viewOffset.x + cell.x) * cellRect.w;
 | 
								cellRect.x = (viewOffset.x + cell.x) * cellRect.w;
 | 
				
			||||||
		cellRect.y = (viewOffset.y + cell.y) * cellRect.h;
 | 
								cellRect.y = (viewOffset.y + cell.y) * cellRect.h;
 | 
				
			||||||
		SDL_RenderRect(renderer, &cellRect);
 | 
								SDL_RenderRect(renderer, &cellRect);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	underpopulatedMutex.unlock();
 | 
						for (std::shared_ptr<ThreadWorkload> wl : born) {
 | 
				
			||||||
	bornMutex.lock();
 | 
							std::scoped_lock l{ wl->mtx };
 | 
				
			||||||
	SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
 | 
							SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
 | 
				
			||||||
	for (Cell const &cell : born) {
 | 
							for (Cell const &cell : wl->changes) {
 | 
				
			||||||
		cellRect.x = (viewOffset.x + cell.x) * cellRect.w;
 | 
								cellRect.x = (viewOffset.x + cell.x) * cellRect.w;
 | 
				
			||||||
		cellRect.y = (viewOffset.y + cell.y) * cellRect.h;
 | 
								cellRect.y = (viewOffset.y + cell.y) * cellRect.h;
 | 
				
			||||||
		SDL_RenderRect(renderer, &cellRect);
 | 
								SDL_RenderRect(renderer, &cellRect);
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
	bornMutex.unlock();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (logGenerationTime) {
 | 
					 | 
				
			||||||
		SDL_Log("End Generation %lf", double(SDL_GetTicksNS() - generationStartTime) * 0.0000000001);
 | 
					 | 
				
			||||||
		logGenerationTime = false;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue