471,357 Members | 1,094 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,357 software developers and data experts.

Synchronizing OnPaint to vsync

Hi,
this probaly isnt the most relevant place to ask this,
but Im using a windows forms in c# timer to process user input
and invalidate a window if its changed.

Im having problems in that the OnPaint messages arnt synchronized to
the vertical refresh wich from what I read I had understood that
there was supposed to be some synchronization.

im using directx to draw the window, its a 3d model editor
wich has multiple 3d windows wich need to be rendered as they
become invalidated rather than a game where it can just render at maximum
rate.

there is a visible tearing wich moves up the screen each frame.
If I use the directx synchronization the problem is worse
as the frame rate periodically drops to half as it misses frames
to keep it in synch.

any ideas ?

thanks
Colin =^.^=
Jun 27 '08 #1
8 8054
On Wed, 28 May 2008 04:47:44 -0700, colin <co*********@ntworld.NOSPAM.com>
wrote:
[...]
Im having problems in that the OnPaint messages arnt synchronized to
the vertical refresh wich from what I read I had understood that
there was supposed to be some synchronization.
There would be, if you were using GDI/GDI+. But...
im using directx to draw the window, its a 3d model editor
wich has multiple 3d windows wich need to be rendered as they
become invalidated rather than a game where it can just render at maximum
rate.
For what it's worth, "invalidation" in the context of a non-game
application isn't really all that different from "invalidation" in the
context of a game. A game is usually always changing the view, due to
animation, thus it always is being "invalidated" and redrawn. But that's
really what's going on with your application too, as long as there's user
input.
there is a visible tearing wich moves up the screen each frame.
If I use the directx synchronization the problem is worse
as the frame rate periodically drops to half as it misses frames
to keep it in synch.
It's not clear to me what you mean by "drops to half", but yes...if you
synchronize to the vertical retrace, your frame rate will necessarily be
restricted to the monitor refresh rate. There is just no way around
that. It's a physical impossibility for it to be otherwise.

But, an LCD monitor is most likely going to have a refresh rate of 60Hz
(some more recent ones are actually higher than that) and a CRT will be
able to support much higher refresh rates. So limiting the frame rate to
the refresh rate is not normally an issue.

Pete
Jun 27 '08 #2
Hi, thanks once again Peter :)

"Peter Duniho" <Np*********@nnowslpianmk.comwrote in message
news:op***************@petes-computer.local...
On Wed, 28 May 2008 04:47:44 -0700, colin <co*********@ntworld.NOSPAM.com>
wrote:
>[...]
Im having problems in that the OnPaint messages arnt synchronized to
the vertical refresh wich from what I read I had understood that
there was supposed to be some synchronization.

There would be, if you were using GDI/GDI+. But...
interesting, "But ..." whats the catch ?
ive not looked at gdi before, a quick google for it gave the
microsoft front page for it wich as typical gives all of the information
you could never need.
For what it's worth, "invalidation" in the context of a non-game
application isn't really all that different from "invalidation" in the
context of a game. A game is usually always changing the view, due to
animation, thus it always is being "invalidated" and redrawn. But that's
really what's going on with your application too, as long as there's user
input.
in such a game invalidation doesnt play a role as the whole frame is always
redrawn regardless, often as fast as possible using all of the cpu.

I was trying to point out that I need to use the invalidation method
becuase I may have many such windows, and so that they are redrawn only
if something like a sibling window moves acros it,
or the user moves the camera etc, or its an animated scene.
It's not clear to me what you mean by "drops to half", but yes...if you
synchronize to the vertical retrace, your frame rate will necessarily be
restricted to the monitor refresh rate. There is just no way around
that. It's a physical impossibility for it to be otherwise.
when I mean half I mean half of the monitor refresh rate.

the idea is to do all the drawing thats needed once per frame
and present it at the next vertical retrace, this gives the smothest
apearence.

however if it just misses a retrace period it has to delay until the next
one wich means it drops to half the rate.
But, an LCD monitor is most likely going to have a refresh rate of 60Hz
(some more recent ones are actually higher than that) and a CRT will be
able to support much higher refresh rates. So limiting the frame rate to
the refresh rate is not normally an issue.
I have realised the problem however, my monitor refresh rate is 66hz
and im using a timer to invalidate, but unfortunatly the timer granularity
means
its limited to 64hz, wich gives a beat frequency of about 2hz.

