From e841c5b20bfcfa8efb35debd348455a85415f5e8 Mon Sep 17 00:00:00 2001 From: ZehMatt Date: Sun, 22 Apr 2018 17:00:47 +0200 Subject: [PATCH 01/20] Use multiple threads to generate object index cache. --- src/openrct2/core/FileIndex.hpp | 86 +++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 15 deletions(-) diff --git a/src/openrct2/core/FileIndex.hpp b/src/openrct2/core/FileIndex.hpp index 4cca33de24..e2440dda8a 100644 --- a/src/openrct2/core/FileIndex.hpp +++ b/src/openrct2/core/FileIndex.hpp @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include "../common.h" #include "Console.hpp" #include "File.h" @@ -178,32 +180,85 @@ private: return ScanResult(stats, files); } - std::vector Build(const ScanResult &scanResult) const + void BuildRange(const ScanResult &scanResult, + size_t rangeStart, + size_t rangeEnd, + std::vector& items, + std::mutex& printLock) const { - std::vector items; - Console::WriteLine("Building %s (%zu items)", _name.c_str(), scanResult.Files.size()); - - auto startTime = std::chrono::high_resolution_clock::now(); - // Start at 1, so that we can reach 100% completion status - size_t i = 1; - for (auto filePath : scanResult.Files) + items.reserve(rangeEnd - rangeStart); + for (size_t i = rangeStart; i < rangeEnd; i++) { - Console::WriteFormat("File %5d of %d, done %3d%%\r", i, scanResult.Files.size(), i * 100 / scanResult.Files.size()); - i++; - log_verbose("FileIndex:Indexing '%s'", filePath.c_str()); + const auto& filePath = scanResult.Files.at(i); + + if (_log_levels[DIAGNOSTIC_LEVEL_VERBOSE]) + { + std::unique_lock lock(printLock); + log_verbose("FileIndex:Indexing '%s'", filePath.c_str()); + } + auto item = Create(filePath); if (std::get<0>(item)) { items.push_back(std::get<1>(item)); } } + } - WriteIndexFile(scanResult.Stats, items); + std::vector Build(const ScanResult &scanResult) const + { + std::vector allItems; + Console::WriteLine("Building %s (%zu items)", _name.c_str(), scanResult.Files.size()); + + auto startTime = std::chrono::high_resolution_clock::now(); + + const size_t totalCount = scanResult.Files.size(); + if (totalCount > 0) + { + const size_t numThreads = std::thread::hardware_concurrency(); + + size_t stepSize = totalCount / numThreads; + + std::vector threads; + std::vector> containers; + std::mutex printLock; // For verbose prints. + containers.resize(numThreads + (totalCount % stepSize == 0 ? 0 : 1)); + + for (size_t rangeStart = 0; rangeStart < totalCount; rangeStart += stepSize) + { + if (rangeStart + stepSize > totalCount) + stepSize = totalCount - rangeStart; + + auto& items = containers[threads.size()]; + + threads.emplace_back(&FileIndex::BuildRange, + this, + std::cref(scanResult), + rangeStart, + rangeStart + stepSize, + std::ref(items), + std::ref(printLock)); + } + + for (auto&& itr : threads) + { + if (itr.joinable()) + itr.join(); + } + + for (auto&& itr : containers) + { + allItems.insert(allItems.end(), itr.begin(), itr.end()); + } + + WriteIndexFile(scanResult.Stats, allItems); + } auto endTime = std::chrono::high_resolution_clock::now(); auto duration = (std::chrono::duration)(endTime - startTime); Console::WriteLine("Finished building %s in %.2f seconds.", _name.c_str(), duration.count()); - return items; + + return allItems; } std::tuple> ReadIndexFile(const DirectoryStats &stats) const @@ -229,6 +284,7 @@ private: header.Stats.FileDateModifiedChecksum == stats.FileDateModifiedChecksum && header.Stats.PathChecksum == stats.PathChecksum) { + items.reserve(header.NumItems); // Directory is the same, just read the saved items for (uint32 i = 0; i < header.NumItems; i++) { @@ -258,7 +314,7 @@ private: log_verbose("FileIndex:Writing index: '%s'", _indexPath.c_str()); Path::CreateDirectory(Path::GetDirectory(_indexPath)); auto fs = FileStream(_indexPath, FILE_MODE_WRITE); - + // Write header FileIndexHeader header; header.MagicNumber = _magicNumber; @@ -268,7 +324,7 @@ private: header.Stats = stats; header.NumItems = (uint32)items.size(); fs.WriteValue(header); - + // Write items for (const auto item : items) { From 254aedefd41f0a0f1dde1566ffd928e674c26430 Mon Sep 17 00:00:00 2001 From: ZehMatt Date: Tue, 24 Apr 2018 10:44:13 +0200 Subject: [PATCH 02/20] Add generic job pool implementation. --- src/openrct2/core/JobPool.cpp | 103 ++++++++++++++++++++++++++++++++++ src/openrct2/core/JobPool.hpp | 57 +++++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 src/openrct2/core/JobPool.cpp create mode 100644 src/openrct2/core/JobPool.hpp diff --git a/src/openrct2/core/JobPool.cpp b/src/openrct2/core/JobPool.cpp new file mode 100644 index 0000000000..4f319ea056 --- /dev/null +++ b/src/openrct2/core/JobPool.cpp @@ -0,0 +1,103 @@ +#include "JobPool.hpp" + +JobPool::JobPool() + : _shouldStop(false), + _processing(0) +{ + for (size_t n = 0; n < std::thread::hardware_concurrency(); n++) + { + _threads.emplace_back(&JobPool::processQueue, this); + } +} + +JobPool::~JobPool() +{ + { + unique_lock lock(_mutex); + _shouldStop = true; + _condPending.notify_all(); + } + + for (auto&& th : _threads) + { + if(th.joinable()) + th.join(); + } +} + +void JobPool::addTask(std::function workFn, std::function completionFn) +{ + unique_lock lock(_mutex); + _pending.push_back(TaskData_t{workFn, completionFn}); + _condPending.notify_one(); +} + +void JobPool::addTask(std::function workFn) +{ + unique_lock lock(_mutex); + _pending.push_back(TaskData_t{ workFn, nullptr }); + _condPending.notify_one(); +} + +void JobPool::join() +{ + while (true) + { + unique_lock lock(_mutex); + _condComplete.wait(lock, [this]() + { + return (_pending.empty() && _processing == 0) || + (_completed.empty() == false); + }); + + if (_completed.empty() && + _pending.empty() && + _processing == 0) + { + break; + } + + auto taskData = _completed.front(); + _completed.pop_front(); + + lock.unlock(); + + taskData.completionFn(); + } +} + +void JobPool::processQueue() +{ + while (true) + { + unique_lock lock(_mutex); + _condPending.wait(lock, [this]() { + return _shouldStop || !_pending.empty(); + }); + if (!_pending.empty()) + { + _processing++; + + auto taskData = _pending.front(); + _pending.pop_front(); + + lock.unlock(); + + taskData.workFn(); + + lock.lock(); + + if (taskData.completionFn) + { + _completed.push_back(taskData); + } + + _processing--; + _condComplete.notify_one(); + } + if(_shouldStop) + break; + } +} + + diff --git a/src/openrct2/core/JobPool.hpp b/src/openrct2/core/JobPool.hpp new file mode 100644 index 0000000000..4e886ce373 --- /dev/null +++ b/src/openrct2/core/JobPool.hpp @@ -0,0 +1,57 @@ +#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include +#include +#include +#include +#include +#include + +class JobPool +{ +private: + struct TaskData_t + { + const std::function workFn; + const std::function completionFn; + }; + + std::vector _threads; + std::deque _pending; + std::deque _completed; + std::condition_variable _condPending; + std::condition_variable _condComplete; + std::atomic _processing; + std::atomic_bool _shouldStop; + std::mutex _mutex; + + typedef std::unique_lock unique_lock; + +public: + JobPool(); + ~JobPool(); + + void addTask(std::function workFn, + std::function completionFn); + + void addTask(std::function workFn); + + void join(); + +private: + void processQueue(); +}; From dfcec4d9dac441d32e53ffa1beb85186e9bd6c4e Mon Sep 17 00:00:00 2001 From: ZehMatt Date: Tue, 24 Apr 2018 10:44:33 +0200 Subject: [PATCH 03/20] Refactor file indexing to use the job pool instead of threads. --- src/openrct2/core/FileIndex.hpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/openrct2/core/FileIndex.hpp b/src/openrct2/core/FileIndex.hpp index e2440dda8a..982fd42f9d 100644 --- a/src/openrct2/core/FileIndex.hpp +++ b/src/openrct2/core/FileIndex.hpp @@ -28,6 +28,7 @@ #include "FileScanner.h" #include "FileStream.hpp" #include "Path.hpp" +#include "JobPool.hpp" template class FileIndex @@ -215,36 +216,35 @@ private: const size_t totalCount = scanResult.Files.size(); if (totalCount > 0) { - const size_t numThreads = std::thread::hardware_concurrency(); - - size_t stepSize = totalCount / numThreads; - - std::vector threads; - std::vector> containers; + JobPool jobPool; std::mutex printLock; // For verbose prints. - containers.resize(numThreads + (totalCount % stepSize == 0 ? 0 : 1)); - for (size_t rangeStart = 0; rangeStart < totalCount; rangeStart += stepSize) + std::vector> containers; + + size_t stepSize = std::thread::hardware_concurrency(); + size_t numTasks = totalCount / stepSize; + size_t taskGroup = 0; + numTasks += (totalCount % stepSize == 0 ? 0 : 1); + + containers.resize(numTasks); + + for (size_t rangeStart = 0; rangeStart < totalCount; rangeStart += stepSize, taskGroup++) { if (rangeStart + stepSize > totalCount) stepSize = totalCount - rangeStart; - auto& items = containers[threads.size()]; + auto& items = containers[taskGroup]; - threads.emplace_back(&FileIndex::BuildRange, + jobPool.addTask(std::bind(&FileIndex::BuildRange, this, std::cref(scanResult), rangeStart, rangeStart + stepSize, std::ref(items), - std::ref(printLock)); + std::ref(printLock))); } - for (auto&& itr : threads) - { - if (itr.joinable()) - itr.join(); - } + jobPool.join(); for (auto&& itr : containers) { From 6b649e6b29cfe82a6dca17fa1a5d07ca4e1e4d55 Mon Sep 17 00:00:00 2001 From: ZehMatt Date: Tue, 24 Apr 2018 11:20:53 +0200 Subject: [PATCH 04/20] Remove unused includes. --- src/openrct2/core/FileIndex.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/openrct2/core/FileIndex.hpp b/src/openrct2/core/FileIndex.hpp index 982fd42f9d..049ed141bb 100644 --- a/src/openrct2/core/FileIndex.hpp +++ b/src/openrct2/core/FileIndex.hpp @@ -20,8 +20,6 @@ #include #include #include -#include -#include #include "../common.h" #include "Console.hpp" #include "File.h" From 8c2ac904b43bf6fa9b393e5255b1b5e6912b3938 Mon Sep 17 00:00:00 2001 From: ZehMatt Date: Tue, 24 Apr 2018 11:21:15 +0200 Subject: [PATCH 05/20] Add missing vector include. --- src/openrct2/core/JobPool.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/openrct2/core/JobPool.hpp b/src/openrct2/core/JobPool.hpp index 4e886ce373..5d8dfb3e3d 100644 --- a/src/openrct2/core/JobPool.hpp +++ b/src/openrct2/core/JobPool.hpp @@ -20,6 +20,7 @@ #include #include #include +#include class JobPool { From ac6b3fb22559af98cf2f4b7001260dca7fc9f7ab Mon Sep 17 00:00:00 2001 From: ZehMatt Date: Tue, 24 Apr 2018 11:23:24 +0200 Subject: [PATCH 06/20] Change order of members. --- src/openrct2/core/JobPool.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openrct2/core/JobPool.hpp b/src/openrct2/core/JobPool.hpp index 5d8dfb3e3d..684e060986 100644 --- a/src/openrct2/core/JobPool.hpp +++ b/src/openrct2/core/JobPool.hpp @@ -31,13 +31,13 @@ private: const std::function completionFn; }; + std::atomic_bool _shouldStop; + std::atomic _processing; std::vector _threads; std::deque _pending; std::deque _completed; std::condition_variable _condPending; std::condition_variable _condComplete; - std::atomic _processing; - std::atomic_bool _shouldStop; std::mutex _mutex; typedef std::unique_lock unique_lock; From bee0fc25b10d7c0749ded7f6ad170ca016b6defc Mon Sep 17 00:00:00 2001 From: ZehMatt Date: Tue, 24 Apr 2018 11:37:07 +0200 Subject: [PATCH 07/20] Move all code into JobPool.hpp --- src/openrct2/core/JobPool.cpp | 103 ------------------------------- src/openrct2/core/JobPool.hpp | 110 +++++++++++++++++++++++++++++++--- 2 files changed, 102 insertions(+), 111 deletions(-) delete mode 100644 src/openrct2/core/JobPool.cpp diff --git a/src/openrct2/core/JobPool.cpp b/src/openrct2/core/JobPool.cpp deleted file mode 100644 index 4f319ea056..0000000000 --- a/src/openrct2/core/JobPool.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include "JobPool.hpp" - -JobPool::JobPool() - : _shouldStop(false), - _processing(0) -{ - for (size_t n = 0; n < std::thread::hardware_concurrency(); n++) - { - _threads.emplace_back(&JobPool::processQueue, this); - } -} - -JobPool::~JobPool() -{ - { - unique_lock lock(_mutex); - _shouldStop = true; - _condPending.notify_all(); - } - - for (auto&& th : _threads) - { - if(th.joinable()) - th.join(); - } -} - -void JobPool::addTask(std::function workFn, std::function completionFn) -{ - unique_lock lock(_mutex); - _pending.push_back(TaskData_t{workFn, completionFn}); - _condPending.notify_one(); -} - -void JobPool::addTask(std::function workFn) -{ - unique_lock lock(_mutex); - _pending.push_back(TaskData_t{ workFn, nullptr }); - _condPending.notify_one(); -} - -void JobPool::join() -{ - while (true) - { - unique_lock lock(_mutex); - _condComplete.wait(lock, [this]() - { - return (_pending.empty() && _processing == 0) || - (_completed.empty() == false); - }); - - if (_completed.empty() && - _pending.empty() && - _processing == 0) - { - break; - } - - auto taskData = _completed.front(); - _completed.pop_front(); - - lock.unlock(); - - taskData.completionFn(); - } -} - -void JobPool::processQueue() -{ - while (true) - { - unique_lock lock(_mutex); - _condPending.wait(lock, [this]() { - return _shouldStop || !_pending.empty(); - }); - if (!_pending.empty()) - { - _processing++; - - auto taskData = _pending.front(); - _pending.pop_front(); - - lock.unlock(); - - taskData.workFn(); - - lock.lock(); - - if (taskData.completionFn) - { - _completed.push_back(taskData); - } - - _processing--; - _condComplete.notify_one(); - } - if(_shouldStop) - break; - } -} - - diff --git a/src/openrct2/core/JobPool.hpp b/src/openrct2/core/JobPool.hpp index 684e060986..bf6f47d723 100644 --- a/src/openrct2/core/JobPool.hpp +++ b/src/openrct2/core/JobPool.hpp @@ -14,6 +14,8 @@ *****************************************************************************/ #pragma endregion +#pragma once + #include #include #include @@ -31,8 +33,8 @@ private: const std::function completionFn; }; - std::atomic_bool _shouldStop; - std::atomic _processing; + std::atomic_bool _shouldStop = false; + std::atomic _processing = 0; std::vector _threads; std::deque _pending; std::deque _completed; @@ -43,16 +45,108 @@ private: typedef std::unique_lock unique_lock; public: - JobPool(); - ~JobPool(); + JobPool() + { + for (size_t n = 0; n < std::thread::hardware_concurrency(); n++) + { + _threads.emplace_back(&JobPool::processQueue, this); + } + } + + ~JobPool() + { + { + unique_lock lock(_mutex); + _shouldStop = true; + _condPending.notify_all(); + } + + for (auto&& th : _threads) + { + if (th.joinable()) + th.join(); + } + } void addTask(std::function workFn, - std::function completionFn); + std::function completionFn) + { + { + unique_lock lock(_mutex); + _pending.push_back(TaskData_t{ workFn, completionFn }); + _condPending.notify_one(); + } + } - void addTask(std::function workFn); + void addTask(std::function workFn) + { + return addTask(workFn, nullptr); + } - void join(); + void join() + { + while (true) + { + unique_lock lock(_mutex); + _condComplete.wait(lock, [this]() + { + return (_pending.empty() && _processing == 0) || + (_completed.empty() == false); + }); + + if (_completed.empty() && + _pending.empty() && + _processing == 0) + { + break; + } + + if (!_completed.empty()) + { + auto taskData = _completed.front(); + _completed.pop_front(); + + lock.unlock(); + + taskData.completionFn(); + + lock.lock(); + } + } + } private: - void processQueue(); + void processQueue() + { + while (true) + { + unique_lock lock(_mutex); + _condPending.wait(lock, [this]() { + return _shouldStop || !_pending.empty(); + }); + if (!_pending.empty()) + { + _processing++; + + auto taskData = _pending.front(); + _pending.pop_front(); + + lock.unlock(); + + taskData.workFn(); + + lock.lock(); + + if (taskData.completionFn) + { + _completed.push_back(taskData); + } + + _processing--; + _condComplete.notify_one(); + } + if (_shouldStop) + break; + } + } }; From 64d91092268a9515b24d4514a6ffdacb80a3002f Mon Sep 17 00:00:00 2001 From: ZehMatt Date: Tue, 24 Apr 2018 12:58:57 +0200 Subject: [PATCH 08/20] Add progress report back. --- src/openrct2/core/FileIndex.hpp | 6 +++++- src/openrct2/core/JobPool.hpp | 35 ++++++++++++++++++++++----------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/openrct2/core/FileIndex.hpp b/src/openrct2/core/FileIndex.hpp index 049ed141bb..1ed4934460 100644 --- a/src/openrct2/core/FileIndex.hpp +++ b/src/openrct2/core/FileIndex.hpp @@ -242,7 +242,11 @@ private: std::ref(printLock))); } - jobPool.join(); + jobPool.join([&]() + { + size_t completed = totalCount - jobPool.countPending(); + Console::WriteFormat("File %5d of %d, done %3d%%\r", completed, totalCount, completed / totalCount); + }); for (auto&& itr : containers) { diff --git a/src/openrct2/core/JobPool.hpp b/src/openrct2/core/JobPool.hpp index bf6f47d723..bb1a511a7d 100644 --- a/src/openrct2/core/JobPool.hpp +++ b/src/openrct2/core/JobPool.hpp @@ -33,8 +33,8 @@ private: const std::function completionFn; }; - std::atomic_bool _shouldStop = false; - std::atomic _processing = 0; + std::atomic_bool _shouldStop; + std::atomic _processing; std::vector _threads; std::deque _pending; std::deque _completed; @@ -47,6 +47,8 @@ private: public: JobPool() { + _shouldStop = false; + _processing = 0; for (size_t n = 0; n < std::thread::hardware_concurrency(); n++) { _threads.emplace_back(&JobPool::processQueue, this); @@ -83,17 +85,21 @@ public: return addTask(workFn, nullptr); } - void join() + void join(std::function reportFn = nullptr) { while (true) { unique_lock lock(_mutex); _condComplete.wait(lock, [this]() { - return (_pending.empty() && _processing == 0) || - (_completed.empty() == false); + return (_pending.empty() && _processing == 0) || !_completed.empty(); }); + if (reportFn) + { + reportFn(); + } + if (_completed.empty() && _pending.empty() && _processing == 0) @@ -106,15 +112,23 @@ public: auto taskData = _completed.front(); _completed.pop_front(); - lock.unlock(); + if (taskData.completionFn) + { + lock.unlock(); - taskData.completionFn(); + taskData.completionFn(); - lock.lock(); + lock.lock(); + } } } } + size_t countPending() + { + return _pending.size(); + } + private: void processQueue() { @@ -137,10 +151,7 @@ private: lock.lock(); - if (taskData.completionFn) - { - _completed.push_back(taskData); - } + _completed.push_back(taskData); _processing--; _condComplete.notify_one(); From b9e0eede44671cf2bed85645d31b738a324df711 Mon Sep 17 00:00:00 2001 From: ZehMatt Date: Tue, 24 Apr 2018 13:23:14 +0200 Subject: [PATCH 09/20] Code cleanup --- src/openrct2/core/FileIndex.hpp | 2 +- src/openrct2/core/JobPool.hpp | 55 ++++++++++++++++++++------------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/openrct2/core/FileIndex.hpp b/src/openrct2/core/FileIndex.hpp index 1ed4934460..60b1365972 100644 --- a/src/openrct2/core/FileIndex.hpp +++ b/src/openrct2/core/FileIndex.hpp @@ -245,7 +245,7 @@ private: jobPool.join([&]() { size_t completed = totalCount - jobPool.countPending(); - Console::WriteFormat("File %5d of %d, done %3d%%\r", completed, totalCount, completed / totalCount); + Console::WriteFormat("File %5d of %d, done %3d%%\r", completed, totalCount, completed * 100 / totalCount); }); for (auto&& itr : containers) diff --git a/src/openrct2/core/JobPool.hpp b/src/openrct2/core/JobPool.hpp index bb1a511a7d..9258df87dd 100644 --- a/src/openrct2/core/JobPool.hpp +++ b/src/openrct2/core/JobPool.hpp @@ -23,6 +23,7 @@ #include #include #include +#include class JobPool { @@ -65,8 +66,8 @@ public: for (auto&& th : _threads) { - if (th.joinable()) - th.join(); + assert(th.joinable() != false); + th.join(); } } @@ -87,27 +88,18 @@ public: void join(std::function reportFn = nullptr) { + unique_lock lock(_mutex); while (true) { - unique_lock lock(_mutex); + // Wait for the queue to become empty or having completed tasks. _condComplete.wait(lock, [this]() { - return (_pending.empty() && _processing == 0) || !_completed.empty(); + return (_pending.empty() && _processing == 0) || + !_completed.empty(); }); - if (reportFn) - { - reportFn(); - } - - if (_completed.empty() && - _pending.empty() && - _processing == 0) - { - break; - } - - if (!_completed.empty()) + // Dispatch all completion callbacks if there are any. + while (!_completed.empty()) { auto taskData = _completed.front(); _completed.pop_front(); @@ -121,6 +113,23 @@ public: lock.lock(); } } + + if (reportFn) + { + lock.unlock(); + + reportFn(); + + lock.lock(); + } + + // If everything is empty and no more work has to be done we can stop waiting. + if (_completed.empty() && + _pending.empty() && + _processing == 0) + { + break; + } } } @@ -132,12 +141,15 @@ public: private: void processQueue() { - while (true) + unique_lock lock(_mutex); + do { - unique_lock lock(_mutex); - _condPending.wait(lock, [this]() { + // Wait for work or cancelation. + _condPending.wait(lock, [this]() + { return _shouldStop || !_pending.empty(); }); + if (!_pending.empty()) { _processing++; @@ -156,8 +168,7 @@ private: _processing--; _condComplete.notify_one(); } - if (_shouldStop) - break; } + while(!_shouldStop); } }; From 7be1cd3e37c18cb7a0a09956d56f17adc103734c Mon Sep 17 00:00:00 2001 From: ZehMatt Date: Tue, 24 Apr 2018 19:06:32 +0200 Subject: [PATCH 10/20] Use std::list and fixed step size. --- src/openrct2/core/FileIndex.hpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/openrct2/core/FileIndex.hpp b/src/openrct2/core/FileIndex.hpp index 60b1365972..7fb12390cc 100644 --- a/src/openrct2/core/FileIndex.hpp +++ b/src/openrct2/core/FileIndex.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "../common.h" #include "Console.hpp" #include "File.h" @@ -192,7 +193,7 @@ private: if (_log_levels[DIAGNOSTIC_LEVEL_VERBOSE]) { - std::unique_lock lock(printLock); + std::lock_guard lock(printLock); log_verbose("FileIndex:Indexing '%s'", filePath.c_str()); } @@ -217,21 +218,17 @@ private: JobPool jobPool; std::mutex printLock; // For verbose prints. - std::vector> containers; + std::list> containers; - size_t stepSize = std::thread::hardware_concurrency(); - size_t numTasks = totalCount / stepSize; - size_t taskGroup = 0; - numTasks += (totalCount % stepSize == 0 ? 0 : 1); + size_t stepSize = 100; // Handpicked, seems to work well with 4/8 cores. - containers.resize(numTasks); - - for (size_t rangeStart = 0; rangeStart < totalCount; rangeStart += stepSize, taskGroup++) + for (size_t rangeStart = 0; rangeStart < totalCount; rangeStart += stepSize) { if (rangeStart + stepSize > totalCount) stepSize = totalCount - rangeStart; - auto& items = containers[taskGroup]; + containers.emplace_back(); + auto& items = containers.back(); jobPool.addTask(std::bind(&FileIndex::BuildRange, this, From d77f06c1eea6725ed670fa18d8ea4644b8db7e58 Mon Sep 17 00:00:00 2001 From: ZehMatt Date: Tue, 24 Apr 2018 21:35:57 +0200 Subject: [PATCH 11/20] Coding style changes. --- src/openrct2/core/JobPool.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/openrct2/core/JobPool.hpp b/src/openrct2/core/JobPool.hpp index 9258df87dd..6233315df2 100644 --- a/src/openrct2/core/JobPool.hpp +++ b/src/openrct2/core/JobPool.hpp @@ -52,7 +52,7 @@ public: _processing = 0; for (size_t n = 0; n < std::thread::hardware_concurrency(); n++) { - _threads.emplace_back(&JobPool::processQueue, this); + _threads.emplace_back(&JobPool::ProcessQueue, this); } } @@ -71,7 +71,7 @@ public: } } - void addTask(std::function workFn, + void AddTask(std::function workFn, std::function completionFn) { { @@ -81,12 +81,12 @@ public: } } - void addTask(std::function workFn) + void AddTask(std::function workFn) { - return addTask(workFn, nullptr); + return AddTask(workFn, nullptr); } - void join(std::function reportFn = nullptr) + void Join(std::function reportFn = nullptr) { unique_lock lock(_mutex); while (true) @@ -133,13 +133,13 @@ public: } } - size_t countPending() + size_t CountPending() { return _pending.size(); } private: - void processQueue() + void ProcessQueue() { unique_lock lock(_mutex); do From b9d939b294ab6691acbfec290992ed94401f2878 Mon Sep 17 00:00:00 2001 From: ZehMatt Date: Tue, 24 Apr 2018 21:36:28 +0200 Subject: [PATCH 12/20] Show progress of processed elements instead of pending tasks. --- src/openrct2/core/FileIndex.hpp | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/openrct2/core/FileIndex.hpp b/src/openrct2/core/FileIndex.hpp index 7fb12390cc..d2017f7aa4 100644 --- a/src/openrct2/core/FileIndex.hpp +++ b/src/openrct2/core/FileIndex.hpp @@ -184,6 +184,7 @@ private: size_t rangeStart, size_t rangeEnd, std::vector& items, + std::atomic& processed, std::mutex& printLock) const { items.reserve(rangeEnd - rangeStart); @@ -202,6 +203,8 @@ private: { items.push_back(std::get<1>(item)); } + + processed++; } } @@ -222,28 +225,36 @@ private: size_t stepSize = 100; // Handpicked, seems to work well with 4/8 cores. + std::atomic processed = ATOMIC_VAR_INIT(0); + + auto reportProgress = [&]() + { + const size_t completed = processed; + Console::WriteFormat("File %5d of %d, done %3d%%\r", completed, totalCount, completed * 100 / totalCount); + }; + for (size_t rangeStart = 0; rangeStart < totalCount; rangeStart += stepSize) { if (rangeStart + stepSize > totalCount) stepSize = totalCount - rangeStart; + // TODO: change to auto& items = containers.emplace_back() in C++17 containers.emplace_back(); auto& items = containers.back(); - jobPool.addTask(std::bind(&FileIndex::BuildRange, + jobPool.AddTask(std::bind(&FileIndex::BuildRange, this, std::cref(scanResult), rangeStart, rangeStart + stepSize, std::ref(items), + std::ref(processed), std::ref(printLock))); + + reportProgress(); } - jobPool.join([&]() - { - size_t completed = totalCount - jobPool.countPending(); - Console::WriteFormat("File %5d of %d, done %3d%%\r", completed, totalCount, completed * 100 / totalCount); - }); + jobPool.Join(reportProgress); for (auto&& itr : containers) { From 20be1cc0a8c71066f30bd7dc54aef7847626c06c Mon Sep 17 00:00:00 2001 From: Ted John Date: Tue, 24 Apr 2018 22:55:28 +0100 Subject: [PATCH 13/20] Small refactor and code format --- src/openrct2/core/FileIndex.hpp | 15 ++++++---- src/openrct2/core/JobPool.hpp | 52 +++++++++++++++++---------------- 2 files changed, 36 insertions(+), 31 deletions(-) diff --git a/src/openrct2/core/FileIndex.hpp b/src/openrct2/core/FileIndex.hpp index d2017f7aa4..c4ea705e30 100644 --- a/src/openrct2/core/FileIndex.hpp +++ b/src/openrct2/core/FileIndex.hpp @@ -26,8 +26,8 @@ #include "File.h" #include "FileScanner.h" #include "FileStream.hpp" -#include "Path.hpp" #include "JobPool.hpp" +#include "Path.hpp" template class FileIndex @@ -227,16 +227,19 @@ private: std::atomic processed = ATOMIC_VAR_INIT(0); - auto reportProgress = [&]() - { - const size_t completed = processed; - Console::WriteFormat("File %5d of %d, done %3d%%\r", completed, totalCount, completed * 100 / totalCount); - }; + auto reportProgress = + [&]() + { + const size_t completed = processed; + Console::WriteFormat("File %5d of %d, done %3d%%\r", completed, totalCount, completed * 100 / totalCount); + }; for (size_t rangeStart = 0; rangeStart < totalCount; rangeStart += stepSize) { if (rangeStart + stepSize > totalCount) + { stepSize = totalCount - rangeStart; + } // TODO: change to auto& items = containers.emplace_back() in C++17 containers.emplace_back(); diff --git a/src/openrct2/core/JobPool.hpp b/src/openrct2/core/JobPool.hpp index 6233315df2..12a1f1ad85 100644 --- a/src/openrct2/core/JobPool.hpp +++ b/src/openrct2/core/JobPool.hpp @@ -16,29 +16,35 @@ #pragma once -#include +#include +#include #include -#include #include #include -#include +#include +#include #include -#include class JobPool { private: - struct TaskData_t + struct TaskData { - const std::function workFn; - const std::function completionFn; + const std::function WorkFn; + const std::function CompletionFn; + + TaskData(std::function workFn, std::function completionFn) + : WorkFn(workFn), + CompletionFn(completionFn) + { + } }; std::atomic_bool _shouldStop; std::atomic _processing; std::vector _threads; - std::deque _pending; - std::deque _completed; + std::deque _pending; + std::deque _completed; std::condition_variable _condPending; std::condition_variable _condComplete; std::mutex _mutex; @@ -48,8 +54,6 @@ private: public: JobPool() { - _shouldStop = false; - _processing = 0; for (size_t n = 0; n < std::thread::hardware_concurrency(); n++) { _threads.emplace_back(&JobPool::ProcessQueue, this); @@ -71,14 +75,11 @@ public: } } - void AddTask(std::function workFn, - std::function completionFn) + void AddTask(std::function workFn, std::function completionFn) { - { - unique_lock lock(_mutex); - _pending.push_back(TaskData_t{ workFn, completionFn }); - _condPending.notify_one(); - } + unique_lock lock(_mutex); + _pending.emplace_back(workFn, completionFn); + _condPending.notify_one(); } void AddTask(std::function workFn) @@ -104,11 +105,11 @@ public: auto taskData = _completed.front(); _completed.pop_front(); - if (taskData.completionFn) + if (taskData.CompletionFn) { lock.unlock(); - taskData.completionFn(); + taskData.CompletionFn(); lock.lock(); } @@ -145,10 +146,11 @@ private: do { // Wait for work or cancelation. - _condPending.wait(lock, [this]() - { - return _shouldStop || !_pending.empty(); - }); + _condPending.wait(lock, + [this]() + { + return _shouldStop || !_pending.empty(); + }); if (!_pending.empty()) { @@ -159,7 +161,7 @@ private: lock.unlock(); - taskData.workFn(); + taskData.WorkFn(); lock.lock(); From 7da60f4950a569d43d1480509f4bba4f766f20e4 Mon Sep 17 00:00:00 2001 From: Ted John Date: Tue, 24 Apr 2018 23:08:58 +0100 Subject: [PATCH 14/20] Make log functions atomic Use only one print call to stdout in log functions so that messages are not malformed. --- src/openrct2/Diagnostic.cpp | 62 ++++++++++++++++++------------------ src/openrct2/core/String.cpp | 8 +++++ src/openrct2/core/String.hpp | 1 + 3 files changed, 40 insertions(+), 31 deletions(-) diff --git a/src/openrct2/Diagnostic.cpp b/src/openrct2/Diagnostic.cpp index 61e738ab22..8ef740c859 100644 --- a/src/openrct2/Diagnostic.cpp +++ b/src/openrct2/Diagnostic.cpp @@ -16,6 +16,7 @@ #include #include +#include "core/String.hpp" #include "Diagnostic.h" #ifdef __ANDROID__ @@ -80,46 +81,45 @@ static constexpr const char * _level_strings[] = { void diagnostic_log(DIAGNOSTIC_LEVEL diagnosticLevel, const char *format, ...) { va_list args; + if (_log_levels[diagnosticLevel]) + { + // Level + auto prefix = String::StdFormat("%s: ", _level_strings[diagnosticLevel]); - if (!_log_levels[diagnosticLevel]) - return; + // Message + va_start(args, format); + auto msg = String::StdFormat_VA(format, args); + va_end(args); - FILE * stream = diagnostic_get_stream(diagnosticLevel); - - // Level - fprintf(stream, "%s: ", _level_strings[diagnosticLevel]); - - // Message - va_start(args, format); - vfprintf(stream, format, args); - va_end(args); - - // Line terminator - fprintf(stream, "\n"); + auto stream = diagnostic_get_stream(diagnosticLevel); + fprintf(stream, "%s%s\n", prefix.c_str(), msg.c_str()); + } } void diagnostic_log_with_location(DIAGNOSTIC_LEVEL diagnosticLevel, const char *file, const char *function, sint32 line, const char *format, ...) { va_list args; + if (_log_levels[diagnosticLevel]) + { + // Level and source code information + std::string prefix; + if (_log_location_enabled) + { + prefix = String::StdFormat("%s[%s:%d (%s)]: ", _level_strings[diagnosticLevel], file, line, function); + } + else + { + prefix = String::StdFormat("%s: ", _level_strings[diagnosticLevel]); + } - if (!_log_levels[diagnosticLevel]) - return; + // Message + va_start(args, format); + auto msg = String::StdFormat_VA(format, args); + va_end(args); - FILE * stream = diagnostic_get_stream(diagnosticLevel); - - // Level and source code information - if (_log_location_enabled) - fprintf(stream, "%s[%s:%d (%s)]: ", _level_strings[diagnosticLevel], file, line, function); - else - fprintf(stream, "%s: ", _level_strings[diagnosticLevel]); - - // Message - va_start(args, format); - vfprintf(stream, format, args); - va_end(args); - - // Line terminator - fprintf(stream, "\n"); + auto stream = diagnostic_get_stream(diagnosticLevel); + fprintf(stream, "%s%s\n", prefix.c_str(), msg.c_str()); + } } #endif // __ANDROID__ diff --git a/src/openrct2/core/String.cpp b/src/openrct2/core/String.cpp index 64464eefc3..11feeb696d 100644 --- a/src/openrct2/core/String.cpp +++ b/src/openrct2/core/String.cpp @@ -41,6 +41,14 @@ namespace String else return std::string(str); } + std::string StdFormat_VA(const utf8 * format, va_list args) + { + auto buffer = Format_VA(format, args); + auto returnValue = ToStd(buffer); + Memory::Free(buffer); + return returnValue; + } + std::string StdFormat(const utf8 * format, ...) { va_list args; diff --git a/src/openrct2/core/String.hpp b/src/openrct2/core/String.hpp index cbb89d4d3d..49e534ba20 100644 --- a/src/openrct2/core/String.hpp +++ b/src/openrct2/core/String.hpp @@ -40,6 +40,7 @@ namespace String constexpr const utf8 * Empty = ""; std::string ToStd(const utf8 * str); + std::string StdFormat_VA(const utf8 * format, va_list args); std::string StdFormat(const utf8 * format, ...); std::string ToUtf8(const std::wstring &s); std::wstring ToUtf16(const std::string &s); From dd58a710ee1a4725117feeae5d67d7df4f027082 Mon Sep 17 00:00:00 2001 From: Ted John Date: Tue, 24 Apr 2018 23:30:53 +0100 Subject: [PATCH 15/20] Make Console::Write functions atomic --- src/openrct2/core/Console.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/openrct2/core/Console.cpp b/src/openrct2/core/Console.cpp index 9887f920e7..2bf9ebc72e 100644 --- a/src/openrct2/core/Console.cpp +++ b/src/openrct2/core/Console.cpp @@ -15,6 +15,7 @@ #pragma endregion #include +#include #include "Console.hpp" #include "../platform/platform.h" @@ -33,10 +34,8 @@ namespace Console void WriteSpace(size_t count) { - for (size_t i = 0; i < count; i++) - { - Write(' '); - } + std::string sz(count, ' '); + Write(sz.c_str()); } void WriteFormat(const utf8 * format, ...) @@ -58,8 +57,8 @@ namespace Console va_list args; va_start(args, format); - vfprintf(stdout, format, args); - puts(""); + auto formatLn = std::string(format) + "\n"; + vfprintf(stdout, formatLn.c_str(), args); va_end(args); } @@ -99,8 +98,8 @@ namespace Console void WriteLine_VA(const utf8 * format, va_list args) { - vfprintf(stdout, format, args); - puts(""); + auto formatLn = std::string(format) + "\n"; + vfprintf(stdout, formatLn.c_str(), args); } } } From ee53855c623a044f1ea009285069f8141090f8b2 Mon Sep 17 00:00:00 2001 From: ZehMatt Date: Thu, 26 Apr 2018 13:31:19 +0200 Subject: [PATCH 16/20] Use emplace_back with reference as return type. --- src/openrct2/core/FileIndex.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/openrct2/core/FileIndex.hpp b/src/openrct2/core/FileIndex.hpp index c4ea705e30..f834e4f2ee 100644 --- a/src/openrct2/core/FileIndex.hpp +++ b/src/openrct2/core/FileIndex.hpp @@ -241,9 +241,7 @@ private: stepSize = totalCount - rangeStart; } - // TODO: change to auto& items = containers.emplace_back() in C++17 - containers.emplace_back(); - auto& items = containers.back(); + auto& items = containers.emplace_back(); jobPool.AddTask(std::bind(&FileIndex::BuildRange, this, From c0ccaa341a8fbabd19e91f884754a4222f6442ef Mon Sep 17 00:00:00 2001 From: Ted John Date: Fri, 27 Apr 2018 13:03:16 +0100 Subject: [PATCH 17/20] Use C++17 for xcode --- OpenRCT2.xcodeproj/project.pbxproj | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index e75854dc5d..a0286e2188 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -3487,7 +3487,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = NO; @@ -3535,7 +3535,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = NO; @@ -3581,7 +3581,7 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CLANG_CXX_LIBRARY = "libc++"; CLANG_WARN_UNREACHABLE_CODE = NO; CLANG_X86_VECTOR_INSTRUCTIONS = default; @@ -3618,7 +3618,7 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CLANG_CXX_LIBRARY = "libc++"; CLANG_WARN_UNREACHABLE_CODE = NO; CLANG_X86_VECTOR_INSTRUCTIONS = default; @@ -3655,7 +3655,7 @@ buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CLANG_ENABLE_OBJC_ARC = NO; CLANG_WARN_DOCUMENTATION_COMMENTS = NO; CLANG_WARN_UNREACHABLE_CODE = NO; @@ -3693,7 +3693,7 @@ buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CLANG_ENABLE_OBJC_ARC = NO; CLANG_WARN_DOCUMENTATION_COMMENTS = NO; CLANG_WARN_UNREACHABLE_CODE = NO; @@ -3731,7 +3731,7 @@ buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CLANG_ENABLE_OBJC_ARC = NO; CLANG_WARN_DOCUMENTATION_COMMENTS = NO; CODE_SIGN_IDENTITY = ""; @@ -3763,7 +3763,7 @@ buildSettings = { CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CLANG_ENABLE_OBJC_ARC = NO; CLANG_WARN_DOCUMENTATION_COMMENTS = NO; CODE_SIGN_IDENTITY = ""; From 76e54dd5ec3093d1a45ba6e29db843c7925dcabd Mon Sep 17 00:00:00 2001 From: ZehMatt Date: Fri, 27 Apr 2018 21:50:16 +0200 Subject: [PATCH 18/20] Fix dead lock due to uninitialized variables. --- src/openrct2/core/JobPool.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openrct2/core/JobPool.hpp b/src/openrct2/core/JobPool.hpp index 12a1f1ad85..af1a1a6ff9 100644 --- a/src/openrct2/core/JobPool.hpp +++ b/src/openrct2/core/JobPool.hpp @@ -40,8 +40,8 @@ private: } }; - std::atomic_bool _shouldStop; - std::atomic _processing; + std::atomic_bool _shouldStop = { false }; + std::atomic _processing = { 0 }; std::vector _threads; std::deque _pending; std::deque _completed; From 64821564ab98dc5f8583e352f68cdeed07ff3e78 Mon Sep 17 00:00:00 2001 From: ZehMatt Date: Fri, 27 Apr 2018 22:36:19 +0200 Subject: [PATCH 19/20] [ci-skip] Update changelog.txt --- distribution/changelog.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 6b0a15004d..6cffa24a8d 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -21,7 +21,8 @@ - Fix: Cut-away view does not draw tile elements that have been moved down on the list. - Improved: [#2989] Multiplayer window now changes title when tab changes. - Improved: [#5339] Change eyedropper icon to actual eyedropper and change cursor to crosshair. -- Improved: Raising land near the map edge makes the affected area smaller instead of showing an 'off edge map' error. +- Improved: [#7302] Raising land near the map edge makes the affected area smaller instead of showing an 'off edge map' error. +- Improved: [#7435] Object indexing now supports multi-threading. 0.1.2 (2018-03-18) ------------------------------------------------------------------------ From 9caa30f84616e3373c96b7bbc13343402de4798e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Janiszewski?= Date: Fri, 27 Apr 2018 22:47:27 +0200 Subject: [PATCH 20/20] Fix TestPaint target Adds missing files to target --- test/testpaint/CMakeLists.txt | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/test/testpaint/CMakeLists.txt b/test/testpaint/CMakeLists.txt index 0f9ed9aaf0..1d362a9706 100644 --- a/test/testpaint/CMakeLists.txt +++ b/test/testpaint/CMakeLists.txt @@ -54,15 +54,28 @@ endif () set(OPENRCT2_SRCPATH "${ROOT_DIR}/src/openrct2") file(GLOB_RECURSE ORCT2_RIDE_SOURCES "${OPENRCT2_SRCPATH}/ride/*/*.cpp") -file(GLOB_RECURSE ORCT2_RIDE_DEP_SOURCES "${OPENRCT2_SRCPATH}/ride/RideData.cpp" - "${OPENRCT2_SRCPATH}/ride/TrackData.cpp" - "${OPENRCT2_SRCPATH}/ride/TrackDataOld.cpp" - "${OPENRCT2_SRCPATH}/ride/TrackPaint.cpp" - "${OPENRCT2_SRCPATH}/rct2/addresses.c" - "${OPENRCT2_SRCPATH}/Diagnostic.cpp" - "${OPENRCT2_SRCPATH}/rct2/hook.c" - "${OPENRCT2_SRCPATH}/paint/tile_element/TileElement.cpp" - "${OPENRCT2_SRCPATH}/paint/PaintHelpers.cpp") +file(GLOB_RECURSE ORCT2_RIDE_DEP_SOURCES + "${OPENRCT2_SRCPATH}/Diagnostic.cpp" + "${OPENRCT2_SRCPATH}/paint/PaintHelpers.cpp" + "${OPENRCT2_SRCPATH}/paint/tile_element/TileElement.cpp" + "${OPENRCT2_SRCPATH}/rct2/addresses.c" + "${OPENRCT2_SRCPATH}/rct2/hook.c" + "${OPENRCT2_SRCPATH}/ride/RideData.cpp" + "${OPENRCT2_SRCPATH}/ride/TrackData.cpp" + "${OPENRCT2_SRCPATH}/ride/TrackDataOld.cpp" + "${OPENRCT2_SRCPATH}/ride/TrackPaint.cpp" + "${ROOT_DIR}/src/openrct2/core/Console.cpp" + "${ROOT_DIR}/src/openrct2/core/Diagnostics.cpp" + "${ROOT_DIR}/src/openrct2/core/Guard.cpp" + "${ROOT_DIR}/src/openrct2/core/String.cpp" + "${ROOT_DIR}/src/openrct2/Diagnostic.cpp" + "${ROOT_DIR}/src/openrct2/localisation/ConversionTables.cpp" + "${ROOT_DIR}/src/openrct2/localisation/Convert.cpp" + "${ROOT_DIR}/src/openrct2/localisation/FormatCodes.cpp" + "${ROOT_DIR}/src/openrct2/localisation/UTF8.cpp" + "${ROOT_DIR}/src/openrct2/util/Util.cpp" + "${ROOT_DIR}/src/openrct2/Version.cpp" +) file(GLOB_RECURSE ORCT2_TESTPAINT_SOURCES "${CMAKE_CURRENT_LIST_DIR}/*.c" "${CMAKE_CURRENT_LIST_DIR}/*.cpp" "${CMAKE_CURRENT_LIST_DIR}/*.h") @@ -73,6 +86,7 @@ set_source_files_properties(${CMAKE_CURRENT_LIST_DIR}/addresses.c PROPERTIES COM add_executable(testpaint EXCLUDE_FROM_ALL ${ORCT2_RIDE_SOURCES} ${ORCT2_RIDE_DEP_SOURCES} ${ORCT2_TESTPAINT_SOURCES} ${RCT2_SECTIONS}) target_include_directories(testpaint PRIVATE "${ROOT_DIR}/src/") +target_link_libraries(testpaint z) set_target_properties(testpaint PROPERTIES COMPILE_FLAGS "-DNO_VEHICLES -D__TESTPAINT__ -Wno-unused") set_target_properties(testpaint PROPERTIES LINK_FLAGS ${RCT2_SEGMENT_LINKER_FLAGS})