diff --git a/apps/plugin.c b/apps/plugin.c index 4474d0d5ee..bbc5d7d15c 100644 --- a/apps/plugin.c +++ b/apps/plugin.c @@ -463,8 +463,8 @@ static const struct plugin_api rockbox_api = { lcd_remote_bitmap, #endif -#if (CONFIG_LCD == LCD_IPODCOLOR || CONFIG_LCD == LCD_IPODNANO) && \ - !defined(SIMULATOR) +#if (CONFIG_LCD == LCD_IPODCOLOR || CONFIG_LCD == LCD_IPODNANO \ + || CONFIG_LCD == LCD_H300) && !defined(SIMULATOR) lcd_yuv_blit, #endif diff --git a/apps/plugin.h b/apps/plugin.h index b764d860c3..f43e0ae08b 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -104,7 +104,7 @@ #define PLUGIN_MAGIC 0x526F634B /* RocK */ /* increase this every time the api struct changes */ -#define PLUGIN_API_VERSION 27 +#define PLUGIN_API_VERSION 28 /* update this to latest version if a change to the api struct breaks backwards compatibility (and please take the opportunity to sort in any @@ -539,8 +539,8 @@ struct plugin_api { void (*lcd_remote_bitmap)(const fb_remote_data *src, int x, int y, int width, int height); #endif -#if (CONFIG_LCD == LCD_IPODCOLOR || CONFIG_LCD == LCD_IPODNANO) && \ - !defined(SIMULATOR) +#if (CONFIG_LCD == LCD_IPODCOLOR || CONFIG_LCD == LCD_IPODNANO \ + || CONFIG_LCD == LCD_H300) && !defined(SIMULATOR) 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/apps/plugins/mpegplayer/video_out_rockbox.c b/apps/plugins/mpegplayer/video_out_rockbox.c index 786d9d0e14..a5fdf5efbb 100644 --- a/apps/plugins/mpegplayer/video_out_rockbox.c +++ b/apps/plugins/mpegplayer/video_out_rockbox.c @@ -35,12 +35,14 @@ static int starttick; #define CSUB_X 2 #define CSUB_Y 2 -static int image_x; -static int image_y; 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 (LCD_DEPTH == 16) && \ ((LCD_PIXELFORMAT == RGB565) || (LCD_PIXELFORMAT == RGB565SWAPPED)) @@ -197,16 +199,16 @@ static void rockbox_draw_frame (vo_instance_t * instance, (void)id; (void)instance; -#if (CONFIG_LCD == LCD_IPODCOLOR || CONFIG_LCD == LCD_IPODNANO) && \ - !defined(SIMULATOR) +#if (CONFIG_LCD == LCD_IPODCOLOR || CONFIG_LCD == LCD_IPODNANO \ + || CONFIG_LCD == LCD_H300) && !defined(SIMULATOR) rb->lcd_yuv_blit(buf, 0,0,image_width, - image_x,image_y,image_width,image_height); + output_x,output_y,output_width,output_height); #elif (LCD_DEPTH == 16) && \ ((LCD_PIXELFORMAT == RGB565) || (LCD_PIXELFORMAT == RGB565SWAPPED)) yuv_bitmap_part(buf,0,0,image_width, - image_x,image_y,image_width,image_height); - rb->lcd_update_rect(image_x,image_y,image_width,image_height); + output_x,output_y,output_width,output_height); + rb->lcd_update_rect(output_x,output_y,output_width,output_height); #endif if (starttick==0) starttick=*rb->current_tick-1; /* Avoid divby0 */ @@ -265,15 +267,19 @@ static int rockbox_setup (vo_instance_t * instance, unsigned int width, image_chroma_y=image_height/chroma_height; if (image_width >= LCD_WIDTH) { - image_x = 0; + output_width = LCD_WIDTH; + output_x = 0; } else { - image_x = (LCD_WIDTH-image_width)/2; + output_width = image_width; + output_x = (LCD_WIDTH-image_width)/2; } if (image_height >= LCD_HEIGHT) { - image_y = 0; + output_height = LCD_HEIGHT; + output_y = 0; } else { - image_y = (LCD_HEIGHT-image_height)/2; + output_height = image_height; + output_y = (LCD_HEIGHT-image_height)/2; } return 0; diff --git a/firmware/drivers/lcd-h300.c b/firmware/drivers/lcd-h300.c index 0bdb123d41..c3f5d48f87 100644 --- a/firmware/drivers/lcd-h300.c +++ b/firmware/drivers/lcd-h300.c @@ -77,18 +77,20 @@ static int xoffset = 0; /* needed for flip */ #define R_HORIZ_RAM_ADDR_POS 0x44 #define R_VERT_RAM_ADDR_POS 0x45 +#define LCD_CMD (*(volatile unsigned short *)0xf0000000) +#define LCD_DATA (*(volatile unsigned short *)0xf0000002) /* called very frequently - inline! */ static inline void lcd_write_reg(int reg, int val) { - *(volatile unsigned short *)0xf0000000 = reg; - *(volatile unsigned short *)0xf0000002 = val; + LCD_CMD = reg; + LCD_DATA = val; } /* called very frequently - inline! */ static inline void lcd_begin_write_gram(void) { - *(volatile unsigned short *)0xf0000000 = R_WRITE_DATA_2_GRAM; + LCD_CMD = R_WRITE_DATA_2_GRAM; } /*** hardware configuration ***/ @@ -299,6 +301,135 @@ void lcd_blit(const fb_data* data, int x, int by, int width, /*if(display_on)*/ } +#define CSUB_X 2 +#define CSUB_Y 2 + +#define RYFAC (31*257) +#define GYFAC (63*257) +#define BYFAC (31*257) +#define RVFAC 11170 /* 31 * 257 * 1.402 */ +#define GVFAC (-11563) /* 63 * 257 * -0.714136 */ +#define GUFAC (-5572) /* 63 * 257 * -0.344136 */ +#define BUFAC 14118 /* 31 * 257 * 1.772 */ + +#define ROUNDOFFS (127*257) + +/* Performance function to blit a YUV bitmap directly to the LCD */ +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) +{ + if (display_on) + { + int ymax; + + width = (width + 1) & ~1; + height = (height + 1) & ~1; + ymax = y + height - 1; + + /* set update window */ + + /* horiz ram addr */ + lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (ymax << 8) | y); + + /* vert ram addr */ + lcd_write_reg(R_VERT_RAM_ADDR_POS,((x+xoffset+width-1) << 8) | (x+xoffset)); + lcd_write_reg(R_RAM_ADDR_SET, ((x+xoffset) << 8) | y); + lcd_begin_write_gram(); + + for (; y <= ymax; y++) + { + /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */ + const unsigned char *ysrc = src[0] + stride * src_y + src_x; + const unsigned char *usrc = src[1] + (stride/CSUB_X) * (src_y/CSUB_Y) + + (src_x/CSUB_X); + const unsigned char *vsrc = src[2] + (stride/CSUB_X) * (src_y/CSUB_Y) + + (src_x/CSUB_X); + const unsigned char *row_end = ysrc + width; + + int y, u, v; + int rc, gc, bc; + int red, green, blue; + unsigned rbits, gbits, bbits; + + do + { + u = *usrc++ - 128; + v = *vsrc++ - 128; + rc = RVFAC * v + ROUNDOFFS; + gc = GVFAC * v + GUFAC * u + ROUNDOFFS; + bc = BUFAC * u + ROUNDOFFS; + + y = *ysrc++; + red = RYFAC * y + rc; + green = GYFAC * y + gc; + blue = BYFAC * y + bc; + + if ((unsigned)red > (RYFAC*255+ROUNDOFFS)) + { + if (red < 0) + red = 0; + else + red = (RYFAC*255+ROUNDOFFS); + } + if ((unsigned)green > (GYFAC*255+ROUNDOFFS)) + { + if (green < 0) + green = 0; + else + green = (GYFAC*255+ROUNDOFFS); + } + if ((unsigned)blue > (BYFAC*255+ROUNDOFFS)) + { + if (blue < 0) + blue = 0; + else + blue = (BYFAC*255+ROUNDOFFS); + } + rbits = ((unsigned)red) >> 16 ; + gbits = ((unsigned)green) >> 16 ; + bbits = ((unsigned)blue) >> 16 ; + + LCD_DATA = (rbits << 11) | (gbits << 5) | bbits; + + y = *ysrc++; + red = RYFAC * y + rc; + green = GYFAC * y + gc; + blue = BYFAC * y + bc; + + if ((unsigned)red > (RYFAC*255+ROUNDOFFS)) + { + if (red < 0) + red = 0; + else + red = (RYFAC*255+ROUNDOFFS); + } + if ((unsigned)green > (GYFAC*255+ROUNDOFFS)) + { + if (green < 0) + green = 0; + else + green = (GYFAC*255+ROUNDOFFS); + } + if ((unsigned)blue > (BYFAC*255+ROUNDOFFS)) + { + if (blue < 0) + blue = 0; + else + blue = (BYFAC*255+ROUNDOFFS); + } + rbits = ((unsigned)red) >> 16 ; + gbits = ((unsigned)green) >> 16 ; + bbits = ((unsigned)blue) >> 16 ; + + LCD_DATA = (rbits << 11) | (gbits << 5) | bbits; + } + while (ysrc < row_end); + + src_y++; + } + } +} /* Update the display. This must be called after all other LCD functions that change the display. */ @@ -324,8 +455,8 @@ void lcd_update(void) void lcd_update_rect(int, int, int, int) ICODE_ATTR; void lcd_update_rect(int x, int y, int width, int height) { - if(display_on) { - int ymax = y + height; + if(display_on) { + int ymax = y + height - 1; if(x + width > LCD_WIDTH) width = LCD_WIDTH - x; diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h index 32a958af2a..7551a1ab23 100644 --- a/firmware/export/lcd.h +++ b/firmware/export/lcd.h @@ -71,7 +71,8 @@ extern void lcd_puts_scroll_style(int x, int y, const unsigned char* string, int style); extern void lcd_icon(int icon, bool enable); -#if CONFIG_LCD == LCD_IPODCOLOR || CONFIG_LCD == LCD_IPODNANO +#if CONFIG_LCD == LCD_IPODCOLOR || CONFIG_LCD == LCD_IPODNANO \ + || CONFIG_LCD == LCD_H300 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);