Board index » delphi » Re: Speeding up offscreen buffer usage

Re: Speeding up offscreen buffer usage


2008-05-17 12:30:25 AM
delphi124
Oh !
So that is not a Delphi part !
DH
 
 

Re: Speeding up offscreen buffer usage

"Remy Lebeau \(TeamB\)" <XXXX@XXXXX.COM>writes:
Quote

"Heath Raftery" <XXXX@XXXXX.COM>writes
news:XXXX@XXXXX.COM...

>That's the solution I was leaning towards, but then there's a
>more fundamental problem. While I am busy spending 30ms
>painting the current value, 3 or 4 triggers might come from
>the hardware.

But, do you really need to draw each individual trigger? Or can you get
away with just drawing whatever the last trigger was?
Should have explained that better - I need to be aware of
every trigger or I will have lost data. That does not mean every
trigger requires a redraw, just that I can not be busy drawing and
miss triggers.
--
*--------------------------------------------------------*
| ^Nothing is foolproof to a sufficiently talented fool^ |
| Heath Raftery, HRSoftWorks _\|/_ |
*______________________________________m_('.')_m_________*
 

Re: Speeding up offscreen buffer usage

David HAROUCHE <XXXX@XXXXX.COM>writes:
Quote
For animated drawings, what you should do is a Not draw !

That is :

pen.mode := pmNot

if not needles.firstdraw
then drawneedles(oldwhere);

drawneedles(actualwhere);
actualwhere := oldwhere;
Nice idea, but that doesn't put the background back - the
needle might have obscured grid lines, unit labels, etc.
--
*--------------------------------------------------------*
| ^Nothing is foolproof to a sufficiently talented fool^ |
| Heath Raftery, HRSoftWorks _\|/_ |
*______________________________________m_('.')_m_________*
 

Re: Speeding up offscreen buffer usage

If only the needles changes, and are above, that should work :
Not(Not(false)) = false !
DH
 

Re: Speeding up offscreen buffer usage

"Peter Below (TeamB)" <XXXX@XXXXX.COM>writes:
Quote
Heath Raftery writes:

>"Peter Below (TeamB)" <XXXX@XXXXX.COM>writes:
>>Heath Raftery writes:
>>
>>>Which just confirmed I was at least on the right track. My
>>>problem is that my "clock" (actually a virtual
>>>instrumentation display) needs to update up to 100 times a
>>>second, not once a second.
>>
>>You have not thought this through, I am afraid. The human eye is way
>>too slow to process such a refresh rate. Even if the data you
>>display is updated 100 times per second it should be plenty to
>>refresh the display of the data 20 times a second, say.
>
>I'm well aware of that, but if I can only just get 30Hz (remember the
>delay was in the order of 33ms) on a well-spec'ed dev machine, how can
>I hope to consistently get 20Hz on a low-end deployment machine?

An option may be to modify the logic. If you used my example basically
as it is you are invalidating the paintbox after each meter change and
the OnPaint event then redraws it completely. Leave the OnPaint event
as it is, since it is required to repaint the paintbox if Windows asks
it to do that. But on a meter change compose a smaller bitmap (as small
as possible, only covering the parts of the meter holding the old and
new values, the part that has to be redrawn). Then do *not* invalidate
the paintbox but simply draw this small bitmap directly to its canvas.
You can draw to a paintbox canvas outside its OnPaint event, you know.
The only problem with that is that the drawings you make this way can
be wiped out by the next invalidation of the paintbox, if you are not
prepared to handle that correctly.
I've now implemented this, and average draw times have dropped from
26 milliseconds to 5! After being carefull to handle situations where
more than the minimum possible has to be drawn (when another window
overlaps for example), I am happy with this method.
Unfortunately, the bottleneck has just moved, and a few other things
I was hoping to do (specifically, updating a few TCharts) every
hardware trigger still means the main thread is busy for 30ms or so.
Quote
A second optimization you should consider is to separate the value
acquisition from your hardware and the display of the values into two
separate threads. The display would have to be done in the main thread,
of course. The value acquisition thread would put the received values
into a queue (it needs to be thread-safe). The main thread can then use
a timer to examine the queue and take the *last* value added to it for
the display, discarding all others. This way your value acquisition can
proceed at the speed required by the hardware and the display can keep
up as best as it can. This will work especially well on a PC with more
than one core, but it should also prevent data loss in the acquisition
part on a single CPU machine since that thread is not blocked by the
painting, regardless how slow that may be.
I was keen to implement this, unfortunately I don't have a great deal
of control over what thread receives the triggers. Short of a massive,
risky rewrite, I am afraid the triggers have to take place on the main
thread. I could easily split the calculations off to another thread,
but since it is actually the screen updates that is taking most of the
time, this would be a pointless exercise.
The conclusion is, that unless there is justification for the work
necessary to push the trigger handling into another thread, we are
just going to have to deal with the fact that triggers may be missed.
Given that these high run speeds are rare, and that one can always
turn off or reduce the size of the live display anyway, I think we'll
just make do.
Thanks for your help everyone, it has been most useful.
--
*--------------------------------------------------------*
| ^Nothing is foolproof to a sufficiently talented fool^ |
| Heath Raftery, HRSoftWorks _\|/_ |
*______________________________________m_('.')_m_________*
 

Re: Speeding up offscreen buffer usage

RandomAccess <XXXX@XXXXX.COM>writes:
Quote
Hello Heath,

"Heath Raftery" <XXXX@XXXXX.COM>writes
news:XXXX@XXXXX.COM...

>I was surprised to find that the bottleneck was this line:
>pbxDraw.Canvas.Draw(0, 0, FOffScreenBuffer);

Ok - The reasons for this don't really matter, and I think there are
probably other significant delays in play here also.

You need to do what games do.

They use back buffering through DirectX where the backbuffer DOES NOT
need to be blit to the display buffer. This makes the display switch
instaneous.
Roger that. I have done that in other projects with good success. At
this stage I am not going to go down that route, but it is a good
suggestion to keep in mind.
--
*--------------------------------------------------------*
| ^Nothing is foolproof to a sufficiently talented fool^ |
| Heath Raftery, HRSoftWorks _\|/_ |
*______________________________________m_('.')_m_________*
 

Re: Speeding up offscreen buffer usage

Pieter Zijlstra <XXXX@XXXXX.COM>writes:
Quote
Heath Raftery writes:

>This still doesn't make a great deal of sense though, so can anyone
>suggest why .Draw is taking so long?

One thing which help is to set the PixelFormat to pfDevice.
No go. TBitmap.Create was already giving me a bitmap with PixelFormat
set to pfDevice.
Quote
I made my own dial gauge component, it may not be what you're looking
for but it might give some ideas (code-wise). Anyway you could try to
run the demo to see what the update rate is on your PC.
Nice! Smooth drawing. I don't think there's anything of immediate
use there, but it is good to see.
--
*--------------------------------------------------------*
| ^Nothing is foolproof to a sufficiently talented fool^ |
| Heath Raftery, HRSoftWorks _\|/_ |
*______________________________________m_('.')_m_________*
 

Re: Speeding up offscreen buffer usage

David J Taylor <XXXX@XXXXX.COM>writes:
Quote
>Heath Raftery writes:
[]
>>Where pbxDraw is the on-screen TPaintBox and the bitmap is
>>666x666 pixels. This line is taking (using GetTickCount to
>>measure) between 15 and 33 milliseconds.

GetTickCount s rather inaccurate. QueryPerformanceCounter provides better
accuracy - perhaps down to the microsecond level.
Great! Much better.
Actual time was a fairly consistent 26ms.
--
*--------------------------------------------------------*
| ^Nothing is foolproof to a sufficiently talented fool^ |
| Heath Raftery, HRSoftWorks _\|/_ |
*______________________________________m_('.')_m_________*
 

Re: Speeding up offscreen buffer usage

Quote
Should have explained that better - I need to be aware of
every trigger or I will have lost data. That does not mean every
trigger requires a redraw, just that I can not be busy drawing and
miss triggers.

How are your triggers arriving? Serial/Parallel/USB? One way to do this is
flow control and buffers - it depends on your hardware - serial uses
xoff/xon or rts/cts handshaking, I imagine there's something similar for
USB. The other way I know of is using non maskable interrupts but that's
hard in windows, probably another group is the best place to get help for
this bit, it is a different problem.
cheers,
Dave
 

Re: Speeding up offscreen buffer usage

Heath Raftery writes:
Quote
I was keen to implement this, unfortunately I don't have a great deal
of control over what thread receives the triggers. Short of a massive,
risky rewrite, I am afraid the triggers have to take place on the main
thread.
Sounds like somebody has designed himself into a corner <g>.
--
Peter Below (TeamB)
Don't be a vampire (slash7.com/pages/vampires),
use the newsgroup archives :
www.tamaracka.com/search.htm
groups.google.com
 

Re: Speeding up offscreen buffer usage

David Ninnes <XXXX@XXXXX.COM>writes:
Quote
>Should have explained that better - I need to be aware of
>every trigger or I will have lost data. That does not mean every
>trigger requires a redraw, just that I can not be busy drawing and
>miss triggers.
How are your triggers arriving? Serial/Parallel/USB? One way to do this is
flow control and buffers - it depends on your hardware - serial uses
xoff/xon or rts/cts handshaking, I imagine there's something similar for
USB. The other way I know of is using non maskable interrupts but that's
hard in windows, probably another group is the best place to get help for
this bit, it is a different problem.
It's a PCI card that communicates with a DLL. The DLL communicates
with the program via a callback. I am not in a position to change
any of this right now, and yep, it is not really on-topic here.
Certainly something to consider for the future though.
--
*--------------------------------------------------------*
| ^Nothing is foolproof to a sufficiently talented fool^ |
| Heath Raftery, HRSoftWorks _\|/_ |
*______________________________________m_('.')_m_________*
 

Re: Speeding up offscreen buffer usage

"Peter Below (TeamB)" <XXXX@XXXXX.COM>writes:
Quote
Heath Raftery writes:

>I was keen to implement this, unfortunately I don't have a great deal
>of control over what thread receives the triggers. Short of a massive,
>risky rewrite, I am afraid the triggers have to take place on the main
>thread.

Sounds like somebody has designed himself into a corner <g>.
True that! In hindsight, the layer between the hardware and the
software should have been future-proofed, but it has meant we've
developed on top of a entirely sufficient, relatively simple
framework for about 10 years now. that is the tradeoffs you make!
--
*--------------------------------------------------------*
| ^Nothing is foolproof to a sufficiently talented fool^ |
| Heath Raftery, HRSoftWorks _\|/_ |
*______________________________________m_('.')_m_________*