protected unsafe virtual void RenderLoop(ISurface surface, Rectangle roi, CancellationToken token, IRenderProgress progress)
{
var dst = new ColorBgra[surface.Height * surface.Width];
fixed(ColorBgra *dst_ptr = dst)
{
var dst_wrap = new ColorBgraArrayWrapper(dst_ptr, surface.Width, surface.Height);
surface.BeginUpdate();
dst_wrap.BeginUpdate();
OnBeginRender(surface, dst_wrap, roi);
var completed_lines = new bool[roi.Height];
var last_completed_index = 0;
if (Settings.SingleThreaded || roi.Height <= 1)
{
for (var y = roi.Y; y <= roi.Bottom; ++y)
{
if (token.IsCancellationRequested)
{
return;
}
RenderLine(surface, dst_wrap, new Rectangle(roi.X, y, roi.Width, 1));
completed_lines[y - roi.Top] = true;
if (progress != null)
{
var last_y = FindLastCompletedLine(completed_lines, last_completed_index);
last_completed_index = last_y;
progress.CompletedRoi = new Rectangle(roi.X, roi.Y, roi.Width, last_y);
progress.PercentComplete = (float)last_y / (float)roi.Height;
}
}
}
else
{
ParallelExtensions.OrderedFor(roi.Y, roi.Bottom + 1, token, (y) => {
RenderLine(surface, dst_wrap, new Rectangle(roi.X, y, roi.Width, 1));
completed_lines[y - roi.Top] = true;
if (progress != null)
{
var last_y = FindLastCompletedLine(completed_lines, last_completed_index);
last_completed_index = last_y;
progress.CompletedRoi = new Rectangle(roi.X, roi.Y, roi.Width, last_y);
progress.PercentComplete = (float)last_y / (float)roi.Height;
}
});
}
// Copy the result from our temp destination back into the source
var op = new IdentityOp();
op.ApplyAsync(dst_wrap, surface, token).Wait();
surface.EndUpdate();
dst_wrap.EndUpdate();
}
}