Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Pixel by pixel operations (Allegro 5)

This thread is locked; no one can reply to it. rss feed Print
Pixel by pixel operations (Allegro 5)
Ediolot
Member #15,215
July 2013

Hi all, I'm having a problem: al_draw_pixel is too slow :(. What I want to do is draw each pixel in the screen according to a number I decide.

For example, I fill a list of X elements (X is equal to the total amount of pixels in my screen) with some random numbers. Then, what I do is drawing each element on a pixel in a bitmap according to their number (for example, element 1 have a 144 number, so I'll put a pixel in position 1 with the color r,g,b = 144,144,144 ) and I will do that with all the elemts in my list. Finally, I draw that bitmap into my screen buffer.

The function I mentioned before is too slow to do it, it takes around 10 seconds in a 1920x1080 screen. I have tried to lock the bitmap for writeonly, but it's still incredible slow. I've been browsing around the internet and saw that you can use "direct adressing" to write directly in the bitmap and it's a fast method to do pixel by pixel operations, but I haven't been able to implement it in my Allegro 5 program ???. Can anybody please help me with this?

Thanks.

(I'm just an english student, so please forgive some grammar errors I could have :-/ )

beoran
Member #12,636
March 2011

Direct addressing is a thing of the distant past. Nowadays your GPU wil do the work for you.

In Allegro 5 you will probably need to use al_draw_prim with ALLEGRO_PRIM_POINT_LIST to draw many points more quickly. Look at examples/ex_prim.c to get more information about this.

Edit: And draw directly to the screen. Drawing to a bitmap is not accelerated.

Trent Gamblin
Member #261
April 2000
avatar

beoran said:

Edit: And draw directly to the screen. Drawing to a bitmap is not accelerated.

It is on any GPU worth anything, which is 99%.

beoran
Member #12,636
March 2011

Ah it is? I stand corrected then.

Trent Gamblin
Member #261
April 2000
avatar

The only machine I have ever seen that runs A5 but doesn't have accelerated render-to-texture is my old PowerPC Mac Mini. It's got some really old ATI GPU that doesn't support it. There are even older PPC Mac's (some old Powerbooks and iBooks) that do support RTT.

SiegeLord
Member #7,827
October 2006
avatar

You could create a bitmap, lock it via al_lock_bitmap and do your pixel drawing and then unlock it and draw it to screen. This will be faster than your current method.

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

ph03nix
Member #15,028
April 2013
avatar

The code for SiegeLord's suggestion would look something like this:

ALLEGRO_LOCKED_REGION *lr = al_lock_bitmap(bitmap, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY);
unsigned char *ptr = (unsigned char*)lr->data;
ptr[0] = red;
ptr[1] = green;
ptr[2] = blue;
ptr[3] = alpha;

obviously bitmap, red, green, blue, and alpha are your own values. This starts at the first (top left) pixel. You can put it in a loop and iterate the pointer by 4 to get the next pixel. If you want a specific pixel, you can do this:

unsigned char *ptr = (unsigned char*)lr->data + y * lr->pitch + (x<<2);

Don't forget to unlock before drawing

SiegeLord
Member #7,827
October 2006
avatar

Eh... not quite. Firstly, if you are going for direct bitmap access, you're not going to want to leave the pixel format up to Allegro. Secondly, just doing this will work fine:

al_lock_bitmap(bitmap, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY);
al_put_pixel(x, y, color); // if you don't need blending
al_put_blended_pixel(x, y, color); // if you need blending
al_unlock_bitmap();

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Kris Asick
Member #1,424
July 2001

Drawing a single pixel with hardware acceleration when controlled by the CPU is practically as slow as drawing a single full-screen bitmap. This is the kind of thing you're much better off using fragment shaders for.

"Fragment Shaders" are basically programs that run on your GPU exclusively and don't need to communicate (at least not much) with the CPU. They're countless times faster than trying to draw pixels one at a time from the CPU, so when you need to do per-pixel access, this is the only way you're gonna get any sort of real speed out of it.

Especially considering you're trying to do an entire 1920x1080 screen worth of pixels. That's slightly over 2,000,000 pixels. Even without hardware acceleration this would go VERY slow at the CPU level. :P

--- Kris Asick (Gemini)
--- http://www.pixelships.com

Edgar Reynaldo
Member #8,592
May 2007
avatar

MiquelFire
Member #3,110
January 2003
avatar

Put the bitmap in memory if you're going to use the CPU to draw pixels?

Depending on what you're doing though, the shader method may be the way to go.

---
Febreze (and other air fresheners actually) is just below perfumes/colognes, and that's just below dead skunks in terms of smells that offend my nose.
MiquelFire.red | +Me
Windows 8 is a toned, stylish, polished professional athlete. But it’s wearing clown makeup, and that creates a serious image problem. ~PCWorld Article

Ediolot
Member #15,215
July 2013

Thanks for the answers.

I've tried both, SiegeLord and ph03nix method. With the first one my "game" goes around 7-8 FPS and with the second it reaches 21 FPS (Fast enough for what I need), I guess that al_put_pixel is still too slow. But there is still something strange with it. This is part of my code:

ALLEGRO_LOCKED_REGION *lr = al_lock_bitmap(earth, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY);
unsigned char *ptr = (unsigned char *)lr->data;

for (y=0; y<screen.h; y++) {
for (x=0 ; x<screen.w; x++) {

pixel = x+y*screen.w;
ptr[pixel*4] = 150;

}
}

al_unlock_bitmap(earth);

This is supposed to set all pixels to red, but they are drawn in blue :o
If I put ptr[pixel*4+2] = 150 they are drawn in red instead.
However, ptr[pixel*4+1] = 150 works fine as they appear in green. It seems that blue and red swapped together.

ph03nix
Member #15,028
April 2013
avatar

I was mistaken when I suggested ALLEGRO_PIXEL_FORMAT_ANY. Use ALLEGRO_PIXEL_FORMAT_ABGR_8888 if you are using a little endian system or ALLEGRO_PIXEL_FORMAT_RGBA_8888 otherwise and the components should be in the right order.

Also here's a minor optimization for your code. If you iterate through it 2 million times you should make sure it's as efficient as possible

ALLEGRO_LOCKED_REGION *lr = al_lock_bitmap(earth, ALLEGRO_PIXEL_FORMAT_ABGR_8888, ALLEGRO_LOCK_WRITEONLY);
unsigned char *ptr = (unsigned char *)lr->data; //points to first pixel
const int screen_pixels = screen.w*screen.h;
for (int i=0; i!=screen_pixels; ++i){
      *ptr++ = 255; //red
      *ptr++ = 0;   //green
      *ptr++ = 0;   //blue
      *ptr++ = 255; //alpha
}
al_unlock_bitmap(earth);

I think you have to set each value, not sure though.

Trent Gamblin
Member #261
April 2000
avatar

SiegeLord said:

Eh... not quite. Firstly, if you are going for direct bitmap access, you're not going to want to leave the pixel format up to Allegro.

If you're doing this frequently, you actually do want to use ALLEGRO_PIXEL_FORMAT_ANY. It doesn't have to do any conversion so it's a lot faster. When you create your bitmaps create them in the desired format then lock with ANY for best performance.

Note: Of course you can create and lock in the same format, but using ANY means one less hardcoded spot.

Edgar Reynaldo
Member #8,592
May 2007
avatar

Semantically it doesn't make sense to use ALLEGRO_PIXEL_FORMAT_ANY unless you are going to have a separate case for each possible format it might be in, which may be hard to keep track of.

Aren't you guys supposed to be using lr->pitch in there somewhere? Can't pitch vary and is not guaranteed to be equal to the width?

int pixel = lr->data + lr->pitch*y + x*4;

Trent Gamblin
Member #261
April 2000
avatar

Semantically it doesn't make sense to use ALLEGRO_PIXEL_FORMAT_ANY unless you are going to have a separate case for each possible format it might be in, which may be hard to keep track of.

Not really. It locks in the actual format of the bitmap, which you should know. Otherwise your code is going to be slow.

Quote:

Can't pitch vary and is not guaranteed to be equal to the width?

Yes, and it can even be negative (in fact it's always negative with OpenGL.)

Edgar Reynaldo
Member #8,592
May 2007
avatar

Go to: