N buffering and access to the hidden video surface

Hello,

I desire to use SDL for visualization of heavy distributed processing. Multiple frames are being rendered simultaneously, with the visualisation trailing just slightly behind ( typically 200ms ). Basically, more than double or triple buffering, I need N buffering ( 8 buffers or more ).

I realize the surface returned by SDL_SetVideoMode() is a shadow software surface, which is copied to the real ( and hidden ) video surface when SDL_UpdateRect() is called. To make any of the N buffers visible, I must first copy the data to this shadow surface, followed by another copy to the video memory with SDL_UpdateRect(). This is very inefficient, copying every frame twice when only one copy should be required.

So, I would like to copy the data of any of the N buffers directly to video memory. Unfortunately, there seems to be no way to acquire the real video surface ( current_video->screen or SDL_VideoSurface ). Alternatively, I could change the SDL_VideoDevice’s shadow surface pointer ( current_video->shadow or SDL_ShadowSurface ) to any of the N buffers I desire to render visible, but all these symbols are not publicly exported.

Briefly, am I missing something or it’s impossible to perform N buffering with SDL? It seems to be a fairly arbitrary limitation, it could easily be done if one could just grab a pointer to the real video surface.

Thanks!

Alexis Naveros
SURVICE Engineering

one could just grab a pointer to the real video surface.

In most cases, there is no such thing as “the real video surface” …
the real framebuffer is hidden by the OS on almost every platform.

That being said:

If your OS supports it, call SDL_SetVideoMode() with SDL_HWSURFACE.

Then build N software surfaces with SDL_CreateRGBSurface(). Render into
their ->pixels fields directly. Don’t make these hardware surfaces,
since you will want to frequently touch their pixels directly, which
would mean moving data back and forth across the bus. You just want to
treat these as memory buffers waiting to be sent to video hardware.
You’ll also want them to be in the same format as the screen surface, so
there’s never a need to convert them, which could slow things down.

Use SDL_BlitSurface() to move one of these software surfaces to the
screen surface, and call SDL_Flip() to put it to the screen once per frame.

In ideal situations, this is one copy–the SDL_BlitSurface() call–and
there’s no shadow surface. In most cases, you’re going to not get a
HWSURFACE from SDL_SetVideoMode(), since most platforms don’t offer it,
and you’ll get the shadow surface anyhow, but the same code will still
work (the SDL_Flip() becomes a second copy, basically).

Alternately, consider using OpenGL…there’s one “copy” when uploading
the surface as a texture to video RAM, then the actual selection of a
buffer is basically “free.” It’s also the only way to avoid the extra
copy on X11, since that target always gives you software surfaces even
when requesting HWSURFACE.

(“Consider using OpenGL” is going to be an increasingly popular
recommendation going forward…the 2D pipeline has been obsolete for
darn near a decade now, so we all need to stop trying to make an
inherently slow thing fast. Many things tend to be faster and much much
easier in 3D APIs, even for 2D graphics. That applies to a lot of
discussions on this list, not just this one.)

–ryan.

Thanks for your reply, Ryan.

If your OS supports it, call SDL_SetVideoMode() with SDL_HWSURFACE.

Obtaining a hardware surface would clearly solve the problem, though that doesn’t seem to ever happen on the platforms used ( X11 shm mostly ).

In ideal situations, this is one copy–the SDL_BlitSurface() call–and
there’s no shadow surface. In most cases, you’re going to not get a
HWSURFACE from SDL_SetVideoMode(), since most platforms don’t offer it,
and you’ll get the shadow surface anyhow, but the same code will still
work (the SDL_Flip() becomes a second copy, basically).

Understood. I think a proper solution would then be to make SDL continuously cycle through multiple “shadow” surfaces, copying the data directly from any of the allocated surfaces. If I’m not mistaken, all that would be required is changing current_video->shadow ( SDL_ShadowSurface macro ) to point to any other surface… yet the API does not appear to expose such a feature. I guess this could be patched without too much trouble though.

Alternately, consider using OpenGL…there’s one “copy” when uploading
the surface as a texture to video RAM, then the actual selection of a
buffer is basically “free.” It’s also the only way to avoid the extra
copy on X11, since that target always gives you software surfaces even
when requesting HWSURFACE.

Right. I’m considering it, I’m just stopped by how a hardware accelerated OpenGL implementation is not likely to be available ( typical Linux laptops hooked to the clusters or the number crunching boxes themselves ).

Do you have any thoughts on a quick SDL patch to perform N buffering with always just one “copy” per frame?

Alexis Naveros

Do you have any thoughts on a quick SDL patch to perform N buffering
with always just one “copy” per frame?

I don’t think it would be something we’d add to SDL itself, but you
could probably wedge this in there fairly easily.

How much overhead does the extra copy cause here?

–ryan.

Hi Ryan,

How much overhead does the extra copy cause here?

The difference between having to copy 300mb or 600mb around per second is not negligible, plus the cost of receiving and decompressing all the data. Briefly, the cheaper operations are, the more frames can be pushed per second… so I would prefer to avoid any unnecessary waste.

I don’t think it would be something we’d add to SDL itself, but you
could probably wedge this in there fairly easily.

I think a function could exist to supply a different “shadow” surface for the “screen”, replacing current_video->shadow, assuming it is of the same resolution and format. SDL_UpdateRect() could then be used to read from this new shadow suface and the previous one would become a regular independant surface.

Do you see any problem with such a feature? Should I understand that there wouldn’t be interest in such a patch? ( or anything equivalent to provide similar functionality )

Thanks,
Alexis