summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorJens Arnold <amiconn@rockbox.org>2005-07-30 12:42:11 +0000
committerJens Arnold <amiconn@rockbox.org>2005-07-30 12:42:11 +0000
commit3d73790ab7da315efd5cb981e730a4fcf8f597bc (patch)
tree7088d4794cf012a8f722a7a19ce3fbc7ac6fea5c /apps
parent204ff7e473ad3e20aaaf758eaaddbc28bbcb1cfd (diff)
downloadrockbox-3d73790ab7da315efd5cb981e730a4fcf8f597bc.tar.gz
rockbox-3d73790ab7da315efd5cb981e730a4fcf8f597bc.zip
Heavily improved mandelbrot plugin: (1) Calculation now uses 64bit fixed point arithmetics to allow zooming in way further before the precision barrier will hit. Added asm-optimised 64bit multiplication routine for SH1; more than twice as fast as what gcc produces. (2) Precision is dynamically selected based on the zoom level, low zoom factors still use 32bit for speed. (3) Maximum number of iterations is adapted to the zoom level. You can still increase / decrease it while staying at a zoom level. (4) Panning only recalculates the scrolled-in part of the screen -> way faster panning.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7258 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-rw-r--r--apps/plugins/mandelbrot.c329
1 files changed, 252 insertions, 77 deletions
diff --git a/apps/plugins/mandelbrot.c b/apps/plugins/mandelbrot.c
index 14b4ef6fb0..6e28f55b57 100644
--- a/apps/plugins/mandelbrot.c
+++ b/apps/plugins/mandelbrot.c
@@ -8,6 +8,7 @@
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Copyright (C) 2004 Matthias Wientapper 10 * Copyright (C) 2004 Matthias Wientapper
11 * Heavily extended 2005 Jens Arnold
11 * 12 *
12 * 13 *
13 * All files in this archive are subject to the GNU General Public License. 14 * All files in this archive are subject to the GNU General Public License.
@@ -53,57 +54,161 @@
53 54
54static struct plugin_api* rb; 55static struct plugin_api* rb;
55static char buff[32]; 56static char buff[32];
56static long aspect; 57
57static long x_min; 58/* Fixed point format: 6 bits integer part incl. sign, 58 bits fractional part */
58static long x_max; 59static long long x_min;
59static long y_min; 60static long long x_max;
60static long y_max; 61static long long x_step;
61static long delta; 62static long long x_delta;
62static int max_iter; 63static long long y_min;
64static long long y_max;
65static long long y_step;
66static long long y_delta;
67
68static int px_min = 0;
69static int px_max = LCD_WIDTH;
70static int py_min = 0;
71static int py_max = LCD_HEIGHT;
72
73static int step_log2;
74static unsigned max_iter;
75
63static unsigned char *gbuf; 76static unsigned char *gbuf;
64static unsigned int gbuf_size = 0; 77static unsigned int gbuf_size = 0;
65static unsigned char graybuffer[LCD_HEIGHT]; 78static unsigned char graybuffer[LCD_HEIGHT];
66 79
80#if CONFIG_CPU == SH7034
81long long mul64(long long f1, long long f2);
82
83asm (
84 /* 64bit * 64bit -> 64bit multiplication. Works for both signed and unsigned */
85 ".global _mul64 \n"
86 ".type _mul64,@function\n"
87"_mul64: \n" /* Notation: abcd * efgh, where each letter */
88 "mov.l r8,@-r15 \n" /* represents 16 bits. Called with: */
89 "mov.l r9,@-r15 \n" /* r4 = ab, r5 = cd, r6 = ef, r7 = gh */
90
91 "swap.w r5,r2 \n" /* r2 = dc */
92 "mulu r2,r7 \n" /* c * h */
93 "swap.w r7,r3 \n" /* r3 = hg */
94 "sts macl,r1 \n" /* r1 = c * h */
95 "mulu r5,r3 \n" /* d * g */
96 "clrt \n"
97 "sts macl,r9 \n" /* r9 = d * g */
98 "addc r9,r1 \n" /* r1 += r9 */
99 "movt r0 \n" /* move carry to r0 */
100 "mov r1,r9 \n" /* r0r1 <<= 16 */
101 "xtrct r0,r9 \n"
102 "mulu r5,r7 \n" /* d * h */
103 "mov r9,r0 \n"
104 "shll16 r1 \n"
105 "sts macl,r9 \n" /* r9 = d * h */
106 "mov #0,r8 \n" /* r8 = 0 */
107 "clrt \n" /* r0r1 += r8r9 */
108 "mulu r4,r7 \n" /* b * h */
109 "addc r9,r1 \n"
110 "addc r8,r0 \n"
111 "sts macl,r8 \n" /* r8 = b * h */
112 "mulu r2,r3 \n" /* c * g */
113 "add r8,r0 \n" /* r0r1 += r8 << 32 */
114 "sts macl,r8 \n" /* r8 = c * g */
115 "mulu r5,r6 \n" /* d * f */
116 "add r8,r0 \n" /* r0r1 += r8 << 32 */
117 "sts macl,r8 \n" /* r8 = d * f */
118 "mulu r4,r3 \n" /* b * g */
119 "add r8,r0 \n" /* r0r1 += r8 << 32 */
120 "sts macl,r8 \n" /* r8 = b * g */
121 "mulu r2,r6 \n" /* c * f */
122 "swap.w r4,r2 \n" /* r2 = ba */
123 "sts macl,r9 \n" /* r9 = c * f */
124 "mulu r2,r7 \n" /* a * h */
125 "add r9,r8 \n" /* r8 += r9 */
126 "swap.w r6,r3 \n" /* r3 = fe */
127 "sts macl,r9 \n" /* r9 = a * h */
128 "mulu r5,r3 \n" /* d * e */
129 "add r9,r8 \n" /* r8 += r9 */
130 "sts macl,r9 \n" /* r9 = d * e */
131 "add r9,r8 \n" /* r8 += r9 */
132 "shll16 r8 \n" /* r8 <<= 16 */
133 "add r8,r0 \n" /* r0r1 += r8 << 32 */
134
135 "mov.l @r15+,r9 \n"
136 "rts \n"
137 "mov.l @r15+,r8 \n"
138);
139#define MUL64(a, b) mul64(a, b)
140#else
141#define MUL64(a, b) ((a)*(b))
142#endif
143
144int ilog2_fp(long long value) /* calculate integer log2(value_fp_6.58) */
145{
146 int i = 0;
147
148 if (value <= 0) {
149 return -32767;
150 } else if (value > (1LL<<58)) {
151 while (value >= (2LL<<58)) {
152 value >>= 1;
153 i++;
154 }
155 } else {
156 while (value < (1LL<<58)) {
157 value <<= 1;
158 i--;
159 }
160 }
161 return i;
162}
67 163
68void init_mandelbrot_set(void){ 164void recalc_parameters(void)
165{
166 x_step = (x_max - x_min) / LCD_WIDTH;
167 x_delta = MUL64(x_step, (LCD_WIDTH/8));
168 y_step = (y_max - y_min) / LCD_HEIGHT;
169 y_delta = MUL64(y_step, (LCD_HEIGHT/8));
170 step_log2 = MIN(ilog2_fp(x_step), ilog2_fp(y_step));
171 max_iter = MAX(10, 10 - 15 * step_log2);
172}
173
174void init_mandelbrot_set(void)
175{
69#if CONFIG_LCD == LCD_SSD1815 /* Recorder, Ondio. */ 176#if CONFIG_LCD == LCD_SSD1815 /* Recorder, Ondio. */
70 x_min = -38<<22; // -2.375<<26 177 x_min = -38LL<<54; // -2.375<<58
71 x_max = 15<<22; // 0.9375<<26 178 x_max = 15LL<<54; // 0.9375<<58
72#else /* Iriver H1x0 */ 179#else /* Iriver H1x0 */
73 x_min = -36<<22; // -2.25<<26 180 x_min = -36LL<<54; // -2.25<<58
74 x_max = 12<<22; // 0.75<<26 181 x_max = 12LL<<54; // 0.75<<58
75#endif 182#endif
76 y_min = -19<<22; // -1.1875<<26 183 y_min = -19LL<<54; // -1.1875<<58
77 y_max = 19<<22; // 1.1875<<26 184 y_max = 19LL<<54; // 1.1875<<58
78 delta = (x_max - x_min) >> 3; // /8 185 recalc_parameters();
79 max_iter = 25;
80} 186}
81 187
82void calc_mandelbrot_set(void){ 188void calc_mandelbrot_32(void)
83 189{
84 long start_tick, last_yield; 190 long start_tick, last_yield;
85 int n_iter; 191 unsigned n_iter;
86 int x_pixel, y_pixel; 192 long long a64, b64;
87 long x, x2, y, y2, a, b; 193 long x, x2, y, y2, a, b;
88 long x_fact, y_fact; 194 int p_x, p_y;
89 int brightness; 195 int brightness;
90
91 start_tick = last_yield = *rb->current_tick;
92
93 gray_ub_clear_display();
94 196
95 x_fact = (x_max - x_min) / LCD_WIDTH; 197 start_tick = last_yield = *rb->current_tick;
96 y_fact = (y_max - y_min) / LCD_HEIGHT;
97 198
98 a = x_min; 199 for (p_x = 0, a64 = x_min; p_x <= px_max; p_x++, a64 += x_step) {
99 for (x_pixel = 0; x_pixel < LCD_WIDTH; x_pixel++){ 200 if (p_x < px_min)
100 b = y_min; 201 continue;
101 for(y_pixel = LCD_HEIGHT-1; y_pixel >= 0; y_pixel--){ 202 a = a64 >> 32;
203 for (p_y = LCD_HEIGHT-1, b64 = y_min; p_y >= py_min; p_y--, b64 += y_step) {
204 if (p_y >= py_max)
205 continue;
206 b = b64 >> 32;
102 x = 0; 207 x = 0;
103 y = 0; 208 y = 0;
104 n_iter = 0; 209 n_iter = 0;
105 210
106 while (++n_iter<=max_iter) { 211 while (++n_iter <= max_iter) {
107 x >>= 13; 212 x >>= 13;
108 y >>= 13; 213 y >>= 13;
109 x2 = x * x; 214 x2 = x * x;
@@ -121,17 +226,67 @@ void calc_mandelbrot_set(void){
121 } else { 226 } else {
122 brightness = 255 - (32 * (n_iter & 7)); 227 brightness = 255 - (32 * (n_iter & 7));
123 } 228 }
124 graybuffer[y_pixel]=brightness; 229 graybuffer[p_y]=brightness;
230 /* be nice to other threads:
231 * if at least one tick has passed, yield */
232 if (*rb->current_tick > last_yield) {
233 rb->yield();
234 last_yield = *rb->current_tick;
235 }
236 }
237 gray_ub_gray_bitmap_part(graybuffer, 0, py_min, 1,
238 p_x, py_min, 1, py_max-py_min);
239 }
240}
241
242void calc_mandelbrot_64(void)
243{
244 long start_tick, last_yield;
245 unsigned n_iter;
246 long long x, x2, y, y2, a, b;
247 int p_x, p_y;
248 int brightness;
249
250 start_tick = last_yield = *rb->current_tick;
251
252 for (p_x = 0, a = x_min; p_x < px_max; p_x++, a += x_step) {
253 if (p_x < px_min)
254 continue;
255 for (p_y = LCD_HEIGHT-1, b = y_min; p_y >= py_min; p_y--, b += y_step) {
256 if (p_y >= py_max)
257 continue;
258 x = 0;
259 y = 0;
260 n_iter = 0;
261
262 while (++n_iter<=max_iter) {
263 x >>= 29;
264 y >>= 29;
265 x2 = MUL64(x, x);
266 y2 = MUL64(y, y);
267
268 if (x2 + y2 > (4LL<<58)) break;
269
270 y = 2 * MUL64(x, y) + b;
271 x = x2 - y2 + a;
272 }
273
274 // "coloring"
275 if (n_iter > max_iter){
276 brightness = 0; // black
277 } else {
278 brightness = 255 - (32 * (n_iter & 7));
279 }
280 graybuffer[p_y]=brightness;
125 /* be nice to other threads: 281 /* be nice to other threads:
126 * if at least one tick has passed, yield */ 282 * if at least one tick has passed, yield */
127 if (*rb->current_tick > last_yield){ 283 if (*rb->current_tick > last_yield){
128 rb->yield(); 284 rb->yield();
129 last_yield = *rb->current_tick; 285 last_yield = *rb->current_tick;
130 } 286 }
131 b += y_fact;
132 } 287 }
133 gray_ub_gray_bitmap(graybuffer, x_pixel, 0, 1, LCD_HEIGHT); 288 gray_ub_gray_bitmap_part(graybuffer, 0, py_min, 1,
134 a += x_fact; 289 p_x, py_min, 1, py_max-py_min);
135 } 290 }
136} 291}
137 292
@@ -142,12 +297,16 @@ void cleanup(void *parameter)
142 gray_release(); 297 gray_release();
143} 298}
144 299
300#define REDRAW_NONE 0
301#define REDRAW_PARTIAL 1
302#define REDRAW_FULL 2
303
145enum plugin_status plugin_start(struct plugin_api* api, void* parameter) 304enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
146{ 305{
147 int button; 306 int button;
148 int lastbutton = BUTTON_NONE; 307 int lastbutton = BUTTON_NONE;
149 int grayscales; 308 int grayscales;
150 bool redraw = true; 309 int redraw = REDRAW_FULL;
151 310
152 TEST_PLUGIN_API(api); 311 TEST_PLUGIN_API(api);
153 rb = api; 312 rb = api;
@@ -160,7 +319,7 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
160 * 8 bitplanes for 9 shades of gray.*/ 319 * 8 bitplanes for 9 shades of gray.*/
161 grayscales = gray_init(rb, gbuf, gbuf_size, false, LCD_WIDTH, 320 grayscales = gray_init(rb, gbuf, gbuf_size, false, LCD_WIDTH,
162 (LCD_HEIGHT*LCD_DEPTH/8), 8, NULL) + 1; 321 (LCD_HEIGHT*LCD_DEPTH/8), 8, NULL) + 1;
163 if (grayscales != 9){ 322 if (grayscales != 9) {
164 rb->snprintf(buff, sizeof(buff), "%d", grayscales); 323 rb->snprintf(buff, sizeof(buff), "%d", grayscales);
165 rb->lcd_puts(0, 1, buff); 324 rb->lcd_puts(0, 1, buff);
166 rb->lcd_update(); 325 rb->lcd_update();
@@ -168,18 +327,28 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
168 return(0); 327 return(0);
169 } 328 }
170 329
171 gray_show(true); /* switch on greyscale overlay */ 330 gray_show(true); /* switch on grayscale overlay */
172 331
173 init_mandelbrot_set(); 332 init_mandelbrot_set();
174 aspect = ((y_max - y_min) / ((x_max-x_min)>>13))<<13;
175 333
176 /* main loop */ 334 /* main loop */
177 while (true){ 335 while (true) {
178 if(redraw) 336 if (redraw > REDRAW_NONE) {
179 calc_mandelbrot_set(); 337 if (redraw == REDRAW_FULL)
338 gray_ub_clear_display();
339
340 if (step_log2 <= -13) /* select precision */
341 calc_mandelbrot_64();
342 else
343 calc_mandelbrot_32();
344
345 px_min = 0;
346 px_max = LCD_WIDTH;
347 py_min = 0;
348 py_max = LCD_HEIGHT;
349 redraw = REDRAW_NONE;
350 }
180 351
181 redraw = false;
182
183 button = rb->button_get(true); 352 button = rb->button_get(true);
184 switch (button) { 353 switch (button) {
185 case MANDELBROT_QUIT: 354 case MANDELBROT_QUIT:
@@ -187,12 +356,12 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
187 return PLUGIN_OK; 356 return PLUGIN_OK;
188 357
189 case MANDELBROT_ZOOM_OUT: 358 case MANDELBROT_ZOOM_OUT:
190 x_min -= delta; 359 x_min -= x_delta;
191 x_max += delta; 360 x_max += x_delta;
192 y_min -= ((delta>>13)*(aspect>>13)); 361 y_min -= y_delta;
193 y_max += ((delta>>13)*(aspect>>13)); 362 y_max += y_delta;
194 delta = (x_max - x_min) >> 3; 363 recalc_parameters();
195 redraw = true; 364 redraw = REDRAW_FULL;
196 break; 365 break;
197 366
198 367
@@ -204,55 +373,61 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
204#ifdef MANDELBROT_ZOOM_IN2 373#ifdef MANDELBROT_ZOOM_IN2
205 case MANDELBROT_ZOOM_IN2: 374 case MANDELBROT_ZOOM_IN2:
206#endif 375#endif
207 x_min += delta; 376 x_min += x_delta;
208 x_max -= delta; 377 x_max -= x_delta;
209 y_min += ((delta>>13)*(aspect>>13)); 378 y_min += y_delta;
210 y_max -= ((delta>>13)*(aspect>>13)); 379 y_max -= y_delta;
211 delta = (x_max - x_min) >> 3; 380 recalc_parameters();
212 redraw = true; 381 redraw = REDRAW_FULL;
213 break; 382 break;
214 383
215 case BUTTON_UP: 384 case BUTTON_UP:
216 y_min += delta; 385 y_min += y_delta;
217 y_max += delta; 386 y_max += y_delta;
218 redraw = true; 387 gray_ub_scroll_down(LCD_HEIGHT/8);
388 py_max = (LCD_HEIGHT/8);
389 redraw = REDRAW_PARTIAL;
219 break; 390 break;
220 391
221 case BUTTON_DOWN: 392 case BUTTON_DOWN:
222 y_min -= delta; 393 y_min -= y_delta;
223 y_max -= delta; 394 y_max -= y_delta;
224 redraw = true; 395 gray_ub_scroll_up(LCD_HEIGHT/8);
396 py_min = (LCD_HEIGHT-LCD_HEIGHT/8);
397 redraw = REDRAW_PARTIAL;
225 break; 398 break;
226 399
227 case BUTTON_LEFT: 400 case BUTTON_LEFT:
228 x_min -= delta; 401 x_min -= x_delta;
229 x_max -= delta; 402 x_max -= x_delta;
230 redraw = true; 403 gray_ub_scroll_right(LCD_WIDTH/8);
404 px_max = (LCD_WIDTH/8);
405 redraw = REDRAW_PARTIAL;
231 break; 406 break;
232 407
233 case BUTTON_RIGHT: 408 case BUTTON_RIGHT:
234 x_min += delta; 409 x_min += x_delta;
235 x_max += delta; 410 x_max += x_delta;
236 redraw = true; 411 gray_ub_scroll_left(LCD_WIDTH/8);
412 px_min = (LCD_WIDTH-LCD_WIDTH/8);
413 redraw = REDRAW_PARTIAL;
237 break; 414 break;
238 415
239 case MANDELBROT_MAXITER_DEC: 416 case MANDELBROT_MAXITER_DEC:
240 if (max_iter>5){ 417 if (max_iter >= 15) {
241 max_iter -= 5; 418 max_iter -= max_iter >> 1;
242 redraw = true; 419 redraw = REDRAW_FULL;
243 } 420 }
244 break; 421 break;
245 422
246 case MANDELBROT_MAXITER_INC: 423 case MANDELBROT_MAXITER_INC:
247 if (max_iter < 195){ 424 max_iter += max_iter >> 1;
248 max_iter += 5; 425 redraw = REDRAW_FULL;
249 redraw = true;
250 }
251 break; 426 break;
252 427
253 case MANDELBROT_RESET: 428 case MANDELBROT_RESET:
254 init_mandelbrot_set(); 429 init_mandelbrot_set();
255 redraw = true; 430 redraw = REDRAW_FULL;
256 break; 431 break;
257 432
258 default: 433 default: