rockbox/apps/plugins/lib/gray_scroll.c

574 lines
20 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Greyscale framework
* Scrolling routines
*
* This is a generic framework to use grayscale display within Rockbox
* plugins. It obviously does not work for the player.
*
* Copyright (C) 2004-2005 Jens Arnold
*
* 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.
*
****************************************************************************/
#ifndef SIMULATOR /* not for simulator by now */
#include "plugin.h"
#ifdef HAVE_LCD_BITMAP /* and also not for the Player */
#include "gray.h"
/* FIXME: intermediate solution until we have properly optimised memmove() */
static void *my_memmove(void *dst0, const void *src0, size_t len0)
{
char *dst = (char *) dst0;
char *src = (char *) src0;
if (dst <= src)
{
while (len0--)
*dst++ = *src++;
}
else
{
dst += len0;
src += len0;
while (len0--)
*(--dst) = *(--src);
}
return dst0;
}
/*** Scrolling ***/
/* Scroll left */
void gray_scroll_left(int count)
{
long shift, length;
int blank;
if ((unsigned)count >= (unsigned)_gray_info.width)
return;
shift = MULU16(_gray_info.height, count);
length = MULU16(_gray_info.height, _gray_info.width - count);
blank = (_gray_info.drawmode & DRMODE_INVERSEVID) ?
_gray_info.fg_brightness : _gray_info.bg_brightness;
my_memmove(_gray_info.cur_buffer, _gray_info.cur_buffer + shift, length);
_gray_rb->memset(_gray_info.cur_buffer + length, blank, shift);
}
/* Scroll right */
void gray_scroll_right(int count)
{
long shift, length;
int blank;
if ((unsigned)count >= (unsigned)_gray_info.width)
return;
shift = MULU16(_gray_info.height, count);
length = MULU16(_gray_info.height, _gray_info.width - count);
blank = (_gray_info.drawmode & DRMODE_INVERSEVID) ?
_gray_info.fg_brightness : _gray_info.bg_brightness;
my_memmove(_gray_info.cur_buffer + shift, _gray_info.cur_buffer, length);
_gray_rb->memset(_gray_info.cur_buffer, blank, shift);
}
/* Scroll up */
void gray_scroll_up(int count)
{
unsigned char *data, *data_end;
int length, blank;
if ((unsigned)count >= (unsigned)_gray_info.height)
return;
data = _gray_info.cur_buffer;
data_end = data + MULU16(_gray_info.width, _gray_info.height);
length = _gray_info.height - count;
blank = (_gray_info.drawmode & DRMODE_INVERSEVID) ?
_gray_info.fg_brightness : _gray_info.bg_brightness;
do
{
my_memmove(data, data + count, length);
_gray_rb->memset(data + length, blank, count);
data += _gray_info.height;
}
while (data < data_end);
}
/* Scroll down */
void gray_scroll_down(int count)
{
unsigned char *data, *data_end;
int length, blank;
if ((unsigned)count >= (unsigned)_gray_info.height)
return;
data = _gray_info.cur_buffer;
data_end = data + MULU16(_gray_info.width, _gray_info.height);
length = _gray_info.height - count;
blank = (_gray_info.drawmode & DRMODE_INVERSEVID) ?
_gray_info.fg_brightness : _gray_info.bg_brightness;
do
{
my_memmove(data + count, data, length);
_gray_rb->memset(data, blank, count);
data += _gray_info.height;
}
while (data < data_end);
}
/*** Unbuffered scrolling functions ***/
/* Scroll left */
void gray_ub_scroll_left(int count)
{
int length;
unsigned char *ptr, *ptr_end;
if ((unsigned) count >= (unsigned) _gray_info.width)
return;
length = _gray_info.width - count;
ptr = _gray_info.plane_data;
ptr_end = ptr + _gray_info.plane_size;
/* Scroll row by row to minimize flicker (pixel block rows) */
do
{
unsigned char *ptr_row = ptr;
unsigned char *row_end = ptr_row
+ MULU16(_gray_info.plane_size, _gray_info.depth);
do
{
my_memmove(ptr_row, ptr_row + count, length);
_gray_rb->memset(ptr_row + length, 0, count);
ptr_row += _gray_info.plane_size;
}
while (ptr_row < row_end);
ptr += _gray_info.width;
}
while (ptr < ptr_end);
}
/* Scroll right */
void gray_ub_scroll_right(int count)
{
int length;
unsigned char *ptr, *ptr_end;
if ((unsigned) count >= (unsigned) _gray_info.width)
return;
length = _gray_info.width - count;
ptr = _gray_info.plane_data;
ptr_end = ptr + _gray_info.plane_size;
/* Scroll row by row to minimize flicker (pixel block rows) */
do
{
unsigned char *ptr_row = ptr;
unsigned char *row_end = ptr_row
+ MULU16(_gray_info.plane_size, _gray_info.depth);
do
{
my_memmove(ptr_row + count, ptr_row, length);
_gray_rb->memset(ptr_row, 0, count);
ptr_row += _gray_info.plane_size;
}
while (ptr_row < row_end);
ptr += _gray_info.width;
}
while (ptr < ptr_end);
}
/* Scroll up */
void gray_ub_scroll_up(int count)
{
int shift;
long blockshift = 0;
unsigned char *ptr, *ptr_end1, *ptr_end2;
if ((unsigned) count >= (unsigned) _gray_info.height)
return;
shift = count >> _PBLOCK_EXP;
count &= (_PBLOCK-1);
if (shift)
{
blockshift = MULU16(_gray_info.width, shift);
ptr = _gray_info.plane_data;
ptr_end2 = ptr + _gray_info.plane_size;
ptr_end1 = ptr_end2 - blockshift;
/* Scroll row by row to minimize flicker (pixel block rows) */
do
{
unsigned char *ptr_row = ptr;
unsigned char *row_end = ptr_row
+ MULU16(_gray_info.plane_size, _gray_info.depth);
if (ptr < ptr_end1)
{
do
{
_gray_rb->memcpy(ptr_row, ptr_row + blockshift,
_gray_info.width);
ptr_row += _gray_info.plane_size;
}
while (ptr_row < row_end);
}
else
{
do
{
_gray_rb->memset(ptr_row, 0, _gray_info.width);
ptr_row += _gray_info.plane_size;
}
while (ptr_row < row_end);
}
ptr += _gray_info.width;
}
while (ptr < ptr_end2);
}
if (count)
{
#if (CONFIG_CPU == SH7034) && (LCD_DEPTH == 1)
/* scroll column by column to minimize flicker */
asm (
"mov #0,r6 \n" /* x = 0 */
"mova .su_shifttbl,r0 \n" /* calculate jump destination for */
"mov.b @(r0,%[cnt]),%[cnt] \n" /* shift amount from table */
"bra .su_cloop \n" /* skip table */
"add r0,%[cnt] \n"
".align 2 \n"
".su_shifttbl: \n" /* shift jump offset table */
".byte .su_shift0 - .su_shifttbl \n"
".byte .su_shift1 - .su_shifttbl \n"
".byte .su_shift2 - .su_shifttbl \n"
".byte .su_shift3 - .su_shifttbl \n"
".byte .su_shift4 - .su_shifttbl \n"
".byte .su_shift5 - .su_shifttbl \n"
".byte .su_shift6 - .su_shifttbl \n"
".byte .su_shift7 - .su_shifttbl \n"
".su_cloop: \n" /* repeat for every column */
"mov %[addr],r2 \n" /* get start address */
"mov #0,r3 \n" /* current_plane = 0 */
".su_oloop: \n" /* repeat for every bitplane */
"mov r2,r4 \n" /* get start address */
"mov #0,r5 \n" /* current_row = 0 */
"mov #0,r1 \n" /* fill with zero */
".su_iloop: \n" /* repeat for all rows */
"sub %[wide],r4 \n" /* address -= width */
"mov.b @r4,r0 \n" /* get data byte */
"shll8 r1 \n" /* old data to 2nd byte */
"extu.b r0,r0 \n" /* extend unsigned */
"or r1,r0 \n" /* combine old data */
"jmp @%[cnt] \n" /* jump into shift "path" */
"extu.b r0,r1 \n" /* store data for next round */
".su_shift6: \n" /* shift right by 0..7 bits */
"shll2 r0 \n"
"bra .su_shift0 \n"
"shlr8 r0 \n"
".su_shift4: \n"
"shlr2 r0 \n"
".su_shift2: \n"
"bra .su_shift0 \n"
"shlr2 r0 \n"
".su_shift7: \n"
"shlr2 r0 \n"
".su_shift5: \n"
"shlr2 r0 \n"
".su_shift3: \n"
"shlr2 r0 \n"
".su_shift1: \n"
"shlr r0 \n"
".su_shift0: \n"
"mov.b r0,@r4 \n" /* store data */
"add #1,r5 \n" /* current_row++ */
"cmp/hi r5,%[rows] \n" /* current_row < bheight - shift ? */
"bt .su_iloop \n"
"add %[psiz],r2 \n" /* start_address += plane_size */
"add #1,r3 \n" /* current_plane++ */
"cmp/hi r3,%[dpth] \n" /* current_plane < depth ? */
"bt .su_oloop \n"
"add #1,%[addr] \n" /* start_address++ */
"add #1,r6 \n" /* x++ */
"cmp/hi r6,%[wide] \n" /* x < width ? */
"bt .su_cloop \n"
: /* outputs */
: /* inputs */
[dpth]"r"(_gray_info.depth),
[addr]"r"(_gray_info.plane_data + _gray_info.plane_size - blockshift),
[wide]"r"(_gray_info.width),
[rows]"r"(_gray_info.bheight - shift),
[psiz]"r"(_gray_info.plane_size),
[cnt] "r"(count)
: /* clobbers */
"r0", "r1", "r2", "r3", "r4", "r5", "r6"
);
#elif defined(CPU_COLDFIRE) && (LCD_DEPTH == 2)
/* scroll column by column to minimize flicker */
asm (
"move.l %[wide],%%d4\n" /* columns = width */
".su_cloop: \n" /* repeat for every column */
"move.l %[addr],%%a0\n" /* get start address */
"move.l %[dpth],%%d2\n" /* planes = depth */
".su_oloop: \n" /* repeat for every bitplane */
"move.l %%a0,%%a1 \n" /* get start address */
"move.l %[rows],%%d3\n" /* rows = row_count */
"clr.l %%d1 \n" /* fill with zero */
".su_iloop: \n" /* repeat for all rows */
"sub.l %[wide],%%a1\n" /* address -= width */
"clr.l %%d0 \n"
"move.b (%%a1),%%d0 \n" /* get data byte */
"lsl.l #8,%%d1 \n" /* old data to 2nd byte */
"or.l %%d1,%%d0 \n" /* combine old data */
"clr.l %%d1 \n"
"move.b %%d0,%%d1 \n" /* keep data for next round */
"lsr.l %[cnt],%%d0 \n" /* shift right */
"move.b %%d0,(%%a1) \n" /* store data */
"subq.l #1,%%d3 \n" /* rows-- */
"bne.b .su_iloop \n"
"add.l %[psiz],%%a0\n" /* start_address += plane_size */
"subq.l #1,%%d2 \n" /* planes-- */
"bne.b .su_oloop \n"
"lea.l (1,%[addr]),%[addr] \n" /* start_address++ */
"subq.l #1,%%d4 \n" /* columns-- */
"bne.b .su_cloop \n"
: /* outputs */
: /* inputs */
[psiz]"r"(_gray_info.plane_size),
[dpth]"r"(_gray_info.depth),
[wide]"r"(_gray_info.width),
[rows]"r"(_gray_info.bheight - shift),
[addr]"a"(_gray_info.plane_data + _gray_info.plane_size - blockshift),
[cnt] "d"(count)
: /* clobbers */
"a0", "a1", "d0", "d1", "d2", "d3", "d4"
);
#endif
}
}
/* Scroll down */
void gray_ub_scroll_down(int count)
{
int shift;
long blockshift = 0;
unsigned char *ptr, *ptr_end1, *ptr_end2;
if ((unsigned) count >= (unsigned) _gray_info.height)
return;
shift = count >> _PBLOCK_EXP;
count &= (_PBLOCK-1);
if (shift)
{
blockshift = MULU16(_gray_info.width, shift);
ptr_end2 = _gray_info.plane_data;
ptr_end1 = ptr_end2 + blockshift;
ptr = ptr_end2 + _gray_info.plane_size;
/* Scroll row by row to minimize flicker (pixel block rows) */
do
{
unsigned char *ptr_row, *row_end;
ptr -= _gray_info.width;
ptr_row = ptr;
row_end = ptr_row + MULU16(_gray_info.plane_size, _gray_info.depth);
if (ptr >= ptr_end1)
{
do
{
_gray_rb->memcpy(ptr_row, ptr_row - blockshift,
_gray_info.width);
ptr_row += _gray_info.plane_size;
}
while (ptr_row < row_end);
}
else
{
do
{
_gray_rb->memset(ptr_row, 0, _gray_info.width);
ptr_row += _gray_info.plane_size;
}
while (ptr_row < row_end);
}
}
while (ptr > ptr_end2);
}
if (count)
{
#if (CONFIG_CPU == SH7034) && (LCD_DEPTH == 1)
/* scroll column by column to minimize flicker */
asm (
"mov #0,r6 \n" /* x = 0 */
"mova .sd_shifttbl,r0 \n" /* calculate jump destination for */
"mov.b @(r0,%[cnt]),%[cnt] \n" /* shift amount from table */
"bra .sd_cloop \n" /* skip table */
"add r0,%[cnt] \n"
".align 2 \n"
".sd_shifttbl: \n" /* shift jump offset table */
".byte .sd_shift0 - .sd_shifttbl \n"
".byte .sd_shift1 - .sd_shifttbl \n"
".byte .sd_shift2 - .sd_shifttbl \n"
".byte .sd_shift3 - .sd_shifttbl \n"
".byte .sd_shift4 - .sd_shifttbl \n"
".byte .sd_shift5 - .sd_shifttbl \n"
".byte .sd_shift6 - .sd_shifttbl \n"
".byte .sd_shift7 - .sd_shifttbl \n"
".sd_cloop: \n" /* repeat for every column */
"mov %[addr],r2 \n" /* get start address */
"mov #0,r3 \n" /* current_plane = 0 */
".sd_oloop: \n" /* repeat for every bitplane */
"mov r2,r4 \n" /* get start address */
"mov #0,r5 \n" /* current_row = 0 */
"mov #0,r1 \n" /* fill with zero */
".sd_iloop: \n" /* repeat for all rows */
"shlr8 r1 \n" /* shift right to get residue */
"mov.b @r4,r0 \n" /* get data byte */
"jmp @%[cnt] \n" /* jump into shift "path" */
"extu.b r0,r0 \n" /* extend unsigned */
".sd_shift6: \n" /* shift left by 0..7 bits */
"shll8 r0 \n"
"bra .sd_shift0 \n"
"shlr2 r0 \n"
".sd_shift4: \n"
"shll2 r0 \n"
".sd_shift2: \n"
"bra .sd_shift0 \n"
"shll2 r0 \n"
".sd_shift7: \n"
"shll2 r0 \n"
".sd_shift5: \n"
"shll2 r0 \n"
".sd_shift3: \n"
"shll2 r0 \n"
".sd_shift1: \n"
"shll r0 \n"
".sd_shift0: \n"
"or r0,r1 \n" /* combine with last residue */
"mov.b r1,@r4 \n" /* store data */
"add %[wide],r4 \n" /* address += width */
"add #1,r5 \n" /* current_row++ */
"cmp/hi r5,%[rows] \n" /* current_row < bheight - shift ? */
"bt .sd_iloop \n"
"add %[psiz],r2 \n" /* start_address += plane_size */
"add #1,r3 \n" /* current_plane++ */
"cmp/hi r3,%[dpth] \n" /* current_plane < depth ? */
"bt .sd_oloop \n"
"add #1,%[addr] \n" /* start_address++ */
"add #1,r6 \n" /* x++ */
"cmp/hi r6,%[wide] \n" /* x < width ? */
"bt .sd_cloop \n"
: /* outputs */
: /* inputs */
[dpth]"r"(_gray_info.depth),
[addr]"r"(_gray_info.plane_data + blockshift),
[wide]"r"(_gray_info.width),
[rows]"r"(_gray_info.bheight - shift),
[psiz]"r"(_gray_info.plane_size),
[cnt] "r"(count)
: /* clobbers */
"r0", "r1", "r2", "r3", "r4", "r5", "r6"
);
#elif defined(CPU_COLDFIRE) && (LCD_DEPTH == 2)
/* scroll column by column to minimize flicker */
asm (
"move.l %[wide],%%d4\n" /* columns = width */
".sd_cloop: \n" /* repeat for every column */
"move.l %[addr],%%a0\n" /* get start address */
"move.l %[dpth],%%d2\n" /* planes = depth */
".sd_oloop: \n" /* repeat for every bitplane */
"move.l %%a0,%%a1 \n" /* get start address */
"move.l %[rows],%%d3\n" /* rows = row_count */
"clr.l %%d1 \n" /* fill with zero */
".sd_iloop: \n" /* repeat for all rows */
"lsr.l #8,%%d1 \n" /* shift right to get residue */
"clr.l %%d0 \n"
"move.b (%%a1),%%d0 \n" /* get data byte */
"lsl.l %[cnt],%%d0 \n"
"or.l %%d0,%%d1 \n" /* combine with last residue */
"move.b %%d1,(%%a1) \n" /* store data */
"add.l %[wide],%%a1\n" /* address += width */
"subq.l #1,%%d3 \n" /* rows-- */
"bne.b .sd_iloop \n"
"add.l %[psiz],%%a0\n" /* start_address += plane_size */
"subq.l #1,%%d2 \n" /* planes-- */
"bne.b .sd_oloop \n"
"lea.l (1,%[addr]),%[addr] \n" /* start_address++ */
"subq.l #1,%%d4 \n" /* columns-- */
"bne.b .sd_cloop \n"
: /* outputs */
: /* inputs */
[dpth]"r"(_gray_info.depth),
[wide]"r"(_gray_info.width),
[rows]"r"(_gray_info.bheight - shift),
[psiz]"r"(_gray_info.plane_size),
[addr]"a"(_gray_info.plane_data + blockshift),
[cnt] "d"(count)
: /* clobbers */
"a0", "a1", "d0", "d1", "d2", "d3", "d4"
);
#endif
}
}
#endif /* HAVE_LCD_BITMAP */
#endif /* !SIMULATOR */