summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Arnold <amiconn@rockbox.org>2004-05-15 22:01:30 +0000
committerJens Arnold <amiconn@rockbox.org>2004-05-15 22:01:30 +0000
commitbde77c047d4e6629cb43b600d070ed80ed6f94fa (patch)
treed1f2538bd3c80d737c40de013a52918aac4eb228
parent9580e3a577829f7162429629c0cc5d981e7f5e05 (diff)
Included improved grayscale framework
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4627 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/plugins/jpeg.c517
1 files changed, 392 insertions, 125 deletions
diff --git a/apps/plugins/jpeg.c b/apps/plugins/jpeg.c
index 5314ac6091..8f872bdab6 100644
--- a/apps/plugins/jpeg.c
+++ b/apps/plugins/jpeg.c
@@ -64,6 +64,9 @@ static struct plugin_api* rb;
#define GRAY_RUNNING 0x0001 /* grayscale overlay is running */
#define GRAY_DEFERRED_UPDATE 0x0002 /* lcd_update() requested */
+/* unsigned 16 bit multiplication (a single instruction on the SH) */
+#define MULU16(a, b) (((unsigned short) (a)) * ((unsigned short) (b)))
+
typedef struct
{
int x;
@@ -81,19 +84,21 @@ typedef struct
} tGraybuf;
static tGraybuf *graybuf = NULL;
+static short gray_random_buffer;
/** prototypes **/
-void timer_isr(void);
+void gray_timer_isr(void);
void graypixel(int x, int y, unsigned long pattern);
-void grayinvertmasked(int x, int yb, unsigned char mask);
+void grayblock(int x, int by, unsigned char* src, int stride);
+void grayinvertmasked(int x, int by, unsigned char mask);
/** implementation **/
/* timer interrupt handler: display next bitplane */
-void timer_isr(void)
+void gray_timer_isr(void)
{
- rb->lcd_blit(graybuf->data + (graybuf->plane_size * graybuf->cur_plane),
+ rb->lcd_blit(graybuf->data + MULU16(graybuf->plane_size, graybuf->cur_plane),
graybuf->x, graybuf->by, graybuf->width, graybuf->bheight,
graybuf->width);
@@ -127,7 +132,6 @@ void timer_isr(void)
* This is the fundamental graphics primitive, asm optimized */
void graypixel(int x, int y, unsigned long pattern)
{
- static short random_buffer;
register long address, mask, random;
/* Some (pseudo-)random function must be used here to shift the bit
@@ -150,7 +154,7 @@ void graypixel(int x, int y, unsigned long pattern)
: /* outputs */
/* %0 */ "=&r"(random)
: /* inputs */
- /* %1 */ "r"(&random_buffer),
+ /* %1 */ "r"(&gray_random_buffer),
/* %2 */ "r"(graybuf->randmask)
: /* clobbers */
"r1","macl"
@@ -259,6 +263,141 @@ void graypixel(int x, int y, unsigned long pattern)
);
}
+/* Set 8 pixels to specific gray values at once, asm optimized
+ * This greatly enhances performance of gray_fillrect() and gray_drawgraymap()
+ * for larger rectangles and graymaps */
+void grayblock(int x, int by, unsigned char* src, int stride)
+{
+ /* precalculate the bit patterns with random shifts (same RNG as graypixel,
+ * see there for an explanation) for all 8 pixels and put them on the
+ * stack (!) */
+ asm(
+ "mova .gb_reload,r0 \n" /* set default loopback address */
+ "tst %1,%1 \n" /* stride == 0 ? */
+ "bf .gb_needreload \n" /* no: keep that address */
+ "mova .gb_reuse,r0 \n" /* yes: set shortcut (no reload) */
+ ".gb_needreload: \n"
+ "mov r0,r2 \n" /* loopback address to r2 */
+ "mov #7,r3 \n" /* loop count in r3: 8 pixels */
+
+ ".align 2 \n" /** load pattern for pixel **/
+ ".gb_reload: \n"
+ "mov.b @%0,r0 \n" /* load src byte */
+ "extu.b r0,r0 \n" /* extend unsigned */
+ "mulu %2,r0 \n" /* macl = byte * depth; */
+ "add %1,%0 \n" /* src += stride; */
+ "sts macl,r4 \n" /* r4 = macl; */
+ "add r4,r0 \n" /* byte += r4; */
+ "shlr8 r0 \n" /* byte >>= 8; */
+ "shll2 r0 \n"
+ "mov.l @(r0,%3),r4 \n" /* r4 = bitpattern[byte]; */
+
+ ".align 2 \n" /** RNG **/
+ ".gb_reuse: \n"
+ "mov.w @%4,r1 \n" /* load last value */
+ "mov #75,r0 \n"
+ "mulu r0,r1 \n" /* multiply by 75 */
+ "sts macl,r1 \n"
+ "add #74,r1 \n" /* add another 74 */
+ "mov.w r1,@%4 \n" /* store new value */
+ /* Since the lower bits are not very random: */
+ "shlr8 r1 \n" /* get bits 8..15 (need max. 5) */
+ "and %5,r1 \n" /* mask out unneeded bits */
+
+ "cmp/hs %2,r1 \n" /* random >= depth ? */
+ "bf .gb_ntrim \n"
+ "sub %2,r1 \n" /* yes: random -= depth; */
+ ".gb_ntrim: \n"
+
+ "mov.l .ashlsi3,r0 \n" /** rotate pattern **/
+ "jsr @r0 \n" /* shift r4 left by r1 */
+ "mov r1,r5 \n"
+
+ "mov %2,r5 \n"
+ "sub r1,r5 \n" /* r5 = depth - r1 */
+ "mov r0,r1 \n" /* last result stored in r1 */
+ "mov.l .lshrsi3,r0 \n"
+ "jsr @r0 \n" /* shift r4 right by r5 */
+ "nop \n"
+
+ "or r1,r0 \n" /* rotated_pattern = r0 | r1 */
+ "mov.l r0,@-r15 \n" /* push pattern */
+
+ "cmp/pl r3 \n" /* loop count > 0? */
+ "bf .gb_patdone \n" /* no: done */
+
+ "jmp @r2 \n" /* yes: loop */
+ "add #-1,r3 \n" /* decrease loop count */
+
+ ".align 2 \n"
+ ".ashlsi3: \n" /* C library routine: */
+ ".long ___ashlsi3 \n" /* shift r4 left by r5, return in r0 */
+ ".lshrsi3: \n" /* C library routine: */
+ ".long ___lshrsi3 \n" /* shift r4 right by r5, return in r0 */
+ /* both routines preserve r4, destroy r5 and take ~16 cycles */
+
+ ".gb_patdone: \n"
+ : /* outputs */
+ : /* inputs */
+ /* %0 */ "r"(src),
+ /* %1 */ "r"(stride),
+ /* %2 */ "r"(graybuf->depth),
+ /* %3 */ "r"(graybuf->bitpattern),
+ /* %4 */ "r"(&gray_random_buffer),
+ /* %5 */ "r"(graybuf->randmask)
+ : /* clobbers */
+ "r0", "r1", "r2", "r3", "r4", "r5", "macl"
+ );
+
+ /* calculate start address in first bitplane and end address */
+ register unsigned char *address = graybuf->data + x
+ + MULU16(graybuf->width, by);
+ register unsigned char *end_addr = address
+ + MULU16(graybuf->depth, graybuf->plane_size);
+
+ /* set the bits for all 8 pixels in all bytes according to the
+ * precalculated patterns on the stack */
+ asm (
+ "mov.l @r15+,r1 \n" /* pop all 8 patterns */
+ "mov.l @r15+,r2 \n"
+ "mov.l @r15+,r3 \n"
+ "mov.l @r15+,r4 \n"
+ "mov.l @r15+,r5 \n"
+ "mov.l @r15+,r6 \n"
+ "mov.l @r15+,r7 \n"
+ "mov.l @r15+,r8 \n"
+
+ ".gb_loop: \n" /* loop for all bitplanes */
+ "shlr r1 \n" /* rotate lsb of pattern 1 to t bit */
+ "rotcl r0 \n" /* rotate t bit into r0 */
+ "shlr r2 \n"
+ "rotcl r0 \n"
+ "shlr r3 \n"
+ "rotcl r0 \n"
+ "shlr r4 \n"
+ "rotcl r0 \n"
+ "shlr r5 \n"
+ "rotcl r0 \n"
+ "shlr r6 \n"
+ "rotcl r0 \n"
+ "shlr r7 \n"
+ "rotcl r0 \n"
+ "shlr r8 \n"
+ "rotcl r0 \n"
+ "mov.b r0,@%0 \n" /* store byte to bitplane */
+ "add %2,%0 \n" /* advance to next bitplane */
+ "cmp/hi %0,%1 \n" /* last bitplane done? */
+ "bt .gb_loop \n" /* no: loop */
+ : /* outputs */
+ : /* inputs */
+ /* %0 */ "r"(address),
+ /* %1 */ "r"(end_addr),
+ /* %2 */ "r"(graybuf->plane_size)
+ : /* clobbers */
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8"
+ );
+}
+
/* Invert the bits for 1-8 pixels within the buffer */
void grayinvertmasked(int x, int by, unsigned char mask)
{
@@ -335,7 +474,9 @@ int gray_init_buffer(unsigned char *gbuf, int gbuf_size, int width,
int possible_depth, plane_size;
int i, j;
- if (width > LCD_WIDTH || bheight > (LCD_HEIGHT >> 3) || depth < 1)
+ if ((unsigned) width > LCD_WIDTH
+ || (unsigned) bheight > (LCD_HEIGHT >> 3)
+ || depth < 1)
return 0;
while ((unsigned long)gbuf & 3) /* the buffer has to be long aligned */
@@ -472,7 +613,7 @@ void gray_show_display(bool enable)
if (enable)
{
graybuf->flags |= GRAY_RUNNING;
- rb->plugin_register_timer(FREQ / 67, 1, timer_isr);
+ rb->plugin_register_timer(FREQ / 67, 1, gray_timer_isr);
}
else
{
@@ -532,7 +673,7 @@ void gray_clear_display(void)
if (graybuf == NULL)
return;
- rb->memset(graybuf->data, 0, graybuf->depth * graybuf->plane_size);
+ rb->memset(graybuf->data, 0, MULU16(graybuf->depth, graybuf->plane_size));
}
/* Set the grayscale display to all black
@@ -542,7 +683,7 @@ void gray_black_display(void)
if (graybuf == NULL)
return;
- rb->memset(graybuf->data, 0xFF, graybuf->depth * graybuf->plane_size);
+ rb->memset(graybuf->data, 0xFF, MULU16(graybuf->depth, graybuf->plane_size));
}
/* Do a lcd_update() to show changes done by rb->lcd_xxx() functions (in areas
@@ -566,11 +707,11 @@ void gray_deferred_update(void)
*/
void gray_scroll_left(int count, bool black_border)
{
- int x, by, d;
- unsigned char *src, *dest;
+ int by, d;
+ unsigned char *ptr;
unsigned char filler;
- if (graybuf == NULL || count >= graybuf->width)
+ if (graybuf == NULL || (unsigned) count >= (unsigned) graybuf->width)
return;
if (black_border)
@@ -581,17 +722,42 @@ void gray_scroll_left(int count, bool black_border)
/* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
for (by = 0; by < graybuf->bheight; by++)
{
+ ptr = graybuf->data + MULU16(graybuf->width, by);
for (d = 0; d < graybuf->depth; d++)
- {
- dest = graybuf->data + graybuf->plane_size * d
- + graybuf->width * by;
- src = dest + count;
-
- for (x = count; x < graybuf->width; x++)
- *dest++ = *src++;
-
- for (x = 0; x < count; x++)
- *dest++ = filler;
+ {
+ if (count & 1) /* odd count: scroll byte-wise */
+ asm volatile (
+ ".sl_loop1: \n"
+ "mov.b @%0+,r1 \n"
+ "mov.b r1,@(%2,%0) \n"
+ "cmp/hi %0,%1 \n"
+ "bt .sl_loop1 \n"
+ : /* outputs */
+ : /* inputs */
+ /* %0 */ "r"(ptr + count),
+ /* %1 */ "r"(ptr + graybuf->width),
+ /* %2 */ "z"(-count - 1)
+ : /* clobbers */
+ "r1"
+ );
+ else /* even count: scroll word-wise */
+ asm volatile (
+ ".sl_loop2: \n"
+ "mov.w @%0+,r1 \n"
+ "mov.w r1,@(%2,%0) \n"
+ "cmp/hi %0,%1 \n"
+ "bt .sl_loop2 \n"
+ : /* outputs */
+ : /* inputs */
+ /* %0 */ "r"(ptr + count),
+ /* %1 */ "r"(ptr + graybuf->width),
+ /* %2 */ "z"(-count - 2)
+ : /* clobbers */
+ "r1"
+ );
+
+ rb->memset(ptr + graybuf->width - count, filler, count);
+ ptr += graybuf->plane_size;
}
}
}
@@ -603,11 +769,11 @@ void gray_scroll_left(int count, bool black_border)
*/
void gray_scroll_right(int count, bool black_border)
{
- int x, by, d;
- unsigned char *src, *dest;
+ int by, d;
+ unsigned char *ptr;
unsigned char filler;
- if (graybuf == NULL || count >= graybuf->width)
+ if (graybuf == NULL || (unsigned) count >= (unsigned) graybuf->width)
return;
if (black_border)
@@ -618,17 +784,42 @@ void gray_scroll_right(int count, bool black_border)
/* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
for (by = 0; by < graybuf->bheight; by++)
{
+ ptr = graybuf->data + MULU16(graybuf->width, by);
for (d = 0; d < graybuf->depth; d++)
{
- dest = graybuf->data + graybuf->plane_size * d
- + graybuf->width * (by + 1) - 1;
- src = dest - count;
-
- for (x = count; x < graybuf->width; x++)
- *dest-- = *src--;
-
- for (x = 0; x < count; x++)
- *dest-- = filler;
+ if (count & 1) /* odd count: scroll byte-wise */
+ asm volatile (
+ ".sr_loop1: \n"
+ "mov.b @(%2,%0),r1 \n"
+ "mov.b r1,@-%0 \n"
+ "cmp/hs %1,%0 \n"
+ "bt .sr_loop1 \n"
+ : /* outputs */
+ : /* inputs */
+ /* %0 */ "r"(ptr + graybuf->width),
+ /* %1 */ "r"(ptr + count),
+ /* %2 */ "z"(-count - 1)
+ : /* clobbers */
+ "r1"
+ );
+ else /* even count: scroll word-wise */
+ asm volatile (
+ ".sr_loop2: \n"
+ "mov.w @(%2,%0),r1 \n"
+ "mov.w r1,@-%0 \n"
+ "cmp/hs %1,%0 \n"
+ "bt .sr_loop2 \n"
+ : /* outputs */
+ : /* inputs */
+ /* %0 */ "r"(ptr + graybuf->width),
+ /* %1 */ "r"(ptr + count),
+ /* %2 */ "z"(-count - 2)
+ : /* clobbers */
+ "r1"
+ );
+
+ rb->memset(ptr, filler, count);
+ ptr += graybuf->plane_size;
}
}
}
@@ -641,7 +832,7 @@ void gray_scroll_right(int count, bool black_border)
void gray_scroll_up8(bool black_border)
{
int by, d;
- unsigned char *src;
+ unsigned char *ptr;
unsigned char filler;
if (graybuf == NULL)
@@ -655,18 +846,19 @@ void gray_scroll_up8(bool black_border)
/* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
for (by = 1; by < graybuf->bheight; by++)
{
+ ptr = graybuf->data + MULU16(graybuf->width, by);
for (d = 0; d < graybuf->depth; d++)
{
- src = graybuf->data + graybuf->plane_size * d
- + graybuf->width * by;
-
- rb->memcpy(src - graybuf->width, src, graybuf->width);
+ rb->memcpy(ptr - graybuf->width, ptr, graybuf->width);
+ ptr += graybuf->plane_size;
}
}
- for (d = 0; d < graybuf->depth; d++) /* fill last row */
+ /* fill last row */
+ ptr = graybuf->data + graybuf->plane_size - graybuf->width;
+ for (d = 0; d < graybuf->depth; d++)
{
- rb->memset(graybuf->data + graybuf->plane_size * (d + 1)
- - graybuf->width, filler, graybuf->width);
+ rb->memset(ptr, filler, graybuf->width);
+ ptr += graybuf->plane_size;
}
}
@@ -678,7 +870,7 @@ void gray_scroll_up8(bool black_border)
void gray_scroll_down8(bool black_border)
{
int by, d;
- unsigned char *dest;
+ unsigned char *ptr;
unsigned char filler;
if (graybuf == NULL)
@@ -692,18 +884,19 @@ void gray_scroll_down8(bool black_border)
/* Scroll row by row to minimize flicker (byte rows = 8 pixels each) */
for (by = graybuf->bheight - 1; by > 0; by--)
{
+ ptr = graybuf->data + MULU16(graybuf->width, by);
for (d = 0; d < graybuf->depth; d++)
{
- dest = graybuf->data + graybuf->plane_size * d
- + graybuf->width * by;
-
- rb->memcpy(dest, dest - graybuf->width, graybuf->width);
+ rb->memcpy(ptr, ptr - graybuf->width, graybuf->width);
+ ptr += graybuf->plane_size;
}
}
- for (d = 0; d < graybuf->depth; d++) /* fill first row */
+ /* fill first row */
+ ptr = graybuf->data;
+ for (d = 0; d < graybuf->depth; d++)
{
- rb->memset(graybuf->data + graybuf->plane_size * d, filler,
- graybuf->width);
+ rb->memset(ptr, filler, graybuf->width);
+ ptr += graybuf->plane_size;
}
}
@@ -851,12 +1044,14 @@ void gray_scroll_down1(bool black_border)
*/
void gray_drawpixel(int x, int y, int brightness)
{
- if (graybuf == NULL || x >= graybuf->width || y >= graybuf->height
- || brightness > 255)
+ if (graybuf == NULL
+ || (unsigned) x >= (unsigned) graybuf->width
+ || (unsigned) y >= (unsigned) graybuf->height
+ || (unsigned) brightness > 255)
return;
- graypixel(x, y, graybuf->bitpattern[(brightness
- * (graybuf->depth + 1)) >> 8]);
+ graypixel(x, y, graybuf->bitpattern[MULU16(brightness,
+ graybuf->depth + 1) >> 8]);
}
/* Invert a pixel
@@ -866,7 +1061,9 @@ void gray_drawpixel(int x, int y, int brightness)
*/
void gray_invertpixel(int x, int y)
{
- if (graybuf == NULL || x >= graybuf->width || y >= graybuf->height)
+ if (graybuf == NULL
+ || (unsigned) x >= (unsigned) graybuf->width
+ || (unsigned) y >= (unsigned) graybuf->height)
return;
grayinvertmasked(x, (y >> 3), 1 << (y & 7));
@@ -886,14 +1083,20 @@ void gray_drawline(int x1, int y1, int x2, int y2, int brightness)
int y, yinc1, yinc2;
unsigned long pattern;
- if (graybuf == NULL || x1 >= graybuf->width || y1 >= graybuf->height
- || x2 >= graybuf->width || y2 >= graybuf->height|| brightness > 255)
+ if (graybuf == NULL
+ || (unsigned) x1 >= (unsigned) graybuf->width
+ || (unsigned) y1 >= (unsigned) graybuf->height
+ || (unsigned) x2 >= (unsigned) graybuf->width
+ || (unsigned) y2 >= (unsigned) graybuf->height
+ || (unsigned) brightness > 255)
return;
- pattern = graybuf->bitpattern[(brightness * (graybuf->depth + 1)) >> 8];
+ pattern = graybuf->bitpattern[MULU16(brightness, graybuf->depth + 1) >> 8];
deltax = abs(x2 - x1);
deltay = abs(y2 - y1);
+ xinc2 = 1;
+ yinc2 = 1;
if (deltax >= deltay)
{
@@ -902,9 +1105,7 @@ void gray_drawline(int x1, int y1, int x2, int y2, int brightness)
dinc1 = deltay * 2;
dinc2 = (deltay - deltax) * 2;
xinc1 = 1;
- xinc2 = 1;
yinc1 = 0;
- yinc2 = 1;
}
else
{
@@ -913,9 +1114,7 @@ void gray_drawline(int x1, int y1, int x2, int y2, int brightness)
dinc1 = deltax * 2;
dinc2 = (deltax - deltay) * 2;
xinc1 = 0;
- xinc2 = 1;
yinc1 = 1;
- yinc2 = 1;
}
numpixels++; /* include endpoints */
@@ -967,12 +1166,17 @@ void gray_invertline(int x1, int y1, int x2, int y2)
int x, xinc1, xinc2;
int y, yinc1, yinc2;
- if (graybuf == NULL || x1 >= graybuf->width || y1 >= graybuf->height
- || x2 >= graybuf->width || y2 >= graybuf->height)
+ if (graybuf == NULL
+ || (unsigned) x1 >= (unsigned) graybuf->width
+ || (unsigned) y1 >= (unsigned) graybuf->height
+ || (unsigned) x2 >= (unsigned) graybuf->width
+ || (unsigned) y2 >= (unsigned) graybuf->height)
return;
deltax = abs(x2 - x1);
deltay = abs(y2 - y1);
+ xinc2 = 1;
+ yinc2 = 1;
if (deltax >= deltay)
{
@@ -981,9 +1185,7 @@ void gray_invertline(int x1, int y1, int x2, int y2)
dinc1 = deltay * 2;
dinc2 = (deltay - deltax) * 2;
xinc1 = 1;
- xinc2 = 1;
yinc1 = 0;
- yinc2 = 1;
}
else
{
@@ -992,9 +1194,7 @@ void gray_invertline(int x1, int y1, int x2, int y2)
dinc1 = deltax * 2;
dinc2 = (deltax - deltay) * 2;
xinc1 = 0;
- xinc2 = 1;
yinc1 = 1;
- yinc2 = 1;
}
numpixels++; /* include endpoints */
@@ -1041,13 +1241,16 @@ void gray_drawrect(int x1, int y1, int x2, int y2, int brightness)
{
int x, y;
unsigned long pattern;
-
- if (graybuf == NULL || x1 >= graybuf->width || y1 >= graybuf->height
- || x2 >= graybuf->width || y2 >= graybuf->height|| brightness > 255)
+ unsigned char srcpixel;
+
+ if (graybuf == NULL
+ || (unsigned) x1 >= (unsigned) graybuf->width
+ || (unsigned) y1 >= (unsigned) graybuf->height
+ || (unsigned) x2 >= (unsigned) graybuf->width
+ || (unsigned) y2 >= (unsigned) graybuf->height
+ || (unsigned) brightness > 255)
return;
- pattern = graybuf->bitpattern[(brightness * (graybuf->depth + 1)) >> 8];
-
if (y1 > y2)
{
y = y1;
@@ -1061,15 +1264,30 @@ void gray_drawrect(int x1, int y1, int x2, int y2, int brightness)
x2 = x;
}
- for (x = x1; x <= x2; x++)
+ pattern = graybuf->bitpattern[MULU16(brightness, graybuf->depth + 1) >> 8];
+ srcpixel = brightness;
+
+ for (x = x1 + 1; x < x2; x++)
{
graypixel(x, y1, pattern);
graypixel(x, y2, pattern);
}
- for (y = y1; y <= y2; y++)
+ for (y = y1; y <= y2; )
{
- graypixel(x1, y, pattern);
- graypixel(x2, y, pattern);
+ if (!(y & 7) && (y2 - y >= 7))
+ /* current row byte aligned in fb & at least 8 rows left */
+ {
+ /* shortcut: draw all 8 rows at once: 2..3 times faster */
+ grayblock(x1, y >> 3, &srcpixel, 0);
+ grayblock(x2, y >> 3, &srcpixel, 0);
+ y += 8;
+ }
+ else
+ {
+ graypixel(x1, y, pattern);
+ graypixel(x2, y, pattern);
+ y++;
+ }
}
}
@@ -1082,9 +1300,14 @@ void gray_fillrect(int x1, int y1, int x2, int y2, int brightness)
{
int x, y;
unsigned long pattern;
-
- if (graybuf == NULL || x1 >= graybuf->width || y1 >= graybuf->height
- || x2 >= graybuf->width || y2 >= graybuf->height || brightness > 255)
+ unsigned char srcpixel;
+
+ if (graybuf == NULL
+ || (unsigned) x1 >= (unsigned) graybuf->width
+ || (unsigned) y1 >= (unsigned) graybuf->height
+ || (unsigned) x2 >= (unsigned) graybuf->width
+ || (unsigned) y2 >= (unsigned) graybuf->height
+ || (unsigned) brightness > 255)
return;
if (y1 > y2)
@@ -1100,13 +1323,28 @@ void gray_fillrect(int x1, int y1, int x2, int y2, int brightness)
x2 = x;
}
- pattern = graybuf->bitpattern[(brightness * (graybuf->depth + 1)) >> 8];
+ pattern = graybuf->bitpattern[MULU16(brightness, graybuf->depth + 1) >> 8];
+ srcpixel = brightness;
- for (y = y1; y <= y2; y++)
+ for (y = y1; y <= y2; )
{
- for (x = x1; x <= x2; x++)
+ if (!(y & 7) && (y2 - y >= 7))
+ /* current row byte aligned in fb & at least 8 rows left */
{
- graypixel(x, y, pattern);
+ for (x = x1; x <= x2; x++)
+ {
+ /* shortcut: draw all 8 rows at once: 2..3 times faster */
+ grayblock(x, y >> 3, &srcpixel, 0);
+ }
+ y += 8;
+ }
+ else
+ {
+ for (x = x1; x <= x2; x++)
+ {
+ graypixel(x, y, pattern);
+ }
+ y++;
}
}
}
@@ -1122,8 +1360,11 @@ void gray_invertrect(int x1, int y1, int x2, int y2)
int x, yb, yb1, yb2;
unsigned char mask;
- if (graybuf == NULL || x1 >= graybuf->width || y1 >= graybuf->height
- || x2 >= graybuf->width || y2 >= graybuf->height)
+ if (graybuf == NULL
+ || (unsigned) x1 >= (unsigned) graybuf->width
+ || (unsigned) y1 >= (unsigned) graybuf->height
+ || (unsigned) x2 >= (unsigned) graybuf->width
+ || (unsigned) y2 >= (unsigned) graybuf->height)
return;
if (y1 > y2)
@@ -1175,7 +1416,7 @@ void gray_invertrect(int x1, int y1, int x2, int y2)
* A grayscale bitmap contains one byte for every pixel that defines the
* brightness of the pixel (0..255). Bytes are read in row-major order.
* The <stride> parameter is useful if you want to show only a part of a
- * bitmap. It should always be set to the "line length" of the bitmap, so
+ * bitmap. It should always be set to the "row length" of the bitmap, so
* for displaying the whole bitmap, nx == stride.
*/
void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny,
@@ -1184,7 +1425,9 @@ void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny,
int xi, yi;
unsigned char *row;
- if (graybuf == NULL || x >= graybuf->width || y >= graybuf->height)
+ if (graybuf == NULL
+ || (unsigned) x >= (unsigned) graybuf->width
+ || (unsigned) y >= (unsigned) graybuf->height)
return;
if ((y + ny) >= graybuf->height) /* clip bottom */
@@ -1193,28 +1436,49 @@ void gray_drawgraymap(unsigned char *src, int x, int y, int nx, int ny,
if ((x + nx) >= graybuf->width) /* clip right */
nx = graybuf->width - x;
- for (yi = y; yi < y + ny; yi++)
+ for (yi = y; yi < y + ny; )
{
- row = src;
- src += stride;
- for (xi = x; xi < x + nx; xi++)
+ row = src;
+
+ if (!(yi & 7) && (y + ny - yi > 7))
+ /* current row byte aligned in fb & at least 8 rows left */
+ {
+ for (xi = x; xi < x + nx; xi++)
+ {
+ /* shortcut: draw all 8 rows at once: 2..3 times faster */
+ grayblock(xi, yi >> 3, row++, stride);
+ }
+ yi += 8;
+ src += stride << 3;
+ }
+ else
{
- graypixel(xi, yi, graybuf->bitpattern[((int)(*row++)
- * (graybuf->depth + 1)) >> 8]);
+ for (xi = x; xi < x + nx; xi++)
+ {
+ graypixel(xi, yi, graybuf->bitpattern[MULU16(*row++,
+ graybuf->depth + 1) >> 8]);
+ }
+ yi++;
+ src += stride;
}
}
}
/* Display a bitmap with specific foreground and background gray values
*
+ * This (now) uses the same bitmap format as the core b&w graphics routines,
+ * so you can use bmp2rb to generate bitmaps for use with this function as
+ * well.
+ *
* A bitmap contains one bit for every pixel that defines if that pixel is
- * foreground (1) or background (0). Bytes are read in row-major order, MSB
- * first. A row consists of an integer number of bytes, extra bits past the
- * right margin are ignored.
+ * foreground (1) or background (0). Bits within a byte are arranged
+ * vertically, LSB at top.
+ * The bytes are stored in row-major order, with byte 0 being top left,
+ * byte 1 2nd from left etc. The first row of bytes defines pixel rows
+ * 0..7, the second row defines pixel row 8..15 etc.
+ *
* The <stride> parameter is useful if you want to show only a part of a
- * bitmap. It should always be set to the "line length" of the bitmap.
- * Beware that this is counted in bytes, so nx == 8 * stride for the whole
- * bitmap.
+ * bitmap. It should always be set to the "row length" of the bitmap.
*
* If draw_bg is false, only foreground pixels are drawn, so the background
* is transparent. In this case bg_brightness is ignored.
@@ -1223,51 +1487,54 @@ void gray_drawbitmap(unsigned char *src, int x, int y, int nx, int ny,
int stride, bool draw_bg, int fg_brightness,
int bg_brightness)
{
- int xi, yi, i;
+ int xi, dy;
+ int bits = 0; /* Have to initialize to prevent warning */
unsigned long fg_pattern, bg_pattern;
- unsigned long bits = 0; /* Have to initialize to prevent warning */
- unsigned char *row;
+ unsigned char *col;
- if (graybuf == NULL || x >= graybuf->width || y >= graybuf->height
- || fg_brightness > 255 || bg_brightness > 255)
+ if (graybuf == NULL
+ || (unsigned) x >= (unsigned) graybuf->width
+ || (unsigned) y >= (unsigned) graybuf->height
+ || (unsigned) fg_brightness > 255
+ || (unsigned) bg_brightness > 255)
return;
-
+
if ((y + ny) >= graybuf->height) /* clip bottom */
ny = graybuf->height - y;
if ((x + nx) >= graybuf->width) /* clip right */
nx = graybuf->width - x;
- fg_pattern = graybuf->bitpattern[(fg_brightness
- * (graybuf->depth + 1)) >> 8];
+ fg_pattern = graybuf->bitpattern[MULU16(fg_brightness,
+ graybuf->depth + 1) >> 8];
- bg_pattern = graybuf->bitpattern[(bg_brightness
- * (graybuf->depth + 1)) >> 8];
+ bg_pattern = graybuf->bitpattern[MULU16(bg_brightness,
+ graybuf->depth + 1) >> 8];
- for (yi = y; yi < y + ny; yi++)
+ for (xi = x; xi < x + nx; xi++)
{
- i = 0;
- row = src;
- src += stride;
- for (xi = x; xi < x + nx; xi++)
+ col = src++;
+ for (dy = 0; dy < ny; dy++)
{
- if (i == 0) /* get next 8 bits */
- bits = (unsigned long)(*row++);
+ if (!(dy & 7)) /* get next 8 bits */
+ {
+ bits = (int)(*col);
+ col += stride;
+ }
- if (bits & 0x80)
- graypixel(xi, yi, fg_pattern);
+ if (bits & 0x01)
+ graypixel(xi, y + dy, fg_pattern);
else
if (draw_bg)
- graypixel(xi, yi, bg_pattern);
+ graypixel(xi, y + dy, bg_pattern);
- bits <<= 1;
- i++;
- i &= 7;
+ bits >>= 1;
}
}
}
-/**************** end grayscale framework ********************/
+/*********************** end grayscale framework ***************************/
+
/* for portability of below JPEG code */
#define MEMSET(p,v,c) rb->memset(p,v,c)