2
\$\begingroup\$

I'm currently trying to do a black and white filter for my game in c++ with Allegro 5.01, I'm doing like this.

void    GameEngine::blackAndWhite()
{
    ALLEGRO_BITMAP *buffer  = al_get_backbuffer(this->windows);
    ALLEGRO_LOCKED_REGION *region = al_lock_bitmap(buffer, ALLEGRO_PIXEL_FORMAT_ARGB_8888, ALLEGRO_LOCK_READWRITE);
    unsigned char *ptr = static_cast<unsigned char *>(region->data);

    for (int x = 0; x != 640; ++x) {
        for (int y = 0; y != 480; ++y) {
        unsigned char   red;
        unsigned char   green;
        unsigned char   blue;

        this->getpixel(ptr, x, y, region->pitch, &red, &green, &blue);
        unsigned char result = (red + green + blue) / 3;
        this->putpixel(ptr, x, y, region->pitch, al_map_rgb(result, result, result));
        }
    }
    al_unlock_bitmap(buffer);
}

And putpixel and getpixel is like this.

void        GameEngine::putpixel(unsigned char *ptr, int x, int y, int offset_y,  ALLEGRO_COLOR color) {
    unsigned char   red;
    unsigned char   green;
    unsigned char   blue;
    unsigned char   alpha;

    ptr += (y * offset_y) + (x * 4);
    al_unmap_rgba(color, &red, &green, &blue, &alpha);
    *ptr++ = red;
    *ptr++ = green;
    *ptr++ = blue;
    *ptr = alpha;
}

void        GameEngine::getpixel(unsigned char *ptr, int x, int y, int offset_y,
unsigned char *red, unsigned char *green, unsigned char *blue)
{
    ptr += (y * offset_y) + (x * 4);
    *red = *ptr++;
    *green = *ptr++;
    *blue = *ptr++;
}

It's working, but it's really slow, I'm thinking it's slow because this operation is do by the CPU and not the GPU.

Is there a way for reduce the time of the operation with allegro or not ?

\$\endgroup\$
  • \$\begingroup\$ Try switching the two for-loop lines. The library probably puts pixels (x, y) and (x+1, y) next to each other in memory, but (x, y) and (x, y+1) will be far apart, so you won't use caching properly. Use profiling tools like gprof to find what function is executed the most. Alternatively pause and resume your debugger a couple of times (your debugger is more likely to pause during execution of a slow function). \$\endgroup\$ – bogglez May 19 '14 at 2:01
2
\$\begingroup\$

Allegro is very slow and unoptimized when drawing single pixels to a bitmap. even slower when that bitmap is the backbuffer of the screen: it is stored in video memory and the CPU is the one responsible to do that operation. The bitmap has to be copied to main memory to work on it, then it is sent back to the GPU, all this operations are I/O bound and are very VERY slow.

A fragment shader could be useful in this case, but your current version of allegro does not have support for them as they are part of the 5.1 branch.

A possible speed-up could be obtained if you copy the buffer to a memory bitmap and write in it all the pixels of the filter and then send that result to the graphics card, which is less work than making drawing calls pixel by pixel.

An easy way to make memory bitmaps that does not mess the allegro flags state is to use this helper function:

ALLEGRO_BITMAP *create_memory_bitmap(int w, int h)
{
    ALLEGRO_BITMAP *bmp;
    int flags = al_get_new_bitmap_flags();
    al_set_new_bitmap_flags(flags | ALLEGRO_MEMORY_BITMAP);
    bmp = al_create_bitmap(w, h);
    al_set_new_bitmap_flags(flags);
    return bmp;
}

That way you have less draw calls that need to call the GPU and the CPU (Only three this time I think), however, don't expect too much speed from this as it is still a very unoptimized function to have direct pixel access.

Source:

al_create_bitmap

[al_set_new_bitmap_flags][2]

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.