internal static CalculationOptions[] Split(CalculationOptions options, uint tasks) { Queue<CalculationOptions> t1 = new Queue<CalculationOptions>(); Queue<CalculationOptions> t2 = new Queue<CalculationOptions>(); t1.Enqueue(options); tasks = (uint)Math.Pow(4, Math.Ceiling(Math.Log(tasks) / Math.Log(4))); while (tasks > 0) { while (t1.Count > 0) { CalculationOptions t = t1.Dequeue(); foreach (CalculationOptions spl in SplitInFour(t)) { t2.Enqueue(spl); } } tasks /= 4; t1 = t2; t2 = new Queue<CalculationOptions>(); } return t1.ToArray(); }
internal static CalculationOptions[] SplitInFour(CalculationOptions options) { CalculationOptions[] opt = new CalculationOptions[4]; opt[0] = options.Duplicate(); opt[0].XSkip *= 2; opt[0].YSkip *= 2; opt[1] = options.Duplicate(); opt[1].XSkip *= 2; opt[1].YSkip *= 2; opt[1].XOff += options.XSkip; opt[2] = options.Duplicate(); opt[2].XSkip *= 2; opt[2].YSkip *= 2; opt[2].YSkip += options.YSkip; opt[3] = options.Duplicate(); opt[3].XSkip *= 2; opt[3].YSkip *= 2; opt[3].XOff += options.XSkip; opt[3].YOff += options.YSkip; return opt; }
public virtual void RenderAsync(CalculationOptions options, RenderCompleteCallback callback) { ThreadPool.QueueUserWorkItem((o) => { CalculationOptions op = (o as object[])[0] as CalculationOptions; RenderCompleteCallback cb = (o as object[])[1] as RenderCompleteCallback; OrbitMap calc = Calculate(op); cb(calc); }, new object[] { options, callback }); }
private void button1_Click(object sender, EventArgs e) { Colorizer c = colorizers[ci++ % colorizers.Count]; CalculationOptions opt = new CalculationOptions(pictureBox1.Width, pictureBox1.Height, 100); opt.BulbChecking = true; opt.OrbitLength = 0; RenderOptions rp = new RenderOptions() { CanvasWidth = pictureBox1.Width, CanvasHeight = pictureBox1.Height }; OrbitMap m = calc.Calculate(opt); Bitmap b = c.DrawBitmap(m, rp, opt, null); pictureBox1.Image = b; }
public override OrbitMap Calculate(CalculationOptions options) { // Needs finetuning - a fast internet connection would benefit from smaller tasks (better utilization of computing cores), // but a slow one might become too slow from the overhead Queue<CalculationOptions> tasks = new Queue<CalculationOptions>(RenderTaskHelper.Split(options, 8 * HostSelector.EffectiveWorkers)); OrbitMap full = new OrbitMap(); List<RendererConnection> connections = new List<RendererConnection>(); while (tasks.Count > 0) // While there are still tasks left { // Distribute tasks to available renderers DistributeTasks(HostSelector, tasks, connections); // While we have running render tasks while (connections.Count > 0) { // Wait for one task to finish WaitHandle[] handles = connections.Select(c => c.WaitHandle).ToArray(); int h = WaitHandle.WaitAny(handles); RendererConnection conn = connections[h]; connections.RemoveAt(h); HostSelector.ConnectionCompleted(conn); if (conn.Success) { // If it was a success, extend the OrbitMap with these results full.Extend(conn.Result); } else { // TODO error handling, retry? tasks.Enqueue(conn.Task); // Re-enqueue it until it succeeds (maybe have to do something about that) } // Got an available renderer - fill it with a task DistributeTasks(HostSelector, tasks, connections); } } return full; // Return the combined orbit map }
internal static CalculationOptions[] Split(CalculationOptions options, int tasks) { if (tasks < 1) throw new ArgumentOutOfRangeException(); return Split(options, (uint)tasks); }
public abstract OrbitMap Calculate(CalculationOptions options);
internal void BeginRenderAsync(CalculationOptions opt) { Task = opt; worker = new Thread(Work); worker.Start(opt); }