Using a framebuffer in Mono C#/SDL (Tao.Sdl)

I wrote this little tutorial because I couldn't find anything out there like it. This tutorial assumes a couple of things: 1) that you want to directly modify the SDL screen data in some way (in C it would be accessing the pixels member of the screen buffer) and 2) that, of course, you're trying to do this in C#.

.NET's manage memory model is a little difficult to wrap your head around at first. I knew for sure, after reading around, that one solution was to copy the buffer from unmanaged memory to managed memory and then back again.

That was not an option.

So, I had to find a way to access the buffer direction from managed memory. Here's what I came up with. The example below fills a pixel buffer and then hand-copies it into the output buffer. While this isn't exactly optimal, it will give you the idea. As an added benefit, it'll also tell you how fast your C# SDL setup is.

This example uses the Tao.Sdl bindings, which can be found in Mono CVS.

using System;
using Tao.Sdl;
using System.Runtime.InteropServices;


class Video
{
	IntPtr sdlBuffer;	 //to be displayed buffer
	IntPtr surfacePtr;
	int [] pixelBuffer;  //offscreen emulated buffer
	int	bpp = 32;
	int	width = 320;
	int	height = 224;
	int resultFlip;
	
	public void FillBuffer(int pixelColor)
	{
		int j;
		for (j = 0; j < (320*240); j++)
		{
			pixelBuffer[j] = pixelColor;
		} 
	}
	
	public void BlitScreen()
	{
		int j, f;
		
		for (j = 0; j < 1000; j++)
		{
			int myPixelColor;
			unsafe {
				int *p = (int *)sdlBuffer;
				int maxlength = width*height;
				
				for (f = 0; f < maxlength; f++)
				{
					myPixelColor =  pixelBuffer[f];
					p[f] = myPixelColor;
				}
			}
			resultFlip = Sdl.SDL_Flip(surfacePtr);
			FillBuffer(j % 255);
		}
	
	}
	public Video()
	{
		//Initialize the SDL frontend
		int init, flags, j;
		
		init = Sdl.SDL_Init(Sdl.SDL_INIT_VIDEO);
		flags = (Sdl.SDL_SWSURFACE|Sdl.SDL_DOUBLEBUF|Sdl.SDL_ANYFORMAT);
		surfacePtr = Sdl.SDL_SetVideoMode(
			width, 
			height, 
			bpp, 
			flags);
				
		Sdl.SDL_Surface surface = 
			(Sdl.SDL_Surface)Marshal.PtrToStructure(surfacePtr, typeof(Sdl.SDL_Surface));
		sdlBuffer = surface.pixels;
		//END Initialize the SDL frontend
		
		//Initialize the offscreen buffer
		pixelBuffer = new int [320*240];
		FillBuffer(255);
		//END Initialize the offscreen buffer
	}
	
	~Video()
	{
 		Sdl.SDL_FreeSurface(ref surfacePtr);
	
	}
}
class MainClass
{
	public static void Main(string[] args)
	{
		Video myVideo = new Video();

		DateTime dt = DateTime.Now;
		myVideo.BlitScreen();
		
		DateTime dtnow = DateTime.Now;
		Console.WriteLine("FPS: " + (1000.0 / ((dtnow-dt).Ticks / 10000000.0)));
	}
}

The meat lies in the following lines:

		Sdl.SDL_Surface surface = 
			(Sdl.SDL_Surface)Marshal.PtrToStructure(surfacePtr, typeof(Sdl.SDL_Surface));
		sdlBuffer = surface.pixels;

Here we "marshal", that is, convert the unmanaged pointer to something that can be used in managed memory, the SDL_Surface pointer that we get back from our SDL_SetVideoMode. Once the variable has been marshalled into something more manageable, we can extract information from the structure. Right now we're only interested in the pixels member, but there are other goodies in there to be had.

		unsafe {
			int *p = (int *)sdlBuffer;
			int maxlength = width*height;
			
			for (f = 0; f < maxlength; f++)
			{
				myPixelColor =  pixelBuffer[f];
				p[f] = myPixelColor;
			}
		}
		resultFlip = Sdl.SDL_Flip(surfacePtr);

In the world of unsafe you're all alone, but if you're a C/C++ programmer that's how it's always been. Take our sdlBuffer from before and change it back to a pointer we can use. The rest follows should look familiar. Make sure you do the flip at the end or you'll beat your head against the table trying to figure out why it isn't working (trust me, mine's still sore).

Email me