In my project I'm sampling heightmap data into a bitmap and then calculating a normal map out of that bitmap and I'd like to parallelize this process. I know that Allegro is not thread safe (I'm using A5) so one way is calculating the data into a buffer and then copying that buffer in a single thread into the bitmap.
The question is whether this could be possibly avoided so I can do something like this:
#pragma omp parallel for for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { // Either sample procedural generator or the heightmap // in case of normal map generation ALLEGRO_COLOR c = getColorValue(x, y); al_put_pixel(x, y, c); } }
That should work fine. A shader would work even better depending on the complexity of getColorValue.
The problem is, that I get a segmentation fault when I try to run the code. Full code snippet is here:
The single threaded version runs just fine. When I've duplicated the loop, let it run in parallel and store into a ALLEGRO_COLOR[ width * height ] array and then copied that array into the bitmap it ran just as fine. But running this code results in segmentation fault.
Update: I've had that running in the release mode, now that I've run it in the debugger it seems that _al_put_pixel is getting 0x0 as the address of the target bitmap which seems odd. The bitmap is properly created before the execution proceeds towards the loop.
Oh right, yes, of course that wouldn't work. al_put_pixel draws to the bitmap obtained by al_get_target_bitmap() which is a per-thread setting. I'd either avoid using al_put_pixel and writing directly to the bitmap or perhaps trying something like this:
Untested.
Ok, I'll try that out. A side question though, how would I go with direct access to that bitmap you've mentioned?
Update: silly me, some time ago I've asked the question about direct access when I was trying to load bitmap data into a OpenGL cubemap. The answer is via the ALLEGRO_LOCKED_REGION.
Update 2: looking at the ex_draw.c it seems the answer is to use unsigned chars to tamper directly with the data. So unmap the color and write it down. I'm going to try that out.
Update 3: it's getting too late, I'll return back to it in the morning. Anyway, so far thanks for the help. I've tried this code:
I still get the segfault at the texel assignment, my pointer arithmetics is most probably to blame. I'll look at it when I'll be more fresh.
Firstly, you probably want to specify a specific pixel format when locking (or even creating the bitmap). Secondly, you still want to do it with two loops. It'll be something like this:
for (unsigned int y = 0; y < aHeight; ++y) { for (unsigned int x = 0; x < aWidth; ++x) { unsigned char *texel = (unsigned char *)(bmp->data + x * bmp->pixel_size + y * bmp->pitch); } }
EDIT:
Incidentally, I tested the other approach and it worked just fine on my computer. Consider using it if this direct bitmap access is too annoying. Test code:
Aw crap, I knew that something was wrong there, I forgot to change the pixel format as the previous version didn't care for it. I've tried the direct approach even with both for loops but to no avail. The problem seems to lie within the negative pitch (at least that's what I guess).
On the second row of the bitmap (y = 1) it throws SEGFAULT because the pointer is out of bounds. I wonder though how's it possible that I'm able to upload bitmap data with negative pitch to the GPU via glTexImage2D.
I'm going to try the other way by providing the pointer to each thread, although I'm not very fond of it. Thanks for help and sorry for not replying earlier.
Update: the problem lied within the negative pitch, because I've used x and y variables as unsigned int which caused "loss" of the negative bit in the pitch variable. Now it's working.