From a472b78b947cb9214ea2cb0c40ea6b8adca93e04 Mon Sep 17 00:00:00 2001 From: b0hoon Date: Sun, 5 Dec 2010 19:45:50 +0000 Subject: [PATCH] HDD6330: implement lcd_yuv_blit() function. The inner loop is written in assembler and the entire function is about 20% faster than the original from the ipod color. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28737 a1c6a512-1295-4272-9138-f99709370657 --- firmware/SOURCES | 1 + .../target/arm/philips/hdd6330/lcd-as-hdd6330.S | 149 +++++++++++++++++++++ firmware/target/arm/philips/hdd6330/lcd-hdd6330.c | 101 ++++++++++++-- 3 files changed, 241 insertions(+), 10 deletions(-) create mode 100644 firmware/target/arm/philips/hdd6330/lcd-as-hdd6330.S diff --git a/firmware/SOURCES b/firmware/SOURCES index 349155f8c..7f21a8977 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -735,6 +735,7 @@ target/arm/philips/fmradio_i2c-hdd.c target/arm/philips/hdd6330/backlight-hdd6330.c target/arm/philips/hdd6330/button-hdd6330.c target/arm/philips/hdd6330/lcd-hdd6330.c +target/arm/philips/hdd6330/lcd-as-hdd6330.S target/arm/philips/hdd6330/powermgmt-hdd6330.c target/arm/usb-fw-pp502x.c #endif /* SIMULATOR */ diff --git a/firmware/target/arm/philips/hdd6330/lcd-as-hdd6330.S b/firmware/target/arm/philips/hdd6330/lcd-as-hdd6330.S new file mode 100644 index 000000000..364eb5b08 --- /dev/null +++ b/firmware/target/arm/philips/hdd6330/lcd-as-hdd6330.S @@ -0,0 +1,149 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id:$ + * + * Copyright (C) 2010 by Szymon Dziok + * + * Philips Gogear HDD6330 LCD assembly routine + * + * This program 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. + * + * 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_yuv_write_inner_loop(unsigned char const * const ysrc, + unsigned char const * const usrc, + unsigned char const * const vsrc, + int width); +*/ + .section .icode, "ax", %progbits + .align 2 + .global lcd_yuv_write_inner_loop + .type lcd_yuv_write_inner_loop, %function +lcd_yuv_write_inner_loop: + @ r0 = ysrc + @ r1 = usrc + @ r2 = vsrc + @ r3 = width + stmfd sp!, { r4-r11, lr } @ save regs + mov r4, #0x70000000 @ r4 = LCD2_BLOCK_CTRL - 0x20 + add r4, r4, #0x8a00 @ + add r5, r4, #0x100 @ r5 = LCD2_BLOCK_DATA +10: @ loop + + ldrb r7, [r1], #1 @ *usrc++ + ldrb r8, [r2], #1 @ *vsrc++ + + add r10, r8, r8, asl #2 @ 101* vsrc + add r10, r10, r8, asl #5 + add r10, r10, r8, asl #6 + sub r10, r10, #0x3600 + sub r10, r10, #0x0020 @ -13856 (ROUNDOFFSR) + + add r11, r8, r8, asl #1 @ 51*vsrc + 24*usrc + add r11, r11, r11, asl #4 + add r11, r11, r7, asl #3 + add r11, r11, r7, asl #4 + mov r12, #0x2100 + add r12, r12, #0x60 @ +8544 (ROUNDOFFSG) - r11 + rsb r11, r11, r12 + + mov r12, r7, asl #7 @ 128 * usrc + sub r12, r12, #0x4300 + sub r12, r12, #0x00a0 @ -17312 (ROUNDOFFSB) + +@ pixel_1 + ldrb r8, [r0], #1 @ *ysrc++ + mov r7, r8, asl #1 + add r7, r7, r8, asl #3 + add r7, r7, r8, asl #6 @ ysrc * 74 + + add r9, r10, r7 + mov r9, r9, asr #9 @ R + + add r8, r11, r7 + mov r8, r8, asr #8 @ G + + add r7, r12, r7 + mov r7, r7, asr #9 @ B + + cmp r9, #31 @ clamp R + mvnhi r9, r9, asr #31 + andhi r9, r9, #31 + + cmp r8, #63 @ clamp G + mvnhi r8, r8, asr #31 + andhi r8, r8, #63 + + cmp r7, #31 @ clamp B + mvnhi r7, r7, asr #31 + andhi r7, r7, #31 + + orr r6, r7, r8, lsl #5 @ pack pixel + orr r6, r6, r9, lsl #11 + + mov r7, r6, lsl #8 @ swap bytes + and r7, r7, #0xff00 + add r6, r7, r6, lsr #8 + +@ pixel_2 + ldrb r8, [r0], #1 @ *ysrc++ + mov r7, r8, asl #1 + add r7, r7, r8, asl #3 + add r7, r7, r8, asl #6 @ ysrc * 74 + + add r9, r10, r7 + mov r9, r9, asr #9 @ R + + add r8, r11, r7 + mov r8, r8, asr #8 @ G + + add r7, r12, r7 + mov r7, r7, asr #9 @ B + + cmp r9, #31 @ clamp R + mvnhi r9, r9, asr #31 + andhi r9, r9, #31 + + cmp r8, #63 @ clamp G + mvnhi r8, r8, asr #31 + andhi r8, r8, #63 + + cmp r7, #31 @ clamp B + mvnhi r7, r7, asr #31 + andhi r7, r7, #31 + + orr r7, r7, r8, lsl #5 @ pack pixel + orr r7, r7, r9, lsl #11 + + orr r6, r6, r7, lsl #24 @ swap bytes and add pixels simultaneously + mov r7, r7, lsr #8 + orr r6, r6, r7, lsl #16 + +11: @ while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_TXOK)); + ldr r11, [r4, #0x20] @ + tst r11, #0x1000000 @ + beq 11b @ + + str r6, [r5] @ send two pixels + + subs r3, r3, #2 @ decrease width + bgt 10b @ loop + + ldmpc regs=r4-r11 @ restore regs + .ltorg @ dump constant pool + .size lcd_yuv_write_inner_loop, .-lcd_yuv_write_inner_loop diff --git a/firmware/target/arm/philips/hdd6330/lcd-hdd6330.c b/firmware/target/arm/philips/hdd6330/lcd-hdd6330.c index c8127c445..53c0be1d6 100644 --- a/firmware/target/arm/philips/hdd6330/lcd-hdd6330.c +++ b/firmware/target/arm/philips/hdd6330/lcd-hdd6330.c @@ -80,21 +80,102 @@ void lcd_yuv_set_options(unsigned options) lcd_yuv_options = options; } +#define CSUB_X 2 +#define CSUB_Y 2 + +/* YUV- > RGB565 conversion + * |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 +*/ + +extern void lcd_yuv_write_inner_loop(unsigned char const * const ysrc, + unsigned char const * const usrc, + unsigned char const * const vsrc, + int width); + /* Performance function to blit a YUV bitmap directly to the LCD */ void lcd_blit_yuv(unsigned char * const src[3], int src_x, int src_y, int stride, int x, int y, int width, int height) { - (void)src; - (void)src_x; - (void)src_y; - (void)stride; - (void)x; - (void)y; - (void)width; - (void)height; + int h; + + width = (width + 1) & ~1; + + lcd_send_reg(0x01); + lcd_send_data(0x48); + + lcd_send_reg(0x05); + lcd_send_data(0x0f); + + lcd_send_reg(0x08); + lcd_send_data(y); + + lcd_send_reg(0x09); + lcd_send_data(y + height - 1); + + lcd_send_reg(0x0a); + lcd_send_data(x + 16); + + lcd_send_reg(0x0b); + lcd_send_data(x + width - 1 + 16); + + lcd_send_reg(0x06); + + const int stride_div_csub_x = stride/CSUB_X; + + h=0; + while (1) + { + /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */ + const unsigned char *ysrc = src[0] + stride * src_y + src_x; + + const int uvoffset = stride_div_csub_x * (src_y/CSUB_Y) + + (src_x/CSUB_X); + + const unsigned char *usrc = src[1] + uvoffset; + const unsigned char *vsrc = src[2] + uvoffset; + + int pixels_to_write; + + if (h==0) + { + while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY)); + LCD2_BLOCK_CONFIG = 0; + + if (height == 0) break; + + pixels_to_write = (width * height) * 2; + h = height; + + /* calculate how much we can do in one go */ + if (pixels_to_write > 0x10000) + { + h = (0x10000/2) / width; + pixels_to_write = (width * h) * 2; + } + + height -= h; + LCD2_BLOCK_CTRL = 0x10000080; + LCD2_BLOCK_CONFIG = 0xc0010000 | (pixels_to_write - 1); + LCD2_BLOCK_CTRL = 0x34000000; + } + + lcd_yuv_write_inner_loop(ysrc,usrc,vsrc,width); + + src_y++; + h--; + } + + while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY)); + LCD2_BLOCK_CONFIG = 0; } - + /* Update the display. This must be called after all other LCD functions that change the display. */ void lcd_update(void) @@ -146,7 +227,7 @@ void lcd_update_rect(int x, int y, int width, int height) addr = (unsigned long*)&lcd_framebuffer[y][x]; - while (height > 0) + while (height > 0) { int c, r; int h, pixels_to_write; -- 2.11.4.GIT