1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
Jens Arnold 2007-10-21 13:46:26 +00:00
parent e1a91b9138
commit c1051549b9
6 changed files with 360 additions and 22 deletions

View file

@ -184,7 +184,7 @@ static const struct plugin_api rockbox_api = {
#if defined(HAVE_LCD_COLOR) #if defined(HAVE_LCD_COLOR)
lcd_yuv_blit, lcd_yuv_blit,
#endif #endif
#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) #if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200)
lcd_yuv_set_options, lcd_yuv_set_options,
#endif #endif
/* list */ /* list */

View file

@ -112,12 +112,12 @@
#define PLUGIN_MAGIC 0x526F634B /* RocK */ #define PLUGIN_MAGIC 0x526F634B /* RocK */
/* increase this every time the api struct changes */ /* increase this every time the api struct changes */
#define PLUGIN_API_VERSION 84 #define PLUGIN_API_VERSION 85
/* update this to latest version if a change to the api struct breaks /* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any backwards compatibility (and please take the opportunity to sort in any
new function which are "waiting" at the end of the function table) */ new function which are "waiting" at the end of the function table) */
#define PLUGIN_MIN_API_VERSION 84 #define PLUGIN_MIN_API_VERSION 85
/* plugin return codes */ /* plugin return codes */
enum plugin_status { enum plugin_status {
@ -266,7 +266,7 @@ struct plugin_api {
int x, int y, int width, int height); int x, int y, int width, int height);
#endif #endif
#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) #if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200)
void (*lcd_yuv_set_options)(unsigned options); void (*lcd_yuv_set_options)(unsigned options);
#endif #endif

View file

@ -101,7 +101,7 @@ static struct configdata config[] =
{TYPE_INT, 0, 2, &settings.skipframes, "Skip frames", NULL, NULL}, {TYPE_INT, 0, 2, &settings.skipframes, "Skip frames", NULL, NULL},
{TYPE_INT, 0, INT_MAX, &settings.resume_count, "Resume count", {TYPE_INT, 0, INT_MAX, &settings.resume_count, "Resume count",
NULL, NULL}, NULL, NULL},
#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) #if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200)
{TYPE_INT, 0, INT_MAX, &settings.displayoptions, "Display options", {TYPE_INT, 0, INT_MAX, &settings.displayoptions, "Display options",
NULL, NULL}, NULL, NULL},
#endif #endif
@ -119,7 +119,7 @@ static void display_options(void)
int options_quit = 0; int options_quit = 0;
static const struct menu_item items[] = { static const struct menu_item items[] = {
#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) #if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200)
[MPEG_OPTION_DITHERING] = [MPEG_OPTION_DITHERING] =
{ "Dithering", NULL }, { "Dithering", NULL },
#endif /* #ifdef TOSHIBA_GIGABEAT_F */ #endif /* #ifdef TOSHIBA_GIGABEAT_F */
@ -142,7 +142,7 @@ static void display_options(void)
switch (result) switch (result)
{ {
#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) #if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200)
case MPEG_OPTION_DITHERING: case MPEG_OPTION_DITHERING:
result = (settings.displayoptions & LCD_YUV_DITHER) ? 1 : 0; result = (settings.displayoptions & LCD_YUV_DITHER) ? 1 : 0;
rb->set_option("Dithering", &result, INT, noyes, 2, NULL); rb->set_option("Dithering", &result, INT, noyes, 2, NULL);
@ -463,7 +463,7 @@ void init_settings(const char* filename)
settings.limitfps = 1; /* Limit FPS */ settings.limitfps = 1; /* Limit FPS */
settings.skipframes = 1; /* Skip frames */ settings.skipframes = 1; /* Skip frames */
settings.resume_count = -1; settings.resume_count = -1;
#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) #if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200)
settings.displayoptions = 0; /* No visual effects */ settings.displayoptions = 0; /* No visual effects */
#endif #endif
@ -479,7 +479,7 @@ void init_settings(const char* filename)
SETTINGS_VERSION); SETTINGS_VERSION);
} }
#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) #if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200)
if ((settings.displayoptions = if ((settings.displayoptions =
configfile_get_value(SETTINGS_FILENAME, "Display options")) < 0) configfile_get_value(SETTINGS_FILENAME, "Display options")) < 0)
{ {
@ -522,7 +522,7 @@ void save_settings(void)
++settings.resume_count); ++settings.resume_count);
} }
#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) #if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200)
configfile_update_entry(SETTINGS_FILENAME, "Display options", configfile_update_entry(SETTINGS_FILENAME, "Display options",
settings.displayoptions); settings.displayoptions);
#endif #endif

