lcd: Fix certain drawmode combinations.

Some seldomly used drawmode combinations did not work in conjunction with
alpha bitmaps and backdrops. Now all should work (see comment added) by using
more bits.

Change-Id: I2bc96ecf471fa8c1a608a321a235b9c8527b3dc5
This commit is contained in:
Thomas Martitz 2013-12-28 14:27:18 +01:00
parent 17a1867c9c
commit a17a7038c2
2 changed files with 64 additions and 35 deletions

View file

@ -623,7 +623,7 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
/* Use extra bit to avoid if () in the switch-cases below */ /* Use extra bit to avoid if () in the switch-cases below */
if ((drmode & DRMODE_BG) && lcd_backdrop) if ((drmode & DRMODE_BG) && lcd_backdrop)
drmode |= DRMODE_INT_MOD; drmode |= DRMODE_INT_BD;
/* go through each column and update each pixel */ /* go through each column and update each pixel */
do do
@ -659,7 +659,7 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
while (--row); while (--row);
break; break;
case DRMODE_BG|DRMODE_INT_MOD: case DRMODE_BG|DRMODE_INT_BD:
bo = lcd_backdrop_offset; bo = lcd_backdrop_offset;
do do
{ {
@ -698,7 +698,7 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
while (--row); while (--row);
break; break;
case DRMODE_SOLID|DRMODE_INT_MOD: case DRMODE_SOLID|DRMODE_INT_BD:
fg = current_vp->fg_pattern; fg = current_vp->fg_pattern;
bo = lcd_backdrop_offset; bo = lcd_backdrop_offset;
do do
@ -817,7 +817,6 @@ static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image,
int stride_image, int stride_src) int stride_image, int stride_src)
{ {
fb_data *dst, *dst_row; fb_data *dst, *dst_row;
const fb_data *image_row;
unsigned dmask = 0x00000000; unsigned dmask = 0x00000000;
int drmode = current_vp->drawmode; int drmode = current_vp->drawmode;
/* nothing to draw? */ /* nothing to draw? */
@ -878,21 +877,33 @@ static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image,
height = LCD_HEIGHT - y; height = LCD_HEIGHT - y;
#endif #endif
/* the following drawmode combinations are possible:
* 1) COMPLEMENT: just negates the framebuffer contents
* 2) BG and BG+backdrop: draws _only_ background pixels with either
* the background color or the backdrop (if any). The backdrop
* is an image in native lcd format
* 3) FG and FG+image: draws _only_ foreground pixels with either
* the foreground color or an image buffer. The image is in
* native lcd format
* 4) SOLID, SOLID+backdrop, SOLID+image, SOLID+backdrop+image, i.e. all
* possible combinations of 2) and 3). Draws both, fore- and background,
* pixels. The rules of 2) and 3) apply.
*
* INVERSEVID swaps fore- and background pixels, i.e. background pixels
* become foreground ones and vice versa.
*/
if (drmode & DRMODE_INVERSEVID) if (drmode & DRMODE_INVERSEVID)
{ {
dmask = 0xffffffff; dmask = 0xffffffff;
drmode &= DRMODE_SOLID; /* mask out inversevid */ drmode &= DRMODE_SOLID; /* mask out inversevid */
} }
if (drmode == DRMODE_BG)
dmask = ~dmask; /* Use extra bits to avoid if () in the switch-cases below */
/* If drawmode is FG use a separate special case that blends the image
* onto the current framebuffer contents. Otherwise BG is forced that
* blends the image with the backdrop (if any, otherwise background color )*/
if (image != NULL) if (image != NULL)
drmode = (drmode == DRMODE_FG) ? DRMODE_FG|DRMODE_INT_MOD : DRMODE_BG; drmode |= DRMODE_INT_IMG;
/* Use extra bit to avoid if () in the switch-cases below */
if ((drmode & DRMODE_BG) && lcd_backdrop) if ((drmode & DRMODE_BG) && lcd_backdrop)
drmode |= DRMODE_INT_MOD; drmode |= DRMODE_INT_BD;
dst_row = FBADDR(x, y); dst_row = FBADDR(x, y);
@ -918,10 +929,11 @@ static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image,
#ifdef ALPHA_BITMAP_READ_WORDS #ifdef ALPHA_BITMAP_READ_WORDS
pixels = 8 - pixels; pixels = 8 - pixels;
#endif #endif
if (image)
image += skip_start_image;
image_row = image;
/* image is only accessed in DRMODE_INT_IMG cases, i.e. when non-NULL.
* Therefore NULL accesses are impossible and we can increment
* unconditionally (applies for stride at the end of the loop as well) */
image += skip_start_image;
/* go through the rows and update each pixel */ /* go through the rows and update each pixel */
do do
{ {
@ -929,16 +941,10 @@ static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image,
* temp vars just before the loop helps gcc to opimize the loop better * temp vars just before the loop helps gcc to opimize the loop better
* (testing showed ~15% speedup) */ * (testing showed ~15% speedup) */
unsigned fg, bg; unsigned fg, bg;
uintptr_t bo; ptrdiff_t bo, img_offset;
col = width; col = width;
dst = dst_row; dst = dst_row;
dst_row += ROW_INC; dst_row += ROW_INC;
if (image_row) {
image = image_row;
image_row += STRIDE_MAIN(stride_image,1);
}
else
image = dst;
#ifdef ALPHA_BITMAP_READ_WORDS #ifdef ALPHA_BITMAP_READ_WORDS
#define UPDATE_SRC_ALPHA do { \ #define UPDATE_SRC_ALPHA do { \
if (--pixels) \ if (--pixels) \
@ -964,8 +970,7 @@ static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image,
data = *(++src) ^ dmask; \ data = *(++src) ^ dmask; \
} while (0) } while (0)
#endif #endif
/* we don't want to have this in our inner
* loop and the codesize increase is minimal */
switch (drmode) switch (drmode)
{ {
case DRMODE_COMPLEMENT: case DRMODE_COMPLEMENT:
@ -978,12 +983,12 @@ static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image,
} }
while (--col); while (--col);
break; break;
case DRMODE_BG|DRMODE_INT_MOD: case DRMODE_BG|DRMODE_INT_BD:
bo = lcd_backdrop_offset; bo = lcd_backdrop_offset;
do do
{ {
fb_data c = *(fb_data *)((uintptr_t)dst + bo); fb_data c = *(fb_data *)((uintptr_t)dst + bo);
*dst = blend_two_colors(c, *image, data & ALPHA_COLOR_LOOKUP_SIZE ); *dst = blend_two_colors(c, *dst, data & ALPHA_COLOR_LOOKUP_SIZE );
dst += COL_INC; dst += COL_INC;
image += STRIDE_MAIN(1, stride_image); image += STRIDE_MAIN(1, stride_image);
UPDATE_SRC_ALPHA; UPDATE_SRC_ALPHA;
@ -994,19 +999,18 @@ static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image,
bg = current_vp->bg_pattern; bg = current_vp->bg_pattern;
do do
{ {
*dst = blend_two_colors(bg, *image, data & ALPHA_COLOR_LOOKUP_SIZE ); *dst = blend_two_colors(bg, *dst, data & ALPHA_COLOR_LOOKUP_SIZE );
dst += COL_INC; dst += COL_INC;
image += STRIDE_MAIN(1, stride_image);
UPDATE_SRC_ALPHA; UPDATE_SRC_ALPHA;
} }
while (--col); while (--col);
break; break;
case DRMODE_FG|DRMODE_INT_MOD: case DRMODE_FG|DRMODE_INT_IMG:
img_offset = image - dst;
do do
{ {
*dst = blend_two_colors(*dst, *image, data & ALPHA_COLOR_LOOKUP_SIZE ); *dst = blend_two_colors(*dst, *(dst + img_offset), data & ALPHA_COLOR_LOOKUP_SIZE );
dst += COL_INC; dst += COL_INC;
image += STRIDE_MAIN(1, stride_image);
UPDATE_SRC_ALPHA; UPDATE_SRC_ALPHA;
} }
while (--col); while (--col);
@ -1021,7 +1025,7 @@ static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image,
} }
while (--col); while (--col);
break; break;
case DRMODE_SOLID|DRMODE_INT_MOD: case DRMODE_SOLID|DRMODE_INT_BD:
bo = lcd_backdrop_offset; bo = lcd_backdrop_offset;
fg = current_vp->fg_pattern; fg = current_vp->fg_pattern;
do do
@ -1033,13 +1037,35 @@ static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image,
} }
while (--col); while (--col);
break; break;
case DRMODE_SOLID|DRMODE_INT_IMG:
bg = current_vp->bg_pattern;
img_offset = image - dst;
do
{
*dst = blend_two_colors(bg, *(dst + img_offset), data & ALPHA_COLOR_LOOKUP_SIZE );
dst += COL_INC;
UPDATE_SRC_ALPHA;
}
while (--col);
break;
case DRMODE_SOLID|DRMODE_INT_BD|DRMODE_INT_IMG:
bo = lcd_backdrop_offset;
img_offset = image - dst;
do
{
fb_data *c = (fb_data *)((uintptr_t)dst + bo);
*dst = blend_two_colors(*c, *(dst + img_offset), data & ALPHA_COLOR_LOOKUP_SIZE );
dst += COL_INC;
UPDATE_SRC_ALPHA;
}
while (--col);
break;
case DRMODE_SOLID: case DRMODE_SOLID:
bg = current_vp->bg_pattern; bg = current_vp->bg_pattern;
fg = current_vp->fg_pattern; fg = current_vp->fg_pattern;
do do
{ {
*dst = blend_two_colors(bg, fg, *dst = blend_two_colors(bg, fg, data & ALPHA_COLOR_LOOKUP_SIZE );
data & ALPHA_COLOR_LOOKUP_SIZE );
dst += COL_INC; dst += COL_INC;
UPDATE_SRC_ALPHA; UPDATE_SRC_ALPHA;
} }
@ -1073,6 +1099,8 @@ static void ICODE_ATTR lcd_alpha_bitmap_part_mix(const fb_data* image,
data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT; data >>= skip_end * ALPHA_COLOR_LOOKUP_SHIFT;
} }
#endif #endif
image += STRIDE_MAIN(stride_image,1);
} while (--row); } while (--row);
BLEND_FINISH; BLEND_FINISH;

View file

@ -287,7 +287,8 @@ extern void lcd_jump_scroll_delay(int ms);
#define DRMODE_SOLID 3 #define DRMODE_SOLID 3
#define DRMODE_INVERSEVID 4 /* used as bit modifier for basic modes */ #define DRMODE_INVERSEVID 4 /* used as bit modifier for basic modes */
/* Internal drawmode modifiers. DO NOT use with set_drawmode() */ /* Internal drawmode modifiers. DO NOT use with set_drawmode() */
#define DRMODE_INT_MOD 8 #define DRMODE_INT_BD 8
#define DRMODE_INT_IMG 16
/* Low-level drawing function types */ /* Low-level drawing function types */
typedef void lcd_pixelfunc_type(int x, int y); typedef void lcd_pixelfunc_type(int x, int y);