|
Learning shaders, one and for all. |
nshade
Member #4,372
February 2004
|
So in the game I'm porting, I have a function where I need recolor pixels in a particular area except for black. It looks something like this Recolor (x1,y1,x2,y2,color); Where x1,y1 is the upper left corner of the area and x2 and y2 is the lower left. Now, how I'm doing it now, is copying the area from the screen to a temp bitmap, and then using a for/next loop to check the color of every pixel and then set that pixel color if it's not black. After that is done, I copy that bitmap section back to the screen. It's super slow, and large bitmaps are causing my game to drop to below 5 FPS. That in itself is strange because, I mean, I'm pushing 3.4Ghz here and someting a trivial as changing a pixel color is bogging down my system. I've been told that I should be using a pixel shader, and doing a quick skims about them they seem over complicated for what I'm trying to accomplish. But now it's serously impacting my game and I need to learn them once and for all. The problem I'm having is that every time I try and research info about what a pixel shader it's either really vague or goes in some crazy OpenGL/Direct3D low level graphics card mathematics junk. The Allegro API is not helpful. It shows me how to make a shader object, but then say I need to attach the source code to a shader to make it work. What source code? What language? How do you "program" a shader? When I look up a shader language it, it gives me like 30 of them with stuff like "fragmets" and you have to pass vectors and stuff. It seems so complex. I guess the upshot is, can someone show me the "front door" on all of this. No 3D OpenGL/DaretX stuff, no low level graphics card gunk, I don't need "vectors" or "fragments" or "tessellation", I am just looking for a fast way to recolor an area of the screen to another color (except for black). |
Edgar Reynaldo
Major Reynaldo
May 2007
|
What you have to realize is that allegro uses video bitmaps by default. This means they are stored on the GPU. Whenever you modify a video bitmap by using al_lock_bitmap, it has to download the texture region you lock off of the video card. Once you're done modifying it, you have to upload it back to the gpu. This is very slow. You can use a shader to alter the color for sure. Trouble comes when you need to read that data off of the gpu. This is where the bottleneck comes from. nshade said: The Allegro API is not helpful. It shows me how to make a shader object, but then say I need to attach the source code to a shader to make it work. What source code? What language? How do you "program" a shader? When I look up a shader language it, it gives me like 30 of them with stuff like "fragmets" and you have to pass vectors and stuff. It seems so complex. You'll find the manual answers several of your questions. https://liballeg.org/a5docs/trunk/shader.html There is an example program called ex_shader.c that demonstrates simple use of a shader. https://github.com/liballeg/allegro5/blob/master/examples/ex_shader.cpp The source code for the shaders used is in the data directory. https://github.com/liballeg/allegro5/tree/master/examples/data You should really try to learn this yourself. However, I will try to make a simple demo sometime later today. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
kenmasters1976
Member #8,794
July 2007
|
Sounds like you want to do a palette effect. Those were quite easy to achieve in the past with Allegro 4 but on modern graphics using hardware acceleration I guess shaders are the only way to go. Someone posted this page a while ago, it has a good introduction to shaders and it should be easy to adapt to using the Allegro shader addon. Also, have you tried locking your bitmaps before manipulating the pixels?.
|
nshade
Member #4,372
February 2004
|
This helps actually. It looks like shaders are linked to a language called "glsl" and I should be looking at that. The "vectors" are just ways of addressing variables. Looking at allegro, it appears that you write a glsl program and then attach that to Allegro. Then you turn it on when you want to use it. I even found a hello world program and a canvas to experiment with on online. (Evidently you can do shaders in a web browser!) neat... As for locking the surfaces.. Yea, I do that... Here is the function in question 1*!
2* \brief Replace a color a particular region, ignoring black
3* \param d Destination buffer
4* \param s Source buffer
5* \param dx Destination X
6* \param dy Destination Y
7* \param sx Source X
8* \param sy Source Y
9* \param w Width
10* \param h Height
11* \param col1 Color to replace
12* \param col2 Color to replace it to
13*/
14void ReplaceColor(int d, int s, int dx, int dy, int sx, int sy, int w,
15 int h, int col1, int col2)
16{
17 ALLEGRO_BITMAP *replacebuf;
18 replacebuf = al_create_bitmap(GameWidth, GameHeight);
19
20 //The native resolution is 1280x800 which is 4x the original 320x200 resolution
21 int scaledSrcX = sx * 4;
22 int scaledSrcY = sy * 4;
23 int scaledDestX = dx * 4;
24 int scaledDestY = dy * 4;
25 int scaledW = w * 4;
26 int scaledH = h * 4;
27
28 int maskx;
29 int masky;
30 unsigned char r1, g1, b1;
31 unsigned char r2, g2, b2;
32 unsigned char r3, g3, b3;
33
34 //deconstruct color 1 and 2
35 al_unmap_rgb(palette[col1], &r1, &g1, &b1);
36 al_unmap_rgb(palette[col2], &r2, &g2, &b2);
37
38 al_set_target_bitmap(replacebuf);
39 al_clear_to_color(al_map_rgb(0, 0, 0));
40 al_draw_bitmap_region(bufmap[s], scaledSrcX, scaledSrcY, scaledW, scaledH, scaledDestX, scaledDestY, 0);
41
42 al_lock_bitmap(replacebuf, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READWRITE);
43 for (masky = 0; masky < scaledH; masky++)
44 {
45 for (maskx = 0; maskx < scaledW; maskx++) {
46 //get pixel color
47 masktemp = al_get_pixel(replacebuf, maskx + scaledDestX, masky + scaledDestY);
48 al_unmap_rgb(masktemp, &r3, &g3, &b3);
49 if (!(r3 == 0 && g3 == 0 && b3 == 0)) {
50 if (r3 == r1 && g3 == g1 && b3 == b1) {
51 al_put_pixel(maskx + scaledDestX, masky + scaledDestY, palette[col2]);
52 }
53 }
54 }
55 }
56
57 al_unlock_bitmap(replacebuf);
58
59 al_set_target_bitmap(bufmap[d]);
60 al_draw_bitmap_region(replacebuf, scaledDestX, scaledDestY, scaledW, scaledH, scaledDestX, scaledDestY, 0);
61 al_set_target_bitmap(al_get_backbuffer(DISPLAY));
62 if (d == SCREEN) { UpdateScreen(); }
63 al_destroy_bitmap(replacebuf);
64}
|
Edgar Reynaldo
Major Reynaldo
May 2007
|
https://learnopengl.com/Getting-started/Shaders has a good intro to shaders. As for why your program is slow, there are several reasons. 1) You're creating a temporary ALLEGRO_BITMAP* buffer every time you draw something in a different color. The constant allocation and destruction of this buffer slows your code down. 2) The buffer is unnecessary, because you're using a locked region. 3) ALLEGRO_LOCK_READWRITE causes the texture to be downloaded off the gpu on locking, and uploaded back to the gpu when unlocked. This is slow. Reading causes download. Writing causes upload. 4) Just lock bufmap[i] directly, using only the region you need to recolor. 5) A shader could replace the color as it is drawn on the gpu, which would avoid all this nonsense altogether. It's perfect for what you want. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
|