If I re invalidate the control in the paint method the fps can go upto about
500fps,
but none of my other code gets a look in, presumably its re entering the
OnPaint straight away.

If I then use the directx present so that it waits until the next vertical
retrace
it still doesnt seem to work properly as it gives an fps lower than the
monitor refresh rate,
wich is tiresom.

However fortunatly I have found if I set an application idle event and sit
there untill the directx
driver.RasterStatus.InVBlank is true then draw the scene independant of
OnPaint it then runs so sweetly.

I just need to tweak things a bit as I stil have the problem of timer
resolution,
If I use Thread.Sleep(1) it still misses frames, using sleep(0) is fine
but uses 100% cpu although at least it is non blocking.

Colin =^.^=
Jun 27 '08 #3
On Wed, 28 May 2008 11:21:43 -0700, colin <co*********@ntworld.NOSPAM.com>
wrote:
[...]
>There would be, if you were using GDI/GDI+. But...

interesting, "But ..." whats the catch ?
ive not looked at gdi before, a quick google for it gave the
microsoft front page for it wich as typical gives all of the information
you could never need.
By "GDI" I simply mean using the .NET support for GDI/GDI+. That is, the
normal drawing mechanisms via the Graphics class.
in such a game invalidation doesnt play a role as the whole frame is
always
redrawn regardless, often as fast as possible using all of the cpu.
My point is that the reason the game is always drawing the whole frame is
that the entire frame has been invalidated. Some games (2D games in
particular) _don't_ invalidate the whole frame and in fact _don't_ redraw
the entire frame each time.

It's true that in a game there's no explicit call to an "Invalidate()"
method, but that's only because the game already knows it needs to redraw
(it's just updated the world, it needs to redraw). The basic issues are
actually a lot more similar than you give them credit for.
[...]
when I mean half I mean half of the monitor refresh rate.

the idea is to do all the drawing thats needed once per frame
and present it at the next vertical retrace, this gives the smothest
apearence.

however if it just misses a retrace period it has to delay until the next
one wich means it drops to half the rate.
Well, yes...if your code can't keep up with the monitor refresh rate, then
you'll wind up with some fraction of the refresh rate. That said, even at
a lower refresh rate like 60Hz, missing the occasional frame shouldn't be
that noticable (beyond 25-30fps, the human brain doesn't keep up very well
anyway). Unless you're missing every other frame every single time, it
shouldn't be _that_ big of a problem, and higher monitor refresh rates can
do a lot to alleviate the problem.
[...]
However fortunatly I have found if I set an application idle event and
sit
there untill the directx
driver.RasterStatus.InVBlank is true then draw the scene independant of
OnPaint it then runs so sweetly.
Well, sure. If you just busy loop then you're not relying on the thread
scheduler to control the execution of the code. This is in fact how most
games deal with the issue, and if you want game-like performance, you'll
have to do something similar.
I just need to tweak things a bit as I stil have the problem of timer
resolution,
If I use Thread.Sleep(1) it still misses frames, using sleep(0) is fine
but uses 100% cpu although at least it is non blocking.
Windows isn't a real-time OS. So if you need real-time-like behavior (as
here), you need to busy loop. Which will naturally use 100% of the CPU.
I would advise lowering the priority of that thread doing the looping, in
addition to using Sleep(0) as you've done. You'll still use 100% of the
CPU, but at least the rest of the OS will remain more responsive.

Pete
Jun 27 '08 #4
"Peter Duniho" <Np*********@nnowslpianmk.comwrote in message
news:op***************@petes-computer.local...
On Wed, 28 May 2008 11:21:43 -0700, colin <co*********@ntworld.NOSPAM.com>
wrote:
By "GDI" I simply mean using the .NET support for GDI/GDI+. That is, the
normal drawing mechanisms via the Graphics class.
ah so thats just what the good old basic 2d one is called.
My point is that the reason the game is always drawing the whole frame is
that the entire frame has been invalidated. Some games (2D games in
particular) _don't_ invalidate the whole frame and in fact _don't_ redraw
the entire frame each time.