View file

@ -3,7 +3,7 @@
enum mpeg_option_id enum mpeg_option_id
{ {
#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) #if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200)
MPEG_OPTION_DITHERING, MPEG_OPTION_DITHERING,
#endif #endif
MPEG_OPTION_DISPLAY_FPS, MPEG_OPTION_DISPLAY_FPS,
@ -33,7 +33,7 @@ struct mpeg_settings {
int resume_count; /* total # of resumes in config file */ int resume_count; /* total # of resumes in config file */
int resume_time; /* resume time for current mpeg (in half minutes) */ int resume_time; /* resume time for current mpeg (in half minutes) */
char resume_filename[128]; /* filename of current mpeg */ char resume_filename[128]; /* filename of current mpeg */
#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) #if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200)
int displayoptions; int displayoptions;
#endif #endif
}; };

View file

@ -241,3 +241,309 @@ lcd_write_yuv420_lines:
.ltorg @ dump constant pool .ltorg @ dump constant pool
.size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines
/****************************************************************************
* void lcd_write_yuv_420_lines_odither(unsigned char const * const src[3],
* int width,
* int stride,
* int x_screen,
* int y_screen);
*
* |R| |1.000000 -0.000001 1.402000| |Y'|
* |G| = |1.000000 -0.334136 -0.714136| |Pb|
* |B| |1.000000 1.772000 0.000000| |Pr|
* Red scaled at twice g & b but at same precision to place it in correct
* bit position after multiply and leave instruction count lower.
* |R| |258 0 408| |Y' - 16|
* |G| = |149 -49 -104| |Cb - 128|
* |B| |149 258 0| |Cr - 128|
*
* Write four RGB565 pixels in the following order on each loop:
* 1 3 + > down
* 2 4 \/ left
*
* Kernel pattern (raw|rotated|use order):
* 5 3 4 2 2 6 3 7 row0 row2 > down
* 1 7 0 6 | 4 0 5 1 | 2 4 6 0 3 5 7 1 col0 left
* 4 2 5 3 | 3 7 2 6 | 3 5 7 1 2 4 6 0 col2 \/
* 0 6 1 7 5 1 4 0
*/
.section .icode, "ax", %progbits
.align 2
.global lcd_write_yuv420_lines_odither
.type lcd_write_yuv420_lines_odither, %function
lcd_write_yuv420_lines_odither:
@ r0 = yuv_src
@ r1 = width
@ r2 = stride
@ r3 = x_screen
@ [sp] = y_screen
stmfd sp!, { r4-r12, lr } @ save non-scratch
ldmia r0, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p
@ r5 = yuv_src[1] = Cb_p
@ r6 = yuv_src[2] = Cr_p
@
sub r2, r2, #1 @
ldr r14, [sp, #40] @ Line up pattern and kernel quadrant
eor r14, r14, r3 @
and r14, r14, #0x2 @
mov r14, r14, lsl #6 @ 0x00 or 0x80
mov r3, #0x70000000 @
orr r3, r3, #0x3000 @ r3 = LCD1_BASE
10: @ loop line @
@
ldrb r7, [r4], #1 @ r7 = *Y'_p++;
ldrb r8, [r5], #1 @ r8 = *Cb_p++;
ldrb r9, [r6], #1 @ r9 = *Cr_p++;
@
eor r14, r14, #0x80 @ flip pattern quadrant
@
sub r7, r7, #16 @ r7 = Y = (Y' - 16)*149
add r12, r7, r7, asl #2 @
add r12, r12, r12, asl #4 @
add r7, r12, r7, asl #6 @
@
sub r8, r8, #128 @ Cb -= 128
sub r9, r9, #128 @ Cr -= 128
@
add r10, r8, r8, asl #4 @ r10 = guv = Cr*104 + Cb*49
add r10, r10, r8, asl #5 @
add r10, r10, r9, asl #3 @
add r10, r10, r9, asl #5 @
add r10, r10, r9, asl #6 @
@
mov r8, r8, asl #1 @ r8 = bu = Cb*258
add r8, r8, r8, asl #7 @
@
add r9, r9, r9, asl #1 @ r9 = rv = Cr*408
add r9, r9, r9, asl #4 @
mov r9, r9, asl #3 @
@
@ compute R, G, and B
add r0, r8, r7 @ r0 = b' = Y + bu
add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
rsb r7, r10, r7 @ r7 = g' = Y + guv
@
@ r8 = bu, r9 = rv, r10 = guv
@
sub r12, r0, r0, lsr #5 @ r0 = 31/32*b + b/256
add r0, r12, r0, lsr #8 @
@
sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256
add r11, r12, r11, lsr #8 @
@
sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256
add r7, r12, r7, lsr #8 @
@
add r12, r14, #0x100 @
@
add r0, r0, r12 @ b = r0 + delta
add r11, r11, r12, lsl #1 @ r = r11 + delta*2
add r7, r7, r12, lsr #1 @ g = r7 + delta/2
@
orr r12, r0, r11, asr #1 @ check if clamping is needed...
orr r12, r12, r7 @ ...at all
movs r12, r12, asr #15 @
beq 15f @ no clamp @
movs r12, r0, asr #15 @ clamp b
mvnne r0, r12, lsr #15 @
andne r0, r0, #0x7c00 @ mask b only if clamped
movs r12, r11, asr #16 @ clamp r
mvnne r11, r12, lsr #16 @
movs r12, r7, asr #15 @ clamp g
mvnne r7, r12, lsr #15 @
15: @ no clamp @
@
ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
@
and r11, r11, #0xf800 @ pack pixel
mov r11, r11, lsr #8
and r7, r7, #0x7e00
orr r11, r11, r7, lsr #12
mov r7, r7, lsr#4
orr r0, r7, r0, lsr #10
1: @ busy @
ldr r7, [r3] @ r7 = LCD1_BASE
tst r7, #LCD1_BUSY_MASK @ bridge busy?
bne 1b @
str r11, [r3, #0x10] @ send MSB
1: @ busy @
ldr r7, [r3] @ r7 = LCD1_BASE
tst r7, #LCD1_BUSY_MASK @ bridge busy?
bne 1b @
str r0, [r3, #0x10] @ send LSB
@
sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
add r12, r7, r7, asl #2 @
add r12, r12, r12, asl #4 @
add r7, r12, r7, asl #6 @
@ compute R, G, and B
add r0, r8, r7 @ r0 = b' = Y + bu
add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
rsb r7, r10, r7 @ r7 = g' = Y + guv
@
sub r12, r0, r0, lsr #5 @ r0 = 31/32*b' + b'/256
add r0, r12, r0, lsr #8 @
@
sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256
add r11, r12, r11, lsr #8 @
@
sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256
add r7, r12, r7, lsr #8 @
@
add r12, r14, #0x200 @
@
add r0, r0, r12 @ b = r0 + delta
add r11, r11, r12, lsl #1 @ r = r11 + delta*2
add r7, r7, r12, lsr #1 @ g = r7 + delta/2
@
orr r12, r0, r11, asr #1 @ check if clamping is needed...
orr r12, r12, r7 @ ...at all
movs r12, r12, asr #15 @
beq 15f @ no clamp @
movs r12, r0, asr #15 @ clamp b
mvnne r0, r12, lsr #15 @
andne r0, r0, #0x7c00 @ mask b only if clamped
movs r12, r11, asr #16 @ clamp r
mvnne r11, r12, lsr #16 @
movs r12, r7, asr #15 @ clamp g
mvnne r7, r12, lsr #15 @
15: @ no clamp @
@
ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++)
and r11, r11, #0xf800 @ pack pixel
mov r11, r11, lsr #8
and r7, r7, #0x7e00
orr r11, r11, r7, lsr #12
mov r7, r7, lsr#4
orr r0, r7, r0, lsr #10
1: @ busy @
ldr r7, [r3] @ r7 = LCD1_BASE
tst r7, #LCD1_BUSY_MASK @ bridge busy?
bne 1b @
str r11, [r3, #0x10] @ send MSB
1: @ busy @
ldr r7, [r3] @ r7 = LCD1_BASE
tst r7, #LCD1_BUSY_MASK @ bridge busy?
bne 1b @
str r0, [r3, #0x10] @ send LSB
sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
add r12, r7, r7, asl #2 @
add r12, r12, r12, asl #4 @
add r7, r12, r7, asl #6 @
@ compute R, G, and B
add r0, r8, r7 @ r0 = b' = Y + bu
add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
rsb r7, r10, r7 @ r7 = g' = Y + guv
@
@ r8 = bu, r9 = rv, r10 = guv
@
sub r12, r0, r0, lsr #5 @ r0 = 31/32*b' + b'/256
add r0, r12, r0, lsr #8 @
@
sub r12, r11, r11, lsr #5 @ r11 = 31/32*r' + r'/256
add r11, r12, r11, lsr #8 @
@
sub r12, r7, r7, lsr #6 @ r7 = 63/64*g' + g'/256
add r7, r12, r7, lsr #8 @
@
add r12, r14, #0x300 @
@
add r0, r0, r12 @ b = r0 + delta
add r11, r11, r12, lsl #1 @ r = r11 + delta*2
add r7, r7, r12, lsr #1 @ g = r7 + delta/2
@
orr r12, r0, r11, asr #1 @ check if clamping is needed...
orr r12, r12, r7 @ ...at all
movs r12, r12, asr #15 @
beq 15f @ no clamp @
movs r12, r0, asr #15 @ clamp b
mvnne r0, r12, lsr #15 @
andne r0, r0, #0x7c00 @ mask b only if clamped
movs r12, r11, asr #16 @ clamp r
mvnne r11, r12, lsr #16 @
movs r12, r7, asr #15 @ clamp g
mvnne r7, r12, lsr #15 @
15: @ no clamp @
@
ldrb r12, [r4, r2] @ r12 = Y' = *(Y'_p + stride)
and r11, r11, #0xf800 @ pack pixel
mov r11, r11, lsr #8
and r7, r7, #0x7e00
orr r11, r11, r7, lsr #12
mov r7, r7, lsr#4
orr r0, r7, r0, lsr #10
1: @ busy @
ldr r7, [r3] @ r7 = LCD1_BASE
tst r7, #LCD1_BUSY_MASK @ bridge busy?
bne 1b @
str r11, [r3, #0x10] @ send MSB
1: @ busy @
ldr r7, [r3] @ r7 = LCD1_BASE
tst r7, #LCD1_BUSY_MASK @ bridge busy?
bne 1b @
str r0, [r3, #0x10] @ send LSB
sub r7, r12, #16 @ r7 = Y = (Y' - 16)*149
add r12, r7, r7, asl #2 @
add r12, r12, r12, asl #4 @
add r7, r12, r7, asl #6 @
@ compute R, G, and B
add r0, r8, r7 @ r0 = b' = Y + bu
add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv
rsb r7, r10, r7 @ r7 = g' = Y + guv
@
sub r12, r0, r0, lsr #5 @ r0 = 31/32*b + b/256
add r0, r12, r0, lsr #8 @
@
sub r12, r11, r11, lsr #5 @ r11 = 31/32*r + r/256
add r11, r12, r11, lsr #8 @
@
sub r12, r7, r7, lsr #6 @ r7 = 63/64*g + g/256
add r7, r12, r7, lsr #8 @
@
@ This element is zero - use r14 @
@
add r0, r0, r14 @ b = r0 + delta
add r11, r11, r14, lsl #1 @ r = r11 + delta*2
add r7, r7, r14, lsr #1 @ g = r7 + delta/2
@
orr r12, r0, r11, asr #1 @ check if clamping is needed...
orr r12, r12, r7 @ ...at all
movs r12, r12, asr #15 @
beq 15f @ no clamp @
movs r12, r0, asr #15 @ clamp b
mvnne r0, r12, lsr #15 @
andne r0, r0, #0x7c00 @ mask b only if clamped
movs r12, r11, asr #16 @ clamp r
mvnne r11, r12, lsr #16 @
movs r12, r7, asr #15 @ clamp g
mvnne r7, r12, lsr #15 @
15: @ no clamp @
and r11, r11, #0xf800 @ pack pixel
mov r11, r11, lsr #8
and r7, r7, #0x7e00
orr r11, r11, r7, lsr #12
mov r7, r7, lsr#4
orr r0, r7, r0, lsr #10
1: @ busy @
ldr r7, [r3] @ r7 = LCD1_BASE
tst r7, #LCD1_BUSY_MASK @ bridge busy?
bne 1b @
str r11, [r3, #0x10] @ send MSB
1: @ busy @
ldr r7, [r3] @ r7 = LCD1_BASE
tst r7, #LCD1_BUSY_MASK @ bridge busy?
bne 1b @
str r0, [r3, #0x10] @ send LSB
subs r1, r1, #2 @ subtract block from width
bgt 10b @ loop line @
@
ldmfd sp!, { r4-r12, pc } @ restore registers and return
.ltorg @ dump constant pool
.size lcd_write_yuv420_lines_odither, .-lcd_write_yuv420_lines_odither

View file

@ -22,6 +22,9 @@
#include "kernel.h" #include "kernel.h"
#include "system.h" #include "system.h"
/* Display status */
static unsigned lcd_yuv_options NOCACHEBSS_ATTR = 0;
/* LCD command set for Samsung S6B33B2 */ /* LCD command set for Samsung S6B33B2 */
#define R_OSCILLATION_MODE 0x02 #define R_OSCILLATION_MODE 0x02
@ -206,10 +209,20 @@ void lcd_blit(const fb_data* data, int x, int by, int width,
(void)stride; (void)stride;
} }
void lcd_yuv_set_options(unsigned options)
{
lcd_yuv_options = options;
}
/* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */ /* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */
extern void lcd_write_yuv420_lines(unsigned char const * const src[3], extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
int width, int width,
int stride); int stride);
extern void lcd_write_yuv420_lines_odither(unsigned char const * const src[3],
int width,
int stride,
int x_screen, /* To align dither pattern */
int y_screen);
/* Performance function to blit a YUV bitmap directly to the LCD */ /* Performance function to blit a YUV bitmap directly to the LCD */
void lcd_yuv_blit(unsigned char * const src[3], void lcd_yuv_blit(unsigned char * const src[3],
int src_x, int src_y, int stride, int src_x, int src_y, int stride,
@ -236,19 +249,38 @@ void lcd_yuv_blit(unsigned char * const src[3],
lcd_send_command(x); lcd_send_command(x);
lcd_send_command(x + width - 1); lcd_send_command(x + width - 1);
do if (lcd_yuv_options & LCD_YUV_DITHER)
{ {
lcd_send_command(R_Y_ADDR_AREA); do
lcd_send_command(y); {
lcd_send_command(y + 1); lcd_send_command(R_Y_ADDR_AREA);
lcd_send_command(y);
lcd_send_command(y + 1);
lcd_write_yuv420_lines(yuv_src, width, stride); lcd_write_yuv420_lines_odither(yuv_src, width, stride, x, y);
yuv_src[0] += stride << 1; /* Skip down two luma lines */ yuv_src[0] += stride << 1; /* Skip down two luma lines */
yuv_src[1] += stride >> 1; /* Skip down one chroma line */ yuv_src[1] += stride >> 1; /* Skip down one chroma line */
yuv_src[2] += stride >> 1; yuv_src[2] += stride >> 1;
y += 2; y += 2;
}
while (--height > 0);
}
else
{
do
{
lcd_send_command(R_Y_ADDR_AREA);
lcd_send_command(y);
lcd_send_command(y + 1);
lcd_write_yuv420_lines(yuv_src, width, stride);
yuv_src[0] += stride << 1; /* Skip down two luma lines */
yuv_src[1] += stride >> 1; /* Skip down one chroma line */
yuv_src[2] += stride >> 1;
y += 2;
}
while (--height > 0);
} }
while (--height > 0);
} }
/* Update the display. /* Update the display.