Search code examples
c++sdlrgbpixelsdl-1.2

How to update single pixels efficiently on SDL 1.2 surface?


I'm writing a little thing that calculates rgb values for each pixel of a image.

I want to display each one after it was calculated. The problem is that I can't figure out how to make this fast. Calculating the complete image and then displaying it takes a few seconds, where as displaying each pixel right takes a few minutes.

It is important that I can see the progress on the image calculation. Is there a way to solve this task efficiently in SDL 1.2?

My code looks as follows for now:

SDL_Surface* screen = NULL;
SDL_Surface* image = NULL;

SDL_Init(SDL_INIT_EVERYTHING);

//Set up screen
screen = SDL_SetVideoMode(img.width(), img.height(), 32, SDL_SWSURFACE);

// create surface with default values
image = SDL_CreateRGBSurface(SDL_SWSURFACE,img.width(),img.height(),32,0,0,0,0);

if(image == NULL) {
    std::cout << "failed creating SDL surface";
}

// create array for pixels
Uint32 *pixels = (Uint32 *)image->pixels;

//Apply image to screen
SDL_BlitSurface(image, NULL, screen, NULL);

//Update screen
SDL_Flip(screen);

// compute image
for (int i = 0; i < img.width(); i++) {
    for (int j = 0; j < img.height(); j++) {
        img(i, j) = computeColor(i, j, img.width(), img.height());
        pixels[i * img.width() + j] = SDL_MapRGB(image->format,(Uint8)getR(img(i,j)), (Uint8)getG(img(i,j)),(Uint8)getB(img(i,j)));
        SDL_BlitSurface(image, NULL, screen, NULL);
        SDL_UpdateRect(screen, i, j, i, j);
    }
}

//Pause
SDL_Delay(2000);

//Free the loaded image
SDL_FreeSurface(image);

//Quit SDL
SDL_Quit();

Solution

  • You do not need the intermediate image, you can put pixels directly onto the screen surface. You may call SDL_Flip() or SDL_UpdateRect() for each line, not for each pixel, it will be much faster.

    Also, looping through lines instead of columns will give you a small speed boost, because pixels on a single line are located near each other in a physical memory, and sequential memory access is faster on modern CPUs.

    // create array for pixels
    Uint32 *pixels = (Uint32 *)screen->pixels;
    
    // Clear screen
    SDL_FillRect(screen, NULL, 0);
    
    //Update screen
    SDL_Flip(screen);
    
    // compute image
    for (int j = 0; j < img.height(); j++) {
        for (int i = 0; i < img.width(); i++) {
            img(i, j) = computeColor(i, j, img.width(), img.height());
            pixels[i + j * img.width()] = SDL_MapRGB(image->format,(Uint8)getR(img(i,j)), (Uint8)getG(img(i,j)),(Uint8)getB(img(i,j)));
        }
        SDL_UpdateRect(screen, i, j, img.width(), 1);
    }
    
    // Display final result
    SDL_Flip(screen);
    SDL_Delay(2000);
    

    You can also create a separate int variables for img.height() and img.width(), so that you won't be doing a function call each iteration, but compiler is usually able to optimize that anyway.