Forum > Graphics

The Lazarus TImage.Canvas is too slow

(1/3) > >>

QuinnMartin:
I have been trying to write a simple program (below) that draws a sine wave.  However it's slow... it takes 50 milliseconds to draw a single wave, even with optimization changed to -O3.  This is very simple mathematics that should be trivial on a modern CPU.  It's plotting a series of 1200 line segments (MoveTo) to draw the sine wave, but still it should really not take half a second considering there are all kinds of games that draw more complex renders (even outside of OpenGL and DirectX) much more quickly.

I can't accomplish what I want to do because I'm trying to draw 20 of these waves, and that adds up to very sluggish performance when you're trying to watch the results of moving the TTrackBar in realtime.

Any thoughts how I can speed this up?  Or is it just not possible in FreePascal?  I tried BitBlt to buffer clearing the image but it was only 5% faster.  I'm not sure if I'm just writing bad code or if there are other settings I need to look at.



--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} --- // NOTES: The code below has been modified to just draw a single wave and is triggered by a TTrackBar that changes the wavelength; it also has some code to time the operation and send it to a TMemo. function TForm1.DrawWave : integer;var  xx, yy, f1, verticaloffset, yy1, yy2, centerratio, r1, r2, r3 : real;  s1 : string;begin  Image1.canvas.rectangle(0,0,Image1.Canvas.Width,Image1.Canvas.Height);   r1 := time*24*60*60;   verticaloffset := 300;   f1 := Wave1Frequency.position;  f1 := f1/10;  if (f1 > 0) then    begin      yy := 300;   // was 0      while (yy < 301) do  // was 600        begin          yy := yy+10;          xx := 1;          while (xx < 1200) do            begin              xx := xx+1;              yy1 := (sin((xx/f1)*pi/180) * 100);              yy2 := (sin(((xx+1)/f1)*pi/180) * 100);              centerratio := 1 - (abs(yy-verticaloffset))/verticaloffset;              yy1 := yy1*centerratio;              yy2 := yy2*centerratio;              yy1 := yy1+yy;              yy2 := yy2+yy;              Image1.Canvas.MoveTo(round(xx),round(yy1));              Image1.Canvas.LineTo(round(xx+1),round(yy2));            end;        end;    end;  r2 := time*24*60*60;  r3 := (r2-r1)*1000;  str(r3:0:0,s1);   Memo1.Lines.Add('Time '+s1+' ms');end;        

howardpc:
Try something like this:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure TForm1.DrawWave;const  PiOver180 = Pi/180;var  frequency: Single = 1;  verticalOffset: Integer = 300;  xx: SizeInt = 1;  yy: SizeInt = 300;  yy1, yy2, centerRatio: Single;begin  Image1.Canvas.Rectangle(Image1.ClientRect);  if frequency <= 0 then Exit;   while yy < 301 do    begin      Inc(yy, 10);      while xx < 1200 do        begin          Inc(xx);          yy1 := (Sin((xx/frequency)*PiOver180) * 100);          yy2 := (sin(((xx+1)/frequency)*PiOver180) * 100);          centerRatio := 1 - (abs(yy-verticaloffset))/verticaloffset;          yy1 := yy1*centerRatio + yy;          yy2 := yy2*centerRatio + yy;          Image1.Canvas.Line(xx, Trunc(yy1), Succ(xx), Trunc(yy2));        end;    end;end; procedure TForm1.FormCreate(Sender: TObject);var  start, elapsed: LongInt;begin  start := DateTimeToTimeStamp(Time).Time;  DrawWave;  elapsed := DateTimeToTimeStamp(Time).Time - start;  Caption := Format('Time to draw sine wave = %d ms', [elapsed]);end;

QuinnMartin:
Thanks, I tried out the code but it doesn't address the speed issue... it runs about the same speed.

I do appreciate the suggestions for writing better code.

For whatever reason yy isn't initializing properly the way you have it set up... if I set a breakpoint on the very first line, yy is always some random large number.  It seems like the code is ignoring the value that was set.  I tried changing yy to yyy, same problem.  If I hardcode yyy := 0; on the line before the breakpoint, then the value is set properly.  I don't understand why it is ignoring the value being set in the var section.

howardpc:
Perhaps you should show a compilable example of yours which is so slow.

Here the sine drawing code I showed times at 0ms, and yy is initialized correctly.


TRon:
@QuinnMartin
If you require full horsepower then you (sh/c)ould make use of a pre-calculated sinus table. Although howardpc' results seem to be satisfactory enough.

Navigation

[0] Message Index

[#] Next page

Go to full version