aboutsummaryrefslogtreecommitdiffstats
path: root/renderer.h
diff options
context:
space:
mode:
Diffstat (limited to 'renderer.h')
-rw-r--r--renderer.h76
1 files changed, 76 insertions, 0 deletions
diff --git a/renderer.h b/renderer.h
new file mode 100644
index 0000000..ec7b170
--- /dev/null
+++ b/renderer.h
@@ -0,0 +1,76 @@
+#include <algorithm>
+#include <atomic>
+#include <memory>
+#include <ranges>
+#include <semaphore>
+#include <thread>
+
+template<int Threads>
+class Renderer
+{
+ std::counting_semaphore<Threads> Workers;
+ std::atomic_uint processed;
+ unsigned total;
+ std::atomic_bool Stop;
+ std::unique_ptr<std::thread> primary;
+
+public:
+ Renderer(auto func, unsigned Width, unsigned Height, auto pbuf):
+ Workers(Threads), processed(0), total(Threads * 8)
+ {
+ Stop.store(false);
+
+ auto threads = std::views::transform(
+ std::views::chunk(
+ std::views::cartesian_product(
+ std::views::iota(0u, Width),
+ std::views::iota(0u, Height),
+ std::views::single(pbuf)),
+ Width * Height / total),
+ [=, this](auto chunk) { return std::thread([=, this] { worker(func, chunk); }); });
+
+ primary.reset(new std::thread([=, this] {
+ for (auto th : threads) {
+ Workers.acquire();
+ th.detach();
+ }
+ for (auto i : std::views::iota(0, Threads))
+ Workers.acquire();
+ for (auto i : std::views::iota(0, Threads))
+ Workers.release();
+ Stop.store(true);
+ }));
+ }
+
+ ~Renderer() {
+ stop();
+ }
+
+ operator bool() const {
+ return !Stop.load();
+ }
+
+ unsigned progress() const {
+ return processed.load() * 100 / total;
+ }
+
+ void stop() {
+ Stop.store(true);
+ if (primary->joinable())
+ primary->join();
+ }
+
+private:
+ void worker(auto func, auto chunk) {
+ for (auto xyb : chunk) {
+ if (Stop.load())
+ break;
+ std::apply(func, xyb);
+ }
+
+ processed++;
+ Workers.release();
+ }
+};
+
+