{ Flame screensaver Copyright (C) 2002 Ronald Hordijk Apophysis Copyright (C) 2001-2004 Mark Townsend Apophysis Copyright (C) 2005-2006 Ronald Hordijk, Piotr Borys, Peter Sdobnov This program 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 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. } unit RenderMT; interface uses Windows, Forms, Classes, Graphics, Render, Controlpoint, ImageMaker, BucketFillerthread, RenderTypes; type TBaseMTRenderer = class(TBaseRenderer) private batchcounter: Integer; WorkingThreads: array of TBucketFillerThread; CriticalSection: TRTLCriticalSection; function NewThread: TBucketFillerThread; protected procedure Prepare; override; procedure SetPixels; override; procedure AddPointsToBuckets(const points: TPointsArray); virtual; abstract; procedure AddPointsToBucketsAngle(const points: TPointsArray); virtual; abstract; public procedure Stop; override; procedure BreakRender; override; procedure Pause; override; procedure UnPause; override; procedure SetThreadPriority(p: TThreadPriority); override; end; implementation uses Math, Sysutils; { TBaseMTRenderer } /////////////////////////////////////////////////////////////////////////////// procedure TBaseMTRenderer.SetPixels; var i: integer; nSamples: Int64; bc : integer; begin if FNumSlices > 1 then TimeTrace(Format('Rendering slice #%d of %d...', [FSlice + 1, FNumSlices])) else TimeTrace('Rendering...'); nSamples := Round(sample_density * NrSlices * BucketSize / (oversample * oversample)); FNumBatches := Round(nSamples / (fcp.nbatches * SUB_BATCH_SIZE)); if FNumBatches = 0 then FNumBatches := 1; FMinBatches := Round(FNumBatches * FMinDensity / fcp.sample_density); batchcounter := 1; Randomize; InitializeCriticalSection(CriticalSection); SetLength(WorkingThreads, NumThreads); for i := 0 to NumThreads - 1 do WorkingThreads[i] := NewThread; for i := 0 to NumThreads - 1 do WorkingThreads[i].Resume; bc := 1; while (FStop = 0) and (bc <= FNumBatches) do begin sleep(250); try EnterCriticalSection(CriticalSection); Progress(batchcounter / FNumBatches); bc := batchcounter; finally LeaveCriticalSection(CriticalSection); end; end; for i := 0 to High(WorkingThreads) do begin WorkingThreads[i].Terminate; WorkingThreads[i].WaitFor; WorkingThreads[i].Free; end; SetLength(WorkingThreads, 0); fcp.actual_density := fcp.actual_density + fcp.sample_density * BatchCounter / FNumBatches; // actual quality of incomplete render FNumBatches := BatchCounter; DeleteCriticalSection(CriticalSection); Progress(1); end; /////////////////////////////////////////////////////////////////////////////// procedure TBaseMTRenderer.Prepare; begin fcp.Prepare; end; /////////////////////////////////////////////////////////////////////////////// procedure TBaseMTRenderer.Stop; var i: integer; begin for i := 0 to High(WorkingThreads) do WorkingThreads[i].Terminate; //SetLength(WorkingThreads, 0); //? inherited; // FStop := 1; end; procedure TBaseMTRenderer.BreakRender; var i: integer; begin inherited; // FStop := -1; {if BatchCounter < FMinBatches then exit;} for i := 0 to High(WorkingThreads) do WorkingThreads[i].Terminate; //SetLength(WorkingThreads, 0); //? end; procedure TBaseMTRenderer.Pause; var i: integer; begin inherited; for i := 0 to High(WorkingThreads) do WorkingThreads[i].Suspend; end; procedure TBaseMTRenderer.UnPause; var i: integer; begin inherited; for i := 0 to High(WorkingThreads) do WorkingThreads[i].Resume; end; procedure TBaseMTRenderer.SetThreadPriority(p: TThreadPriority); var i: integer; begin inherited; for i := 0 to High(WorkingThreads) do WorkingThreads[i].Priority := p; end; /////////////////////////////////////////////////////////////////////////////// function TBaseMTRenderer.NewThread: TBucketFillerThread; begin Result := TBucketFillerThread.Create(fcp); assert(Result<>nil); if FThreadPriority <> tpNormal then Result.Priority := {tpLower;} FThreadPriority; if FCP.FAngle = 0 then Result.AddPointsProc := self.AddPointsToBuckets else Result.AddPointsProc := self.AddPointsToBucketsAngle; Result.CriticalSection := CriticalSection; Result.Nrbatches := FNumBatches; Result.batchcounter := @batchcounter; end; end.