summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Arnold <amiconn@rockbox.org>2007-10-21 13:46:26 +0000
committerJens Arnold <amiconn@rockbox.org>2007-10-21 13:46:26 +0000
commitc1051549b93d1905602ba25409cbd8f4a607c3b5 (patch)
tree303c0129884c3c32c6ca1e425b8edd4c9caf3ebc
parente1a91b9138148bd33ee0bae72a7367b6282aca7f (diff)
downloadrockbox-c1051549b93d1905602ba25409cbd8f4a607c3b5.tar.gz
rockbox-c1051549b93d1905602ba25409cbd8f4a607c3b5.zip
Implement YUV dithering for c200, and enable the option in mpegplayer.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15246 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/plugin.c2
-rw-r--r--apps/plugin.h6
-rw-r--r--apps/plugins/mpegplayer/mpeg_settings.c12
-rw-r--r--apps/plugins/mpegplayer/mpeg_settings.h4
-rw-r--r--firmware/target/arm/sandisk/sansa-c200/lcd-as-c200.S306
-rw-r--r--firmware/target/arm/sandisk/sansa-c200/lcd-c200.c54
6 files changed, 361 insertions, 23 deletions
diff --git a/apps/plugin.c b/apps/plugin.c
index bbb6d6feb2..a8781dd1ac 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -184,7 +184,7 @@ static const struct plugin_api rockbox_api = {
184#if defined(HAVE_LCD_COLOR) 184#if defined(HAVE_LCD_COLOR)
185 lcd_yuv_blit, 185 lcd_yuv_blit,
186#endif 186#endif
187#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) 187#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200)
188 lcd_yuv_set_options, 188 lcd_yuv_set_options,
189#endif 189#endif
190 /* list */ 190 /* list */
diff --git a/apps/plugin.h b/apps/plugin.h
index ee58687bf0..27ab2ce166 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -112,12 +112,12 @@
112#define PLUGIN_MAGIC 0x526F634B /* RocK */ 112#define PLUGIN_MAGIC 0x526F634B /* RocK */
113 113
114/* increase this every time the api struct changes */ 114/* increase this every time the api struct changes */
115#define PLUGIN_API_VERSION 84 115#define PLUGIN_API_VERSION 85
116 116
117/* update this to latest version if a change to the api struct breaks 117/* update this to latest version if a change to the api struct breaks
118 backwards compatibility (and please take the opportunity to sort in any 118 backwards compatibility (and please take the opportunity to sort in any
119 new function which are "waiting" at the end of the function table) */ 119 new function which are "waiting" at the end of the function table) */
120#define PLUGIN_MIN_API_VERSION 84 120#define PLUGIN_MIN_API_VERSION 85
121 121
122/* plugin return codes */ 122/* plugin return codes */
123enum plugin_status { 123enum plugin_status {
@@ -266,7 +266,7 @@ struct plugin_api {
266 int x, int y, int width, int height); 266 int x, int y, int width, int height);
267#endif 267#endif
268 268
269#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) 269#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200)
270 void (*lcd_yuv_set_options)(unsigned options); 270 void (*lcd_yuv_set_options)(unsigned options);
271#endif 271#endif
272 272
diff --git a/apps/plugins/mpegplayer/mpeg_settings.c b/apps/plugins/mpegplayer/mpeg_settings.c
index 94781988c7..9e6fa57fb5 100644
--- a/apps/plugins/mpegplayer/mpeg_settings.c
+++ b/apps/plugins/mpegplayer/mpeg_settings.c
@@ -101,7 +101,7 @@ static struct configdata config[] =
101 {TYPE_INT, 0, 2, &settings.skipframes, "Skip frames", NULL, NULL}, 101 {TYPE_INT, 0, 2, &settings.skipframes, "Skip frames", NULL, NULL},
102 {TYPE_INT, 0, INT_MAX, &settings.resume_count, "Resume count", 102 {TYPE_INT, 0, INT_MAX, &settings.resume_count, "Resume count",
103 NULL, NULL}, 103 NULL, NULL},
104#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) 104#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200)
105 {TYPE_INT, 0, INT_MAX, &settings.displayoptions, "Display options", 105 {TYPE_INT, 0, INT_MAX, &settings.displayoptions, "Display options",
106 NULL, NULL}, 106 NULL, NULL},
107#endif 107#endif
@@ -119,7 +119,7 @@ static void display_options(void)
119 int options_quit = 0; 119 int options_quit = 0;
120 120
121 static const struct menu_item items[] = { 121 static const struct menu_item items[] = {
122#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) 122#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200)
123 [MPEG_OPTION_DITHERING] = 123 [MPEG_OPTION_DITHERING] =
124 { "Dithering", NULL }, 124 { "Dithering", NULL },
125#endif /* #ifdef TOSHIBA_GIGABEAT_F */ 125#endif /* #ifdef TOSHIBA_GIGABEAT_F */
@@ -142,7 +142,7 @@ static void display_options(void)
142 142
143 switch (result) 143 switch (result)
144 { 144 {
145#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) 145#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200)
146 case MPEG_OPTION_DITHERING: 146 case MPEG_OPTION_DITHERING:
147 result = (settings.displayoptions & LCD_YUV_DITHER) ? 1 : 0; 147 result = (settings.displayoptions & LCD_YUV_DITHER) ? 1 : 0;
148 rb->set_option("Dithering", &result, INT, noyes, 2, NULL); 148 rb->set_option("Dithering", &result, INT, noyes, 2, NULL);
@@ -463,7 +463,7 @@ void init_settings(const char* filename)
463 settings.limitfps = 1; /* Limit FPS */ 463 settings.limitfps = 1; /* Limit FPS */
464 settings.skipframes = 1; /* Skip frames */ 464 settings.skipframes = 1; /* Skip frames */
465 settings.resume_count = -1; 465 settings.resume_count = -1;
466#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) 466#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200)
467 settings.displayoptions = 0; /* No visual effects */ 467 settings.displayoptions = 0; /* No visual effects */
468#endif 468#endif
469 469
@@ -479,7 +479,7 @@ void init_settings(const char* filename)
479 SETTINGS_VERSION); 479 SETTINGS_VERSION);
480 } 480 }
481 481
482#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) 482#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200)
483 if ((settings.displayoptions = 483 if ((settings.displayoptions =
484 configfile_get_value(SETTINGS_FILENAME, "Display options")) < 0) 484 configfile_get_value(SETTINGS_FILENAME, "Display options")) < 0)
485 { 485 {
@@ -522,7 +522,7 @@ void save_settings(void)
522 ++settings.resume_count); 522 ++settings.resume_count);
523 } 523 }
524 524
525#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) 525#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200)
526 configfile_update_entry(SETTINGS_FILENAME, "Display options", 526 configfile_update_entry(SETTINGS_FILENAME, "Display options",
527 settings.displayoptions); 527 settings.displayoptions);
528#endif 528#endif
diff --git a/apps/plugins/mpegplayer/mpeg_settings.h b/apps/plugins/mpegplayer/mpeg_settings.h
index 340deb46fe..37ceda7225 100644
--- a/apps/plugins/mpegplayer/mpeg_settings.h
+++ b/apps/plugins/mpegplayer/mpeg_settings.h
@@ -3,7 +3,7 @@
3 3
4enum mpeg_option_id 4enum mpeg_option_id
5{ 5{
6#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) 6#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200)
7 MPEG_OPTION_DITHERING, 7 MPEG_OPTION_DITHERING,
8#endif 8#endif
9 MPEG_OPTION_DISPLAY_FPS, 9 MPEG_OPTION_DISPLAY_FPS,
@@ -33,7 +33,7 @@ struct mpeg_settings {
33 int resume_count; /* total # of resumes in config file */ 33 int resume_count; /* total # of resumes in config file */
34 int resume_time; /* resume time for current mpeg (in half minutes) */ 34 int resume_time; /* resume time for current mpeg (in half minutes) */
35 char resume_filename[128]; /* filename of current mpeg */ 35 char resume_filename[128]; /* filename of current mpeg */
36#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) 36#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200)
37 int displayoptions; 37 int displayoptions;
38#endif 38#endif
39}; 39};
diff --git a/firmware/target/arm/sandisk/sansa-c200/lcd-as-c200.S b/firmware/target/arm/sandisk/sansa-c200/lcd-as-c200.S
index 9b0cd75bae..aaeb8439b6 100644
--- a/firmware/target/arm/sandisk/sansa-c200/lcd-as-c200.S
+++ b/firmware/target/arm/sandisk/sansa-c200/lcd-as-c200.S
@@ -241,3 +241,309 @@ lcd_write_yuv420_lines:
241 .ltorg @ dump constant pool 241 .ltorg @ dump constant pool
242 .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines 242 .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines
243 243
244/****************************************************************************
245 * void lcd_write_yuv_420_lines_odither(unsigned char const * const src[3],
246 * int width,
247 * int stride,
248 * int x_screen,
249 * int y_screen);
250 *
251 * |R| |1.000000 -0.000001 1.402000| |Y'|
252 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
253 * |B| |1.000000 1.772000 0.000000| |Pr|
254 * Red scaled at twice g & b but at same precision to place it in correct
255 * bit position after multiply and leave instruction count lower.
256 * |R| |258 0 408| |Y' - 16|
257 * |G| = |149 -49 -104| |Cb - 128|
258 * |B| |149 258 0| |Cr - 128|
259 *
260 * Write four RGB565 pixels in the following order on each loop:
261 * 1 3 + > down
262 * 2 4 \/ left
263 *
264 * Kernel pattern (raw|rotated|use order):
265 * 5 3 4 2 2 6 3 7 row0 row2 > down
266 * 1 7 0 6 | 4 0 5 1 | 2 4 6 0 3 5 7 1 col0 left
267 * 4 2 5 3 | 3 7 2 6 | 3 5 7 1 2 4 6 0 col2 \/
268 * 0 6 1 7 5 1 4 0
269 */
270 .section .icode, "ax", %progbits
271 .align 2
272 .global lcd_write_yuv420_lines_odither
273 .type lcd_write_yuv420_lines_odither, %function
274lcd_write_yuv420_lines_odither:
275 @ r0 = yuv_src
276 @ r1 = width
277 @ r2 = stride
278 @ r3 = x_screen
279 @ [sp] = y_screen
280 stmfd sp!, { r4-r12, lr } @ save non-scratch
281 ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p
282 @ r5 = yuv_src[1] = Cb_p
283 @ r6 = yuv_src[2] = Cr_p
284 @
285 sub r2, r2, #1 @
286 ldr r14, [sp, #40] @ Line up pattern and kernel quadrant
287 eor r14, r14, r3 @
288 and r14, r14, #0x2 @
289 mov r14, r14, lsl #6 @ 0x00 or 0x80
290 mov r3, #0x70000000 @
291 orr r3, r3, #0x3000 @ r3 = LCD1_BASE
29210: @ loop line @
293 @
294 ldrb r7, [r4], #1 @ r7 = *Y'_p++;
295 ldrb r8, [r5], #1 @ r8 = *Cb_p++;
296 ldrb r9, [r6], #1 @ r9 = *Cr_p++;
297 @
298 eor r14, r14, #0x80 @ flip pattern quadrant
299 @
300 sub r7, r7, #16 @ r7 = Y = (Y' - 16)*149
301 add r12, r7, r7, asl #2 @
302 add r12, r12, r12, asl #4 @
303 add r7, r12, r7, asl #6 @
304 @
305 sub r8, r8, #128 @ Cb -= 128
306 sub r9, r9, #128 @ Cr -= 128
307 @
308 add r10, r8, r8, asl #4 @ r10 = guv = Cr*104 + Cb*49
309 add r10, r10, r8, asl #5 @
310 add r10, r10, r9, asl #3 @
311 add r10, r10, r9, asl #5 @
312 add r10, r10, r9, asl #6 @
313 @
314 mov r8, r8, asl #1 @ r8 = bu = Cb*258
315 add r8, r8, r8, asl #7 @
316 @
317 add r9, r9, r9, asl #1 @ r9 = rv = Cr*408
318 add r9, r9, r9, asl #4 @
319 mov r9, r9, asl #3 @
320 @
321 @ compute R, G, and B
322 add r0, r8, r7 @ r0 = b' = Y + bu
323 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
324 rsb r7, r10, r7 @ r7 = g' = Y + guv
325 @
326 @ r8 = bu, r9 = rv, r10 = guv
327 @
328 sub r12, r0, r0, lsr #5 @ r0 = 31/32*b + b/256
329 add r0, r12, r0, lsr #8 @
330 @
331 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256
332 add r11, r12, r11, lsr #8 @
333 @
334 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256
335 add r7, r12, r7, lsr #8 @
336 @
337 add r12, r14, #0x100 @
338 @
339 add r0, r0, r12 @ b = r0 + delta
340 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
341 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
342 @
343 orr r12, r0, r11, asr #1 @ check if clamping is needed...
344 orr r12, r12, r7 @ ...at all
345 movs r12, r12, asr #15 @
346 beq 15f @ no clamp @
347 movs r12, r0, asr #15 @ clamp b
348 mvnne r0, r12, lsr #15 @
349 andne r0, r0, #0x7c00 @ mask b only if clamped
350 movs r12, r11, asr #16 @ clamp r
351 mvnne r11, r12, lsr #16 @
352 movs r12, r7, asr #15 @ clamp g
353 mvnne r7, r12, lsr #15 @
35415: @ no clamp @
355 @
356 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
357 @
358
359 and r11, r11, #0xf800 @ pack pixel
360 mov r11, r11, lsr #8
361 and r7, r7, #0x7e00
362 orr r11, r11, r7, lsr #12
363 mov r7, r7, lsr#4
364 orr r0, r7, r0, lsr #10
3651: @ busy @
366 ldr r7, [r3] @ r7 = LCD1_BASE
367 tst r7, #LCD1_BUSY_MASK @ bridge busy?
368 bne 1b @
369 str r11, [r3, #0x10] @ send MSB
3701: @ busy @
371 ldr r7, [r3] @ r7 = LCD1_BASE
372 tst r7, #LCD1_BUSY_MASK @ bridge busy?
373 bne 1b @
374 str r0, [r3, #0x10] @ send LSB
375 @
376 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
377 add r12, r7, r7, asl #2 @
378 add r12, r12, r12, asl #4 @
379 add r7, r12, r7, asl #6 @
380 @ compute R, G, and B
381 add r0, r8, r7 @ r0 = b' = Y + bu
382 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
383 rsb r7, r10, r7 @ r7 = g' = Y + guv
384 @
385 sub r12, r0, r0, lsr #5 @ r0 = 31/32*b' + b'/256
386 add r0, r12, r0, lsr #8 @
387 @
388 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256
389 add r11, r12, r11, lsr #8 @
390 @
391 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256
392 add r7, r12, r7, lsr #8 @
393 @
394 add r12, r14, #0x200 @
395 @
396 add r0, r0, r12 @ b = r0 + delta
397 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
398 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
399 @
400 orr r12, r0, r11, asr #1 @ check if clamping is needed...
401 orr r12, r12, r7 @ ...at all
402 movs r12, r12, asr #15 @
403 beq 15f @ no clamp @
404 movs r12, r0, asr #15 @ clamp b
405 mvnne r0, r12, lsr #15 @
406 andne r0, r0, #0x7c00 @ mask b only if clamped
407 movs r12, r11, asr #16 @ clamp r
408 mvnne r11, r12, lsr #16 @
409 movs r12, r7, asr #15 @ clamp g
410 mvnne r7, r12, lsr #15 @
41115: @ no clamp @
412 @
413 ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++)
414
415 and r11, r11, #0xf800 @ pack pixel
416 mov r11, r11, lsr #8
417 and r7, r7, #0x7e00
418 orr r11, r11, r7, lsr #12
419 mov r7, r7, lsr#4
420 orr r0, r7, r0, lsr #10
4211: @ busy @
422 ldr r7, [r3] @ r7 = LCD1_BASE
423 tst r7, #LCD1_BUSY_MASK @ bridge busy?
424 bne 1b @
425 str r11, [r3, #0x10] @ send MSB
4261: @ busy @
427 ldr r7, [r3] @ r7 = LCD1_BASE
428 tst r7, #LCD1_BUSY_MASK @ bridge busy?
429 bne 1b @
430 str r0, [r3, #0x10] @ send LSB
431
432 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
433 add r12, r7, r7, asl #2 @
434 add r12, r12, r12, asl #4 @
435 add r7, r12, r7, asl #6 @
436 @ compute R, G, and B
437 add r0, r8, r7 @ r0 = b' = Y + bu
438 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
439 rsb r7, r10, r7 @ r7 = g' = Y + guv
440 @
441 @ r8 = bu, r9 = rv, r10 = guv
442 @
443 sub r12, r0, r0, lsr #5 @ r0 = 31/32*b' + b'/256
444 add r0, r12, r0, lsr #8 @
445 @
446 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256
447 add r11, r12, r11, lsr #8 @
448 @
449 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256
450 add r7, r12, r7, lsr #8 @
451 @
452 add r12, r14, #0x300 @
453 @
454 add r0, r0, r12 @ b = r0 + delta
455 add r11, r11, r12, lsl #1 @ r = r11 + delta*2
456 add r7, r7, r12, lsr #1 @ g = r7 + delta/2
457 @
458 orr r12, r0, r11, asr #1 @ check if clamping is needed...
459 orr r12, r12, r7 @ ...at all
460 movs r12, r12, asr #15 @
461 beq 15f @ no clamp @
462 movs r12, r0, asr #15 @ clamp b
463 mvnne r0, r12, lsr #15 @
464 andne r0, r0, #0x7c00 @ mask b only if clamped
465 movs r12, r11, asr #16 @ clamp r
466 mvnne r11, r12, lsr #16 @
467 movs r12, r7, asr #15 @ clamp g
468 mvnne r7, r12, lsr #15 @
46915: @ no clamp @
470 @
471 ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
472
473 and r11, r11, #0xf800 @ pack pixel
474 mov r11, r11, lsr #8
475 and r7, r7, #0x7e00
476 orr r11, r11, r7, lsr #12
477 mov r7, r7, lsr#4
478 orr r0, r7, r0, lsr #10
4791: @ busy @
480 ldr r7, [r3] @ r7 = LCD1_BASE
481 tst r7, #LCD1_BUSY_MASK @ bridge busy?
482 bne 1b @
483 str r11, [r3, #0x10] @ send MSB
4841: @ busy @
485 ldr r7, [r3] @ r7 = LCD1_BASE
486 tst r7, #LCD1_BUSY_MASK @ bridge busy?
487 bne 1b @
488 str r0, [r3, #0x10] @ send LSB
489
490 sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
491 add r12, r7, r7, asl #2 @
492 add r12, r12, r12, asl #4 @
493 add r7, r12, r7, asl #6 @
494 @ compute R, G, and B
495 add r0, r8, r7 @ r0 = b' = Y + bu
496 add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
497 rsb r7, r10, r7 @ r7 = g' = Y + guv
498 @
499 sub r12, r0, r0, lsr #5 @ r0 = 31/32*b + b/256
500 add r0, r12, r0, lsr #8 @
501 @
502 sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256
503 add r11, r12, r11, lsr #8 @
504 @
505 sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256
506 add r7, r12, r7, lsr #8 @
507 @
508 @ This element is zero - use r14 @
509 @
510 add r0, r0, r14 @ b = r0 + delta
511 add r11, r11, r14, lsl #1 @ r = r11 + delta*2
512 add r7, r7, r14, lsr #1 @ g = r7 + delta/2
513 @
514 orr r12, r0, r11, asr #1 @ check if clamping is needed...
515 orr r12, r12, r7 @ ...at all
516 movs r12, r12, asr #15 @
517 beq 15f @ no clamp @
518 movs r12, r0, asr #15 @ clamp b
519 mvnne r0, r12, lsr #15 @
520 andne r0, r0, #0x7c00 @ mask b only if clamped
521 movs r12, r11, asr #16 @ clamp r
522 mvnne r11, r12, lsr #16 @
523 movs r12, r7, asr #15 @ clamp g
524 mvnne r7, r12, lsr #15 @
52515: @ no clamp @
526
527 and r11, r11, #0xf800 @ pack pixel
528 mov r11, r11, lsr #8
529 and r7, r7, #0x7e00
530 orr r11, r11, r7, lsr #12
531 mov r7, r7, lsr#4
532 orr r0, r7, r0, lsr #10
5331: @ busy @
534 ldr r7, [r3] @ r7 = LCD1_BASE
535 tst r7, #LCD1_BUSY_MASK @ bridge busy?
536 bne 1b @
537 str r11, [r3, #0x10] @ send MSB
5381: @ busy @
539 ldr r7, [r3] @ r7 = LCD1_BASE
540 tst r7, #LCD1_BUSY_MASK @ bridge busy?
541 bne 1b @
542 str r0, [r3, #0x10] @ send LSB
543
544 subs r1, r1, #2 @ subtract block from width
545 bgt 10b @ loop line @
546 @
547 ldmfd sp!, { r4-r12, pc } @ restore registers and return
548 .ltorg @ dump constant pool
549 .size lcd_write_yuv420_lines_odither, .-lcd_write_yuv420_lines_odither
diff --git a/firmware/target/arm/sandisk/sansa-c200/lcd-c200.c b/firmware/target/arm/sandisk/sansa-c200/lcd-c200.c
index 5975ab159d..fa8581f286 100644
--- a/firmware/target/arm/sandisk/sansa-c200/lcd-c200.c
+++ b/firmware/target/arm/sandisk/sansa-c200/lcd-c200.c
@@ -22,6 +22,9 @@
22#include "kernel.h" 22#include "kernel.h"
23#include "system.h" 23#include "system.h"
24 24
25/* Display status */
26static unsigned lcd_yuv_options NOCACHEBSS_ATTR = 0;
27
25/* LCD command set for Samsung S6B33B2 */ 28/* LCD command set for Samsung S6B33B2 */
26 29
27#define R_OSCILLATION_MODE 0x02 30#define R_OSCILLATION_MODE 0x02
@@ -206,10 +209,20 @@ void lcd_blit(const fb_data* data, int x, int by, int width,
206 (void)stride; 209 (void)stride;
207} 210}
208 211
212void lcd_yuv_set_options(unsigned options)
213{
214 lcd_yuv_options = options;
215}
216
209/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */ 217/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
210extern void lcd_write_yuv420_lines(unsigned char const * const src[3], 218extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
211 int width, 219 int width,
212 int stride); 220 int stride);
221extern void lcd_write_yuv420_lines_odither(unsigned char const * const src[3],
222 int width,
223 int stride,
224 int x_screen, /* To align dither pattern */
225 int y_screen);
213/* Performance function to blit a YUV bitmap directly to the LCD */ 226/* Performance function to blit a YUV bitmap directly to the LCD */
214void lcd_yuv_blit(unsigned char * const src[3], 227void lcd_yuv_blit(unsigned char * const src[3],
215 int src_x, int src_y, int stride, 228 int src_x, int src_y, int stride,
@@ -236,19 +249,38 @@ void lcd_yuv_blit(unsigned char * const src[3],
236 lcd_send_command(x); 249 lcd_send_command(x);
237 lcd_send_command(x + width - 1); 250 lcd_send_command(x + width - 1);
238 251
239 do 252 if (lcd_yuv_options & LCD_YUV_DITHER)
240 { 253 {
241 lcd_send_command(R_Y_ADDR_AREA); 254 do
242 lcd_send_command(y); 255 {
243 lcd_send_command(y + 1); 256 lcd_send_command(R_Y_ADDR_AREA);
244 257 lcd_send_command(y);
245 lcd_write_yuv420_lines(yuv_src, width, stride); 258 lcd_send_command(y + 1);
246 yuv_src[0] += stride << 1; /* Skip down two luma lines */ 259
247 yuv_src[1] += stride >> 1; /* Skip down one chroma line */ 260 lcd_write_yuv420_lines_odither(yuv_src, width, stride, x, y);
248 yuv_src[2] += stride >> 1; 261 yuv_src[0] += stride << 1; /* Skip down two luma lines */
249 y += 2; 262 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
263 yuv_src[2] += stride >> 1;
264 y += 2;
265 }
266 while (--height > 0);
267 }
268 else
269 {
270 do
271 {
272 lcd_send_command(R_Y_ADDR_AREA);
273 lcd_send_command(y);
274 lcd_send_command(y + 1);
275
276 lcd_write_yuv420_lines(yuv_src, width, stride);
277 yuv_src[0] += stride << 1; /* Skip down two luma lines */
278 yuv_src[1] += stride >> 1; /* Skip down one chroma line */
279 yuv_src[2] += stride >> 1;
280 y += 2;
281 }
282 while (--height > 0);
250 } 283 }
251 while (--height > 0);
252} 284}
253 285
254/* Update the display. 286/* Update the display.