From a9f5dedc517e86c3785234d8632bb5c726000c8a Mon Sep 17 00:00:00 2001 From: patacongo Date: Sat, 9 Jul 2011 16:01:00 +0000 Subject: [PATCH] Redesign of NXTEXT font cache git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3761 42af7a65-404d-4744-a932-0658087f49c3 --- examples/nxtext/nxtext_bkgd.c | 20 +- examples/nxtext/nxtext_internal.h | 24 +- examples/nxtext/nxtext_popup.c | 2 +- examples/nxtext/nxtext_putc.c | 412 ++++++++++++++++++------------ 4 files changed, 273 insertions(+), 185 deletions(-) diff --git a/examples/nxtext/nxtext_bkgd.c b/examples/nxtext/nxtext_bkgd.c index ee6640bcc..abf170a75 100644 --- a/examples/nxtext/nxtext_bkgd.c +++ b/examples/nxtext/nxtext_bkgd.c @@ -161,8 +161,8 @@ static void nxbg_position(NXWINDOW hwnd, FAR const struct nxgl_size_s *size, /* Save the window limits (these should be the same for all places and all windows */ - g_xres = bounds->pt2.x; - g_yres = bounds->pt2.y; + g_xres = bounds->pt2.x + 1; + g_yres = bounds->pt2.y + 1; b_haveresolution = true; sem_post(&g_semevent); @@ -202,7 +202,6 @@ static void nxbg_kbdin(NXWINDOW hwnd, uint8_t nch, FAR const uint8_t *ch, static void nxbg_scroll(NXWINDOW hwnd, int lineheight) { - struct nxgl_rect_s rect; int i; int j; @@ -220,7 +219,7 @@ static void nxbg_scroll(NXWINDOW hwnd, int lineheight) /* Has any part of this character scrolled off the screen? */ - if (bm->bounds.pt1.y < lineheight) + if (bm->pos.y < lineheight) { /* Yes... Delete the character by moving all of the data */ @@ -242,10 +241,9 @@ static void nxbg_scroll(NXWINDOW hwnd, int lineheight) else { - bm->bounds.pt1.y -= lineheight; - bm->bounds.pt2.y -= lineheight; + bm->pos.y -= lineheight; - /* Increment to the next character */ + /* We are keeping this one so increment to the next character */ i++; } @@ -258,11 +256,7 @@ static void nxbg_scroll(NXWINDOW hwnd, int lineheight) /* Then re-draw the entire display */ - rect.pt1.x = 0; - rect.pt1.y = 0; - rect.pt2.x = g_bgstate.wsize.w - 1; - rect.pt2.y = g_bgstate.wsize.h - 1; - nxbg_redrawrect(hwnd, &rect); + nxbg_redrawrect(hwnd, NULL); } /**************************************************************************** @@ -375,7 +369,7 @@ void nxbg_redrawrect(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect) nxtext_home(&g_bgstate); for (i = 0; i < g_bgstate.nchars; i++) { - nxtext_fillchar(hwnd, rect, &g_bgstate.bm[i]); + nxtext_fillchar(hwnd, rect, &g_bgstate, &g_bgstate.bm[i]); } } diff --git a/examples/nxtext/nxtext_internal.h b/examples/nxtext/nxtext_internal.h index 7494c31af..fe3cf549f 100644 --- a/examples/nxtext/nxtext_internal.h +++ b/examples/nxtext/nxtext_internal.h @@ -111,11 +111,7 @@ #endif #ifndef CONFIG_EXAMPLES_NXTEXT_GLCACHE -# if CONFIG_NXFONTS_CHARBITS < 8 -# define CONFIG_EXAMPLES_NXTEXT_GLCACHE MIN(CONFIG_EXAMPLES_NXTEXT_BMCACHE, 128) -# else -# define CONFIG_EXAMPLES_NXTEXT_GLCACHE MIN(CONFIG_EXAMPLES_NXTEXT_BMCACHE, 256) -# endif +# define CONFIG_EXAMPLES_NXTEXT_BMCACHE 16 #endif #ifdef CONFIG_NX_MULTIUSER @@ -168,6 +164,16 @@ # endif #endif +/* Bitmap flags */ + +#define BMFLAGS_NOGLYPH (1 << 0) /* No glyph available, use space */ + +#define BM_ISSPACE(bm) (((bm)->flags & BMFLAGS_NOGLYPH) != 0) + +/* Sizes and maximums */ + +#define MAX_USECNT 255 + /**************************************************************************** * Public Types ****************************************************************************/ @@ -202,6 +208,7 @@ struct nxtext_glyph_s uint8_t height; /* Height of this glyph (in rows) */ uint8_t width; /* Width of this glyph (in pixels) */ uint8_t stride; /* Width of the glyph row (in bytes) */ + uint8_t usecnt; /* Use count */ FAR uint8_t *bitmap; /* Allocated bitmap memory */ }; @@ -209,8 +216,9 @@ struct nxtext_glyph_s struct nxtext_bitmap_s { - struct nxgl_rect_s bounds; /* Size/position of bitmap */ - FAR const struct nxtext_glyph_s *glyph; /* The cached glyph */ + uint8_t code; /* Character code */ + uint8_t flags; /* See BMFLAGS_* */ + struct nxgl_point_s pos; /* Character position */ }; /* Describes the state of one text display */ @@ -236,7 +244,6 @@ struct nxtext_state_s uint16_t maxchars; /* Size of the mb array */ uint8_t maxglyphs; /* Size of the glyph array */ uint8_t nchars; /* Number of chars already displayed */ - uint8_t nglyphs; /* Number of glyphs cached */ FAR struct nxtext_bitmap_s *bm; /* List of characters on the display */ FAR struct nxtext_glyph_s *glyph; /* Cache of rendered fonts in use */ @@ -301,6 +308,7 @@ extern void nxtext_newline(FAR struct nxtext_state_s *st); extern void nxtext_putc(NXWINDOW hwnd, FAR struct nxtext_state_s *st, uint8_t ch); extern void nxtext_fillchar(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect, + FAR struct nxtext_state_s *st, FAR const struct nxtext_bitmap_s *bm); #endif /* __EXAMPLES_NXTEXT_NXTEXT_INTERNAL_H */ diff --git a/examples/nxtext/nxtext_popup.c b/examples/nxtext/nxtext_popup.c index ea2306286..4ee704652 100644 --- a/examples/nxtext/nxtext_popup.c +++ b/examples/nxtext/nxtext_popup.c @@ -196,7 +196,7 @@ static inline void nxpu_fillwindow(NXWINDOW hwnd, nxtext_home(st); for (i = 0; i < st->nchars; i++) { - nxtext_fillchar(hwnd, rect, &st->bm[i]); + nxtext_fillchar(hwnd, rect, st, &st->bm[i]); } #endif } diff --git a/examples/nxtext/nxtext_putc.c b/examples/nxtext/nxtext_putc.c index b3fa1c0bc..90170e113 100644 --- a/examples/nxtext/nxtext_putc.c +++ b/examples/nxtext/nxtext_putc.c @@ -103,7 +103,122 @@ * Name: nxtext_renderglyph ****************************************************************************/ -static inline FAR const struct nxtext_glyph_s * +static void nxtext_freeglyph(FAR struct nxtext_glyph_s *glyph) +{ + if (glyph->bitmap) + { + free(glyph->bitmap); + } + memset(glyph, 0, sizeof(struct nxtext_glyph_s)); +} + +/**************************************************************************** + * Name: nxtext_allocglyph + ****************************************************************************/ + +static inline FAR struct nxtext_glyph_s * +nxtext_allocglyph(FAR struct nxtext_state_s *st) +{ + FAR struct nxtext_glyph_s *glyph = NULL; + FAR struct nxtext_glyph_s *luglyph = NULL; + uint8_t luusecnt; + int i; + + /* Search through the glyph cache looking for an unused glyph. Also, keep + * track of the least used glyph as well. We need that if we have to replace + * a glyph in the cache. + */ + + for (i = 0; i < st->maxglyphs; i++) + { + /* Is this glyph in use? */ + + glyph = &st->glyph[i]; + if (!glyph->usecnt) + { + /* No.. return this glyph with a use count of one */ + + glyph->usecnt = 1; + return glyph; + } + + /* Yes.. check for the least recently used */ + + if (!luglyph || glyph->usecnt < luglyph->usecnt) + { + luglyph = glyph; + } + } + + /* If we get here, the glyph cache is full. We replace the least used + * glyph with the one we need now. (luglyph can't be NULL). + */ + + luusecnt = luglyph->usecnt; + nxtext_freeglyph(luglyph); + + /* But lets decrement all of the usecnts so that the new one one be so + * far behind in the counts as the older ones. + */ + + if (luusecnt > 1) + { + uint8_t decr = luusecnt - 1; + + for (i = 0; i < st->maxglyphs; i++) + { + /* Is this glyph in use? */ + + glyph = &st->glyph[i]; + if (glyph->usecnt > decr) + { + glyph->usecnt -= decr; + } + } + } + + /* Then return the least used glyph */ + + luglyph->usecnt = 1; + return luglyph; +} + +/**************************************************************************** + * Name: nxtext_findglyph + ****************************************************************************/ + +static FAR struct nxtext_glyph_s * +nxtext_findglyph(FAR struct nxtext_state_s *st, uint8_t ch) +{ + int i; + + /* First, try to find the glyph in the cache of pre-rendered glyphs */ + + for (i = 0; i < st->maxglyphs; i++) + { + FAR struct nxtext_glyph_s *glyph = &st->glyph[i]; + if (glyph->usecnt > 0 && glyph->code == ch) + { + /* Increment the use count (unless it is already at the max) */ + + if (glyph->usecnt < MAX_USECNT) + { + glyph->usecnt++; + } + + /* And return the glyph that we found */ + + return glyph; + } + } + return NULL; +} + +/**************************************************************************** + * Name: nxtext_renderglyph + ****************************************************************************/ + +static inline FAR struct nxtext_glyph_s * nxtext_renderglyph(FAR struct nxtext_state_s *st, FAR const struct nx_fontbitmap_s *bm, uint8_t ch) { @@ -120,182 +235,116 @@ nxtext_renderglyph(FAR struct nxtext_state_s *st, /* Make sure that there is room for another glyph */ message("nxtext_renderglyph: ch=%02x\n", ch); - if (st->nglyphs < st->maxglyphs) + + /* Allocate the glyph (always succeeds) */ + + glyph = nxtext_allocglyph(st); + glyph->code = ch; + + /* Get the dimensions of the glyph */ + + glyph->width = bm->metric.width + bm->metric.xoffset; + glyph->height = bm->metric.height + bm->metric.yoffset; + + /* Allocate memory to hold the glyph with its offsets */ + + glyph->stride = (glyph->width * CONFIG_EXAMPLES_NXTEXT_BPP + 7) / 8; + bmsize = glyph->stride * glyph->height; + glyph->bitmap = (FAR uint8_t *)malloc(bmsize); + + if (glyph->bitmap) { - /* Allocate the glyph */ - - glyph = &st->glyph[st->nglyphs]; - glyph->code = ch; - - /* Get the dimensions of the glyph */ - - glyph->width = bm->metric.width + bm->metric.xoffset; - glyph->height = bm->metric.height + bm->metric.yoffset; - - /* Allocate memory to hold the glyph with its offsets */ - - glyph->stride = (glyph->width * CONFIG_EXAMPLES_NXTEXT_BPP + 7) / 8; - bmsize = glyph->stride * glyph->height; - glyph->bitmap = (FAR uint8_t *)malloc(bmsize); - - if (glyph->bitmap) - { - /* Initialize the glyph memory to the background color */ + /* Initialize the glyph memory to the background color */ #if CONFIG_EXAMPLES_NXTEXT_BPP < 8 - pixel = st->wcolor[0]; + pixel = st->wcolor[0]; # if CONFIG_EXAMPLES_NXTEXT_BPP == 1 - /* Pack 1-bit pixels into a 2-bits */ + /* Pack 1-bit pixels into a 2-bits */ - pixel &= 0x01; - pixel = (pixel) << 1 |pixel; + pixel &= 0x01; + pixel = (pixel) << 1 |pixel; # endif # if CONFIG_EXAMPLES_NXTEXT_BPP < 4 - /* Pack 2-bit pixels into a nibble */ + /* Pack 2-bit pixels into a nibble */ - pixel &= 0x03; - pixel = (pixel) << 2 |pixel; + pixel &= 0x03; + pixel = (pixel) << 2 |pixel; # endif - /* Pack 4-bit nibbles into a byte */ + /* Pack 4-bit nibbles into a byte */ - pixel &= 0x0f; - pixel = (pixel) << 4 | pixel; + pixel &= 0x0f; + pixel = (pixel) << 4 | pixel; - ptr = (FAR nxgl_mxpixel_t *)glyph->bitmap; - for (row = 0; row < glyph->height; row++) + ptr = (FAR nxgl_mxpixel_t *)glyph->bitmap; + for (row = 0; row < glyph->height; row++) + { + for (col = 0; col < glyph->stride; col++) { - for (col = 0; col < glyph->stride; col++) - { - /* Transfer the packed bytes into the buffer */ + /* Transfer the packed bytes into the buffer */ - *ptr++ = pixel; - } + *ptr++ = pixel; } + } #elif CONFIG_EXAMPLES_NXTEXT_BPP == 24 # error "Additional logic is needed here for 24bpp support" #else /* CONFIG_EXAMPLES_NXTEXT_BPP = {8,16,32} */ - ptr = (FAR nxgl_mxpixel_t *)glyph->bitmap; - for (row = 0; row < glyph->height; row++) - { - /* Just copy the color value into the glyph memory */ + ptr = (FAR nxgl_mxpixel_t *)glyph->bitmap; + for (row = 0; row < glyph->height; row++) + { + /* Just copy the color value into the glyph memory */ - for (col = 0; col < glyph->width; col++) - { - *ptr++ = st->wcolor[0]; - } + for (col = 0; col < glyph->width; col++) + { + *ptr++ = st->wcolor[0]; } + } #endif - /* Then render the glyph into the allocated memory */ + /* Then render the glyph into the allocated memory */ - ret = RENDERER((FAR nxgl_mxpixel_t*)glyph->bitmap, - glyph->height, glyph->width, glyph->stride, - bm, st->fcolor[0]); - if (ret < 0) - { - /* Actually, the RENDERER never returns a failure */ - - message("nxtext_renderglyph: RENDERER failed\n"); - free(glyph->bitmap); - glyph->bitmap = NULL; - glyph = NULL; - } - else - { - /* Make it permanent */ - - st->nglyphs++; - } - } - } - - return glyph; -} - -/**************************************************************************** - * Name: nxtext_addspace - ****************************************************************************/ - -static inline FAR const struct nxtext_glyph_s * -nxtext_addspace(FAR struct nxtext_state_s *st, uint8_t ch) -{ - FAR struct nxtext_glyph_s *glyph = NULL; - - /* Make sure that there is room for another glyph */ - - if (st->nglyphs < st->maxglyphs) - { - /* Allocate the NULL glyph */ - - glyph = &st->glyph[st->nglyphs]; - memset(glyph, 0, sizeof(struct nxtext_glyph_s)); - - glyph->code = ' '; - glyph->width = st->spwidth; - - st->nglyphs++; - } - return glyph; -} - -/**************************************************************************** - * Name: nxtext_findglyph - ****************************************************************************/ - -static FAR const struct nxtext_glyph_s * -nxtext_findglyph(FAR struct nxtext_state_s *st, uint8_t ch) -{ - int i; - - /* First, try to find the glyph in the cache of pre-rendered glyphs */ - - for (i = 0; i < st->nglyphs; i++) - { - if (st->glyph[i].code == ch) + ret = RENDERER((FAR nxgl_mxpixel_t*)glyph->bitmap, + glyph->height, glyph->width, glyph->stride, + bm, st->fcolor[0]); + if (ret < 0) { - return &st->glyph[i]; + /* Actually, the RENDERER never returns a failure */ + + message("nxtext_renderglyph: RENDERER failed\n"); + nxtext_freeglyph(glyph); + glyph = NULL; } } - return NULL; + + return glyph; } /**************************************************************************** * Name: nxtext_getglyph ****************************************************************************/ -static FAR const struct nxtext_glyph_s * +static FAR struct nxtext_glyph_s * nxtext_getglyph(FAR struct nxtext_state_s *st, uint8_t ch) { - FAR const struct nxtext_glyph_s *glyph; - FAR const struct nx_fontbitmap_s *bm; + FAR struct nxtext_glyph_s *glyph; + FAR const struct nx_fontbitmap_s *fbm; /* First, try to find the glyph in the cache of pre-rendered glyphs */ glyph = nxtext_findglyph(st, ch); if (!glyph) { - /* No, it is not cached... Does the code map to a glyph? */ + /* No, it is not cached... Does the code map to a font? */ - bm = nxf_getbitmap(ch); - if (!bm) + fbm = nxf_getbitmap(ch); + if (fbm) { - /* No, there is no glyph for this code. Use space */ + /* Yes.. render the glyph */ - glyph = nxtext_findglyph(st, ' '); - if (!glyph) - { - /* There isn't fake glyph for ' ' yet... create one */ - - glyph = nxtext_addspace(st, ' '); - } - } - else - { - glyph = nxtext_renderglyph(st, bm, ch); + glyph = nxtext_renderglyph(st, fbm, ch); } } @@ -304,50 +353,52 @@ nxtext_getglyph(FAR struct nxtext_state_s *st, uint8_t ch) /**************************************************************************** * Name: nxtext_addchar + * + * Description: + * This is part of the nxtext_putc logic. It creates and positions a + * the character and renders (or re-uses) a glyph for font. + * ****************************************************************************/ static FAR const struct nxtext_bitmap_s * nxtext_addchar(FAR struct nxtext_state_s *st, uint8_t ch) { FAR struct nxtext_bitmap_s *bm = NULL; - FAR struct nxtext_bitmap_s *bmleft; + FAR struct nxtext_glyph_s *glyph; /* Is there space for another character on the display? */ if (st->nchars < st->maxchars) { - /* Yes, setup the bitmap */ + /* Yes, setup the bitmap information */ - bm = &st->bm[st->nchars]; + bm = &st->bm[st->nchars]; + bm->code = ch; + bm->flags = 0; + bm->pos.x = st->fpos.x; + bm->pos.y = st->fpos.y; - /* Find the matching glyph */ + /* Find (or create) the matching glyph */ - bm->glyph = nxtext_getglyph(st, ch); - if (!bm->glyph) + glyph = nxtext_getglyph(st, ch); + if (!glyph) { - return NULL; - } + /* No, there is no font for this code. Just mark this as a space. */ - /* Set up the bounds for the bitmap */ + bm->flags |= BMFLAGS_NOGLYPH; - if (st->nchars <= 0) - { - /* The first character is one space from the left */ + /* Set up the next character position */ - st->fpos.x = st->spwidth; + st->fpos.x += st->spwidth; } else { - /* Otherwise, it is to the left of the preceding char */ + /* Set up the next character position */ - bmleft = &st->bm[st->nchars-1]; - st->fpos.x = bmleft->bounds.pt2.x + 1; + st->fpos.x += glyph->width; } - bm->bounds.pt1.x = st->fpos.x; - bm->bounds.pt1.y = st->fpos.y; - bm->bounds.pt2.x = st->fpos.x + bm->glyph->width - 1; - bm->bounds.pt2.y = st->fpos.y + bm->glyph->height - 1; + /* Success.. increment nchars to retain this character */ st->nchars++; } @@ -427,7 +478,7 @@ void nxtext_putc(NXWINDOW hwnd, FAR struct nxtext_state_s *st, uint8_t ch) bm = nxtext_addchar(st, ch); if (bm) { - nxtext_fillchar(hwnd, &bm->bounds, bm); + nxtext_fillchar(hwnd, NULL, st, bm); } } } @@ -442,28 +493,63 @@ void nxtext_putc(NXWINDOW hwnd, FAR struct nxtext_state_s *st, uint8_t ch) ****************************************************************************/ void nxtext_fillchar(NXWINDOW hwnd, FAR const struct nxgl_rect_s *rect, + FAR struct nxtext_state_s *st, FAR const struct nxtext_bitmap_s *bm) { - FAR const void *src = (FAR const void *)bm->glyph->bitmap; + FAR struct nxtext_glyph_s *glyph; + struct nxgl_rect_s bounds; struct nxgl_rect_s intersection; int ret; /* Handle the special case of spaces which have no glyph bitmap */ - if (src) + if (BM_ISSPACE(bm)) + { + return; + } + + /* Find (or create) the matching glyph */ + + glyph = nxtext_getglyph(st, bm->code); + if (!glyph) + { + /* This shouldn't happen */ + + return; + } + + /* Construct a bounding box for the glyph */ + + bounds.pt1.x = bm->pos.x; + bounds.pt1.y = bm->pos.y; + bounds.pt1.x = bm->pos.x + glyph->width - 1; + bounds.pt1.y = bm->pos.y + glyph->height - 1; + + /* Should this also be clipped to a region in the window? */ + + if (rect) { /* Get the intersection of the redraw region and the character bitmap */ - nxgl_rectintersect(&intersection, rect, &bm->bounds); - if (!nxgl_nullrect(&intersection)) + nxgl_rectintersect(&intersection, rect, &bounds); + } + else + { + /* The intersection is the whole glyph */ + + nxgl_rectcopy(&intersection, &bounds); + } + + /* Check for empty intersections */ + + if (!nxgl_nullrect(&intersection)) + { + FAR const void *src = (FAR const void *)glyph->bitmap; + ret = nx_bitmap((NXWINDOW)hwnd, &intersection, &src, + &bm->pos, (unsigned int)glyph->stride); + if (ret < 0) { - ret = nx_bitmap((NXWINDOW)hwnd, &intersection, &src, - &bm->bounds.pt1, - (unsigned int)bm->glyph->stride); - if (ret < 0) - { - message("nxtext_fillchar: nx_bitmapwindow failed: %d\n", errno); - } + message("nxtext_fillchar: nx_bitmapwindow failed: %d\n", errno); } } }