It's true that in a game there's no explicit call to an "Invalidate()"
method, but that's only because the game already knows it needs to redraw
(it's just updated the world, it needs to redraw). The basic issues are
actually a lot more similar than you give them credit for.
well whatever, the issue is most common game loops for 3d are different to
what
im wanting becuase as you say they just assume its all been invalidated.
Well, yes...if your code can't keep up with the monitor refresh rate, then
you'll wind up with some fraction of the refresh rate. That said, even at
a lower refresh rate like 60Hz, missing the occasional frame shouldn't be
that noticable (beyond 25-30fps, the human brain doesn't keep up very well
anyway). Unless you're missing every other frame every single time, it
shouldn't be _that_ big of a problem, and higher monitor refresh rates can
do a lot to alleviate the problem.
the code isnt unable to keep up, it can easily manage 500fps with the test
model im using, the problem is synchronizing it to the frame rate.
for some reason it refuses to go at anything other than too fast or too
slow.

it seems as though its not doing properly what I think the documentaion
is saying it should do, im not sure if this is a driver issue,
or something ive missed, but seems theres quite a bit on google
about how difficult this is to actually acheive in practice.
>[...]
However fortunatly I have found if I set an application idle event and
sit
there untill the directx
driver.RasterStatus.InVBlank is true then draw the scene independant of
OnPaint it then runs so sweetly.

Well, sure. If you just busy loop then you're not relying on the thread
scheduler to control the execution of the code. This is in fact how most
games deal with the issue, and if you want game-like performance, you'll
have to do something similar.
well that shouldnt be the case, the vsync mechanism should be
able to synchronise the frame rate, and it should be able to do so
without having to have a busy loop, or missing frames for no good reason
that I can see. especialy so if as you say the old GDI can do so without
problems.
>I just need to tweak things a bit as I stil have the problem of timer
resolution,
If I use Thread.Sleep(1) it still misses frames, using sleep(0) is fine
but uses 100% cpu although at least it is non blocking.

Windows isn't a real-time OS. So if you need real-time-like behavior (as
here), you need to busy loop. Which will naturally use 100% of the CPU.
I would advise lowering the priority of that thread doing the looping, in
addition to using Sleep(0) as you've done. You'll still use 100% of the
CPU, but at least the rest of the OS will remain more responsive.
I dont think this is a real-time issue at all,
if it misses the frame then nothing unrecoverable happens,
its just that a timer granularity of 15ms is so way behind the times for
cpu with clock rates well in excess of 2ghz.
it was ok back in the days of clock rates of 10mhz...

those are good ideas, but either way 100%cpu means my pc makes a lot more
noise
with fans speeding up to remove the extra heat etc wich is undesirable.

Colin =^.^=
Jun 27 '08 #5
On Wed, 28 May 2008 13:05:23 -0700, colin <co*********@ntworld.NOSPAM.com>
wrote:
[...]
the code isnt unable to keep up, it can easily manage 500fps with the
test
model im using, the problem is synchronizing it to the frame rate.
The code _is_ unable to keep up. Just because the actual rendering can be
done quickly doesn't change things. The fact that it yields to the OS and
doesn't get scheduled until too late is what prevents it from being able
to keep up. All that "keep up" means is that your code is ready to draw
another frame when the vertical retrace happens.
for some reason it refuses to go at anything other than too fast or too
slow.
I don't understand that comment. It's not "for some reason". It's for
well-known specific reasons.
it seems as though its not doing properly what I think the documentaion
is saying it should do, im not sure if this is a driver issue,
or something ive missed, but seems theres quite a bit on google
about how difficult this is to actually acheive in practice.
Your previous message seemed to imply that you understood the issue. This
comment seems to suggest that you don't. Can you clarify?
[...]
>Well, sure. If you just busy loop then you're not relying on the thread
scheduler to control the execution of the code. This is in fact how
most
games deal with the issue, and if you want game-like performance, you'll
have to do something similar.

well that shouldnt be the case, the vsync mechanism should be
able to synchronise the frame rate, and it should be able to do so
without having to have a busy loop, or missing frames for no good reason
that I can see. especialy so if as you say the old GDI can do so without
problems.
If all you do is wait on the vertical retrace, it will work fine. And I
thought that's exactly what you wrote in your previous message.

But the vertical retrace synchronization isn't the only thing you need to
worry about. As soon as you bring other aspects of the OS into the
picture, such as the thread scheduler, your code is at risk for not being
able to keep up.
[...]
I dont think this is a real-time issue at all,
It is.
if it misses the frame then nothing unrecoverable happens,
its just that a timer granularity of 15ms is so way behind the times for
cpu with clock rates well in excess of 2ghz.
it was ok back in the days of clock rates of 10mhz...
It's not just an issue of "timer granularity". It's that once you yield
your thread to Windows, lots of other threads get a chance to run
(including some other ones in your process). You have no control over
when your thread will get control back.
those are good ideas, but either way 100%cpu means my pc makes a lot
more noise
with fans speeding up to remove the extra heat etc wich is undesirable.
High frame rates and low CPU utilization are mutually exclusive. This is
true even on a real-time OS.

For what it's worth, DirectX has (or at least, did ten years ago...it
should still be in there somewhere) a way to use double-buffering and tell
the driver to flip to your newly rendered frame when _it_ can, rather than
your own code waiting for the vertical retrace. Using this technique, you
should be able to draw into an on-screen video surface at any time, with
the "flip" (oftentimes this is actually just a blt, especially if you're
not doing full-screen video) happening during the vertical retrace under
control of the video driver.

Unfortunately, it's been a long time since I've messed around in that API
so I can't provide the specifics. And of course, depending on how you're
accessing DirectX via .NET, that part of the API may or not actually be
exposed. But I do remember that it was part of DirectDraw, and inasmuch
as any of DirectDraw is still around (I seem to recall it getting
superceded by Direct3D somehow, or merged with, or whatever), it's
probably still there.

Pete
Jun 27 '08 #6
"Peter Duniho" <Np*********@nnowslpianmk.comwrote in message
news:op***************@petes-computer.local...
On Wed, 28 May 2008 13:05:23 -0700, colin <co*********@ntworld.NOSPAM.com>
wrote:
>[...]
the code isnt unable to keep up, it can easily manage 500fps with the
test
model im using, the problem is synchronizing it to the frame rate.

The code _is_ unable to keep up. Just because the actual rendering can be
done quickly doesn't change things. The fact that it yields to the OS and
doesn't get scheduled until too late is what prevents it from being able
to keep up. All that "keep up" means is that your code is ready to draw
another frame when the vertical retrace happens.
so its not my code that cant keep up its the underlying API
that cant respond in time. either way its a pointless debate as to where to
aportion blame.
>for some reason it refuses to go at anything other than too fast or too
slow.

I don't understand that comment. It's not "for some reason". It's for
well-known specific reasons.
then please explain the specific reason using "Present.One" does not presnt
once per frame ie 66fps and instead drops to about 45fps,
wheres as Prsesnt.Imediate manages to display the same thing at 500fps.
so it can hardly be due to running out of processing time.
>it seems as though its not doing properly what I think the documentaion
is saying it should do, im not sure if this is a driver issue,
or something ive missed, but seems theres quite a bit on google
about how difficult this is to actually acheive in practice.

Your previous message seemed to imply that you understood the issue. This
comment seems to suggest that you don't. Can you clarify?
I understand that it doesnt work very well due to timing problems,
and specificaly why my attempt to use the timer to recitfy this doesnt work
so well,
but I dont understand why a multimedia OS would not have
a smooth mechanism to cope with vsync.

I also think there are more differences between fullscreen and windowed mode
than
I have manged to find out so far.
>[...]
>>Well, sure. If you just busy loop then you're not relying on the thread
scheduler to control the execution of the code. This is in fact how
most
games deal with the issue, and if you want game-like performance, you'll
have to do something similar.

well that shouldnt be the case, the vsync mechanism should be
able to synchronise the frame rate, and it should be able to do so
without having to have a busy loop, or missing frames for no good reason
that I can see. especialy so if as you say the old GDI can do so without
problems.

