By KawaungaXDG


2019-02-09 13:37:39 8 Comments

In my current project I need to fill a 256x224 screen with the pixel values from an array. The array is declared this way:

uint8_t *vram = new uint8_t[7168];

So as you might have noticed, every bit in this array represent 1 pixel in the screen (256 x 224 / 8 = 7168). My current attempt to render a screen looks like this: (it is executed at 60hz)

int x = 0;  
int y = 0;
for (int i = 0; i < 7168; i++)
{
    //read the byte
    uint8_t b = vram[i];
    for (int j = 7; j >= 0; j--)
    {
        //read 1 bit from the original byte
        bool pixel = (b >> j) & 1;
        SetPixel(x, y, pixel);

        //if end of line reached, go to next line
        if (((x + 1) % 256) == 0)
        {
            x = 0;
            y++;
        }
        else
        {
            x++;
        }
    }
}

and my SetPixel function:

void SetPixel(int x, int y, Uint32 pixel)
{
    Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * 4;
    *(Uint32 *)p = pixel;
}

My window and surface declarations:

window = SDL_CreateWindow("Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 256, 224, SDL_WINDOW_OPENGL);
surface = SDL_GetWindowSurface(window);

Currently I have two big problems:

  • My surface isn't been changed, doesn't matter what I try
  • I not even sure if this method is efficient, looking at profiling data from Visual Studio it doesn't seem to be

So, how could I render a black and white screen from an byte array in a somewhat efficient way?

Any help will be very appreciated!

1 comments

@Sardonic 2019-02-09 19:58:22

It seems like you have 2 questions here: 1. Why doesn't this code change the surface? 2. Is there a way to do this faster?

Why doesn't this code work?

For me, opening a window, grabbing the screen surface, and writing to the pixels with the function you have there works perfectly fine, so the problem is likely not in your SetPixels function. Instead, it's likely with your surface. There are a couple of possible problems here; most likely, however, is that you simply forgot to call SDL_UpdateWindowSurface( window ) after making your changes. If this doesn't fix it, make sure that:

  1. Your surface is from your window. Surfaces can come from a lot of different places in SDL, so make sure this surface is indeed the surface that backs the window. You can get this from SDL_GetWindowSurface( window )

  2. Depending on the surface, you may need to lock it and unlock it with SDL_LockSurface() and SDL_UnlockSurface(), modifying the pixels in between those two calls.

How can it be faster?

Ideally, by using more memory. The best thing to do would be to do away with the bit-array altogether and simply use a texture (or SDL_Surface) that is the same size as the window surface. Then, copy the whole thing, perhaps with an SDL_BlitSurface() or, even better, using an SDL_Renderer and SDL_RenderCopy(). The main thing slowing down the code is unpacking the bits. If you can store the whole texture at once, you'll be able to skip that step entirely. Then, when copying a giant texture all at once, SDL will be able to take advantage of all the CPU's efficient memory copying features (if using SDL_Surfaces) or all of the extreme texture-copying might of the GPU (if using an SDL_Renderer).

If this isn't possible, the more pixels you can copy at once, the better off you'll be.

The SDL docs demonstrate clearing an entire surface on the CPU using the call SDL_memset(surface->pixels, 0, surface->h * surface->pitch) (Source). In your case, SDL_memcpy may be a more useful call. You should try to expand the pixels out into a block of memory several bytes long (the more the better), and then call something like SDL_memcpy(surface->pixels, eightPixels, sizeof(Uint32_t) * 8) if you were copying eight pixels at once, for example. I don't have an exact working sample of this, but it should give you a useful direction to move in.

@Maximus Minimus 2019-02-10 12:14:04

I'll add to this that attempting to micro-optimize by having each bit in an array be a pixel is only going to make things worse. This goes hand-in-hand with your "how can it be faster" section - most displays are 32-bit RGBX, so storing the source data in the same 32-bit format allows it to be quickly written from source to destination in a single operation, rather than having to go through intermediate bit-by-bit unpacking. This is one of those seemingly counter-intuitive things about graphics programming - using substantially more memory can make your program orders of magnitude faster.

@Sardonic 2019-02-11 02:04:14

@MaximusMinimus I added a bit about this to the answer.

@KawaungaXDG 2019-02-11 11:06:48

@MaximusMinumus I totally agree with you now, after some attempts to make this code batter. The major problem is that this bit array is a memory dump from an old hardware that rendered image like this so I really was biased towards this solution that worked well for the time it was used. It's really counter intuitive as you pointed out!

@KawaungaXDG 2019-02-11 11:07:56

@Sardonic Thank you for your answer! You helped me a lot!

Related Questions

Sponsored Content

2 Answered Questions

[SOLVED] Removing a pair from array of pairs

  • 2018-10-09 19:30:24
  • Marko Petričević
  • 116 View
  • 0 Score
  • 2 Answer
  • Tags:   c++ sdl2

1 Answered Questions

[SOLVED] How do I render to a texture loaded from a PNG file using SDL2

1 Answered Questions

[SOLVED] SDL TTF render variable

  • 2017-01-03 18:59:38
  • FIREHIVE
  • 584 View
  • 0 Score
  • 1 Answer
  • Tags:   sdl sdl2 ttf

1 Answered Questions

[SOLVED] Rendering three-dimentional array of tiles (as a tilemap)

1 Answered Questions

[SOLVED] Efficiently blit texture rotated by 90° to renderer with SDL 2

  • 2016-04-09 14:26:21
  • François Beaune
  • 234 View
  • 2 Score
  • 1 Answer
  • Tags:   sdl2

1 Answered Questions

[SOLVED] Why does SDL render the background from the operating system to the window?

  • 2016-03-06 13:09:38
  • Hugo dijkstra
  • 899 View
  • 0 Score
  • 1 Answer
  • Tags:   c++ sdl2

2 Answered Questions

[SOLVED] Array of 3d points, construct point cloud or surface (OpenGL)

2 Answered Questions

[SOLVED] Colour values of a pixel array from a spritesheet image wrong (C++, SDL2)

  • 2015-02-03 20:27:16
  • heap_trouble
  • 470 View
  • 0 Score
  • 2 Answer
  • Tags:   c++ sdl pixel sdl2

1 Answered Questions

[SOLVED] 2D Software Lighting Issues in Java

1 Answered Questions

[SOLVED] How do I multiply pixels on an SDL Surface?

  • 2012-10-05 14:46:04
  • NoobScratcher
  • 619 View
  • 3 Score
  • 1 Answer
  • Tags:   sdl pixel

Sponsored Content