package iron.culling; #if (target.threaded) class JobSystem { public static var numWorkers(default, null): Int = 0; static var jobQueue: sys.thread.DequeVoid> = null; static var doneLock: sys.thread.Lock = null; static var jobError: Dynamic = null; public static function init(workers: Int = 3) { if (jobQueue != null) return; numWorkers = workers < 1 ? 1 : workers; jobQueue = new sys.thread.Deque(); doneLock = new sys.thread.Lock(); for (_ in 0...numWorkers) { sys.thread.Thread.create(workerLoop); } } static function workerLoop() { while (true) { var job = jobQueue.pop(true); if (job == null) return; try { job(); } catch (e: Dynamic) { jobError = e; } doneLock.release(); } } public static function parallelFor(count: Int, fn: Int -> Int -> Void) { init(); var chunks = numWorkers + 1; var chunkSize = Std.int((count + chunks - 1) / chunks); if (chunkSize < 1) chunkSize = 1; var jobs = 0; var start = chunkSize; // Chunk 0 runs on the calling thread while (start < count) { var s = start; var e = start + chunkSize > count ? count : start + chunkSize; jobQueue.add(function() fn(s, e)); jobs++; start = e; } fn(0, chunkSize > count ? count : chunkSize); for (_ in 0...jobs) doneLock.wait(); if (jobError != null) { var e = jobError; jobError = null; throw e; } } } #end