From cc5812bdfdf3d5b76e7c71cd46cf163e8e88d9c6 Mon Sep 17 00:00:00 2001 From: jethead71 Date: Tue, 25 Sep 2007 02:59:42 +0000 Subject: [PATCH] Dithering option for mpegplayer on gigabeat-f/x and e200. Assembly IDCT for ARm just to make it all work more nicely. Move UI simulator YUV code to its core to adapt it. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@14851 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugin.c | 6 +- apps/plugin.h | 8 +- apps/plugins/mpegplayer/SOURCES | 3 +- apps/plugins/mpegplayer/mpeg_settings.c | 106 +++- apps/plugins/mpegplayer/mpeg_settings.h | 3 + apps/plugins/mpegplayer/video_out_rockbox.c | 374 ++++---------- firmware/SOURCES | 4 +- firmware/export/lcd.h | 4 +- firmware/target/arm/lcd-as-memframe.S | 554 +++++++++++++++++++++ .../target/arm/s3c2440/gigabeat-fx/lcd-as-meg-fx.S | 279 ----------- .../target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c | 45 +- .../target/arm/sandisk/sansa-e200/lcd-as-e200.S | 279 ----------- firmware/target/arm/sandisk/sansa-e200/lcd-e200.c | 45 +- uisimulator/sdl/lcd-bitmap.c | 204 ++++++++ 14 files changed, 1020 insertions(+), 894 deletions(-) rewrite apps/plugins/mpegplayer/video_out_rockbox.c (66%) create mode 100644 firmware/target/arm/lcd-as-memframe.S delete mode 100644 firmware/target/arm/s3c2440/gigabeat-fx/lcd-as-meg-fx.S delete mode 100644 firmware/target/arm/sandisk/sansa-e200/lcd-as-e200.S diff --git a/apps/plugin.c b/apps/plugin.c index bdb59e600..f56d53253 100644 --- a/apps/plugin.c +++ b/apps/plugin.c @@ -179,7 +179,7 @@ static const struct plugin_api rockbox_api = { lcd_remote_bitmap, #endif -#if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR) +#if defined(HAVE_LCD_COLOR) lcd_yuv_blit, #endif /* list */ @@ -505,6 +505,10 @@ static const struct plugin_api rockbox_api = { get_metadata, #endif led, + +#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) + lcd_yuv_set_options, +#endif }; int plugin_load(const char* plugin, void* parameter) diff --git a/apps/plugin.h b/apps/plugin.h index c7049c7fd..a2e24f88d 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -112,7 +112,7 @@ #define PLUGIN_MAGIC 0x526F634B /* RocK */ /* increase this every time the api struct changes */ -#define PLUGIN_API_VERSION 76 +#define PLUGIN_API_VERSION 77 /* update this to latest version if a change to the api struct breaks backwards compatibility (and please take the opportunity to sort in any @@ -259,7 +259,7 @@ struct plugin_api { void (*lcd_remote_bitmap)(const fb_remote_data *src, int x, int y, int width, int height); #endif -#if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR) +#if defined(HAVE_LCD_COLOR) void (*lcd_yuv_blit)(unsigned char * const src[3], int src_x, int src_y, int stride, int x, int y, int width, int height); @@ -623,6 +623,10 @@ struct plugin_api { bool (*get_metadata)(struct mp3entry* id3, int fd, const char* trackname); #endif void (*led)(bool on); + +#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) + void (*lcd_yuv_set_options)(unsigned options); +#endif }; /* plugin header */ diff --git a/apps/plugins/mpegplayer/SOURCES b/apps/plugins/mpegplayer/SOURCES index e9a01b73d..6629cf7a4 100644 --- a/apps/plugins/mpegplayer/SOURCES +++ b/apps/plugins/mpegplayer/SOURCES @@ -1,14 +1,15 @@ alloc.c decode.c header.c -idct.c motion_comp.c #ifdef CPU_ARM +idct_arm_c.c motion_comp_arm_c.c motion_comp_arm_s.S #else /* other CPU or SIM */ +idct.c motion_comp_c.c #endif /* CPU_* */ diff --git a/apps/plugins/mpegplayer/mpeg_settings.c b/apps/plugins/mpegplayer/mpeg_settings.c index 964bad08b..28062f456 100644 --- a/apps/plugins/mpegplayer/mpeg_settings.c +++ b/apps/plugins/mpegplayer/mpeg_settings.c @@ -9,41 +9,87 @@ extern struct plugin_api* rb; struct mpeg_settings settings; static struct mpeg_settings old_settings; -#define SETTINGS_VERSION 1 +#define SETTINGS_VERSION 2 #define SETTINGS_MIN_VERSION 1 #define SETTINGS_FILENAME "mpegplayer.cfg" -static char* showfps_options[] = {"No", "Yes"}; -static char* limitfps_options[] = {"No", "Yes"}; -static char* skipframes_options[] = {"No", "Yes"}; - static struct configdata config[] = { - {TYPE_ENUM, 0, 2, &settings.showfps, "Show FPS", showfps_options, NULL}, - {TYPE_ENUM, 0, 2, &settings.limitfps, "Limit FPS", limitfps_options, NULL}, - {TYPE_ENUM, 0, 2, &settings.skipframes, "Skip frames", skipframes_options, NULL}, + {TYPE_ENUM, 0, 2, &settings.showfps, "Show FPS", + (char *[]){ "No", "Yes" }, NULL}, + {TYPE_ENUM, 0, 2, &settings.limitfps, "Limit FPS", + (char *[]){ "No", "Yes" }, NULL}, + {TYPE_ENUM, 0, 2, &settings.skipframes, "Skip frames", + (char *[]){ "No", "Yes" }, NULL}, +#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) + {TYPE_INT, 0, INT_MAX, &settings.displayoptions, "Display options", + NULL, NULL}, +#endif +}; + +enum mpeg_menu_ids +{ + __MPEG_OPTION_START = -1, +#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) + MPEG_OPTION_DISPLAY_SETTINGS, +#endif + MPEG_OPTION_DISPLAY_FPS, + MPEG_OPTION_LIMIT_FPS, + MPEG_OPTION_SKIP_FRAMES, + MPEG_OPTION_QUIT, +}; + +static const struct opt_items noyes[2] = { + { "No", -1 }, + { "Yes", -1 }, }; +#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) +static bool set_option_dithering(void) +{ + int val = (settings.displayoptions & LCD_YUV_DITHER) ? 1 : 0; + rb->set_option("Dithering", &val, INT, noyes, 2, NULL); + settings.displayoptions = (settings.displayoptions & ~LCD_YUV_DITHER) + | ((val != 0) ? LCD_YUV_DITHER : 0); + rb->lcd_yuv_set_options(settings.displayoptions); + return false; +} + +static void display_options(void) +{ + static const struct menu_item items[] = { + { "Dithering", set_option_dithering }, + }; + + int m = menu_init(rb, items, ARRAYLEN(items), + NULL, NULL, NULL, NULL); + menu_run(m); + menu_exit(m); +} +#endif /* #ifdef TOSHIBA_GIGABEAT_F */ + bool mpeg_menu(void) { int m; int result; int menu_quit=0; - static const struct opt_items noyes[2] = { - { "No", -1 }, - { "Yes", -1 }, - }; - static const struct menu_item items[] = { - { "Display FPS", NULL }, - { "Limit FPS", NULL }, - { "Skip frames", NULL }, - { "Quit mpegplayer", NULL }, +#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) + [MPEG_OPTION_DISPLAY_SETTINGS] = + { "Display Options", NULL }, +#endif + [MPEG_OPTION_DISPLAY_FPS] = + { "Display FPS", NULL }, + [MPEG_OPTION_LIMIT_FPS] = + { "Limit FPS", NULL }, + [MPEG_OPTION_SKIP_FRAMES] = + { "Skip frames", NULL }, + [MPEG_OPTION_QUIT] = + { "Quit mpegplayer", NULL }, }; - m = menu_init(rb, items, sizeof(items) / sizeof(*items), - NULL, NULL, NULL, NULL); + m = menu_init(rb, items, ARRAYLEN(items), NULL, NULL, NULL, NULL); rb->button_clear_queue(); @@ -52,22 +98,28 @@ bool mpeg_menu(void) switch(result) { - case 0: /* Show FPS */ +#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) + case MPEG_OPTION_DISPLAY_SETTINGS: + display_options(); + break; +#endif + case MPEG_OPTION_DISPLAY_FPS: rb->set_option("Display FPS",&settings.showfps,INT, noyes, 2, NULL); break; - case 1: /* Limit FPS */ + case MPEG_OPTION_LIMIT_FPS: rb->set_option("Limit FPS",&settings.limitfps,INT, noyes, 2, NULL); break; - case 2: /* Skip frames */ + case MPEG_OPTION_SKIP_FRAMES: rb->set_option("Skip frames",&settings.skipframes,INT, noyes, 2, NULL); break; + case MPEG_OPTION_QUIT: default: menu_quit=1; if (result == MENU_ATTACHED_USB) - result = 3; + result = MPEG_OPTION_QUIT; break; } } @@ -77,7 +129,7 @@ bool mpeg_menu(void) rb->lcd_clear_display(); rb->lcd_update(); - return (result==3); + return (result==MPEG_OPTION_QUIT); } @@ -87,6 +139,9 @@ void init_settings(void) settings.showfps = 0; /* Do not show FPS */ settings.limitfps = 1; /* Limit FPS */ settings.skipframes = 1; /* Skip frames */ +#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) + settings.displayoptions = 0; /* No visual effects */ +#endif configfile_init(rb); @@ -105,6 +160,9 @@ void init_settings(void) /* Keep a copy of the saved version of the settings - so we can check if the settings have changed when we quit */ old_settings = settings; +#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) + rb->lcd_yuv_set_options(settings.displayoptions); +#endif } void save_settings(void) diff --git a/apps/plugins/mpegplayer/mpeg_settings.h b/apps/plugins/mpegplayer/mpeg_settings.h index cd2dcd234..7721c46f6 100644 --- a/apps/plugins/mpegplayer/mpeg_settings.h +++ b/apps/plugins/mpegplayer/mpeg_settings.h @@ -5,6 +5,9 @@ struct mpeg_settings { int showfps; int limitfps; int skipframes; +#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) + unsigned displayoptions; +#endif }; extern struct mpeg_settings settings; diff --git a/apps/plugins/mpegplayer/video_out_rockbox.c b/apps/plugins/mpegplayer/video_out_rockbox.c dissimilarity index 66% index b57f77bc0..2aac0b803 100644 --- a/apps/plugins/mpegplayer/video_out_rockbox.c +++ b/apps/plugins/mpegplayer/video_out_rockbox.c @@ -1,289 +1,85 @@ -/* - * video_out_null.c - * Copyright (C) 2000-2003 Michel Lespinasse - * Copyright (C) 1999-2000 Aaron Holtzman - * - * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. - * See http://libmpeg2.sourceforge.net/ for updates. - * - * mpeg2dec is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mpeg2dec is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "mpeg2dec_config.h" - -#include "plugin.h" -#include "gray.h" - -extern struct plugin_api* rb; - -#include "mpeg2.h" -#include "video_out.h" - -static int image_width; -static int image_height; -static int image_chroma_x; -static int image_chroma_y; -static int output_x; -static int output_y; -static int output_width; -static int output_height; - -#if defined(SIMULATOR) && defined(HAVE_LCD_COLOR) - -/** - * |R| |1.000000 -0.000001 1.402000| |Y'| - * |G| = |1.000000 -0.334136 -0.714136| |Pb| - * |B| |1.000000 1.772000 0.000000| |Pr| - * Scaled, normalized, rounded and tweaked to yield RGB 565: - * |R| |74 0 101| |Y' - 16| >> 9 - * |G| = |74 -24 -51| |Cb - 128| >> 8 - * |B| |74 128 0| |Cr - 128| >> 9 - */ -#define YFAC (74) -#define RVFAC (101) -#define GUFAC (-24) -#define GVFAC (-51) -#define BUFAC (128) - -static inline int clamp(int val, int min, int max) -{ - if (val < min) - val = min; - else if (val > max) - val = max; - return val; -} - -/* Draw a partial YUV colour bitmap - similiar behavior to lcd_yuv_blit - in the core */ -static void yuv_bitmap_part(unsigned char * const src[3], - int src_x, int src_y, int stride, - int x, int y, int width, int height) -{ - const unsigned char *ysrc, *usrc, *vsrc; - fb_data *dst, *row_end; - off_t z; - - /* width and height must be >= 2 and an even number */ - width &= ~1; - height >>= 1; - -#if LCD_WIDTH >= LCD_HEIGHT - dst = rb->lcd_framebuffer + LCD_WIDTH * y + x; - row_end = dst + width; -#else - dst = rb->lcd_framebuffer + x * LCD_WIDTH + (LCD_WIDTH - y) - 1; - row_end = dst + LCD_WIDTH * width; -#endif - - z = stride * src_y; - ysrc = src[0] + z + src_x; - usrc = src[1] + (z >> 2) + (src_x >> 1); - vsrc = src[2] + (usrc - src[1]); - - /* stride => amount to jump from end of last row to start of next */ - stride -= width; - - /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */ - - do - { - do - { - int y, cb, cr, rv, guv, bu, r, g, b; - - y = YFAC*(*ysrc++ - 16); - cb = *usrc++ - 128; - cr = *vsrc++ - 128; - - rv = RVFAC*cr; - guv = GUFAC*cb + GVFAC*cr; - bu = BUFAC*cb; - - r = y + rv; - g = y + guv; - b = y + bu; - - if ((unsigned)(r | g | b) > 64*256-1) - { - r = clamp(r, 0, 64*256-1); - g = clamp(g, 0, 64*256-1); - b = clamp(b, 0, 64*256-1); - } - - *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); - -#if LCD_WIDTH >= LCD_HEIGHT - dst++; -#else - dst += LCD_WIDTH; -#endif - - y = YFAC*(*ysrc++ - 16); - r = y + rv; - g = y + guv; - b = y + bu; - - if ((unsigned)(r | g | b) > 64*256-1) - { - r = clamp(r, 0, 64*256-1); - g = clamp(g, 0, 64*256-1); - b = clamp(b, 0, 64*256-1); - } - - *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); - -#if LCD_WIDTH >= LCD_HEIGHT - dst++; -#else - dst += LCD_WIDTH; -#endif - } - while (dst < row_end); - - ysrc += stride; - usrc -= width >> 1; - vsrc -= width >> 1; - -#if LCD_WIDTH >= LCD_HEIGHT - row_end += LCD_WIDTH; - dst += LCD_WIDTH - width; -#else - row_end -= 1; - dst -= LCD_WIDTH*width + 1; -#endif - - do - { - int y, cb, cr, rv, guv, bu, r, g, b; - - y = YFAC*(*ysrc++ - 16); - cb = *usrc++ - 128; - cr = *vsrc++ - 128; - - rv = RVFAC*cr; - guv = GUFAC*cb + GVFAC*cr; - bu = BUFAC*cb; - - r = y + rv; - g = y + guv; - b = y + bu; - - if ((unsigned)(r | g | b) > 64*256-1) - { - r = clamp(r, 0, 64*256-1); - g = clamp(g, 0, 64*256-1); - b = clamp(b, 0, 64*256-1); - } - - *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); - -#if LCD_WIDTH >= LCD_HEIGHT - dst++; -#else - dst += LCD_WIDTH; -#endif - - y = YFAC*(*ysrc++ - 16); - r = y + rv; - g = y + guv; - b = y + bu; - - if ((unsigned)(r | g | b) > 64*256-1) - { - r = clamp(r, 0, 64*256-1); - g = clamp(g, 0, 64*256-1); - b = clamp(b, 0, 64*256-1); - } - - *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); - -#if LCD_WIDTH >= LCD_HEIGHT - dst++; -#else - dst += LCD_WIDTH; -#endif - } - while (dst < row_end); - - ysrc += stride; - usrc += stride >> 1; - vsrc += stride >> 1; - -#if LCD_WIDTH >= LCD_HEIGHT - row_end += LCD_WIDTH; - dst += LCD_WIDTH - width; -#else - row_end -= 1; - dst -= LCD_WIDTH*width + 1; -#endif - } - while (--height > 0); -} -#endif /* defined(SIMULATOR) && defined(HAVE_LCD_COLOR) */ - -void vo_draw_frame (uint8_t * const * buf) -{ -#ifdef HAVE_LCD_COLOR -#ifdef SIMULATOR - yuv_bitmap_part(buf,0,0,image_width, - output_x,output_y,output_width,output_height); -#if LCD_WIDTH >= LCD_HEIGHT - rb->lcd_update_rect(output_x,output_y,output_width,output_height); -#else - rb->lcd_update_rect(output_y,output_x,output_height,output_width); -#endif -#else - rb->lcd_yuv_blit(buf, - 0,0,image_width, - output_x,output_y,output_width,output_height); -#endif -#else - gray_ub_gray_bitmap_part(buf[0],0,0,image_width, - output_x,output_y,output_width,output_height); -#endif -} - -#if LCD_WIDTH >= LCD_HEIGHT -#define SCREEN_WIDTH LCD_WIDTH -#define SCREEN_HEIGHT LCD_HEIGHT -#else /* Assume the screen is rotates on portraid LCDs */ -#define SCREEN_WIDTH LCD_HEIGHT -#define SCREEN_HEIGHT LCD_WIDTH -#endif - -void vo_setup(const mpeg2_sequence_t * sequence) -{ - image_width=sequence->width; - image_height=sequence->height; - image_chroma_x=image_width/sequence->chroma_width; - image_chroma_y=image_height/sequence->chroma_height; - - if (sequence->display_width >= SCREEN_WIDTH) { - output_width = SCREEN_WIDTH; - output_x = 0; - } else { - output_width = sequence->display_width; - output_x = (SCREEN_WIDTH-sequence->display_width)/2; - } - - if (sequence->display_height >= SCREEN_HEIGHT) { - output_height = SCREEN_HEIGHT; - output_y = 0; - } else { - output_height = sequence->display_height; - output_y = (SCREEN_HEIGHT-sequence->display_height)/2; - } -} +/* + * video_out_null.c + * Copyright (C) 2000-2003 Michel Lespinasse + * Copyright (C) 1999-2000 Aaron Holtzman + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * See http://libmpeg2.sourceforge.net/ for updates. + * + * mpeg2dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mpeg2dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "mpeg2dec_config.h" + +#include "plugin.h" +#include "gray.h" + +extern struct plugin_api* rb; + +#include "mpeg2.h" +#include "video_out.h" + +static int image_width; +static int image_height; +static int image_chroma_x; +static int image_chroma_y; +static int output_x; +static int output_y; +static int output_width; +static int output_height; + +void vo_draw_frame (uint8_t * const * buf) +{ +#ifdef HAVE_LCD_COLOR + rb->lcd_yuv_blit(buf, + 0,0,image_width, + output_x,output_y,output_width,output_height); +#else + gray_ub_gray_bitmap_part(buf[0],0,0,image_width, + output_x,output_y,output_width,output_height); +#endif +} + +#if LCD_WIDTH >= LCD_HEIGHT +#define SCREEN_WIDTH LCD_WIDTH +#define SCREEN_HEIGHT LCD_HEIGHT +#else /* Assume the screen is rotates on portraid LCDs */ +#define SCREEN_WIDTH LCD_HEIGHT +#define SCREEN_HEIGHT LCD_WIDTH +#endif + +void vo_setup(const mpeg2_sequence_t * sequence) +{ + image_width=sequence->width; + image_height=sequence->height; + image_chroma_x=image_width/sequence->chroma_width; + image_chroma_y=image_height/sequence->chroma_height; + + if (sequence->display_width >= SCREEN_WIDTH) { + output_width = SCREEN_WIDTH; + output_x = 0; + } else { + output_width = sequence->display_width; + output_x = (SCREEN_WIDTH-sequence->display_width)/2; + } + + if (sequence->display_height >= SCREEN_HEIGHT) { + output_height = SCREEN_HEIGHT; + output_y = 0; + } else { + output_height = sequence->display_height; + output_y = (SCREEN_HEIGHT-sequence->display_height)/2; + } +} diff --git a/firmware/SOURCES b/firmware/SOURCES index c98b44d43..45bedd9db 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -407,9 +407,9 @@ target/sh/archos/ondio/usb-ondio.c #ifdef SANSA_E200 #ifndef SIMULATOR +target/arm/lcd-as-memframe.S target/arm/sandisk/ata-c200_e200.c target/arm/sandisk/sansa-e200/lcd-e200.c -target/arm/sandisk/sansa-e200/lcd-as-e200.S target/arm/sandisk/adc-c200_e200.c target/arm/sandisk/backlight-c200_e200.c target/arm/usb-fw-pp502x.c @@ -572,13 +572,13 @@ target/arm/usb-fw-pp502x.c #ifdef GIGABEAT_F #ifndef SIMULATOR +target/arm/lcd-as-memframe.S target/arm/s3c2440/gigabeat-fx/adc-meg-fx.c target/arm/s3c2440/gigabeat-fx/ata-meg-fx.c target/arm/s3c2440/gigabeat-fx/backlight-meg-fx.c target/arm/s3c2440/gigabeat-fx/button-meg-fx.c target/arm/s3c2440/gigabeat-fx/i2c-meg-fx.c target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c -target/arm/s3c2440/gigabeat-fx/lcd-as-meg-fx.S target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c target/arm/s3c2440/gigabeat-fx/power-meg-fx.c target/arm/s3c2440/gigabeat-fx/powermgmt-meg-fx.c diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h index 49256ff50..ac0aea866 100644 --- a/firmware/export/lcd.h +++ b/firmware/export/lcd.h @@ -84,7 +84,9 @@ extern void lcd_puts_scroll(int x, int y, const unsigned char* string); extern void lcd_puts_scroll_style(int x, int y, const unsigned char* string, int style); -#if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR) +#if defined(HAVE_LCD_COLOR) +#define LCD_YUV_DITHER 0x1 +extern void lcd_yuv_set_options(unsigned options); extern void lcd_yuv_blit(unsigned char * const src[3], int src_x, int src_y, int stride, int x, int y, int width, int height); diff --git a/firmware/target/arm/lcd-as-memframe.S b/firmware/target/arm/lcd-as-memframe.S new file mode 100644 index 000000000..7071bec7a --- /dev/null +++ b/firmware/target/arm/lcd-as-memframe.S @@ -0,0 +1,554 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2007 by Michael Sevakis + * + * ARM code for memory framebuffer LCDs + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "config.h" +#include "cpu.h" + +/**************************************************************************** + * void lcd_copy_buffer_rect(fb_data *dst, fb_data *src, int width, + * int height); + */ + .section .icode, "ax", %progbits + .align 2 + .global lcd_copy_buffer_rect + .type lcd_copy_buffer_rect, %function + @ r0 = dst + @ r1 = src + @ r2 = width + @ r3 = height +lcd_copy_buffer_rect: @ + stmfd sp!, { r4-r12, lr } @ save non-scratch regs + mov r5, r2 @ r5 = cached width + rsb r4, r2, #LCD_WIDTH @ r4 = LCD_WIDTH - width +10: @ copy line @ + subs r2, r5, #1 @ r2 = width - 1 + beq 40f @ finish line @ one halfword? skip to trailing copy + tst r0, #2 @ word aligned? + beq 20f @ rem copy @ yes? skip to word copy + ldrh r6, [r1], #2 @ copy leading halfword + subs r2, r2, #1 @ + strh r6, [r0], #2 @ + ble 40f @ finish line @ next line if lt or finish + @ trailing halfword if eq +20: @ rem copy @ + add r14, r2, #1 @ get remaining width mod 16 after word + @ align (rw) + and r14, r14, #0xe @ r14 = 0 (16), 2, 4, 6, 8, 10, 12, 14 + add pc, pc, r14, lsl #3 @ branch to 32-byte align + nop @ + b 30f @ rw % 16 = 0 or 1? use octword loop + nop @ + nop @ + nop @ + ldr r6, [r1], #4 @ rw % 16 = 2 or 3 + subs r2, r2, #2 @ + str r6, [r0], #4 @ + b 25f @ copy up done @ + ldmia r1!, { r6-r7 } @ rw % 16 = 4 or 5 + subs r2, r2, #4 @ + stmia r0!, { r6-r7 } @ + b 25f @ copy up done @ + ldmia r1!, { r6-r8 } @ rw % 16 = 6 or 7 + subs r2, r2, #6 @ + stmia r0!, { r6-r8 } @ + b 25f @ copy up done @ + ldmia r1!, { r6-r9 } @ rw % 16 = 8 or 9 + subs r2, r2, #8 @ + stmia r0!, { r6-r9 } @ + b 25f @ copy up done @ + ldmia r1!, { r6-r10 } @ rw % 16 = 10 or 11 + subs r2, r2, #10 @ + stmia r0!, { r6-r10 } @ + b 25f @ copy up done @ + ldmia r1!, { r6-r11 } @ rw % 16 = 12 or 13 + subs r2, r2, #12 @ + stmia r0!, { r6-r11 } @ + b 25f @ copy up done @ + ldmia r1!, { r6-r12 } @ rw % 16 = 14 or 15 + subs r2, r2, #14 @ + stmia r0!, { r6-r12 } @ +25: @ copy up done @ + ble 40f @ finish line @ no 32-byte segments remaining? +30: @ octword loop @ copy 16 pixels per loop + ldmia r1!, { r6-r12, r14 } @ + subs r2, r2, #16 @ + stmia r0!, { r6-r12, r14 } @ + bgt 30b @ octword loop @ +40: @ finish line @ + ldreqh r6, [r1], #2 @ finish last halfword if eq ... + add r1, r1, r4, lsl #1 @ + streqh r6, [r0], #2 @ ... + add r0, r0, r4, lsl #1 @ + subs r3, r3, #1 @ next line + bgt 10b @ copy line @ + ldmfd sp!, { r4-r12, pc } @ restore regs and return + .ltorg @ dump constant pool + .size lcd_copy_buffer_rect, .-lcd_copy_buffer_rect + + +/**************************************************************************** + * void lcd_write_yuv_420_lines(fb_data *dst, + * unsigned char const * const src[3], + * int width, + * int stride); + * + * |R| |1.000000 -0.000001 1.402000| |Y'| + * |G| = |1.000000 -0.334136 -0.714136| |Pb| + * |B| |1.000000 1.772000 0.000000| |Pr| + * Scaled, normalized, rounded and tweaked to yield RGB 565: + * |R| |74 0 101| |Y' - 16| >> 9 + * |G| = |74 -24 -51| |Cb - 128| >> 8 + * |B| |74 128 0| |Cr - 128| >> 9 + * + * Write four RGB565 pixels in the following order on each loop: + * 1 3 + > down + * 2 4 \/ left + */ + .section .icode, "ax", %progbits + .align 2 + .global lcd_write_yuv420_lines + .type lcd_write_yuv420_lines, %function +lcd_write_yuv420_lines: + @ r0 = dst + @ r1 = yuv_src + @ r2 = width + @ r3 = stride + stmfd sp!, { r4-r12 } @ save non-scratch + ldmia r1, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p + @ r5 = yuv_src[1] = Cb_p + @ r6 = yuv_src[2] = Cr_p + @ r1 = scratch + sub r3, r3, #1 @ +10: @ loop line @ + ldrb r7, [r4], #1 @ r7 = *Y'_p++; + ldrb r8, [r5], #1 @ r8 = *Cb_p++; + ldrb r9, [r6], #1 @ r9 = *Cr_p++; + @ + sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74 + add r12, r7, r7, asl #2 @ actually (Y' - 16)*37 and shift right + add r7, r12, r7, asl #5 @ by one less when adding - same for all + @ + sub r8, r8, #128 @ Cb -= 128 + sub r9, r9, #128 @ Cr -= 128 + @ + add r10, r9, r9, asl #1 @ r10 = Cr*51 + Cb*24 + add r10, r10, r10, asl #4 @ + add r10, r10, r8, asl #3 @ + add r10, r10, r8, asl #4 @ + @ + add r11, r9, r9, asl #2 @ r9 = Cr*101 + add r11, r11, r9, asl #5 @ + add r9, r11, r9, asl #6 @ + @ + add r8, r8, #2 @ r8 = bu = (Cb*128 + 128) >> 8 + mov r8, r8, asr #2 @ + add r9, r9, #256 @ r9 = rv = (r9 + 256) >> 9 + mov r9, r9, asr #9 @ + rsb r10, r10, #128 @ r10 = guv = (-r10 + 128) >> 8 + mov r10, r10, asr #8 @ + @ compute R, G, and B + add r1, r8, r7, asr #8 @ r1 = b = (Y >> 9) + bu + add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv + add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv + @ + orr r12, r1, r11 @ check if clamping is needed... + orr r12, r12, r7, asr #1 @ ...at all + cmp r12, #31 @ + bls 15f @ no clamp @ + cmp r1, #31 @ clamp b + mvnhi r1, r1, asr #31 @ + andhi r1, r1, #31 @ + cmp r11, #31 @ clamp r + mvnhi r11, r11, asr #31 @ + andhi r11, r11, #31 @ + cmp r7, #63 @ clamp g + mvnhi r7, r7, asr #31 @ + andhi r7, r7, #63 @ +15: @ no clamp @ + @ + ldrb r12, [r4, r3] @ r12 = Y' = *(Y'_p + stride) + @ + orr r1, r1, r7, lsl #5 @ r4 |= (g << 5) + orr r1, r1, r11, lsl #11 @ r4 = b | (r << 11) + strh r1, [r0], #LCD_WIDTH @ store pixel + @ + sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 + add r12, r7, r7, asl #2 @ + add r7, r12, r7, asl #5 @ + @ compute R, G, and B + add r1, r8, r7, asr #8 @ r1 = b = (Y >> 9) + bu + add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv + add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv + @ + orr r12, r1, r11 @ check if clamping is needed... + orr r12, r12, r7, asr #1 @ ...at all + cmp r12, #31 @ + bls 15f @ no clamp @ + cmp r1, #31 @ clamp b + mvnhi r1, r1, asr #31 @ + andhi r1, r1, #31 @ + cmp r11, #31 @ clamp r + mvnhi r11, r11, asr #31 @ + andhi r11, r11, #31 @ + cmp r7, #63 @ clamp g + mvnhi r7, r7, asr #31 @ + andhi r7, r7, #63 @ +15: @ no clamp @ + @ + ldrb r12, [r4], #1 @ r12 = Y' = *(Y'_p++) + @ + orr r1, r1, r11, lsl #11 @ r1 = b | (r << 11) + orr r1, r1, r7, lsl #5 @ r1 |= (g << 5) + strh r1, [r0, #-LCD_WIDTH-2] @ store pixel + @ + sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 + add r12, r7, r7, asl #2 @ + add r7, r12, r7, asl #5 @ + @ compute R, G, and B + add r1, r8, r7, asr #8 @ r1 = b = (Y >> 9) + bu + add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv + add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv + @ + orr r12, r1, r11 @ check if clamping is needed... + orr r12, r12, r7, asr #1 @ ...at all + cmp r12, #31 @ + bls 15f @ no clamp @ + cmp r1, #31 @ clamp b + mvnhi r1, r1, asr #31 @ + andhi r1, r1, #31 @ + cmp r11, #31 @ clamp r + mvnhi r11, r11, asr #31 @ + andhi r11, r11, #31 @ + cmp r7, #63 @ clamp g + mvnhi r7, r7, asr #31 @ + andhi r7, r7, #63 @ +15: @ no clamp @ + @ + ldrb r12, [r4, r3] @ r12 = Y' = *(Y'_p + stride) + @ + orr r1, r1, r7, lsl #5 @ r1 = b | (g << 5) + orr r1, r1, r11, lsl #11 @ r1 |= (r << 11) + strh r1, [r0, #LCD_WIDTH]! @ store pixel + @ + sub r7, r12, #16 @ r7 = Y = (Y' - 16)*74 + add r12, r7, r7, asl #2 @ + add r7, r12, r7, asl #5 @ + @ compute R, G, and B + add r1, r8, r7, asr #8 @ r1 = b = (Y >> 9) + bu + add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv + add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv + @ + orr r12, r1, r11 @ check if clamping is needed... + orr r12, r12, r7, asr #1 @ ...at all + cmp r12, #31 @ + bls 15f @ no clamp @ + cmp r1, #31 @ clamp b + mvnhi r1, r1, asr #31 @ + andhi r1, r1, #31 @ + cmp r11, #31 @ clamp r + mvnhi r11, r11, asr #31 @ + andhi r11, r11, #31 @ + cmp r7, #63 @ clamp g + mvnhi r7, r7, asr #31 @ + andhi r7, r7, #63 @ +15: @ no clamp @ + @ + orr r12, r1, r11, lsl #11 @ r12 = b | (r << 11) + orr r12, r12, r7, lsl #5 @ r12 |= (g << 5) + strh r12, [r0, #-2] @ store pixel + add r0, r0, #2*LCD_WIDTH @ + @ + subs r2, r2, #2 @ subtract block from width + bgt 10b @ loop line @ + @ + ldmfd sp!, { r4-r12 } @ restore registers and return + bx lr @ + .ltorg @ dump constant pool + .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines + + +/**************************************************************************** + * void lcd_write_yuv_420_lines_odither(fb_data *dst, + * 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 = dst + @ r1 = yuv_src + @ r2 = width + @ r3 = stride + @ [sp] = x_screen + @ [sp+4] = y_screen + stmfd sp!, { r4-r12, lr } @ save non-scratch + ldmia r1, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p + @ r5 = yuv_src[1] = Cb_p + @ r6 = yuv_src[2] = Cr_p + @ + sub r3, r3, #1 @ + add r1, sp, #40 @ Line up pattern and kernel quadrant + ldmia r1, { r12, r14 } @ + eor r14, r14, r12 @ + and r14, r14, #0x2 @ + mov r14, r14, lsl #6 @ 0x00 or 0x80 +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 r1, r8, r7 @ r1 = 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, r1, r1, lsr #5 @ r1 = 31/32*b + b/256 + add r1, r12, r1, 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 r1, r1, r12 @ b = r1 + delta + add r11, r11, r12, lsl #1 @ r = r11 + delta*2 + add r7, r7, r12, lsr #1 @ g = r7 + delta/2 + @ + orr r12, r1, 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, r1, asr #15 @ clamp b + mvnne r1, r12, lsr #15 @ + andne r1, r1, #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, r3] @ r12 = Y' = *(Y'_p + stride) + @ + and r11, r11, #0xf800 @ pack pixel + and r7, r7, #0x7e00 @ r1 = pixel = (r & 0xf800) | + orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | + orr r1, r11, r1, lsr #10 @ (b >> 10) + @ + strh r1, [r0], #LCD_WIDTH @ store pixel + @ + 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 r1, r8, r7 @ r1 = b' = Y + bu + add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv + rsb r7, r10, r7 @ r7 = g' = Y + guv + @ + sub r12, r1, r1, lsr #5 @ r1 = 31/32*b' + b'/256 + add r1, r12, r1, 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 r1, r1, r12 @ b = r1 + delta + add r11, r11, r12, lsl #1 @ r = r11 + delta*2 + add r7, r7, r12, lsr #1 @ g = r7 + delta/2 + @ + orr r12, r1, 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, r1, asr #15 @ clamp b + mvnne r1, r12, lsr #15 @ + andne r1, r1, #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 + and r7, r7, #0x7e00 @ r1 = pixel = (r & 0xf800) | + orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | + orr r1, r11, r1, lsr #10 @ (b >> 10) + @ + strh r1, [r0, #-LCD_WIDTH-2] @ store pixel + @ + 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 r1, r8, r7 @ r1 = 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, r1, r1, lsr #5 @ r1 = 31/32*b' + b'/256 + add r1, r12, r1, 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 r1, r1, r12 @ b = r1 + delta + add r11, r11, r12, lsl #1 @ r = r11 + delta*2 + add r7, r7, r12, lsr #1 @ g = r7 + delta/2 + @ + orr r12, r1, 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, r1, asr #15 @ clamp b + mvnne r1, r12, lsr #15 @ + andne r1, r1, #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, r3] @ r12 = Y' = *(Y'_p + stride) + @ + and r11, r11, #0xf800 @ pack pixel + and r7, r7, #0x7e00 @ r1 = pixel = (r & 0xf800) | + orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | + orr r1, r11, r1, lsr #10 @ (b >> 10) + @ + strh r1, [r0, #LCD_WIDTH]! @ store pixel + @ + 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 r1, r8, r7 @ r1 = b' = Y + bu + add r11, r9, r7, asl #1 @ r11 = r' = Y*2 + rv + rsb r7, r10, r7 @ r7 = g' = Y + guv + @ + sub r12, r1, r1, lsr #5 @ r1 = 31/32*b + b/256 + add r1, r12, r1, 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 r1, r1, r14 @ b = r1 + delta + add r11, r11, r14, lsl #1 @ r = r11 + delta*2 + add r7, r7, r14, lsr #1 @ g = r7 + delta/2 + @ + orr r12, r1, 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, r1, asr #15 @ clamp b + mvnne r1, r12, lsr #15 @ + andne r1, r1, #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 + and r7, r7, #0x7e00 @ r1 = pixel = (r & 0xf800) | + orr r11, r11, r7, lsr #4 @ ((g & 0x7e00) >> 4) | + orr r1, r11, r1, lsr #10 @ (b >> 10) + @ + strh r1, [r0, #-2] @ store pixel + add r0, r0, #2*LCD_WIDTH @ + @ + subs r2, r2, #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 diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/lcd-as-meg-fx.S b/firmware/target/arm/s3c2440/gigabeat-fx/lcd-as-meg-fx.S deleted file mode 100644 index 4926c7fa7..000000000 --- a/firmware/target/arm/s3c2440/gigabeat-fx/lcd-as-meg-fx.S +++ /dev/null @@ -1,279 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2007 by Michael Sevakis - * - * All files in this archive are subject to the GNU General Public License. - * See the file COPYING in the source tree root for full license agreement. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#include "config.h" -#include "cpu.h" - -/**************************************************************************** - * void lcd_copy_buffer_rect(fb_data *dst, fb_data *src, int width, - * int height); - */ - .section .icode, "ax", %progbits - .align 2 - .global lcd_copy_buffer_rect - .type lcd_copy_buffer_rect, %function - @ r0 = dst - @ r1 = src - @ r2 = width - @ r3 = height -lcd_copy_buffer_rect: @ - stmfd sp!, { r4-r12, lr } @ save non-scratch regs - mov r5, r2 @ r5 = cached width - rsb r4, r2, #LCD_WIDTH @ r4 = LCD_WIDTH - width -10: @ copy line @ - subs r2, r5, #1 @ r2 = width - 1 - beq 40f @ finish line @ one halfword? skip to trailing copy - tst r0, #2 @ word aligned? - beq 20f @ rem copy @ yes? skip to word copy - ldrh r6, [r1], #2 @ copy leading halfword - subs r2, r2, #1 @ - strh r6, [r0], #2 @ - ble 40f @ finish line @ next line if lt or finish - @ trailing halfword if eq -20: @ rem copy @ - add r14, r2, #1 @ get remaining width mod 16 after word - @ align (rw) - and r14, r14, #0xe @ r14 = 0 (16), 2, 4, 6, 8, 10, 12, 14 - add pc, pc, r14, lsl #3 @ branch to 32-byte align - nop @ - b 30f @ rw % 16 = 0 or 1? use octword loop - nop @ - nop @ - nop @ - ldr r6, [r1], #4 @ rw % 16 = 2 or 3 - subs r2, r2, #2 @ - str r6, [r0], #4 @ - b 25f @ copy up done @ - ldmia r1!, { r6-r7 } @ rw % 16 = 4 or 5 - subs r2, r2, #4 @ - stmia r0!, { r6-r7 } @ - b 25f @ copy up done @ - ldmia r1!, { r6-r8 } @ rw % 16 = 6 or 7 - subs r2, r2, #6 @ - stmia r0!, { r6-r8 } @ - b 25f @ copy up done @ - ldmia r1!, { r6-r9 } @ rw % 16 = 8 or 9 - subs r2, r2, #8 @ - stmia r0!, { r6-r9 } @ - b 25f @ copy up done @ - ldmia r1!, { r6-r10 } @ rw % 16 = 10 or 11 - subs r2, r2, #10 @ - stmia r0!, { r6-r10 } @ - b 25f @ copy up done @ - ldmia r1!, { r6-r11 } @ rw % 16 = 12 or 13 - subs r2, r2, #12 @ - stmia r0!, { r6-r11 } @ - b 25f @ copy up done @ - ldmia r1!, { r6-r12 } @ rw % 16 = 14 or 15 - subs r2, r2, #14 @ - stmia r0!, { r6-r12 } @ -25: @ copy up done @ - ble 40f @ finish line @ no 32-byte segments remaining? -30: @ octword loop @ copy 16 pixels per loop - ldmia r1!, { r6-r12, r14 } @ - subs r2, r2, #16 @ - stmia r0!, { r6-r12, r14 } @ - bgt 30b @ octword loop @ -40: @ finish line @ - ldreqh r6, [r1], #2 @ finish last halfword if eq ... - add r1, r1, r4, lsl #1 @ - streqh r6, [r0], #2 @ ... - add r0, r0, r4, lsl #1 @ - subs r3, r3, #1 @ next line - bgt 10b @ copy line @ - ldmfd sp!, { r4-r12, pc } @ restore regs and return - .size lcd_copy_buffer_rect, .-lcd_copy_buffer_rect - - -/**************************************************************************** - * void lcd_write_yuv_420_lines(fb_data *dst, - * unsigned char const * const src[3], - * int width, - * int stride); - * - * |R| |1.000000 -0.000001 1.402000| |Y'| - * |G| = |1.000000 -0.334136 -0.714136| |Pb| - * |B| |1.000000 1.772000 0.000000| |Pr| - * Scaled, normalized, rounded and tweaked to yield RGB 565: - * |R| |74 0 101| |Y' - 16| >> 9 - * |G| = |74 -24 -51| |Cb - 128| >> 8 - * |B| |74 128 0| |Cr - 128| >> 9 - * - * Write four RGB565 pixels in the following order on each loop: - * 1 3 + > down - * 2 4 \/ left - */ - .section .icode, "ax", %progbits - .align 2 - .global lcd_write_yuv420_lines - .type lcd_write_yuv420_lines, %function -lcd_write_yuv420_lines: - @ r0 = dst - @ r1 = yuv_src - @ r2 = width - @ r3 = stride - stmfd sp!, { r4-r12 } @ save non-scratch - ldmia r1, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p - @ r5 = yuv_src[1] = Cb_p - @ r6 = yuv_src[2] = Cr_p - @ r1 = scratch -10: @ loop line @ - ldrb r7, [r4] @ r7 = *Y'_p; - ldrb r8, [r5], #1 @ r8 = *Cb_p++; - ldrb r9, [r6], #1 @ r9 = *Cr_p++; - @ - sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74 - add r12, r7, r7, asl #2 @ actually (Y' - 16)*37 and shift right - add r7, r12, r7, asl #5 @ by one less when adding - same for all - @ - sub r8, r8, #128 @ Cb -= 128 - sub r9, r9, #128 @ Cr -= 128 - @ - add r10, r9, r9, asl #1 @ r10 = Cr*51 + Cb*24 - add r10, r10, r10, asl #4 @ - add r10, r10, r8, asl #3 @ - add r10, r10, r8, asl #4 @ - @ - add r11, r9, r9, asl #2 @ r9 = Cr*101 - add r11, r11, r9, asl #5 @ - add r9, r11, r9, asl #6 @ - @ - add r8, r8, #2 @ r8 = bu = (Cb*128 + 128) >> 8 - mov r8, r8, asr #2 @ - add r9, r9, #256 @ r9 = rv = (r9 + 256) >> 9 - mov r9, r9, asr #9 @ - rsb r10, r10, #128 @ r10 = guv = (-r10 + 128) >> 8 - mov r10, r10, asr #8 @ - @ compute R, G, and B - add r1, r8, r7, asr #8 @ r1 = b = (Y >> 9) + bu - add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv - add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv - @ - orr r12, r1, r11 @ check if clamping is needed... - orr r12, r12, r7, asr #1 @ ...at all - cmp r12, #31 @ - bls 15f @ no clamp @ - cmp r1, #31 @ clamp b - mvnhi r1, r1, asr #31 @ - andhi r1, r1, #31 @ - cmp r11, #31 @ clamp r - mvnhi r11, r11, asr #31 @ - andhi r11, r11, #31 @ - cmp r7, #63 @ clamp g - mvnhi r7, r7, asr #31 @ - andhi r7, r7, #63 @ -15: @ no clamp @ - @ - orr r12, r1, r7, lsl #5 @ r4 |= (g << 5) - ldrb r7, [r4, r3] @ r7 = Y' = *(Y'_p + stride) - orr r12, r12, r11, lsl #11 @ r4 = b | (r << 11) - strh r12, [r0] @ store pixel - @ - sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74 - add r12, r7, r7, asl #2 @ - add r7, r12, r7, asl #5 @ - @ compute R, G, and B - add r1, r8, r7, asr #8 @ r1 = b = (Y >> 9) + bu - add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv - add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv - @ - orr r12, r1, r11 @ check if clamping is needed... - orr r12, r12, r7, asr #1 @ ...at all - cmp r12, #31 @ - bls 15f @ no clamp @ - cmp r1, #31 @ clamp b - mvnhi r1, r1, asr #31 @ - andhi r1, r1, #31 @ - cmp r11, #31 @ clamp r - mvnhi r11, r11, asr #31 @ - andhi r11, r11, #31 @ - cmp r7, #63 @ clamp g - mvnhi r7, r7, asr #31 @ - andhi r7, r7, #63 @ -15: @ no clamp @ - @ - orr r12, r1, r11, lsl #11 @ r12 = b | (r << 11) - orr r12, r12, r7, lsl #5 @ r12 |= (g << 5) - ldrb r7, [r4, #1]! @ r7 = Y' = *(++Y'_p) - strh r12, [r0, #-2] @ store pixel - add r0, r0, #2*LCD_WIDTH @ - @ - sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74 - add r12, r7, r7, asl #2 @ - add r7, r12, r7, asl #5 @ - @ compute R, G, and B - add r1, r8, r7, asr #8 @ r1 = b = (Y >> 9) + bu - add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv - add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv - @ - orr r12, r1, r11 @ check if clamping is needed... - orr r12, r12, r7, asr #1 @ ...at all - cmp r12, #31 @ - bls 15f @ no clamp @ - cmp r1, #31 @ clamp b - mvnhi r1, r1, asr #31 @ - andhi r1, r1, #31 @ - cmp r11, #31 @ clamp r - mvnhi r11, r11, asr #31 @ - andhi r11, r11, #31 @ - cmp r7, #63 @ clamp g - mvnhi r7, r7, asr #31 @ - andhi r7, r7, #63 @ -15: @ no clamp @ - @ - orr r12, r1, r7, lsl #5 @ r12 = b | (g << 5) - ldrb r7, [r4, r3] @ r7 = Y' = *(Y'_p + stride) - orr r12, r12, r11, lsl #11 @ r12 |= (r << 11) - strh r12, [r0] @ store pixel - @ - sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74 - add r12, r7, r7, asl #2 @ - add r7, r12, r7, asl #5 @ - @ compute R, G, and B - add r1, r8, r7, asr #8 @ r1 = b = (Y >> 9) + bu - add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv - add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv - @ - orr r12, r1, r11 @ check if clamping is needed... - orr r12, r12, r7, asr #1 @ ...at all - cmp r12, #31 @ - bls 15f @ no clamp @ - cmp r1, #31 @ clamp b - mvnhi r1, r1, asr #31 @ - andhi r1, r1, #31 @ - cmp r11, #31 @ clamp r - mvnhi r11, r11, asr #31 @ - andhi r11, r11, #31 @ - cmp r7, #63 @ clamp g - mvnhi r7, r7, asr #31 @ - andhi r7, r7, #63 @ -15: @ no clamp @ - @ - orr r12, r1, r11, lsl #11 @ r12 = b | (r << 11) - orr r12, r12, r7, lsl #5 @ r12 |= (g << 5) - strh r12, [r0, #-2] @ store pixel - add r0, r0, #2*LCD_WIDTH @ - add r4, r4, #1 @ - @ - subs r2, r2, #2 @ subtract block from width - bgt 10b @ loop line @ - @ - ldmfd sp!, { r4-r12 } @ restore registers and return - bx lr @ - .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c index ab7c91437..91b2eae98 100644 --- a/firmware/target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c +++ b/firmware/target/arm/s3c2440/gigabeat-fx/lcd-meg-fx.c @@ -9,6 +9,7 @@ static volatile bool lcd_on = true; volatile bool lcd_poweroff = false; +static unsigned lcd_yuv_options = 0; /* ** These are imported from lcd-16bit.c */ @@ -248,11 +249,22 @@ void lcd_bitmap_transparent_part(const fb_data *src, int src_x, int src_y, ); } +void lcd_yuv_set_options(unsigned options) +{ + lcd_yuv_options = options; +} + /* Line write helper function for lcd_yuv_blit. Write two lines of yuv420. */ extern void lcd_write_yuv420_lines(fb_data *dst, unsigned char const * const src[3], int width, int stride); +extern void lcd_write_yuv420_lines_odither(fb_data *dst, + 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 */ /* For the Gigabeat - show it rotated */ /* So the LCD_WIDTH is now the height */ @@ -272,22 +284,39 @@ void lcd_yuv_blit(unsigned char * const src[3], width &= ~1; height >>= 1; - fb_data *dst = (fb_data*)FRAME + x * LCD_WIDTH + (LCD_WIDTH - y) - 1; + y = LCD_WIDTH - 1 - y; + fb_data *dst = (fb_data*)FRAME + x * LCD_WIDTH + y; z = stride*src_y; yuv_src[0] = src[0] + z + src_x; yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); yuv_src[2] = src[2] + (yuv_src[1] - src[1]); - do + if (lcd_yuv_options & LCD_YUV_DITHER) + { + do + { + lcd_write_yuv420_lines_odither(dst, yuv_src, width, stride, y, x); + 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; + dst -= 2; + y -= 2; + } + while (--height > 0); + } + else { - lcd_write_yuv420_lines(dst, 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; - dst -= 2; + do + { + lcd_write_yuv420_lines(dst, 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; + dst -= 2; + } + while (--height > 0); } - while (--height > 0); } void lcd_set_contrast(int val) { diff --git a/firmware/target/arm/sandisk/sansa-e200/lcd-as-e200.S b/firmware/target/arm/sandisk/sansa-e200/lcd-as-e200.S deleted file mode 100644 index 4926c7fa7..000000000 --- a/firmware/target/arm/sandisk/sansa-e200/lcd-as-e200.S +++ /dev/null @@ -1,279 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2007 by Michael Sevakis - * - * All files in this archive are subject to the GNU General Public License. - * See the file COPYING in the source tree root for full license agreement. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#include "config.h" -#include "cpu.h" - -/**************************************************************************** - * void lcd_copy_buffer_rect(fb_data *dst, fb_data *src, int width, - * int height); - */ - .section .icode, "ax", %progbits - .align 2 - .global lcd_copy_buffer_rect - .type lcd_copy_buffer_rect, %function - @ r0 = dst - @ r1 = src - @ r2 = width - @ r3 = height -lcd_copy_buffer_rect: @ - stmfd sp!, { r4-r12, lr } @ save non-scratch regs - mov r5, r2 @ r5 = cached width - rsb r4, r2, #LCD_WIDTH @ r4 = LCD_WIDTH - width -10: @ copy line @ - subs r2, r5, #1 @ r2 = width - 1 - beq 40f @ finish line @ one halfword? skip to trailing copy - tst r0, #2 @ word aligned? - beq 20f @ rem copy @ yes? skip to word copy - ldrh r6, [r1], #2 @ copy leading halfword - subs r2, r2, #1 @ - strh r6, [r0], #2 @ - ble 40f @ finish line @ next line if lt or finish - @ trailing halfword if eq -20: @ rem copy @ - add r14, r2, #1 @ get remaining width mod 16 after word - @ align (rw) - and r14, r14, #0xe @ r14 = 0 (16), 2, 4, 6, 8, 10, 12, 14 - add pc, pc, r14, lsl #3 @ branch to 32-byte align - nop @ - b 30f @ rw % 16 = 0 or 1? use octword loop - nop @ - nop @ - nop @ - ldr r6, [r1], #4 @ rw % 16 = 2 or 3 - subs r2, r2, #2 @ - str r6, [r0], #4 @ - b 25f @ copy up done @ - ldmia r1!, { r6-r7 } @ rw % 16 = 4 or 5 - subs r2, r2, #4 @ - stmia r0!, { r6-r7 } @ - b 25f @ copy up done @ - ldmia r1!, { r6-r8 } @ rw % 16 = 6 or 7 - subs r2, r2, #6 @ - stmia r0!, { r6-r8 } @ - b 25f @ copy up done @ - ldmia r1!, { r6-r9 } @ rw % 16 = 8 or 9 - subs r2, r2, #8 @ - stmia r0!, { r6-r9 } @ - b 25f @ copy up done @ - ldmia r1!, { r6-r10 } @ rw % 16 = 10 or 11 - subs r2, r2, #10 @ - stmia r0!, { r6-r10 } @ - b 25f @ copy up done @ - ldmia r1!, { r6-r11 } @ rw % 16 = 12 or 13 - subs r2, r2, #12 @ - stmia r0!, { r6-r11 } @ - b 25f @ copy up done @ - ldmia r1!, { r6-r12 } @ rw % 16 = 14 or 15 - subs r2, r2, #14 @ - stmia r0!, { r6-r12 } @ -25: @ copy up done @ - ble 40f @ finish line @ no 32-byte segments remaining? -30: @ octword loop @ copy 16 pixels per loop - ldmia r1!, { r6-r12, r14 } @ - subs r2, r2, #16 @ - stmia r0!, { r6-r12, r14 } @ - bgt 30b @ octword loop @ -40: @ finish line @ - ldreqh r6, [r1], #2 @ finish last halfword if eq ... - add r1, r1, r4, lsl #1 @ - streqh r6, [r0], #2 @ ... - add r0, r0, r4, lsl #1 @ - subs r3, r3, #1 @ next line - bgt 10b @ copy line @ - ldmfd sp!, { r4-r12, pc } @ restore regs and return - .size lcd_copy_buffer_rect, .-lcd_copy_buffer_rect - - -/**************************************************************************** - * void lcd_write_yuv_420_lines(fb_data *dst, - * unsigned char const * const src[3], - * int width, - * int stride); - * - * |R| |1.000000 -0.000001 1.402000| |Y'| - * |G| = |1.000000 -0.334136 -0.714136| |Pb| - * |B| |1.000000 1.772000 0.000000| |Pr| - * Scaled, normalized, rounded and tweaked to yield RGB 565: - * |R| |74 0 101| |Y' - 16| >> 9 - * |G| = |74 -24 -51| |Cb - 128| >> 8 - * |B| |74 128 0| |Cr - 128| >> 9 - * - * Write four RGB565 pixels in the following order on each loop: - * 1 3 + > down - * 2 4 \/ left - */ - .section .icode, "ax", %progbits - .align 2 - .global lcd_write_yuv420_lines - .type lcd_write_yuv420_lines, %function -lcd_write_yuv420_lines: - @ r0 = dst - @ r1 = yuv_src - @ r2 = width - @ r3 = stride - stmfd sp!, { r4-r12 } @ save non-scratch - ldmia r1, { r4, r5, r6 } @ r4 = yuv_src[0] = Y'_p - @ r5 = yuv_src[1] = Cb_p - @ r6 = yuv_src[2] = Cr_p - @ r1 = scratch -10: @ loop line @ - ldrb r7, [r4] @ r7 = *Y'_p; - ldrb r8, [r5], #1 @ r8 = *Cb_p++; - ldrb r9, [r6], #1 @ r9 = *Cr_p++; - @ - sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74 - add r12, r7, r7, asl #2 @ actually (Y' - 16)*37 and shift right - add r7, r12, r7, asl #5 @ by one less when adding - same for all - @ - sub r8, r8, #128 @ Cb -= 128 - sub r9, r9, #128 @ Cr -= 128 - @ - add r10, r9, r9, asl #1 @ r10 = Cr*51 + Cb*24 - add r10, r10, r10, asl #4 @ - add r10, r10, r8, asl #3 @ - add r10, r10, r8, asl #4 @ - @ - add r11, r9, r9, asl #2 @ r9 = Cr*101 - add r11, r11, r9, asl #5 @ - add r9, r11, r9, asl #6 @ - @ - add r8, r8, #2 @ r8 = bu = (Cb*128 + 128) >> 8 - mov r8, r8, asr #2 @ - add r9, r9, #256 @ r9 = rv = (r9 + 256) >> 9 - mov r9, r9, asr #9 @ - rsb r10, r10, #128 @ r10 = guv = (-r10 + 128) >> 8 - mov r10, r10, asr #8 @ - @ compute R, G, and B - add r1, r8, r7, asr #8 @ r1 = b = (Y >> 9) + bu - add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv - add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv - @ - orr r12, r1, r11 @ check if clamping is needed... - orr r12, r12, r7, asr #1 @ ...at all - cmp r12, #31 @ - bls 15f @ no clamp @ - cmp r1, #31 @ clamp b - mvnhi r1, r1, asr #31 @ - andhi r1, r1, #31 @ - cmp r11, #31 @ clamp r - mvnhi r11, r11, asr #31 @ - andhi r11, r11, #31 @ - cmp r7, #63 @ clamp g - mvnhi r7, r7, asr #31 @ - andhi r7, r7, #63 @ -15: @ no clamp @ - @ - orr r12, r1, r7, lsl #5 @ r4 |= (g << 5) - ldrb r7, [r4, r3] @ r7 = Y' = *(Y'_p + stride) - orr r12, r12, r11, lsl #11 @ r4 = b | (r << 11) - strh r12, [r0] @ store pixel - @ - sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74 - add r12, r7, r7, asl #2 @ - add r7, r12, r7, asl #5 @ - @ compute R, G, and B - add r1, r8, r7, asr #8 @ r1 = b = (Y >> 9) + bu - add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv - add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv - @ - orr r12, r1, r11 @ check if clamping is needed... - orr r12, r12, r7, asr #1 @ ...at all - cmp r12, #31 @ - bls 15f @ no clamp @ - cmp r1, #31 @ clamp b - mvnhi r1, r1, asr #31 @ - andhi r1, r1, #31 @ - cmp r11, #31 @ clamp r - mvnhi r11, r11, asr #31 @ - andhi r11, r11, #31 @ - cmp r7, #63 @ clamp g - mvnhi r7, r7, asr #31 @ - andhi r7, r7, #63 @ -15: @ no clamp @ - @ - orr r12, r1, r11, lsl #11 @ r12 = b | (r << 11) - orr r12, r12, r7, lsl #5 @ r12 |= (g << 5) - ldrb r7, [r4, #1]! @ r7 = Y' = *(++Y'_p) - strh r12, [r0, #-2] @ store pixel - add r0, r0, #2*LCD_WIDTH @ - @ - sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74 - add r12, r7, r7, asl #2 @ - add r7, r12, r7, asl #5 @ - @ compute R, G, and B - add r1, r8, r7, asr #8 @ r1 = b = (Y >> 9) + bu - add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv - add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv - @ - orr r12, r1, r11 @ check if clamping is needed... - orr r12, r12, r7, asr #1 @ ...at all - cmp r12, #31 @ - bls 15f @ no clamp @ - cmp r1, #31 @ clamp b - mvnhi r1, r1, asr #31 @ - andhi r1, r1, #31 @ - cmp r11, #31 @ clamp r - mvnhi r11, r11, asr #31 @ - andhi r11, r11, #31 @ - cmp r7, #63 @ clamp g - mvnhi r7, r7, asr #31 @ - andhi r7, r7, #63 @ -15: @ no clamp @ - @ - orr r12, r1, r7, lsl #5 @ r12 = b | (g << 5) - ldrb r7, [r4, r3] @ r7 = Y' = *(Y'_p + stride) - orr r12, r12, r11, lsl #11 @ r12 |= (r << 11) - strh r12, [r0] @ store pixel - @ - sub r7, r7, #16 @ r7 = Y = (Y' - 16)*74 - add r12, r7, r7, asl #2 @ - add r7, r12, r7, asl #5 @ - @ compute R, G, and B - add r1, r8, r7, asr #8 @ r1 = b = (Y >> 9) + bu - add r11, r9, r7, asr #8 @ r11 = r = (Y >> 9) + rv - add r7, r10, r7, asr #7 @ r7 = g = (Y >> 8) + guv - @ - orr r12, r1, r11 @ check if clamping is needed... - orr r12, r12, r7, asr #1 @ ...at all - cmp r12, #31 @ - bls 15f @ no clamp @ - cmp r1, #31 @ clamp b - mvnhi r1, r1, asr #31 @ - andhi r1, r1, #31 @ - cmp r11, #31 @ clamp r - mvnhi r11, r11, asr #31 @ - andhi r11, r11, #31 @ - cmp r7, #63 @ clamp g - mvnhi r7, r7, asr #31 @ - andhi r7, r7, #63 @ -15: @ no clamp @ - @ - orr r12, r1, r11, lsl #11 @ r12 = b | (r << 11) - orr r12, r12, r7, lsl #5 @ r12 |= (g << 5) - strh r12, [r0, #-2] @ store pixel - add r0, r0, #2*LCD_WIDTH @ - add r4, r4, #1 @ - @ - subs r2, r2, #2 @ subtract block from width - bgt 10b @ loop line @ - @ - ldmfd sp!, { r4-r12 } @ restore registers and return - bx lr @ - .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines diff --git a/firmware/target/arm/sandisk/sansa-e200/lcd-e200.c b/firmware/target/arm/sandisk/sansa-e200/lcd-e200.c index 3e1f74d7a..0d3a1a304 100644 --- a/firmware/target/arm/sandisk/sansa-e200/lcd-e200.c +++ b/firmware/target/arm/sandisk/sansa-e200/lcd-e200.c @@ -29,6 +29,7 @@ /* Power and display status */ static bool power_on = false; /* Is the power turned on? */ static bool display_on NOCACHEBSS_ATTR = false; /* Is the display turned on? */ +static unsigned lcd_yuv_options NOCACHEBSS_ATTR = 0; /* Reverse Flag */ #define R_DISP_CONTROL_NORMAL 0x0004 @@ -625,11 +626,22 @@ void lcd_blit(const fb_data* data, int x, int by, int width, (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. */ extern void lcd_write_yuv420_lines(fb_data *dst, unsigned char const * const src[3], int width, int stride); +extern void lcd_write_yuv420_lines_odither(fb_data *dst, + 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 */ /* For the e200 - show it rotated */ /* So the LCD_WIDTH is now the height */ @@ -647,21 +659,38 @@ void lcd_yuv_blit(unsigned char * const src[3], width &= ~1; height >>= 1; + y = LCD_WIDTH - 1 - y; fb_data *dst = (fb_data*)lcd_driver_framebuffer + - x * LCD_WIDTH + (LCD_WIDTH - y) - 1; + x * LCD_WIDTH + y; z = stride*src_y; yuv_src[0] = src[0] + z + src_x; yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1); yuv_src[2] = src[2] + (yuv_src[1] - src[1]); - do + if (lcd_yuv_options & LCD_YUV_DITHER) + { + do + { + lcd_write_yuv420_lines_odither(dst, yuv_src, width, stride, y, x); + 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; + dst -= 2; + y -= 2; + } + while (--height > 0); + } + else { - lcd_write_yuv420_lines(dst, 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; - dst -= 2; + do + { + lcd_write_yuv420_lines(dst, 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; + dst -= 2; + } + while (--height > 0); } - while (--height > 0); } diff --git a/uisimulator/sdl/lcd-bitmap.c b/uisimulator/sdl/lcd-bitmap.c index da6acce1b..12cc06328 100644 --- a/uisimulator/sdl/lcd-bitmap.c +++ b/uisimulator/sdl/lcd-bitmap.c @@ -159,3 +159,207 @@ void sim_lcd_ex_update_rect(int x_start, int y_start, int width, int height) } #endif +#ifdef HAVE_LCD_COLOR +/** + * |R| |1.000000 -0.000001 1.402000| |Y'| + * |G| = |1.000000 -0.334136 -0.714136| |Pb| + * |B| |1.000000 1.772000 0.000000| |Pr| + * Scaled, normalized, rounded and tweaked to yield RGB 565: + * |R| |74 0 101| |Y' - 16| >> 9 + * |G| = |74 -24 -51| |Cb - 128| >> 8 + * |B| |74 128 0| |Cr - 128| >> 9 + */ +#define YFAC (74) +#define RVFAC (101) +#define GUFAC (-24) +#define GVFAC (-51) +#define BUFAC (128) + +static inline int clamp(int val, int min, int max) +{ + if (val < min) + val = min; + else if (val > max) + val = max; + return val; +} + +void lcd_yuv_set_options(unsigned options) +{ + (void)options; +} + +/* Draw a partial YUV colour bitmap - similiar behavior to lcd_yuv_blit + in the core */ +void lcd_yuv_blit(unsigned char * const src[3], + int src_x, int src_y, int stride, + int x, int y, int width, int height) +{ + const unsigned char *ysrc, *usrc, *vsrc; + int linecounter; + fb_data *dst, *row_end; + long z; + + /* width and height must be >= 2 and an even number */ + width &= ~1; + linecounter = height >> 1; + +#if LCD_WIDTH >= LCD_HEIGHT + dst = &lcd_framebuffer[y][x]; + row_end = dst + width; +#else + dst = &lcd_framebuffer[x][LCD_WIDTH - y - 1]; + row_end = dst + LCD_WIDTH * width; +#endif + + z = stride * src_y; + ysrc = src[0] + z + src_x; + usrc = src[1] + (z >> 2) + (src_x >> 1); + vsrc = src[2] + (usrc - src[1]); + + /* stride => amount to jump from end of last row to start of next */ + stride -= width; + + /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */ + + do + { + do + { + int y, cb, cr, rv, guv, bu, r, g, b; + + y = YFAC*(*ysrc++ - 16); + cb = *usrc++ - 128; + cr = *vsrc++ - 128; + + rv = RVFAC*cr; + guv = GUFAC*cb + GVFAC*cr; + bu = BUFAC*cb; + + r = y + rv; + g = y + guv; + b = y + bu; + + if ((unsigned)(r | g | b) > 64*256-1) + { + r = clamp(r, 0, 64*256-1); + g = clamp(g, 0, 64*256-1); + b = clamp(b, 0, 64*256-1); + } + + *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); + +#if LCD_WIDTH >= LCD_HEIGHT + dst++; +#else + dst += LCD_WIDTH; +#endif + + y = YFAC*(*ysrc++ - 16); + r = y + rv; + g = y + guv; + b = y + bu; + + if ((unsigned)(r | g | b) > 64*256-1) + { + r = clamp(r, 0, 64*256-1); + g = clamp(g, 0, 64*256-1); + b = clamp(b, 0, 64*256-1); + } + + *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); + +#if LCD_WIDTH >= LCD_HEIGHT + dst++; +#else + dst += LCD_WIDTH; +#endif + } + while (dst < row_end); + + ysrc += stride; + usrc -= width >> 1; + vsrc -= width >> 1; + +#if LCD_WIDTH >= LCD_HEIGHT + row_end += LCD_WIDTH; + dst += LCD_WIDTH - width; +#else + row_end -= 1; + dst -= LCD_WIDTH*width + 1; +#endif + + do + { + int y, cb, cr, rv, guv, bu, r, g, b; + + y = YFAC*(*ysrc++ - 16); + cb = *usrc++ - 128; + cr = *vsrc++ - 128; + + rv = RVFAC*cr; + guv = GUFAC*cb + GVFAC*cr; + bu = BUFAC*cb; + + r = y + rv; + g = y + guv; + b = y + bu; + + if ((unsigned)(r | g | b) > 64*256-1) + { + r = clamp(r, 0, 64*256-1); + g = clamp(g, 0, 64*256-1); + b = clamp(b, 0, 64*256-1); + } + + *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); + +#if LCD_WIDTH >= LCD_HEIGHT + dst++; +#else + dst += LCD_WIDTH; +#endif + + y = YFAC*(*ysrc++ - 16); + r = y + rv; + g = y + guv; + b = y + bu; + + if ((unsigned)(r | g | b) > 64*256-1) + { + r = clamp(r, 0, 64*256-1); + g = clamp(g, 0, 64*256-1); + b = clamp(b, 0, 64*256-1); + } + + *dst = LCD_RGBPACK_LCD(r >> 9, g >> 8, b >> 9); + +#if LCD_WIDTH >= LCD_HEIGHT + dst++; +#else + dst += LCD_WIDTH; +#endif + } + while (dst < row_end); + + ysrc += stride; + usrc += stride >> 1; + vsrc += stride >> 1; + +#if LCD_WIDTH >= LCD_HEIGHT + row_end += LCD_WIDTH; + dst += LCD_WIDTH - width; +#else + row_end -= 1; + dst -= LCD_WIDTH*width + 1; +#endif + } + while (--linecounter > 0); + +#if LCD_WIDTH >= LCD_HEIGHT + lcd_update_rect(x, y, width, height); +#else + lcd_update_rect(y, x, height, width); +#endif +} +#endif /* HAVE_LCD_COLOR */ -- 2.11.4.GIT