retrace/SDL_UpdateRect question

Hey,

I’ve been having bad problems with tearing and so I am attempting to synch
my animation to the vertical retrace of the monitor. I understand that in
SDL the only way to do this is to use double buffered hardware surfaces and
SDL_Flip(). However, as my game uses a significant amount of alpha-bending,
I can’t use HW surfaces because of the speed hit. I have tried using glSDL
for accelerated alpha blends, but that was a huge speed shock in itself,
maybe because of all the still unoptimized code.

In any event, I thought the easiest way to go about synching to the vertical
retrace might be a platform specific solution. I am working primarily on
Win32, and have found a simple way to wait for the start of a vertical
retrace. I am doing this directly before I am calling SDL_UpdateRect for
each area of the screen that has changed since the last animation frame, so
according to my theory the screen should be updated completely during the
retrace and everything should be peachy. However, the tearing persists. Is
this not a sound theory? I am sure that the mechanism to wait for the
vertical retrace is working correctly.

Does SDL_UpdateRect update the screen immediately? That is, does it actually
do the writing to video memory? Or does it just flag a rect to be updated
later? The documentation says that in “ensures” that the given rect will be
updated. I’m not sure exactly what that means.

Any help would be greatly appreciated.

Thanks,
Dave

Hey,

I’ve been having bad problems with tearing and so I am attempting
to synch my animation to the vertical retrace of the monitor. I
understand that in SDL the only way to do this is to use double
buffered hardware surfaces and SDL_Flip(). However, as my game uses
a significant amount of alpha-bending, I can’t use HW surfaces
because of the speed hit.

The speed hit is when you blend into VRAM - but that doesn’t mean you
can’t use h/w surfaces at all. :wink:

I have tried using glSDL for accelerated
alpha blends, but that was a huge speed shock in itself, maybe
because of all the still unoptimized code.

Well, I don’t know what you’re doing, or how, but do note that glSDL
can only accelerate blits to the screen…

In any event, I thought the easiest way to go about synching to the
vertical retrace might be a platform specific solution. I am
working primarily on Win32, and have found a simple way to wait for
the start of a vertical retrace. I am doing this directly before I
am calling SDL_UpdateRect for each area of the screen that has
changed since the last animation frame, so according to my theory
the screen should be updated completely during the retrace and
everything should be peachy. However, the tearing persists. Is this
not a sound theory? I am sure that the mechanism to wait for the
vertical retrace is working correctly.

Problem with this kind of solution is that it requires a hard real
time OS to work properly. Even if the actual sync works properly,
there’s no way Windows or (standard) Linux can get the blitting done
at the right moment. It might work most of the time, at best. More
likely is the commonly seen (with OpenGL on Linux) “stationary
tearing” near the top of the screen, which can actually be worse than
normal “no sync” tearing in some cases.

Does SDL_UpdateRect update the screen immediately? That is, does it
actually do the writing to video memory? Or does it just flag a
rect to be updated later? The documentation says that in "ensures"
that the given rect will be updated. I’m not sure exactly what that
means.

That may differ between backends, I think, but your biggest problem
here is that it doesn’t really matter; you can’t ensure that the
blits are done at the right moment anyway.

Anyway, there’s no way a general purpose OS will allow you to schedule
blits to start a fraction of a ms after the retrace sync. What you
need is slack. Hardware pageflipping gives you N-1 full frame
durations of slack, where N is the number of buffers. Use that
whenever possible.

It does mean you have to render into an off-screen s/w buffer and then
blit from that to VRAM - but that blit can be accelerated on some
machines, including your average Windows/DirectX + PCI or AGP video
card setup.

Keep in mind that you don’t have to copy the whole screen every
frame just because you’re rendering into a shadow buffer. Just do
what SDL_UpdateRects() does internally; blit only the requested areas
from the shadow surface to the screen. Then SDL_Flip() to make the
updated page visible, hopefully after the next retrace.

//David Olofson - Programmer, Composer, Open Source Advocate

.- Audiality -----------------------------------------------.
| Free/Open Source audio engine for games and multimedia. |
| MIDI, modular synthesis, real time effects, scripting,… |
`-----------------------------------> http://audiality.org -’
http://olofson.nethttp://www.reologica.se —On Friday 17 October 2003 21.39, Dave wrote:

Thanks for another really helpful response David.

Unfortunately I still can’t get this thing solved. I went back and
implemented your suggestion of rendering into a s/w buffer, blitting that to
VRAM, and then using SDL_Flip for hardware page flipping. But the damn thing
STILL TEARS. I am sure that the double buffered hardware surface is getting
set up correctly. SDL_Flip appears to be working correctly, or at least it
is waiting the correct amount of time. I am assuming this because my frame
won’t go above 75 frames/sec, the refresh rate of the monitor.

I basically set up a hardware, double buffered video mode, and then in my
animation loop, call SDL_BlitSurface for each rect that needs updating
(taking into account the double buffered setup), then immediately afterwards
call SDL_Flip. Am I missing a step here?

I am developing on a Dell with a GeForce4 running WinXP, and the tearing is
barely noticable but definately there. I have also tested on a IBM ThinkPad
running Win2000 and the tearing is just aweful.

This is driving me crazy. Any additional help would be very much
appreciated.

Thanks,
Dave> Just do=20

what SDL_UpdateRects() does internally; blit only the requested areas=20
from the shadow surface to the screen. Then SDL_Flip() to make the=20
updated page visible, hopefully after the next retrace.

Well, I managed to ‘solve’ the problem by changing the background on which
the torn sprites were being drawn. It was originally composed of 16x16
squares, alternating white and light yellow. By changing the background to a
flat color, or a darker pattern w/ bigger squares, the ‘tearing’ goes away!

Strange, but it works for me. Thanks for the help.

Dave

[…]

I basically set up a hardware, double buffered video mode, and then
in my animation loop, call SDL_BlitSurface for each rect that needs
updating (taking into account the double buffered setup), then
immediately afterwards call SDL_Flip. Am I missing a step here?

You can hardly go wrong with a double buffered display… Since SDL
only gives you access to the back page, it takes a bug in SDL or the
driver to get tearing.

I am developing on a Dell with a GeForce4 running WinXP, and the
tearing is barely noticable but definately there.

Are you sure this is tearing; ie graphics of different age being
visible in the same video fram? Does it happen with other apps? Other
SDL apps…? Have you tried other SDL and/or driver versions?

I have also
tested on a IBM ThinkPad running Win2000 and the tearing is just
aweful.

This could have another explanation, though. LCDs usually have rather
low refresh rates (60 Hz or so), and that’s fine so far; you just get
more time per video frame. (LDCs don’t have the “stroboscope” feature
of CRTs, so this is no problem.)

However, it seems that some laptops have a buffer/converter somewhere,
allowing the video card to operate at a different frame rate. This
obviously results in terrible tearing, double buffering or not, as
the video card runs totally out of sync with the LCD.

//David Olofson - Programmer, Composer, Open Source Advocate

.- Audiality -----------------------------------------------.
| Free/Open Source audio engine for games and multimedia. |
| MIDI, modular synthesis, real time effects, scripting,… |
`-----------------------------------> http://audiality.org -’
http://olofson.nethttp://www.reologica.se —On Tuesday 21 October 2003 01.20, Dave wrote:

Sounds very strange indeed… Are you sure it wasn’t some bonus
effects in the RAMDAC and/or monitor? Sometimes, with some hardware,
you can get horizontal offsets and/or color shifts following (ie to
the right of) areas of certain colors.

//David Olofson - Programmer, Composer, Open Source Advocate

.- Audiality -----------------------------------------------.
| Free/Open Source audio engine for games and multimedia. |
| MIDI, modular synthesis, real time effects, scripting,… |
`-----------------------------------> http://audiality.org -’
http://olofson.nethttp://www.reologica.se —On Tuesday 21 October 2003 08.26, Dave wrote:

Well, I managed to ‘solve’ the problem by changing the background
on which the torn sprites were being drawn. It was originally
composed of 16x16 squares, alternating white and light yellow. By
changing the background to a flat color, or a darker pattern w/
bigger squares, the ‘tearing’ goes away!

Strange, but it works for me. Thanks for the help.

Couldn’t say for sure what was causing it. Perhaps it was just a after-glow
or a similar phenomenon. The small size of the checkers (actually 8x8, as
opposed to the 16x16 size I incorrectly put in my previous post) was
definately a necessary component. Athough it happened too quickly for me to
really get a fix on it, it looked as though the parts of the sprites drawn
on the yellow checkers were lagging a bit behind the parts drawn on the
white checkers, or perhaps visa versa (on the edge of the direction of
motion only). It did look AWEFUL on that ThinkPad.

Whatever it was, it is gone now and that is good enough for me!

Thanks again,
Dave

on 10/21/03 1:06 AM, David Olofson at david at olofson.net wrote:>

Sounds very strange indeed… Are you sure it wasn’t some bonus
effects in the RAMDAC and/or monitor? Sometimes, with some hardware,
you can get horizontal offsets and/or color shifts following (ie to
the right of) areas of certain colors.