If all you do is wait on the vertical retrace, it will work fine. And I
thought that's exactly what you wrote in your previous message.
its not fine if it uses 100% cpu. to do 5% real work.
But the vertical retrace synchronization isn't the only thing you need to
worry about. As soon as you bring other aspects of the OS into the
picture, such as the thread scheduler, your code is at risk for not being
able to keep up.
>[...]
I dont think this is a real-time issue at all,

It is.
arguing about the definition of wether an issue is real time
is often a long and pointless debate. this is however a multimedia issue
and this is described as a multimedia capable OS.
>if it misses the frame then nothing unrecoverable happens,
its just that a timer granularity of 15ms is so way behind the times for
cpu with clock rates well in excess of 2ghz.
it was ok back in the days of clock rates of 10mhz...

It's not just an issue of "timer granularity". It's that once you yield
your thread to Windows, lots of other threads get a chance to run
(including some other ones in your process). You have no control over
when your thread will get control back.
again this isnt an issue because the background work is miniscule.
there is plenty of spare time to go nearly 10 times as fast as needed.

if theres work to be done elsewhere then the graphics isnt a priority so
its not big issue. but its a waste if its doing nothing else and still cant
manage it.
the point is to at least get it working well when its got lots of spare
procesing.
>those are good ideas, but either way 100%cpu means my pc makes a lot
more noise
with fans speeding up to remove the extra heat etc wich is undesirable.

High frame rates and low CPU utilization are mutually exclusive. This is
true even on a real-time OS.
I dont need high frame rate as such I need to synchronize to vsync.
66fps is about 5% cpu, what I dont need is 66fps with 100% cpu 95% of wich
is wasted.
>
For what it's worth, DirectX has (or at least, did ten years ago...it
should still be in there somewhere) a way to use double-buffering and tell
the driver to flip to your newly rendered frame when _it_ can, rather than
your own code waiting for the vertical retrace. Using this technique, you
should be able to draw into an on-screen video surface at any time, with
the "flip" (oftentimes this is actually just a blt, especially if you're
not doing full-screen video) happening during the vertical retrace under
control of the video driver.

Unfortunately, it's been a long time since I've messed around in that API
so I can't provide the specifics. And of course, depending on how you're
accessing DirectX via .NET, that part of the API may or not actually be
exposed. But I do remember that it was part of DirectDraw, and inasmuch
as any of DirectDraw is still around (I seem to recall it getting
superceded by Direct3D somehow, or merged with, or whatever), it's
probably still there.
well I was pretty sure you should be able to do something like that quite
easily.
im not sure if using multiple swap chains or something else im doing is
cuasing problems,
again I think this might actualy work more smoothly in fullscreen mode .

but I have tried al maner and permutations of options such as the folowing
:-

seting the SwapEffect from SwapEffect.discard,copy,flip.
setting present interval to imediate,one,defualt,
seting the number of backbufers from 1 to 3,
using DoNotWait parameter on the SwapChain.Present
and also setting the ati control panel options for vsync
from 1=never to 4=always

and it either goes at 500fps or 45fps never 66fps !

im sure it isnt this hard im surprised there isnt an easy answer,
however I have come accros this and managed to get something similar to
work.
http://www.codeproject.com/KB/GDI/te...eedrawing.aspx
it looks at the current scan line then sets up a multimedia timer
to fire when it predicts the vertical refresh to ocur.

seems to work reasonably well, however its not ideal as it is a prediction
for vsync wich isnt able to know the time its going to take to render the
frame in advance.
unfortunatly this is also true of sitting in a busy loop.
im not sure if its posible to do the rendering then wait for vsync then do
present as
it seems to just queue up al the draw operations then execute them once
present is called.

Colin =^.^=
Jun 27 '08 #7
final solution:- I had the bright idea
to measure the time taken to draw the last frame and
use this to compensate when predicting when the best time
is to start drawing the next frame.
it looks realy sweet now, it keeps in perfect sync even when
taking 95% cpu time to draw a large scene wich is about 700k vertices.
public static int lineDelay, noScanLines = 1200;
public static long last, now, lastLine, maxLines;
public static float verticalFrequency = 66
, verticalInterval = 1f / verticalFrequency;

