1 /**
2  * @file lv_draw_sdl_stack_blur.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_draw_sdl_stack_blur.h"
10 
11 #if LV_USE_GPU_SDL
12 /*********************
13  *      DEFINES
14  *********************/
15 
16 /**********************
17  *      TYPEDEFS
18  **********************/
19 
20 /**********************
21  *  STATIC PROTOTYPES
22  **********************/
23 
24 static void
25 stack_blur_job(lv_opa_t * src, unsigned int w, unsigned int h, unsigned int radius, int cores, int core, int step);
26 
27 /**********************
28  *  STATIC VARIABLES
29  **********************/
30 
31 // Based heavily on http://vitiy.info/Code/stackblur.cpp
32 // See http://vitiy.info/stackblur-algorithm-multi-threaded-blur-for-cpp/
33 // Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>
34 
35 static unsigned short const stackblur_mul[255] = {
36     512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292, 512,
37     454, 405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 292, 273, 512,
38     482, 454, 428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259, 496, 475, 456,
39     437, 420, 404, 388, 374, 360, 347, 335, 323, 312, 302, 292, 282, 273, 265, 512,
40     497, 482, 468, 454, 441, 428, 417, 405, 394, 383, 373, 364, 354, 345, 337, 328,
41     320, 312, 305, 298, 291, 284, 278, 271, 265, 259, 507, 496, 485, 475, 465, 456,
42     446, 437, 428, 420, 412, 404, 396, 388, 381, 374, 367, 360, 354, 347, 341, 335,
43     329, 323, 318, 312, 307, 302, 297, 292, 287, 282, 278, 273, 269, 265, 261, 512,
44     505, 497, 489, 482, 475, 468, 461, 454, 447, 441, 435, 428, 422, 417, 411, 405,
45     399, 394, 389, 383, 378, 373, 368, 364, 359, 354, 350, 345, 341, 337, 332, 328,
46     324, 320, 316, 312, 309, 305, 301, 298, 294, 291, 287, 284, 281, 278, 274, 271,
47     268, 265, 262, 259, 257, 507, 501, 496, 491, 485, 480, 475, 470, 465, 460, 456,
48     451, 446, 442, 437, 433, 428, 424, 420, 416, 412, 408, 404, 400, 396, 392, 388,
49     385, 381, 377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344, 341, 338, 335,
50     332, 329, 326, 323, 320, 318, 315, 312, 310, 307, 304, 302, 299, 297, 294, 292,
51     289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259
52 };
53 
54 static unsigned char const stackblur_shr[255] = {
55     9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17,
56     17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19,
57     19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
58     20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
59     21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
60     21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22,
61     22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
62     22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23,
63     23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
64     23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
65     23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
66     23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
67     24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
68     24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
69     24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
70     24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24
71 };
72 
73 /**********************
74  *      MACROS
75  **********************/
76 
77 /**********************
78  *   GLOBAL FUNCTIONS
79  **********************/
80 
lv_stack_blur_grayscale(lv_opa_t * buf,uint16_t w,uint16_t h,uint16_t r)81 void lv_stack_blur_grayscale(lv_opa_t * buf, uint16_t w, uint16_t h, uint16_t r)
82 {
83     stack_blur_job(buf, w, h, r, 1, 0, 1);
84     stack_blur_job(buf, w, h, r, 1, 0, 2);
85 }
86 
87 /**********************
88  *   STATIC FUNCTIONS
89  **********************/
90 
stack_blur_job(lv_opa_t * src,unsigned int w,unsigned int h,unsigned int radius,int cores,int core,int step)91 static void stack_blur_job(lv_opa_t * src, unsigned int w, unsigned int h, unsigned int radius, int cores, int core,
92                            int step)
93 {
94     if(radius < 2 || radius > 254) {
95         /* Silently ignore bad radius */
96         return;
97     }
98 
99     unsigned int x, y, xp, yp, i;
100     unsigned int sp;
101     unsigned int stack_start;
102     unsigned char * stack_ptr;
103 
104     lv_opa_t * src_ptr;
105     lv_opa_t * dst_ptr;
106 
107     unsigned long sum_r;
108     unsigned long sum_in_r;
109     unsigned long sum_out_r;
110 
111     unsigned int wm = w - 1;
112     unsigned int hm = h - 1;
113     unsigned int stride = w;
114     unsigned int div = (radius * 2) + 1;
115     unsigned int mul_sum = stackblur_mul[radius];
116     unsigned char shr_sum = stackblur_shr[radius];
117     unsigned char stack[254 * 2 + 1];
118 
119     if(step == 1) {
120         unsigned int minY = core * h / cores;
121         unsigned int maxY = (core + 1) * h / cores;
122 
123         for(y = minY; y < maxY; y++) {
124             sum_r =
125                 sum_in_r =
126                     sum_out_r = 0;
127 
128             src_ptr = src + stride * y; // start of line (0,y)
129 
130             for(i = 0; i <= radius; i++) {
131                 stack_ptr = &stack[i];
132                 stack_ptr[0] = src_ptr[0];
133                 sum_r += src_ptr[0] * (i + 1);
134                 sum_out_r += src_ptr[0];
135             }
136 
137 
138             for(i = 1; i <= radius; i++) {
139                 if(i <= wm) src_ptr += 1;
140                 stack_ptr = &stack[i + radius];
141                 stack_ptr[0] = src_ptr[0];
142                 sum_r += src_ptr[0] * (radius + 1 - i);
143                 sum_in_r += src_ptr[0];
144             }
145 
146 
147             sp = radius;
148             xp = radius;
149             if(xp > wm) xp = wm;
150             src_ptr = src + (xp + y * w); //   img.pix_ptr(xp, y);
151             dst_ptr = src + y * stride; // img.pix_ptr(0, y);
152             for(x = 0; x < w; x++) {
153                 dst_ptr[0] = LV_CLAMP((sum_r * mul_sum) >> shr_sum, 0, 255);
154                 dst_ptr += 1;
155 
156                 sum_r -= sum_out_r;
157 
158                 stack_start = sp + div - radius;
159                 if(stack_start >= div) stack_start -= div;
160                 stack_ptr = &stack[stack_start];
161 
162                 sum_out_r -= stack_ptr[0];
163 
164                 if(xp < wm) {
165                     src_ptr += 1;
166                     ++xp;
167                 }
168 
169                 stack_ptr[0] = src_ptr[0];
170 
171                 sum_in_r += src_ptr[0];
172                 sum_r += sum_in_r;
173 
174                 ++sp;
175                 if(sp >= div) sp = 0;
176                 stack_ptr = &stack[sp];
177 
178                 sum_out_r += stack_ptr[0];
179                 sum_in_r -= stack_ptr[0];
180             }
181 
182         }
183     }
184 
185     // step 2
186     if(step == 2) {
187         unsigned int minX = core * w / cores;
188         unsigned int maxX = (core + 1) * w / cores;
189 
190         for(x = minX; x < maxX; x++) {
191             sum_r =
192                 sum_in_r =
193                     sum_out_r = 0;
194 
195             src_ptr = src + x; // x,0
196             for(i = 0; i <= radius; i++) {
197                 stack_ptr = &stack[i];
198                 stack_ptr[0] = src_ptr[0];
199                 sum_r += src_ptr[0] * (i + 1);
200                 sum_out_r += src_ptr[0];
201             }
202             for(i = 1; i <= radius; i++) {
203                 if(i <= hm) src_ptr += stride;  // +stride
204 
205                 stack_ptr = &stack[i + radius];
206                 stack_ptr[0] = src_ptr[0];
207                 sum_r += src_ptr[0] * (radius + 1 - i);
208                 sum_in_r += src_ptr[0];
209             }
210 
211             sp = radius;
212             yp = radius;
213             if(yp > hm) yp = hm;
214             src_ptr = src + (x + yp * w); // img.pix_ptr(x, yp);
215             dst_ptr = src + x;               // img.pix_ptr(x, 0);
216             for(y = 0; y < h; y++) {
217                 dst_ptr[0] = LV_CLAMP((sum_r * mul_sum) >> shr_sum, 0, 255);
218                 dst_ptr += stride;
219 
220                 sum_r -= sum_out_r;
221 
222                 stack_start = sp + div - radius;
223                 if(stack_start >= div) stack_start -= div;
224                 stack_ptr = &stack[stack_start];
225 
226                 sum_out_r -= stack_ptr[0];
227 
228                 if(yp < hm) {
229                     src_ptr += stride; // stride
230                     ++yp;
231                 }
232 
233                 stack_ptr[0] = src_ptr[0];
234 
235                 sum_in_r += src_ptr[0];
236                 sum_r += sum_in_r;
237 
238                 ++sp;
239                 if(sp >= div) sp = 0;
240                 stack_ptr = &stack[sp];
241 
242                 sum_out_r += stack_ptr[0];
243                 sum_in_r -= stack_ptr[0];
244             }
245         }
246     }
247 }
248 
249 #endif /*LV_USE_GPU_SDL*/
250