A strange plot

An idea came to me the other day, while I was writing some 2D drawing functions, specifically the timeless ‘plot’ function.  In case you don’t know, the plot function puts one pixel on the screen at a given location.

This is a function that has to be fast, because it is convenient to use it in some places such at line and circle drawing.  Image drawing on the other hand can be optimized in may ways making plot redundant for that use.

Here I will present a nice and generic plot function, that is useful when you cant optimize pixel writes, or are too lazy and just want to get on with other things.

A simple plot command may be as follows…

inline void plot( int x, int y )
{
    uint32 *pixels = screen_buffer;
    pixels[ x + y * screen_width ] = colour;
}

One problem that must be tackled with a plot function is this…  what if we draw off screen?  For instance with Plot( -1, -1 ).  In this case, the program has been asked to write to memory that it doesn’t own, and will cause all sorts of terrible bugs.

Well aha, we can fix it with the following code…

inline void plot( int x, int y )
{
    if ( x < 0 || x >= screen_width  ) return;
    if ( y < 0 || y >= screen_height ) return;
    uint32 *pixels = screen_buffer;
    pixels[ x + y * screen_width ] = colour;
}

That may have stopped us from crashing the program when a pixel is written off the screen but what might that do for the performance.  Branching is terrible in performance critical code, and this function may get called 1000+ times each frame.

I had an idea to help speed things up a little, by getting what we want, without the branches.Have a look at this code…

inline void plot( int x, int y )
{
    bool off_screen |= (x < 0);
         off_screen |= (y < 0);
         off_screen |= (x >= screen_width);
         off_screen |= (y >= screen_height);
         
    // 0xFFFFFFFF if on  screen
    // 0x00000000 if off screen
    int mask   = off_screen - 1;
    int index  = x + y * screen_width;
    int index &= mask;
    
    uint32 *pixels  = screen_buffer;
    
    pixels[ index ] = colour;
}

Here I have replaced the branch instruction with a mask operation.  In this case whenever we may write off screen, it will redirect the write to pixel [0,0].  Yay, now the program doesn’t crash anymore, and the performance shouldn’t suck too much.

There is however the problem of this distracting pixel in the upper left corner that may flash all kinds of strange colors now.  One hilarious solution is to do a final plot(0,0) with black, before you present the screen, giving up this pixel all together.  I would never be satisfied with that solution because it is just ugly.  A solution that I was able to use (because I am rendering to an intermediate screen buffer) is to allocate one more pixel then I need.  Change this one line, to have a + 1.

   int index  = ( x + y * screen_width ) + 1;

Every time I reference, the screen buffer, I first + 1 to the pointer to skip over the [0,0] pixel.  So, we treat the screen buffer as starting from [1,0], making the first pixel invisible and ofscreen.  Thus in effect, our masking operation ensures that it uses pixel (-1,0) for all off screen writes, which is legal memory now, but not visible.  The downside here is that a +1 of the screen buffer everywhere is still a bit ugly however.

Anyway, that’s my hopefully interesting take on the timeless plot(x,y) function…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s