internal static void Present(Control control)
{
int lineStart = device.RasterStatus.ScanLine;
swap_Chain.Present(control);
int lineEnd = device.RasterStatus.ScanLine;
lineDelay = lineEnd - lineStart;
if (lineDelay < 0)
lineDelay += noScanLines;
}
public static void WaitVBlank()//cal this on WM_ENTERIDLE
{
if (device == null)
return;
now = stopwatch.ElapsedTicks;
float interval = (now - last)/(float)Stopwatch.Frequency;
if (interval < verticalInterval)// abandon vsync if fps to slow.
{//use last present delay as an offset
int line = (device.RasterStatus.ScanLine+ lineDelay)
% noScanLines;
int linesTillRetrace = noScanLines - line;
if (linesTillRetrace 0)
{
float t = (linesTillRetrace) * verticalInterval /
noScanLines;
//try to wait until scanline
timeBeginPeriod(2); //multimedia timer resolution
mmtimer.dll
Thread.Sleep((int)(t * 1000));
timeEndPeriod(2);
}
}
last = stopwatch.ElapsedTicks;
}//this assumes drawing will comence as soon as it leaves this
function

PS sorry if my frustration with this silly issue wich has taken 2 days now
has made my posts seem a bit unfriendly.

"colin" <co*********@ntworld.NOSPAM.comwrote in message
news:DD*******************@newsfe17.ams2...
Hi,
this probaly isnt the most relevant place to ask this,
but Im using a windows forms in c# timer to process user input
and invalidate a window if its changed.

Im having problems in that the OnPaint messages arnt synchronized to
the vertical refresh wich from what I read I had understood that
there was supposed to be some synchronization.

im using directx to draw the window, its a 3d model editor
wich has multiple 3d windows wich need to be rendered as they
become invalidated rather than a game where it can just render at maximum
rate.

there is a visible tearing wich moves up the screen each frame.
If I use the directx synchronization the problem is worse
as the frame rate periodically drops to half as it misses frames
to keep it in synch.

any ideas ?

thanks
Colin =^.^=


Jun 27 '08 #8
It seems the problem was using powerstrip - a refresh rate tool
to adjust the monitor refresh rate to 66hz instead of 60hz
as my old but loved crt monitor is limited to 66 at 1600x1200.

60 is an abomination for eye ache and headaches,
66 seems fine despit only being 10% more.
lower resolutions simply dont alow me to see enough after youve got many
tiled windows
each with so much wasted space for the title bar/menu etc.

seems powerstrip omits to inform anyone else the refresh rate has changed,
therefore the directx was waiting for the next vsync as if it was a 60hz
refresh rate, but at 66hz it arrives earlier than expected so it often gets
missed and waits for the next one so the fps drops.

I now managed to fool it by making windows think its 70hz not 60,
where as its actualy 66hz, so i presume directx sleeps for less time
than needed then wakes up and polls for the next vsync.
just using the present parameter to present once per refresh works fine now
:D

I cant beleive ive wasted so smuch time and got so frustrated with this
issue lol.

even with my timing prediction wich took into acount the drawing time it
never got it exactly right with complex scenes.

"You dont need to be mad to be here but you will be by the time you leave"

Colin =^.^=

"colin" <co*********@ntworld.NOSPAM.comwrote in message
news:DD*******************@newsfe17.ams2...
Hi,
this probaly isnt the most relevant place to ask this,
but Im using a windows forms in c# timer to process user input
and invalidate a window if its changed.

Im having problems in that the OnPaint messages arnt synchronized to
the vertical refresh wich from what I read I had understood that
there was supposed to be some synchronization.

im using directx to draw the window, its a 3d model editor
wich has multiple 3d windows wich need to be rendered as they
become invalidated rather than a game where it can just render at maximum
rate.

there is a visible tearing wich moves up the screen each frame.
If I use the directx synchronization the problem is worse
as the frame rate periodically drops to half as it misses frames
to keep it in synch.

any ideas ?

thanks
Colin =^.^=


Jun 27 '08 #9

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

3 posts views Thread by Keith Veleba | last post: by
2 posts views Thread by Christopher D. Wiederspan | last post: by
4 posts views Thread by dominique | last post: by
reply views Thread by SirThanxALot | last post: by
14 posts views Thread by raylopez99 | last post: by
reply views Thread by XIAOLAOHU | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.