From dc05af64369e7aafff423ddeba5c0aa64fbc6060 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 5 Jan 2017 18:36:29 -0600 Subject: [PATCH 1/6] Graphics: Initial separation of font cache from graphics/nxterm. Now in libnx/nxfronts --- graphics/nxterm/nxterm.h | 38 +- graphics/nxterm/nxterm_font.c | 341 +-------------- graphics/nxterm/nxterm_putc.c | 2 +- graphics/nxterm/nxterm_register.c | 31 +- graphics/nxterm/nxterm_unregister.c | 28 +- include/nuttx/nx/nxfonts.h | 104 +++++ libnx/nxfonts/Make.defs | 2 +- libnx/nxfonts/nxfonts_cache.c | 639 ++++++++++++++++++++++++++++ 8 files changed, 796 insertions(+), 389 deletions(-) create mode 100644 libnx/nxfonts/nxfonts_cache.c diff --git a/graphics/nxterm/nxterm.h b/graphics/nxterm/nxterm.h index 326a2ed5f9b..49eded0c884 100644 --- a/graphics/nxterm/nxterm.h +++ b/graphics/nxterm/nxterm.h @@ -1,7 +1,7 @@ /**************************************************************************** * nuttx/graphics/nxterm/nxterm.h * - * Copyright (C) 2012, 2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2012, 2014, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -33,8 +33,8 @@ * ****************************************************************************/ -#ifndef __GRAPHICS_NXTERM_NXTERM_INTERNAL_H -#define __GRAPHICS_NXTERM_NXTERM_INTERNAL_H +#ifndef __GRAPHICS_NXTERM_NXTERM_H +#define __GRAPHICS_NXTERM_NXTERM_H /**************************************************************************** * Included Files @@ -61,10 +61,6 @@ #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 /* Limit to range of a uint8_t */ - /* Device path formats */ #define NX_DEVNAME_FORMAT "/dev/nxterm%d" @@ -81,6 +77,7 @@ /**************************************************************************** * Public Types ****************************************************************************/ + /* Identifies the state of the VT100 escape sequence processing */ enum nxterm_vt100state_e @@ -111,18 +108,6 @@ struct nxterm_operations_s unsigned int stride); }; -/* Describes one cached glyph bitmap */ - -struct nxterm_glyph_s -{ - uint8_t code; /* Character code */ - 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 */ -}; - /* Describes on character on the display */ struct nxterm_bitmap_s @@ -138,8 +123,7 @@ struct nxterm_state_s { FAR const struct nxterm_operations_s *ops; /* Window operations */ FAR void *handle; /* The window handle */ - FAR struct nxterm_window_s wndo; /* Describes the window and font */ - NXHANDLE font; /* The current font handle */ + FAR struct nxterm_window_s wndo; /* Describes the window and font */ sem_t exclsem; /* Forces mutually exclusive access */ #ifdef CONFIG_DEBUG_FEATURES pid_t holder; /* Deadlock avoidance */ @@ -151,7 +135,6 @@ struct nxterm_state_s uint8_t fheight; /* Max height of a font in pixels */ uint8_t fwidth; /* Max width of a font in pixels */ uint8_t spwidth; /* The width of a space */ - uint8_t maxglyphs; /* Size of the glyph[] array */ uint16_t maxchars; /* Size of the bm[] array */ uint16_t nchars; /* Number of chars in the bm[] array */ @@ -165,13 +148,10 @@ struct nxterm_state_s /* Font cache data storage */ + FCACHE fcache; /* Font cache handle */ struct nxterm_bitmap_s cursor; struct nxterm_bitmap_s bm[CONFIG_NXTERM_MXCHARS]; - /* Glyph cache data storage */ - - struct nxterm_glyph_s glyph[CONFIG_NXTERM_CACHESIZE]; - /* Keyboard input support */ #ifdef CONFIG_NXTERM_NXKBDIN @@ -235,8 +215,8 @@ enum nxterm_vt100state_e nxterm_vt100(FAR struct nxterm_state_s *priv, char ch); void nxterm_home(FAR struct nxterm_state_s *priv); void nxterm_newline(FAR struct nxterm_state_s *priv); -FAR const struct nxterm_bitmap_s *nxterm_addchar(NXHANDLE hfont, - FAR struct nxterm_state_s *priv, uint8_t ch); +FAR const struct nxterm_bitmap_s *nxterm_addchar(FAR struct nxterm_state_s *priv, + uint8_t ch); int nxterm_hidechar(FAR struct nxterm_state_s *priv, FAR const struct nxterm_bitmap_s *bm); int nxterm_backspace(FAR struct nxterm_state_s *priv); @@ -251,4 +231,4 @@ void nxterm_hidecursor(FAR struct nxterm_state_s *priv); void nxterm_scroll(FAR struct nxterm_state_s *priv, int scrollheight); -#endif /* __GRAPHICS_NXTERM_NXTERM_INTERNAL_H */ +#endif /* __GRAPHICS_NXTERM_NXTERM_H */ diff --git a/graphics/nxterm/nxterm_font.c b/graphics/nxterm/nxterm_font.c index b3e95d220de..4b0c2c4fd2d 100644 --- a/graphics/nxterm/nxterm_font.c +++ b/graphics/nxterm/nxterm_font.c @@ -48,294 +48,26 @@ #include "nxterm.h" -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* Select renderer -- Some additional logic would be required to support - * pixel depths that are not directly addressable (1,2,4, and 24). - */ - -#if CONFIG_NXTERM_BPP == 1 -# define RENDERER nxf_convert_1bpp -#elif CONFIG_NXTERM_BPP == 2 -# define RENDERER nxf_convert_2bpp -#elif CONFIG_NXTERM_BPP == 4 -# define RENDERER nxf_convert_4bpp -#elif CONFIG_NXTERM_BPP == 8 -# define RENDERER nxf_convert_8bpp -#elif CONFIG_NXTERM_BPP == 16 -# define RENDERER nxf_convert_16bpp -#elif CONFIG_NXTERM_BPP == 24 -# define RENDERER nxf_convert_24bpp -#elif CONFIG_NXTERM_BPP == 32 -# define RENDERER nxf_convert_32bpp -#else -# error "Unsupported CONFIG_NXTERM_BPP" -#endif - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - /**************************************************************************** * Private Functions ****************************************************************************/ -/**************************************************************************** - * Name: nxterm_freeglyph - ****************************************************************************/ - -static void nxterm_freeglyph(FAR struct nxterm_glyph_s *glyph) -{ - if (glyph->bitmap) - { - kmm_free(glyph->bitmap); - } - memset(glyph, 0, sizeof(struct nxterm_glyph_s)); -} - -/**************************************************************************** - * Name: nxterm_allocglyph - ****************************************************************************/ - -static inline FAR struct nxterm_glyph_s * -nxterm_allocglyph(FAR struct nxterm_state_s *priv) -{ - FAR struct nxterm_glyph_s *glyph = NULL; - FAR struct nxterm_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 < priv->maxglyphs; i++) - { - /* Is this glyph in use? */ - - glyph = &priv->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; - nxterm_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 < priv->maxglyphs; i++) - { - /* Is this glyph in use? */ - - glyph = &priv->glyph[i]; - if (glyph->usecnt > decr) - { - glyph->usecnt -= decr; - } - } - } - - /* Then return the least used glyph */ - - luglyph->usecnt = 1; - return luglyph; -} - -/**************************************************************************** - * Name: nxterm_findglyph - ****************************************************************************/ - -static FAR struct nxterm_glyph_s * -nxterm_findglyph(FAR struct nxterm_state_s *priv, uint8_t ch) -{ - int i; - - /* First, try to find the glyph in the cache of pre-rendered glyphs */ - - for (i = 0; i < priv->maxglyphs; i++) - { - FAR struct nxterm_glyph_s *glyph = &priv->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: nxterm_renderglyph - ****************************************************************************/ - -static inline FAR struct nxterm_glyph_s * -nxterm_renderglyph(FAR struct nxterm_state_s *priv, - FAR const struct nx_fontbitmap_s *fbm, uint8_t ch) -{ - FAR struct nxterm_glyph_s *glyph = NULL; - FAR nxgl_mxpixel_t *ptr; -#if CONFIG_NXTERM_BPP < 8 - nxgl_mxpixel_t pixel; -#endif - int bmsize; - int row; - int col; - int ret; - - /* Allocate the glyph (always succeeds) */ - - glyph = nxterm_allocglyph(priv); - glyph->code = ch; - - /* Get the dimensions of the glyph */ - - glyph->width = fbm->metric.width + fbm->metric.xoffset; - glyph->height = fbm->metric.height + fbm->metric.yoffset; - - /* Get the physical width of the glyph in bytes */ - - glyph->stride = (glyph->width * CONFIG_NXTERM_BPP + 7) / 8; - - /* Allocate memory to hold the glyph with its offsets */ - - bmsize = glyph->stride * glyph->height; - glyph->bitmap = (FAR uint8_t *)kmm_malloc(bmsize); - - if (glyph->bitmap) - { - /* Initialize the glyph memory to the background color using the - * hard-coded bits-per-pixel (BPP). - * - * TODO: The rest of NX is configured to support multiple devices - * with differing BPP. They logic should be extended to support - * differing BPP's as well. - */ - -#if CONFIG_NXTERM_BPP < 8 - pixel = priv->wndo.wcolor[0]; - -# if CONFIG_NXTERM_BPP == 1 - - /* Pack 1-bit pixels into a 2-bits */ - - pixel &= 0x01; - pixel = (pixel) << 1 | pixel; - -# endif -# if CONFIG_NXTERM_BPP < 4 - - /* Pack 2-bit pixels into a nibble */ - - pixel &= 0x03; - pixel = (pixel) << 2 | pixel; - -# endif - - /* Pack 4-bit nibbles into a byte */ - - pixel &= 0x0f; - pixel = (pixel) << 4 | pixel; - - ptr = (FAR nxgl_mxpixel_t *)glyph->bitmap; - for (row = 0; row < glyph->height; row++) - { - for (col = 0; col < glyph->stride; col++) - { - /* Transfer the packed bytes into the buffer */ - - *ptr++ = pixel; - } - } - -#elif CONFIG_NXTERM_BPP == 24 -# error "Additional logic is needed here for 24bpp support" - -#else /* CONFIG_NXTERM_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 */ - - for (col = 0; col < glyph->width; col++) - { - *ptr++ = priv->wndo.wcolor[0]; - } - } -#endif - - /* Then render the glyph into the allocated memory */ - - ret = RENDERER((FAR nxgl_mxpixel_t *)glyph->bitmap, - glyph->height, glyph->width, glyph->stride, - fbm, priv->wndo.fcolor[0]); - if (ret < 0) - { - /* Actually, the RENDERER never returns a failure */ - - gerr("ERROR: nxterm_renderglyph: RENDERER failed\n"); - nxterm_freeglyph(glyph); - glyph = NULL; - } - } - - return glyph; -} - /**************************************************************************** * Name: nxterm_fontsize ****************************************************************************/ -static int nxterm_fontsize(NXHANDLE hfont, uint8_t ch, FAR struct nxgl_size_s *size) +static int nxterm_fontsize(FAR struct nxterm_state_s *priv, uint8_t ch, + FAR struct nxgl_size_s *size) { FAR const struct nx_fontbitmap_s *fbm; + NXHANDLE hfont; - /* No, it is not cached... Does the code map to a font? */ + /* Get the handle of the font managed by the font cache */ + + hfont = nxf_cache_getfonthandle(priv->fcache); + DEBUGASSERT(hfront != NULL); + + /* Does the character code map to a font? */ fbm = nxf_getbitmap(hfont, ch); if (fbm) @@ -347,40 +79,7 @@ static int nxterm_fontsize(NXHANDLE hfont, uint8_t ch, FAR struct nxgl_size_s *s return OK; } - return ERROR; -} - -/**************************************************************************** - * Name: nxterm_getglyph - ****************************************************************************/ - -static FAR struct nxterm_glyph_s * -nxterm_getglyph(NXHANDLE hfont, FAR struct nxterm_state_s *priv, uint8_t ch) -{ - FAR struct nxterm_glyph_s *glyph; - FAR const struct nx_fontbitmap_s *fbm; - - /* First, try to find the glyph in the cache of pre-rendered glyphs */ - - glyph = nxterm_findglyph(priv, ch); - if (glyph) - { - /* We found it in the cache .. return the cached glyph */ - - return glyph; - } - - /* No, it is not cached... Does the code map to a font? */ - - fbm = nxf_getbitmap(hfont, ch); - if (fbm) - { - /* Yes.. render the glyph */ - - glyph = nxterm_renderglyph(priv, fbm, ch); - } - - return glyph; + return -ENOENT; } /**************************************************************************** @@ -397,10 +96,10 @@ nxterm_getglyph(NXHANDLE hfont, FAR struct nxterm_state_s *priv, uint8_t ch) ****************************************************************************/ FAR const struct nxterm_bitmap_s * -nxterm_addchar(NXHANDLE hfont, FAR struct nxterm_state_s *priv, uint8_t ch) +nxterm_addchar(FAR struct nxterm_state_s *priv, uint8_t ch) { FAR struct nxterm_bitmap_s *bm = NULL; - FAR struct nxterm_glyph_s *glyph; + FAR struct nxfonts_glyph_s *glyph; /* Is there space for another character on the display? */ @@ -416,7 +115,7 @@ nxterm_addchar(NXHANDLE hfont, FAR struct nxterm_state_s *priv, uint8_t ch) /* Find (or create) the matching glyph */ - glyph = nxterm_getglyph(hfont, priv, ch); + glyph = nxf_cache_getglyph(priv->fcache, ch); if (!glyph) { /* No, there is no font for this code. Just mark this as a space. */ @@ -449,6 +148,7 @@ nxterm_addchar(NXHANDLE hfont, FAR struct nxterm_state_s *priv, uint8_t ch) * Erase a character from the window. * ****************************************************************************/ + int nxterm_hidechar(FAR struct nxterm_state_s *priv, FAR const struct nxterm_bitmap_s *bm) { @@ -461,7 +161,7 @@ int nxterm_hidechar(FAR struct nxterm_state_s *priv, * modification is required (not an error). */ - ret = nxterm_fontsize(priv->font, bm->code, &fsize); + ret = nxterm_fontsize(priv, bm->code, &fsize); if (ret < 0) { /* It was rendered as a space. */ @@ -572,10 +272,10 @@ void nxterm_newline(FAR struct nxterm_state_s *priv) ****************************************************************************/ void nxterm_fillchar(FAR struct nxterm_state_s *priv, - FAR const struct nxgl_rect_s *rect, - FAR const struct nxterm_bitmap_s *bm) + FAR const struct nxgl_rect_s *rect, + FAR const struct nxterm_bitmap_s *bm) { - FAR struct nxterm_glyph_s *glyph; + FAR struct nxfonts_glyph_s *glyph; struct nxgl_rect_s bounds; struct nxgl_rect_s intersection; struct nxgl_size_s fsize; @@ -590,7 +290,7 @@ void nxterm_fillchar(FAR struct nxterm_state_s *priv, /* Get the size of the font glyph (which may not have been created yet) */ - ret = nxterm_fontsize(priv->font, bm->code, &fsize); + ret = nxterm_fontsize(priv, bm->code, &fsize); if (ret < 0) { /* This would mean that there is no bitmap for the character code and @@ -632,7 +332,7 @@ void nxterm_fillchar(FAR struct nxterm_state_s *priv, /* Find (or create) the glyph that goes with this font */ - glyph = nxterm_getglyph(priv->font, priv, bm->code); + glyph = nxf_cache_getglyph(priv->fcache, bm->code); if (!glyph) { /* Shouldn't happen */ @@ -648,4 +348,3 @@ void nxterm_fillchar(FAR struct nxterm_state_s *priv, DEBUGASSERT(ret >= 0); } } - diff --git a/graphics/nxterm/nxterm_putc.c b/graphics/nxterm/nxterm_putc.c index b0479404caf..1aea8559ecf 100644 --- a/graphics/nxterm/nxterm_putc.c +++ b/graphics/nxterm/nxterm_putc.c @@ -142,7 +142,7 @@ void nxterm_putc(FAR struct nxterm_state_s *priv, uint8_t ch) * display. */ - bm = nxterm_addchar(priv->font, priv, ch); + bm = nxterm_addchar(priv, ch); if (bm) { nxterm_fillchar(priv, NULL, bm); diff --git a/graphics/nxterm/nxterm_register.c b/graphics/nxterm/nxterm_register.c index d1d99d16a43..087f6513e57 100644 --- a/graphics/nxterm/nxterm_register.c +++ b/graphics/nxterm/nxterm_register.c @@ -1,7 +1,7 @@ /**************************************************************************** * nuttx/graphics/nxterm/nxterm_register.c * - * Copyright (C) 2012, 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2012, 2016-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -66,7 +66,9 @@ FAR struct nxterm_state_s * FAR const struct nxterm_operations_s *ops, int minor) { FAR struct nxterm_state_s *priv; + FAR const struct nx_font_s *fontset; char devname[NX_DEVNAME_SIZE]; + NXHANDLE hfont; int ret; DEBUGASSERT(handle && wndo && ops && (unsigned)minor < 256); @@ -101,22 +103,32 @@ FAR struct nxterm_state_s * sem_setprotocol(&priv->waitsem, SEM_PRIO_NONE); #endif - /* Select the font */ + /* Connect to the font cache for the configured font characteristics */ - priv->font = nxf_getfonthandle(wndo->fontid); - if (!priv->font) + priv->fcache = nxf_cache_connect(wndo->fontid, wndo->fcolor[0], + wndo->wcolor[0], CONFIG_NXTERM_BPP); + if (priv->fcache == NULL) { - gerr("ERROR: Failed to get font ID %d: %d\n", wndo->fontid, errno); + gerr("ERROR: Failed to connect to font cache for font ID %d: %d\n", + wndo->fontid, errno); goto errout; } - FAR const struct nx_font_s *fontset; + /* Get the handle of the font managed by the font cache */ + + hfont = nxf_cache_getfonthandle(priv->fcache); + if (hfont == NULL) + { + gerr("ERROR: Failed to get handlr for font ID %d: %d\n", + wndo->fontid, errno); + goto errout; + } /* Get information about the font set being used and save this in the * state structure */ - fontset = nxf_getfontset(priv->font); + fontset = nxf_getfontset(hfont); priv->fheight = fontset->mxheight; priv->fwidth = fontset->mxwidth; priv->spwidth = fontset->spwidth; @@ -125,10 +137,6 @@ FAR struct nxterm_state_s * priv->maxchars = CONFIG_NXTERM_MXCHARS; - /* Set up the font glyph bitmap cache */ - - priv->maxglyphs = CONFIG_NXTERM_CACHESIZE; - /* Set the initial display position */ nxterm_home(priv); @@ -146,6 +154,7 @@ FAR struct nxterm_state_s * { gerr("ERROR: Failed to register %s\n", devname); } + return (NXTERM)priv; errout: diff --git a/graphics/nxterm/nxterm_unregister.c b/graphics/nxterm/nxterm_unregister.c index e51e44c1739..06ad4648817 100644 --- a/graphics/nxterm/nxterm_unregister.c +++ b/graphics/nxterm/nxterm_unregister.c @@ -50,22 +50,6 @@ #include "nxterm.h" -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -89,7 +73,6 @@ void nxterm_unregister(NXTERM handle) { FAR struct nxterm_state_s *priv; char devname[NX_DEVNAME_SIZE]; - int i; DEBUGASSERT(handle); @@ -101,16 +84,9 @@ void nxterm_unregister(NXTERM handle) sem_destroy(&priv->waitsem); #endif - /* Free all allocated glyph bitmap */ + /* Free the font cache */ - for (i = 0; i < CONFIG_NXTERM_CACHESIZE; i++) - { - FAR struct nxterm_glyph_s *glyph = &priv->glyph[i]; - if (glyph->bitmap) - { - kmm_free(glyph->bitmap); - } - } + nxf_cache_disconnect(priv->fcache); /* Unregister the driver */ diff --git a/include/nuttx/nx/nxfonts.h b/include/nuttx/nx/nxfonts.h index aca51a08749..8cca725e818 100644 --- a/include/nuttx/nx/nxfonts.h +++ b/include/nuttx/nx/nxfonts.h @@ -51,6 +51,7 @@ * Pre-processor definitions ****************************************************************************/ +/* Font Definitions *********************************************************/ /* Select the default font. If no fonts are selected, then a compilation * error is likely down the road. */ @@ -202,10 +203,16 @@ #endif +/* Font Cache Definitions (**************************************************/ +/* Limit to range of font cache usage count */ + +#define MAX_USECNT 255 /* Limit to range of a uint8_t */ + /**************************************************************************** * Public Types ****************************************************************************/ +/* Font Types ***************************************************************/ /* Font IDs */ enum nx_fontid_e @@ -453,6 +460,23 @@ struct nx_fontpackage_s #endif }; +/* Font Cache ***************************************************************/ +/* Opaque handle used to reference a font cache */ + +typedef FAR void *FCACHE; + +/* Describes one cached font glyph */ + +struct nxfonts_glyph_s +{ + uint8_t code; /* Character code */ + 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 */ +}; + /**************************************************************************** * Public Data ****************************************************************************/ @@ -480,6 +504,9 @@ extern "C" * Input Parameters: * fontid: Identifies the font set to get * + * Returned Value: + * One success, a non-NULL font handle is returned. + * ****************************************************************************/ NXHANDLE nxf_getfonthandle(enum nx_fontid_e fontid); @@ -564,6 +591,83 @@ int nxf_convert_32bpp(FAR uint32_t *dest, uint16_t height, FAR const struct nx_fontbitmap_s *bm, nxgl_mxpixel_t color); +/**************************************************************************** + * Name: nxf_cache_connect + * + * Description: + * Create a new font cache for the provided 'fontid'. If the cache + * already, then just increment a reference count return the handler for + * the existing font cache. + * + * Input Parameters: + * fontid - Identifies the font supported by this cache + * + * Returned value: + * On success a non-NULL handle is returned that then may sequently be + * used with nxf_getglyph() to extract fonts from the font cache. NULL + * returned on any failure with the errno value set to indicate the nature + * of the error. + * + ****************************************************************************/ + +FCACHE nxf_cache_connect(enum nx_fontid_e fontid, + nxgl_mxpixel_t fgcolor, nxgl_mxpixel_t bgcolor, + int bpp); + +/**************************************************************************** + * Name: nxf_cache_disconnect + * + * Description: + * Decrement the reference count on the font cache and, if the reference + * count goes to zero, free all resources used by the font cache. The + * font handler is invalid upon return in either case. + * + * Input Parameters: + * fcache - A font cache handler previously returned by nxf_cache_connect(); + * + * Returned value: + * None + * + ****************************************************************************/ + +void nxf_cache_disconnect(FCACHE fcache); + +/**************************************************************************** + * Name: nxf_cache_getfonthandle + * + * Description: + * Return the handle to the font set used by this instance of the font + * cache. + * + * Input Parameters: + * fcache - A font cache handle previously returned by nxf_cache_connect(); + * + * Returned value: + * Zero (OK) is returned if the metrics were + * + * Returned Value: + * One success, a non-NULL font handle is returned. + * + ****************************************************************************/ + +NXHANDLE nxf_cache_getfonthandle(FCACHE fcache); + +/**************************************************************************** + * Name: nxf_cache_getglyph + * + * Description: + * Get the font glyph for the character code 'ch' from the font cache. If + * the glyph for that character code does not exist in the font cache, it + * be rendered. + * + * Returned Value: + * On success, a non-NULL pointer to the rendered glyph in the font cache + * is returned. NULL is returned on any failure. + * + ****************************************************************************/ + +FAR struct nxfonts_glyph_s *nxf_cache_getglyph(FCACHE fcache, uint8_t ch); + #undef EXTERN #if defined(__cplusplus) } diff --git a/libnx/nxfonts/Make.defs b/libnx/nxfonts/Make.defs index 9403f08bdd6..fee5f77baa5 100644 --- a/libnx/nxfonts/Make.defs +++ b/libnx/nxfonts/Make.defs @@ -37,7 +37,7 @@ ifeq ($(CONFIG_NX),y) -CSRCS += nxfonts_getfont.c +CSRCS += nxfonts_getfont.c nxfonts_cache.c CSRCS += nxfonts_convert_1bpp.c nxfonts_convert_2bpp.c CSRCS += nxfonts_convert_4bpp.c nxfonts_convert_8bpp.c CSRCS += nxfonts_convert_16bpp.c nxfonts_convert_24bpp.c diff --git a/libnx/nxfonts/nxfonts_cache.c b/libnx/nxfonts/nxfonts_cache.c new file mode 100644 index 00000000000..f8222ab10f8 --- /dev/null +++ b/libnx/nxfonts/nxfonts_cache.c @@ -0,0 +1,639 @@ +/**************************************************************************** + * libnx/nxfonts/nxfonts_cache.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +/**************************************************************************** + * Private Types + ****************************************************************************/ +/* This describes a rendering function */ + +typedef CODE int (*nxf_renderer_t)(FAR nxgl_mxpixel_t *dest, uint16_t height, + uint16_t width, uint16_t stride, + FAR const struct nx_fontbitmap_s *bm, + nxgl_mxpixel_t color); + +/* This structure defines one font cache */ + +struct nxfonts_fcache_s +{ + FAR struct nxfonts_fcache_s *flink; /* Supports a singly linked list */ + NXHANDLE font; /* Font handle associated with fontid */ + sem_t fsem; /* Serializes access to the font cache */ + uint16_t fontid; /* ID of font in this cache */ + int16_t fclients; /* Number of connected clients */ + uint8_t maxglyphs; /* Size of glyph[] array */ + uint8_t bpp; /* Bits per pixel */ + nxgl_mxpixel_t fgcolor; /* Foreground color */ + nxgl_mxpixel_t bgcolor; /* Background color */ + nxf_renderer_t renderer; /* Font renderer */ + + /* Glyph cache data storage */ + + struct nxfonts_glyph_s glyph[CONFIG_NXTERM_CACHESIZE]; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Head of a list of font caches */ + +static FAR struct nxfonts_fcache_s *g_fcaches; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxf_freeglyph + ****************************************************************************/ + +static void nxf_freeglyph(FAR struct nxfonts_glyph_s *glyph) +{ + if (glyph->bitmap) + { + kmm_free(glyph->bitmap); + } + + memset(glyph, 0, sizeof(struct nxfonts_glyph_s)); +} + +/**************************************************************************** + * Name: nxf_allocglyph + ****************************************************************************/ + +static inline FAR struct nxfonts_glyph_s * +nxf_allocglyph(FAR struct nxfonts_fcache_s *priv) +{ + FAR struct nxfonts_glyph_s *glyph = NULL; + FAR struct nxfonts_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 < priv->maxglyphs; i++) + { + /* Is this glyph in use? */ + + glyph = &priv->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; + nxf_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 < priv->maxglyphs; i++) + { + /* Is this glyph in use? */ + + glyph = &priv->glyph[i]; + if (glyph->usecnt > decr) + { + glyph->usecnt -= decr; + } + } + } + + /* Then return the least used glyph */ + + luglyph->usecnt = 1; + return luglyph; +} + +/**************************************************************************** + * Name: nxf_findglyph + ****************************************************************************/ + +static FAR struct nxfonts_glyph_s * +nxf_findglyph(FAR struct nxfonts_fcache_s *priv, uint8_t ch) +{ + int i; + + /* First, try to find the glyph in the cache of pre-rendered glyphs */ + + for (i = 0; i < priv->maxglyphs; i++) + { + FAR struct nxfonts_glyph_s *glyph = &priv->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: nxf_renderglyph + ****************************************************************************/ + +static inline FAR struct nxfonts_glyph_s * +nxf_renderglyph(FAR struct nxfonts_fcache_s *priv, + FAR const struct nx_fontbitmap_s *fbm, uint8_t ch) +{ + FAR struct nxfonts_glyph_s *glyph = NULL; + FAR nxgl_mxpixel_t *ptr; +#if CONFIG_NXTERM_BPP < 8 + nxgl_mxpixel_t pixel; +#endif + int bmsize; + int row; + int col; + int ret; + + /* Allocate the glyph (always succeeds) */ + + glyph = nxf_allocglyph(priv); + glyph->code = ch; + + /* Get the dimensions of the glyph */ + + glyph->width = fbm->metric.width + fbm->metric.xoffset; + glyph->height = fbm->metric.height + fbm->metric.yoffset; + + /* Get the physical width of the glyph in bytes */ + + glyph->stride = (glyph->width * CONFIG_NXTERM_BPP + 7) / 8; + + /* Allocate memory to hold the glyph with its offsets */ + + bmsize = glyph->stride * glyph->height; + glyph->bitmap = (FAR uint8_t *)kmm_malloc(bmsize); + + if (glyph->bitmap) + { + /* Initialize the glyph memory to the background color using the + * hard-coded bits-per-pixel (BPP). + * + * TODO: The rest of NX is configured to support multiple devices + * with differing BPP. They logic should be extended to support + * differing BPP's as well. + */ + +#if CONFIG_NXTERM_BPP < 8 + pixel = priv->bgcolor; + +# if CONFIG_NXTERM_BPP == 1 + + /* Pack 1-bit pixels into a 2-bits */ + + pixel &= 0x01; + pixel = (pixel) << 1 | pixel; + +# endif +# if CONFIG_NXTERM_BPP < 4 + + /* Pack 2-bit pixels into a nibble */ + + pixel &= 0x03; + pixel = (pixel) << 2 | pixel; + +# endif + + /* Pack 4-bit nibbles into a byte */ + + pixel &= 0x0f; + pixel = (pixel) << 4 | pixel; + + ptr = (FAR nxgl_mxpixel_t *)glyph->bitmap; + for (row = 0; row < glyph->height; row++) + { + for (col = 0; col < glyph->stride; col++) + { + /* Transfer the packed bytes into the buffer */ + + *ptr++ = pixel; + } + } + +#elif CONFIG_NXTERM_BPP == 24 +# error "Additional logic is needed here for 24bpp support" + +#else /* CONFIG_NXTERM_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 */ + + for (col = 0; col < glyph->width; col++) + { + *ptr++ = priv->bgcolor; + } + } +#endif + + /* Then render the glyph into the allocated memory */ + + ret = priv->renderer((FAR nxgl_mxpixel_t *)glyph->bitmap, + glyph->height, glyph->width, glyph->stride, + fbm, priv->fgcolor); + if (ret < 0) + { + /* Actually, the renderer never returns a failure */ + + gerr("ERROR: nxf_renderglyph: Renderer failed\n"); + nxf_freeglyph(glyph); + glyph = NULL; + } + } + + return glyph; +} + +/**************************************************************************** + * Name: nxf_findcache + ****************************************************************************/ + +static FAR struct nxfonts_fcache_s * +nxf_findcache(enum nx_fontid_e fontid, nxgl_mxpixel_t fgcolor, + nxgl_mxpixel_t bgcolor, int bpp) +{ + FAR struct nxfonts_fcache_s *fcache; + + /* Get exclusive access to the font cache list */ +#warning Missing logic + + /* Search for a cache for this font characteristics */ + + for (fcache = g_fcaches; fcache != NULL; fcache = fcache->flink) + { + /* Does this font have the same characteristics? */ + + if (fcache->fontid == fontid && + fcache->fgcolor == fgcolor && + fcache->bgcolor == bgcolor && + fcache->bpp == bpp) + { + /* Yes... return it */ + + return fcache; + } + } + + return NULL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxf_cache_connect + * + * Description: + * Create a new font cache for the provided 'fontid'. If the cache + * already, then just increment a reference count return the handle for + * the existing font cache. + * + * Input Parameters: + * fontid - Identifies the font supported by this cache + * fgcolor - Foreground color + * bgcolor - Background color + * bpp - Bits per pixel + * + * Returned value: + * On success a non-NULL handle is returned that then may sequently be + * used with nxf_getglyph() to extract fonts from the font cache. NULL + * returned on any failure with the errno value set to indicate the nature + * of the error. + * + ****************************************************************************/ + +FCACHE nxf_cache_connect(enum nx_fontid_e fontid, + nxgl_mxpixel_t fgcolor, nxgl_mxpixel_t bgcolor, + int bpp) +{ + FAR struct nxfonts_fcache_s *priv; + int errcode; + + /* Find a font cache with the matching font characteristics */ + + priv = nxf_findcache(fontid, fgcolor, bgcolor, bpp); + if (priv == NULL) + { + /* There isn't one... we will have to create a new font cache for this + * client. + */ + + /* Allocate memory for the (empty) font cache */ + + priv = (FAR struct nxfonts_fcache_s *) + kmm_malloc(sizeof( struct nxfonts_fcache_s)); + + if (priv == NULL) + { + errcode = ENOMEM; + goto errout; + } + + /* Initialize the font cache */ + + priv->maxglyphs = CONFIG_NXTERM_CACHESIZE; + priv->fontid = fontid; + priv->fgcolor = fgcolor; + priv->bgcolor = bgcolor; + priv->bpp = bpp; + + /* Select the rendering function */ + + /* Select renderer -- Some additional logic would be required to + * support pixel depths that are not directly addressable (1,2,4, and + * 24). + */ + +#ifndef CONFIG_NX_DISABLE_1BPP + if (bpp == 1) + { + priv->renderer = (nxf_renderer_t)nxf_convert_1bpp; + } + else +#endif +#ifndef CONFIG_NX_DISABLE_2BPP + if (bpp == 2) + { + priv->renderer = (nxf_renderer_t)nxf_convert_2bpp; + } + else +#endif +#ifndef CONFIG_NX_DISABLE_4BPP + if (bpp == 4) + { + priv->renderer = (nxf_renderer_t)nxf_convert_4bpp; + } + else +#endif +#ifndef CONFIG_NX_DISABLE_8BPP + if (bpp == 8) + { + priv->renderer = (nxf_renderer_t)nxf_convert_8bpp; + } + else +#endif +#ifndef CONFIG_NX_DISABLE_16BPP + if (bpp == 16) + { + priv->renderer = (nxf_renderer_t)nxf_convert_16bpp; + } + else +#endif +#ifndef CONFIG_NX_DISABLE_24BPP + if (bpp == 24) + { + priv->renderer = (nxf_renderer_t)nxf_convert_24bpp; + } + else +#endif +#ifndef CONFIG_NX_DISABLE_32BPP + if (bpp == 32) + { + priv->renderer = (nxf_renderer_t)nxf_convert_32bpp; + } + else +#endif + { + gerr("ERROR: Unsupported pixel depth: %d\n", bpp); + errcode = ENOSYS; + goto errout_with_fcache; + } + + /* Select the font */ + + priv->font = nxf_getfonthandle(fontid); + if (priv->font == NULL) + { + errcode = get_errno(); + gerr("ERROR: Failed to get font ID %d: %d\n", fontid, errcode); + goto errout_with_fcache; + } + } + + return (FCACHE)priv; + +errout_with_fcache: + kmm_free(priv); +errout: + set_errno(errcode); + return NULL; +} + +/**************************************************************************** + * Name: nxf_cache_disconnect + * + * Description: + * Decrement the reference count on the font cache and, if the reference + * count goes to zero, free all resources used by the font cache. The + * font handle is invalid upon return in either case. + * + * Input Parameters: + * fcache - A font cache handle previously returned by nxf_cache_connect(); + * + * Returned value: + * None + * + ****************************************************************************/ + +void nxf_cache_disconnect(FCACHE fcache) +{ + FAR struct nxfonts_fcache_s *priv = (FAR struct nxfonts_fcache_s *)fcache; + int ret; + int i; + + DEBUGASSERT(priv != NULL && priv->fclients > 0); + + /* Get exclusive access to the font cache */ + + while ((ret = sem_wait(&priv->fsem)) < 0) + { + int errorcode = errno; + DEBUGASSERT(errorcode == EINTR || errorcode == ECANCELED); + UNUSED(errorcode); + } + + /* Is this the last client of the font cache? */ + + if (priv->fclients <= 1) + { + /* Yes.. destroy the font cache */ + + /* Free all allocated glyph bitmap */ + + for (i = 0; i < CONFIG_NXTERM_CACHESIZE; i++) + { + FAR struct nxfonts_glyph_s *glyph = &priv->glyph[i]; + if (glyph->bitmap) + { + kmm_free(glyph->bitmap); + } + } + + /* Destroy the serializing semaphore... while we are holding it? */ + + sem_destroy(&priv->fsem); + + /* Finally, free the font cache stucture itself */ + + kmm_free(fcache); + } + else + { + /* No.. just decrement the number of clients connected to the font + * cache. + */ + + priv->fclients--; + sem_post(&priv->fsem); + } +} + +/**************************************************************************** + * Name: nxf_cache_getfonthandle + * + * Description: + * Return the handle to the font set used by this instance of the font + * cache. + * + * Input Parameters: + * fcache - A font cache handle previously returned by nxf_cache_connect(); + * + * Returned value: + * Zero (OK) is returned if the metrics were + * + * Returned Value: + * One success, a non-NULL font handle is returned. + * + ****************************************************************************/ + +NXHANDLE nxf_cache_getfonthandle(FCACHE fcache) +{ + FAR struct nxfonts_fcache_s *priv = (FAR struct nxfonts_fcache_s *)fcache; + + DEBUGASSERT(priv != NULL && priv->font != NULL); + return priv->font; +} + +/**************************************************************************** + * Name: nxf_cache_getglyph + * + * Description: + * Get the font glyph for the character code 'ch' from the font cache. If + * the glyph for that character code does not exist in the font cache, it + * be rendered. + * + * Returned Value: + * On success, a non-NULL pointer to the rendered glyph in the font cache + * is returned. NULL is returned on any failure. + * + ****************************************************************************/ + +FAR struct nxfonts_glyph_s *nxf_cache_getglyph(FCACHE fcache, uint8_t ch) +{ + FAR struct nxfonts_fcache_s *priv = (FAR struct nxfonts_fcache_s *)fcache; + FAR struct nxfonts_glyph_s *glyph; + FAR const struct nx_fontbitmap_s *fbm; + + /* First, try to find the glyph in the cache of pre-rendered glyphs */ + + glyph = nxf_findglyph(priv, ch); + if (glyph) + { + /* We found it in the cache .. return the cached glyph */ + + return glyph; + } + + /* No, it is not cached... Does the code map to a font? */ + + fbm = nxf_getbitmap(priv->font, ch); + if (fbm) + { + /* Yes.. render the glyph */ + + glyph = nxf_renderglyph(priv, fbm, ch); + } + + return glyph; +} From a0199be503b8ca2ce73433eaf5ee4116923d03a7 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 6 Jan 2017 07:06:51 -0600 Subject: [PATCH 2/6] Font cache in libnx needs to use context-specific memory allocators. --- libnx/nxfonts/nxfonts_cache.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/libnx/nxfonts/nxfonts_cache.c b/libnx/nxfonts/nxfonts_cache.c index f8222ab10f8..2f6817ab448 100644 --- a/libnx/nxfonts/nxfonts_cache.c +++ b/libnx/nxfonts/nxfonts_cache.c @@ -45,7 +45,6 @@ #include #include -#include #include /**************************************************************************** @@ -98,7 +97,7 @@ static void nxf_freeglyph(FAR struct nxfonts_glyph_s *glyph) { if (glyph->bitmap) { - kmm_free(glyph->bitmap); + lib_free(glyph->bitmap); } memset(glyph, 0, sizeof(struct nxfonts_glyph_s)); @@ -241,7 +240,7 @@ nxf_renderglyph(FAR struct nxfonts_fcache_s *priv, /* Allocate memory to hold the glyph with its offsets */ bmsize = glyph->stride * glyph->height; - glyph->bitmap = (FAR uint8_t *)kmm_malloc(bmsize); + glyph->bitmap = (FAR uint8_t *)lib_malloc(bmsize); if (glyph->bitmap) { @@ -402,7 +401,7 @@ FCACHE nxf_cache_connect(enum nx_fontid_e fontid, /* Allocate memory for the (empty) font cache */ priv = (FAR struct nxfonts_fcache_s *) - kmm_malloc(sizeof( struct nxfonts_fcache_s)); + lib_zalloc(sizeof( struct nxfonts_fcache_s)); if (priv == NULL) { @@ -494,7 +493,7 @@ FCACHE nxf_cache_connect(enum nx_fontid_e fontid, return (FCACHE)priv; errout_with_fcache: - kmm_free(priv); + lib_free(priv); errout: set_errno(errcode); return NULL; @@ -546,7 +545,7 @@ void nxf_cache_disconnect(FCACHE fcache) FAR struct nxfonts_glyph_s *glyph = &priv->glyph[i]; if (glyph->bitmap) { - kmm_free(glyph->bitmap); + lib_free(glyph->bitmap); } } @@ -556,7 +555,7 @@ void nxf_cache_disconnect(FCACHE fcache) /* Finally, free the font cache stucture itself */ - kmm_free(fcache); + lib_free(fcache); } else { From 0b52e6f571885fabfca83162d98dca0077a1f334 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 6 Jan 2017 09:07:25 -0600 Subject: [PATCH 3/6] Font cache: Replace fixed-size array with variable size link list. --- graphics/nxterm/nxterm_font.c | 4 +- graphics/nxterm/nxterm_register.c | 3 +- include/nuttx/nx/nxfonts.h | 23 +- libc/queue/sq_addfirst.c | 1 + libc/queue/sq_remafter.c | 5 +- libnx/nxfonts/nxfonts_cache.c | 465 +++++++++++++++++++----------- 6 files changed, 312 insertions(+), 189 deletions(-) diff --git a/graphics/nxterm/nxterm_font.c b/graphics/nxterm/nxterm_font.c index 4b0c2c4fd2d..1bab0e6c79c 100644 --- a/graphics/nxterm/nxterm_font.c +++ b/graphics/nxterm/nxterm_font.c @@ -99,7 +99,7 @@ FAR const struct nxterm_bitmap_s * nxterm_addchar(FAR struct nxterm_state_s *priv, uint8_t ch) { FAR struct nxterm_bitmap_s *bm = NULL; - FAR struct nxfonts_glyph_s *glyph; + FAR const struct nxfonts_glyph_s *glyph; /* Is there space for another character on the display? */ @@ -275,7 +275,7 @@ void nxterm_fillchar(FAR struct nxterm_state_s *priv, FAR const struct nxgl_rect_s *rect, FAR const struct nxterm_bitmap_s *bm) { - FAR struct nxfonts_glyph_s *glyph; + FAR const struct nxfonts_glyph_s *glyph; struct nxgl_rect_s bounds; struct nxgl_rect_s intersection; struct nxgl_size_s fsize; diff --git a/graphics/nxterm/nxterm_register.c b/graphics/nxterm/nxterm_register.c index 087f6513e57..a83e84cffc9 100644 --- a/graphics/nxterm/nxterm_register.c +++ b/graphics/nxterm/nxterm_register.c @@ -106,7 +106,8 @@ FAR struct nxterm_state_s * /* Connect to the font cache for the configured font characteristics */ priv->fcache = nxf_cache_connect(wndo->fontid, wndo->fcolor[0], - wndo->wcolor[0], CONFIG_NXTERM_BPP); + wndo->wcolor[0], CONFIG_NXTERM_BPP, + CONFIG_NXTERM_CACHESIZE); if (priv->fcache == NULL) { gerr("ERROR: Failed to connect to font cache for font ID %d: %d\n", diff --git a/include/nuttx/nx/nxfonts.h b/include/nuttx/nx/nxfonts.h index 8cca725e818..82af4327577 100644 --- a/include/nuttx/nx/nxfonts.h +++ b/include/nuttx/nx/nxfonts.h @@ -203,11 +203,6 @@ #endif -/* Font Cache Definitions (**************************************************/ -/* Limit to range of font cache usage count */ - -#define MAX_USECNT 255 /* Limit to range of a uint8_t */ - /**************************************************************************** * Public Types ****************************************************************************/ @@ -469,14 +464,16 @@ typedef FAR void *FCACHE; struct nxfonts_glyph_s { + FAR struct nxfonts_glyph_s *flink; /* Implements a singly linked list */ uint8_t code; /* Character code */ 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 */ + FAR uint8_t bitmap[1]; /* Bitmap memory, actual size varies */ }; +#define SIZEOF_NXFONTS_GLYPH_S(b) (sizeof(struct nxfonts_glyph_s) + (b) - 1) + /**************************************************************************** * Public Data ****************************************************************************/ @@ -596,11 +593,15 @@ int nxf_convert_32bpp(FAR uint32_t *dest, uint16_t height, * * Description: * Create a new font cache for the provided 'fontid'. If the cache - * already, then just increment a reference count return the handler for + * already, then just increment a reference count return the handle for * the existing font cache. * * Input Parameters: - * fontid - Identifies the font supported by this cache + * fontid - Identifies the font supported by this cache + * fgcolor - Foreground color + * bgcolor - Background color + * bpp - Bits per pixel + * maxglyphs - Maximum number of glyphs permitted in the cache * * Returned value: * On success a non-NULL handle is returned that then may sequently be @@ -612,7 +613,7 @@ int nxf_convert_32bpp(FAR uint32_t *dest, uint16_t height, FCACHE nxf_cache_connect(enum nx_fontid_e fontid, nxgl_mxpixel_t fgcolor, nxgl_mxpixel_t bgcolor, - int bpp); + int bpp, int maxglyph); /**************************************************************************** * Name: nxf_cache_disconnect @@ -666,7 +667,7 @@ NXHANDLE nxf_cache_getfonthandle(FCACHE fcache); * ****************************************************************************/ -FAR struct nxfonts_glyph_s *nxf_cache_getglyph(FCACHE fcache, uint8_t ch); +FAR const struct nxfonts_glyph_s *nxf_cache_getglyph(FCACHE fcache, uint8_t ch); #undef EXTERN #if defined(__cplusplus) diff --git a/libc/queue/sq_addfirst.c b/libc/queue/sq_addfirst.c index a00841cfaad..bbc9f26a9c1 100644 --- a/libc/queue/sq_addfirst.c +++ b/libc/queue/sq_addfirst.c @@ -58,5 +58,6 @@ void sq_addfirst(FAR sq_entry_t *node, sq_queue_t *queue) { queue->tail = node; } + queue->head = node; } diff --git a/libc/queue/sq_remafter.c b/libc/queue/sq_remafter.c index a3527b7908a..34685ae9615 100644 --- a/libc/queue/sq_remafter.c +++ b/libc/queue/sq_remafter.c @@ -44,10 +44,10 @@ ****************************************************************************/ /**************************************************************************** - * Name: + * Name: sq_remafter * * Description: - * sq_remafter removes the entry following 'node; from the'queue' Returns + * sq_remafter removes the entry following 'node' from the'queue' Returns * a reference to the removed entry. * ****************************************************************************/ @@ -55,6 +55,7 @@ FAR sq_entry_t *sq_remafter(FAR sq_entry_t *node, sq_queue_t *queue) { FAR sq_entry_t *ret = node->flink; + if (queue->head && ret) { if (queue->tail == ret) diff --git a/libnx/nxfonts/nxfonts_cache.c b/libnx/nxfonts/nxfonts_cache.c index 2f6817ab448..6ea6db8ef28 100644 --- a/libnx/nxfonts/nxfonts_cache.c +++ b/libnx/nxfonts/nxfonts_cache.c @@ -47,6 +47,8 @@ #include +#include "nxcontext.h" + /**************************************************************************** * Private Types ****************************************************************************/ @@ -66,7 +68,8 @@ struct nxfonts_fcache_s sem_t fsem; /* Serializes access to the font cache */ uint16_t fontid; /* ID of font in this cache */ int16_t fclients; /* Number of connected clients */ - uint8_t maxglyphs; /* Size of glyph[] array */ + uint8_t maxglyphs; /* Maximum size of glyph[] array */ + uint8_t nglyphs; /* Current size of glyph[] array */ uint8_t bpp; /* Bits per pixel */ nxgl_mxpixel_t fgcolor; /* Foreground color */ nxgl_mxpixel_t bgcolor; /* Background color */ @@ -74,7 +77,8 @@ struct nxfonts_fcache_s /* Glyph cache data storage */ - struct nxfonts_glyph_s glyph[CONFIG_NXTERM_CACHESIZE]; + FAR struct nxfonts_glyph_s *head; /* Head of the list of glyphs */ + FAR struct nxfonts_glyph_s *tail; /* Tail of the list of glyphs */ }; /**************************************************************************** @@ -90,121 +94,280 @@ static FAR struct nxfonts_fcache_s *g_fcaches; ****************************************************************************/ /**************************************************************************** - * Name: nxf_freeglyph + * Name: nxf_removeglyph + * + * Description: + * Removes the entry 'glyph' from the font cache. + * ****************************************************************************/ -static void nxf_freeglyph(FAR struct nxfonts_glyph_s *glyph) +static inline void nxf_removeglyph(FAR struct nxfonts_fcache_s *priv, + FAR struct nxfonts_glyph_s *glyph, + FAR struct nxfonts_glyph_s *prev) { - if (glyph->bitmap) + /* Remove the glyph for the list. First check for removal from the head */ + + if (prev == NULL) { - lib_free(glyph->bitmap); + /* Replace the head with the node following glyph */ + + priv->head = glyph->flink; + + /* If there is no node following glyph, then the list is empty */ + + if (priv->head == NULL) + { + priv->tail = NULL; + } } - memset(glyph, 0, sizeof(struct nxfonts_glyph_s)); + /* Check for removal from the tail (we know that the list cannot become + * empty in either of the next two cases). + */ + + else if (glyph->flink == NULL) + { + priv->tail = prev; + prev->flink = NULL; + } + + /* No.. removae from mid-list */ + + else + { + prev->flink = glyph->flink; + } + + glyph->flink = NULL; + + /* Decrement the count of glyphs in the font cache */ + + DEBUGASSERT(priv->nglyphs > 0); + priv->nglyphs--; } /**************************************************************************** - * Name: nxf_allocglyph + * Name: nxf_addglyph + * + * Description: + * Add the entry 'glyph' to the head font cache list. + * ****************************************************************************/ -static inline FAR struct nxfonts_glyph_s * -nxf_allocglyph(FAR struct nxfonts_fcache_s *priv) +static inline void nxf_addglyph(FAR struct nxfonts_fcache_s *priv, + FAR struct nxfonts_glyph_s *glyph) { - FAR struct nxfonts_glyph_s *glyph = NULL; - FAR struct nxfonts_glyph_s *luglyph = NULL; - uint8_t luusecnt; - int i; + /* Add the glyph to the head of the list */ - /* 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. - */ + glyph->flink = priv->head; - for (i = 0; i < priv->maxglyphs; i++) + if (priv->head == NULL) { - /* Is this glyph in use? */ - - glyph = &priv->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; - } + priv->tail = 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). - */ + priv->head = glyph - luusecnt = luglyph->usecnt; - nxf_freeglyph(luglyph); + /* Increment the count of glyphs in the font cache. */ - /* 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 < priv->maxglyphs; i++) - { - /* Is this glyph in use? */ - - glyph = &priv->glyph[i]; - if (glyph->usecnt > decr) - { - glyph->usecnt -= decr; - } - } - } - - /* Then return the least used glyph */ - - luglyph->usecnt = 1; - return luglyph; + DEBUGASSERT(priv->nglyphs < priv->maxglyphs); + priv->nglyphs++; } /**************************************************************************** * Name: nxf_findglyph + * + * Description: + * Find the glyph for the specific character 'ch' in the list of pre- + * rendered fonts in the font cache. + * + * This is logically a part of nxf_cache_getglyph(). nxf_cache_getglyph() + * will attempt to find the cached glyph before rendering a new one. So + * this function has two unexpected side-effects: (1) If the font cache + * is full and the font is not found, then the least-recently-used glyph + * is deleted to make space for the new glyph that will be allocated. + * + * If the glyph is found, then it is moved to the head of the list of + * glyphs since it is now the most recently used (leaving the least + * recently used glyph at the tail of the list). + * ****************************************************************************/ static FAR struct nxfonts_glyph_s * nxf_findglyph(FAR struct nxfonts_fcache_s *priv, uint8_t ch) { - int i; + FAR struct nxfonts_glyph_s *glyph; + FAR struct nxfonts_glyph_s *prev; - /* First, try to find the glyph in the cache of pre-rendered glyphs */ + /* Try to find the glyph in the list of pre-rendered glyphs */ - for (i = 0; i < priv->maxglyphs; i++) + for (prev = NULL, glyph = priv->head; + glyph != NULL; + prev = glyph, glyph = glyph->flink) { - FAR struct nxfonts_glyph_s *glyph = &priv->glyph[i]; - if (glyph->usecnt > 0 && glyph->code == ch) - { - /* Increment the use count (unless it is already at the max) */ + /* Check if we found the the glyph for this character */ - if (glyph->usecnt < MAX_USECNT) - { - glyph->usecnt++; - } + if (glyph->code == ch) + { + /* This is now the most recently used glyph. Move it to the head + * of the list. + */ + + nxf_removeglyph(priv, glyph, prev); + nxf_addglyph(priv, glyph); /* And return the glyph that we found */ return glyph; } + + /* Is this the last glyph in the list? Has the cache reached its + * limited for the number of cached fonts? + */ + + if (glyph->flink == NULL && priv->nglyphs >= priv->maxglyphs) + { + /* Yes.. then remove it from the list and free the glyph memory. + * We do this because we have all of the information in hand now + * and we will surely need to have this space later. + */ + + nxf_removeglyph(priv, glyph, prev); + return NULL; + } } + return NULL; } +/**************************************************************************** + * Name: nxf_fillglyph + * + * Description: + * Fill the glyph memory with the background color + * + ****************************************************************************/ + +static inline void nxf_fillglyph(FAR struct nxfonts_fcache_s *priv, + FAR struct nxfonts_glyph_s *glyph) +{ + int row; + int col; + + /* Initialize the glyph memory to the background color. */ + +#if !defined(CONFIG_NX_DISABLE_1BPP) || !defined(CONFIG_NX_DISABLE_2BPP) || \ + !defined(CONFIG_NX_DISABLE_4BPP) || !defined(CONFIG_NX_DISABLE_8BPP) + + /* For pixel depths of 1, 2, 4, and 8, build up an 8-bit value containing + * multiple background colored pixels. + */ + + if (priv->bpp <= 8) + { + uint8_t pixel = (uint8_t)priv->bgcolor; + FAR uint8_t *ptr; + +#ifndef CONFIG_NX_DISABLE_1BPP + /* Pack a 1-bit pixel to 2 pixels */ + + if (priv->bpp < 2) + { + /* Pack 1-bit pixels into a 2-bits */ + + pixel &= 0x01; + pixel = (pixel) << 1 | pixel; + } +#endif + +#if !defined(CONFIG_NX_DISABLE_1BPP) || !defined(CONFIG_NX_DISABLE_2BPP) + /* Pack a 2-bit pixel to a 4-bit nibble */ + + if (priv->bpp < 4) + { + /* Pack 2-bit pixels into a nibble */ + + pixel &= 0x03; + pixel = (pixel) << 2 | pixel; + } +#endif + +#if !defined(CONFIG_NX_DISABLE_1BPP) || !defined(CONFIG_NX_DISABLE_2BPP) || \ + !defined(CONFIG_NX_DISABLE_4BPP) + /* Pack the 4-bit nibble into a byte */ + + if (priv->bpp < 8) + { + pixel &= 0x0f; + pixel = (pixel) << 4 | pixel; + } +#endif + + /* Then fill the glyph with the packed background color */ + + ptr = (FAR uint8_t *)glyph->bitmap; + for (row = 0; row < glyph->height; row++) + { + for (col = 0; col < glyph->stride; col++) + { + /* Transfer the packed bytes into the buffer */ + + *ptr++ = pixel; + } + } + } + else +#endif + +#if !defined(CONFIG_NX_DISABLE_16BPP) + if (priv->bpp == 16) + { + FAR uint16_t *ptr = (FAR uint16_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++ = priv->bgcolor; + } + } + } + else +#endif + +#ifndef CONFIG_NX_DISABLE_24BPP + if (priv->bpp == 24) + { + gerr("ERROR: Additional logic is needed to support 24-bit color\n"); + goto errout_with_glyph; + } + else +#endif + +#if !defined(CONFIG_NX_DISABLE_32BPP) + if (priv->bpp == 32) + { + FAR uint32_t *ptr = (FAR uint32_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++ = priv->bgcolor; + } + } + } + else +#endif + { + PANIC(); + } +} + /**************************************************************************** * Name: nxf_renderglyph ****************************************************************************/ @@ -214,98 +377,40 @@ nxf_renderglyph(FAR struct nxfonts_fcache_s *priv, FAR const struct nx_fontbitmap_s *fbm, uint8_t ch) { FAR struct nxfonts_glyph_s *glyph = NULL; - FAR nxgl_mxpixel_t *ptr; -#if CONFIG_NXTERM_BPP < 8 - nxgl_mxpixel_t pixel; -#endif - int bmsize; - int row; - int col; + size_t bmsize; + unsigned int height; + unsigned int width; + unsigned int stride; int ret; - /* Allocate the glyph (always succeeds) */ + /* Get the size of the glyph */ - glyph = nxf_allocglyph(priv); - glyph->code = ch; - - /* Get the dimensions of the glyph */ - - glyph->width = fbm->metric.width + fbm->metric.xoffset; - glyph->height = fbm->metric.height + fbm->metric.yoffset; + width = fbm->metric.width + fbm->metric.xoffset; + height = fbm->metric.height + fbm->metric.yoffset; /* Get the physical width of the glyph in bytes */ - glyph->stride = (glyph->width * CONFIG_NXTERM_BPP + 7) / 8; + stride = (width * priv->bpp + 7) >> 3; - /* Allocate memory to hold the glyph with its offsets */ + /* Allocate the glyph (always succeeds) */ - bmsize = glyph->stride * glyph->height; - glyph->bitmap = (FAR uint8_t *)lib_malloc(bmsize); + bmsize = stride * height; + glyph = (FAR struct nxfonts_glyph_s *)lib_malloc(SIZEOF_NXFONTS_GLYPH_S(bmsize)); - if (glyph->bitmap) + if (glyph != NULL) { - /* Initialize the glyph memory to the background color using the - * hard-coded bits-per-pixel (BPP). - * - * TODO: The rest of NX is configured to support multiple devices - * with differing BPP. They logic should be extended to support - * differing BPP's as well. - */ + /* Save the character code, dimensions, and physcial width of the glyph */ -#if CONFIG_NXTERM_BPP < 8 - pixel = priv->bgcolor; + glyph->code = ch; + glyph->width = width; + glyph->height = height; + glyph->stride = stride; -# if CONFIG_NXTERM_BPP == 1 + /* Initialize the glyph memory to the background color. */ - /* Pack 1-bit pixels into a 2-bits */ + nxf_fillglyph(priv, glyph); - pixel &= 0x01; - pixel = (pixel) << 1 | pixel; - -# endif -# if CONFIG_NXTERM_BPP < 4 - - /* Pack 2-bit pixels into a nibble */ - - pixel &= 0x03; - pixel = (pixel) << 2 | pixel; - -# endif - - /* Pack 4-bit nibbles into a byte */ - - pixel &= 0x0f; - pixel = (pixel) << 4 | pixel; - - ptr = (FAR nxgl_mxpixel_t *)glyph->bitmap; - for (row = 0; row < glyph->height; row++) - { - for (col = 0; col < glyph->stride; col++) - { - /* Transfer the packed bytes into the buffer */ - - *ptr++ = pixel; - } - } - -#elif CONFIG_NXTERM_BPP == 24 -# error "Additional logic is needed here for 24bpp support" - -#else /* CONFIG_NXTERM_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 */ - - for (col = 0; col < glyph->width; col++) - { - *ptr++ = priv->bgcolor; - } - } -#endif - - /* Then render the glyph into the allocated memory */ + /* Then render the glyph into the allocated, initialized memory */ ret = priv->renderer((FAR nxgl_mxpixel_t *)glyph->bitmap, glyph->height, glyph->width, glyph->stride, @@ -315,9 +420,13 @@ nxf_renderglyph(FAR struct nxfonts_fcache_s *priv, /* Actually, the renderer never returns a failure */ gerr("ERROR: nxf_renderglyph: Renderer failed\n"); - nxf_freeglyph(glyph); - glyph = NULL; + lib_free(glyph); + return NULL; } + + /* Add the new glyph to the font cache */ + + nxf_addglyph(priv, glyph); } return glyph; @@ -369,10 +478,11 @@ nxf_findcache(enum nx_fontid_e fontid, nxgl_mxpixel_t fgcolor, * the existing font cache. * * Input Parameters: - * fontid - Identifies the font supported by this cache - * fgcolor - Foreground color - * bgcolor - Background color - * bpp - Bits per pixel + * fontid - Identifies the font supported by this cache + * fgcolor - Foreground color + * bgcolor - Background color + * bpp - Bits per pixel + * maxglyphs - Maximum number of glyphs permitted in the cache * * Returned value: * On success a non-NULL handle is returned that then may sequently be @@ -384,7 +494,7 @@ nxf_findcache(enum nx_fontid_e fontid, nxgl_mxpixel_t fgcolor, FCACHE nxf_cache_connect(enum nx_fontid_e fontid, nxgl_mxpixel_t fgcolor, nxgl_mxpixel_t bgcolor, - int bpp) + int bpp, int maxglyphs) { FAR struct nxfonts_fcache_s *priv; int errcode; @@ -411,7 +521,7 @@ FCACHE nxf_cache_connect(enum nx_fontid_e fontid, /* Initialize the font cache */ - priv->maxglyphs = CONFIG_NXTERM_CACHESIZE; + priv->maxglyphs = maxglyphs; priv->fontid = fontid; priv->fgcolor = fgcolor; priv->bgcolor = bgcolor; @@ -489,6 +599,17 @@ FCACHE nxf_cache_connect(enum nx_fontid_e fontid, goto errout_with_fcache; } } + else + { + /* A font cache with these characteristics already exists. Just make + * sure that it is as least a big as the size requested. + */ + + if (priv->maxglyphs < maxglyphs) + { + priv->maxglyphs = maxglyphs; + } + } return (FCACHE)priv; @@ -518,8 +639,9 @@ errout: void nxf_cache_disconnect(FCACHE fcache) { FAR struct nxfonts_fcache_s *priv = (FAR struct nxfonts_fcache_s *)fcache; + FAR struct nxfonts_glyph_s *glyph; + FAR struct nxfonts_glyph_s *next; int ret; - int i; DEBUGASSERT(priv != NULL && priv->fclients > 0); @@ -538,15 +660,12 @@ void nxf_cache_disconnect(FCACHE fcache) { /* Yes.. destroy the font cache */ - /* Free all allocated glyph bitmap */ + /* Free all allocated glyph memory */ - for (i = 0; i < CONFIG_NXTERM_CACHESIZE; i++) + for (glyph = priv->head; glyph != NULL; glyph = next) { - FAR struct nxfonts_glyph_s *glyph = &priv->glyph[i]; - if (glyph->bitmap) - { - lib_free(glyph->bitmap); - } + next = glyph->flink; + lib_free(glyph); } /* Destroy the serializing semaphore... while we are holding it? */ @@ -555,7 +674,7 @@ void nxf_cache_disconnect(FCACHE fcache) /* Finally, free the font cache stucture itself */ - lib_free(fcache); + lib_free(priv); } else { @@ -608,7 +727,7 @@ NXHANDLE nxf_cache_getfonthandle(FCACHE fcache) * ****************************************************************************/ -FAR struct nxfonts_glyph_s *nxf_cache_getglyph(FCACHE fcache, uint8_t ch) +FAR const struct nxfonts_glyph_s *nxf_cache_getglyph(FCACHE fcache, uint8_t ch) { FAR struct nxfonts_fcache_s *priv = (FAR struct nxfonts_fcache_s *)fcache; FAR struct nxfonts_glyph_s *glyph; @@ -617,7 +736,7 @@ FAR struct nxfonts_glyph_s *nxf_cache_getglyph(FCACHE fcache, uint8_t ch) /* First, try to find the glyph in the cache of pre-rendered glyphs */ glyph = nxf_findglyph(priv, ch); - if (glyph) + if (glyph != NULL) { /* We found it in the cache .. return the cached glyph */ From d7173f2eb5764c803b5a3462c9675db9c508b531 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 6 Jan 2017 09:50:30 -0600 Subject: [PATCH 4/6] Font cache: Enforce mutually exclusive access to the font cache --- include/nuttx/nx/nxfonts.h | 10 +- libnx/nxfonts/nxfonts_cache.c | 213 ++++++++++++++++++++++++++++------ 2 files changed, 180 insertions(+), 43 deletions(-) diff --git a/include/nuttx/nx/nxfonts.h b/include/nuttx/nx/nxfonts.h index 82af4327577..525a5f56a24 100644 --- a/include/nuttx/nx/nxfonts.h +++ b/include/nuttx/nx/nxfonts.h @@ -624,14 +624,14 @@ FCACHE nxf_cache_connect(enum nx_fontid_e fontid, * font handler is invalid upon return in either case. * * Input Parameters: - * fcache - A font cache handler previously returned by nxf_cache_connect(); + * fhandle - A font cache handler previously returned by nxf_cache_connect(); * * Returned value: * None * ****************************************************************************/ -void nxf_cache_disconnect(FCACHE fcache); +void nxf_cache_disconnect(FCACHE fhandle); /**************************************************************************** * Name: nxf_cache_getfonthandle @@ -641,7 +641,7 @@ void nxf_cache_disconnect(FCACHE fcache); * cache. * * Input Parameters: - * fcache - A font cache handle previously returned by nxf_cache_connect(); + * fhandle - A font cache handle previously returned by nxf_cache_connect(); * * Returned value: * Zero (OK) is returned if the metrics were @@ -651,7 +651,7 @@ void nxf_cache_disconnect(FCACHE fcache); * ****************************************************************************/ -NXHANDLE nxf_cache_getfonthandle(FCACHE fcache); +NXHANDLE nxf_cache_getfonthandle(FCACHE fhandle); /**************************************************************************** * Name: nxf_cache_getglyph @@ -667,7 +667,7 @@ NXHANDLE nxf_cache_getfonthandle(FCACHE fcache); * ****************************************************************************/ -FAR const struct nxfonts_glyph_s *nxf_cache_getglyph(FCACHE fcache, uint8_t ch); +FAR const struct nxfonts_glyph_s *nxf_cache_getglyph(FCACHE fhandle, uint8_t ch); #undef EXTERN #if defined(__cplusplus) diff --git a/libnx/nxfonts/nxfonts_cache.c b/libnx/nxfonts/nxfonts_cache.c index 6ea6db8ef28..3426d87fd8b 100644 --- a/libnx/nxfonts/nxfonts_cache.c +++ b/libnx/nxfonts/nxfonts_cache.c @@ -88,11 +88,93 @@ struct nxfonts_fcache_s /* Head of a list of font caches */ static FAR struct nxfonts_fcache_s *g_fcaches; +static sem_t g_cachesem = SEM_INITIALIZER(1); /**************************************************************************** * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: nxf_list_lock and nxf_list_unlock + * + * Description: + * Get/relinquish exclusive access to the font cache list + * + ****************************************************************************/ + +static void nxf_list_lock(void) +{ + int ret; + + /* Get exclusive access to the font cache */ + + while ((ret = sem_wait(&g_cachesem)) < 0) + { + int errorcode = errno; + DEBUGASSERT(errorcode == EINTR || errorcode == ECANCELED); + UNUSED(errorcode); + } +} + +#define nxf_list_unlock() (sem_post(&g_cachesem)) + +/**************************************************************************** + * Name: nxf_removecache + * + * Description: + * Removes the entry 'glyph' from the font cache. + * + * Assumptions: + * The caller holds the font cache list semaphore. + * + ****************************************************************************/ + +static inline void nxf_removecache(FAR struct nxfonts_fcache_s *fcache, + FAR struct nxfonts_fcache_s *prev) +{ + /* Remove the cache for the list. First check for removal from the head */ + + if (prev == NULL) + { + /* Replace the head with the node following glyph */ + + g_fcaches = fcache->flink; + } + + /* No.. Remove from the head or from mid-list */ + + else + { + prev->flink = fcache->flink; + } + + fcache->flink = NULL; +} + +/**************************************************************************** + * Name: nxf_cache_lock and nxf_cache_unlock + * + * Description: + * Get/relinquish exclusive access to the font cache + * + ****************************************************************************/ + +static void nxf_cache_lock(FAR struct nxfonts_fcache_s *priv) +{ + int ret; + + /* Get exclusive access to the font cache */ + + while ((ret = sem_wait(&priv->fsem)) < 0) + { + int errorcode = errno; + DEBUGASSERT(errorcode == EINTR || errorcode == ECANCELED); + UNUSED(errorcode); + } +} + +#define nxf_cache_unlock(p) (sem_post(&priv->fsem)) + /**************************************************************************** * Name: nxf_removeglyph * @@ -131,7 +213,7 @@ static inline void nxf_removeglyph(FAR struct nxfonts_fcache_s *priv, prev->flink = NULL; } - /* No.. removae from mid-list */ + /* No.. remove from mid-list */ else { @@ -191,6 +273,9 @@ static inline void nxf_addglyph(FAR struct nxfonts_fcache_s *priv, * glyphs since it is now the most recently used (leaving the least * recently used glyph at the tail of the list). * + * Assumptions: + * The caller has exclusive access to the font cache. + * ****************************************************************************/ static FAR struct nxfonts_glyph_s * @@ -340,8 +425,26 @@ static inline void nxf_fillglyph(FAR struct nxfonts_fcache_s *priv, #ifndef CONFIG_NX_DISABLE_24BPP if (priv->bpp == 24) { - gerr("ERROR: Additional logic is needed to support 24-bit color\n"); - goto errout_with_glyph; + FAR uint32_t *ptr = (FAR uint32_t *)glyph->bitmap; + FAR uint32_t pixel[3]; + + /* Get two 32-bit values for alternating 32 representations */ + + pixel[0] = (uint32_t)priv->bgcolor << 8 | (uint32_t)priv->bgcolor >> 16; + pixel[1] = (uint32_t)priv->bgcolor << 16 | (uint32_t)priv->bgcolor >> 8; + pixel[1] = (uint32_t)priv->bgcolor << 24 | (uint32_t)priv->bgcolor; + + for (row = 0; row < glyph->height; row++) + { + /* Just copy the color value into the glyph memory */ + + for (col = 0; col < glyph->width; col += 3) + { + *ptr++ = pixel[0]; + *ptr++ = pixel[1]; + *ptr++ = pixel[2]; + } + } } else #endif @@ -370,6 +473,14 @@ static inline void nxf_fillglyph(FAR struct nxfonts_fcache_s *priv, /**************************************************************************** * Name: nxf_renderglyph + * + * Description: + * Allocate memory for a new glyph and render the bitmap font into the + * allocated glyph memory. + * + * Assumptions: + * The caller holds the font cache semaphore. + * ****************************************************************************/ static inline FAR struct nxfonts_glyph_s * @@ -434,6 +545,13 @@ nxf_renderglyph(FAR struct nxfonts_fcache_s *priv, /**************************************************************************** * Name: nxf_findcache + * + * Description: + * Find a font cache tht matches the font charcteristics. + * + * Assumptions: + * The caller holds the font cache list semaphore. + * ****************************************************************************/ static FAR struct nxfonts_fcache_s * @@ -442,9 +560,6 @@ nxf_findcache(enum nx_fontid_e fontid, nxgl_mxpixel_t fgcolor, { FAR struct nxfonts_fcache_s *fcache; - /* Get exclusive access to the font cache list */ -#warning Missing logic - /* Search for a cache for this font characteristics */ for (fcache = g_fcaches; fcache != NULL; fcache = fcache->flink) @@ -499,6 +614,10 @@ FCACHE nxf_cache_connect(enum nx_fontid_e fontid, FAR struct nxfonts_fcache_s *priv; int errcode; + /* Get exclusive access to the font cache list */ + + nxf_list_lock(); + /* Find a font cache with the matching font characteristics */ priv = nxf_findcache(fontid, fgcolor, bgcolor, bpp); @@ -516,7 +635,7 @@ FCACHE nxf_cache_connect(enum nx_fontid_e fontid, if (priv == NULL) { errcode = ENOMEM; - goto errout; + goto errout_with_lock; } /* Initialize the font cache */ @@ -598,6 +717,11 @@ FCACHE nxf_cache_connect(enum nx_fontid_e fontid, gerr("ERROR: Failed to get font ID %d: %d\n", fontid, errcode); goto errout_with_fcache; } + + /* Add the new font cache to the list of font caches */ + + priv->flink = g_fcaches; + g_fcaches = priv; } else { @@ -611,11 +735,13 @@ FCACHE nxf_cache_connect(enum nx_fontid_e fontid, } } + nxf_list_unlock(); return (FCACHE)priv; errout_with_fcache: lib_free(priv); -errout: +errout_with_lock: + nxf_list_unlock(); set_errno(errcode); return NULL; } @@ -629,36 +755,46 @@ errout: * font handle is invalid upon return in either case. * * Input Parameters: - * fcache - A font cache handle previously returned by nxf_cache_connect(); + * fhandle - A font cache handle previously returned by nxf_cache_connect(); * * Returned value: * None * ****************************************************************************/ -void nxf_cache_disconnect(FCACHE fcache) +void nxf_cache_disconnect(FCACHE fhandle) { - FAR struct nxfonts_fcache_s *priv = (FAR struct nxfonts_fcache_s *)fcache; + FAR struct nxfonts_fcache_s *priv = (FAR struct nxfonts_fcache_s *)fhandle; + FAR struct nxfonts_fcache_s *fcache; + FAR struct nxfonts_fcache_s *prev; FAR struct nxfonts_glyph_s *glyph; FAR struct nxfonts_glyph_s *next; - int ret; DEBUGASSERT(priv != NULL && priv->fclients > 0); /* Get exclusive access to the font cache */ - while ((ret = sem_wait(&priv->fsem)) < 0) - { - int errorcode = errno; - DEBUGASSERT(errorcode == EINTR || errorcode == ECANCELED); - UNUSED(errorcode); - } + nxf_cache_lock(priv); /* Is this the last client of the font cache? */ if (priv->fclients <= 1) { - /* Yes.. destroy the font cache */ + /* Get exclusive access to the font cache list */ + + nxf_list_lock(); + + /* Remove the font cache from the list of caches. This is a singly + * linked list, so we must do this the hard way. + */ + + for (prev = NULL, fcache = g_fcaches; + fcache != priv && fcache != NULL; + fcache = fcache->flink); + + ASSERT(fcache == priv); + nxf_removecache(fcache, prev); + nxf_list_unlock(); /* Free all allocated glyph memory */ @@ -683,7 +819,7 @@ void nxf_cache_disconnect(FCACHE fcache) */ priv->fclients--; - sem_post(&priv->fsem); + nxf_cache_unlock(priv); } } @@ -695,7 +831,7 @@ void nxf_cache_disconnect(FCACHE fcache) * cache. * * Input Parameters: - * fcache - A font cache handle previously returned by nxf_cache_connect(); + * fhandle - A font cache handle previously returned by nxf_cache_connect(); * * Returned value: * Zero (OK) is returned if the metrics were @@ -705,9 +841,9 @@ void nxf_cache_disconnect(FCACHE fcache) * ****************************************************************************/ -NXHANDLE nxf_cache_getfonthandle(FCACHE fcache) +NXHANDLE nxf_cache_getfonthandle(FCACHE fhandle) { - FAR struct nxfonts_fcache_s *priv = (FAR struct nxfonts_fcache_s *)fcache; + FAR struct nxfonts_fcache_s *priv = (FAR struct nxfonts_fcache_s *)fhandle; DEBUGASSERT(priv != NULL && priv->font != NULL); return priv->font; @@ -727,31 +863,32 @@ NXHANDLE nxf_cache_getfonthandle(FCACHE fcache) * ****************************************************************************/ -FAR const struct nxfonts_glyph_s *nxf_cache_getglyph(FCACHE fcache, uint8_t ch) +FAR const struct nxfonts_glyph_s *nxf_cache_getglyph(FCACHE fhandle, uint8_t ch) { - FAR struct nxfonts_fcache_s *priv = (FAR struct nxfonts_fcache_s *)fcache; + FAR struct nxfonts_fcache_s *priv = (FAR struct nxfonts_fcache_s *)fhandle; FAR struct nxfonts_glyph_s *glyph; FAR const struct nx_fontbitmap_s *fbm; + /* Get exclusive access to the font cache */ + + nxf_cache_lock(priv); + /* First, try to find the glyph in the cache of pre-rendered glyphs */ glyph = nxf_findglyph(priv, ch); - if (glyph != NULL) + if (glyph == NULL) { - /* We found it in the cache .. return the cached glyph */ + /* No, it is not cached... Does the code map to a font? */ - return glyph; - } - - /* No, it is not cached... Does the code map to a font? */ - - fbm = nxf_getbitmap(priv->font, ch); - if (fbm) - { - /* Yes.. render the glyph */ - - glyph = nxf_renderglyph(priv, fbm, ch); + fbm = nxf_getbitmap(priv->font, ch); + if (fbm) + { + /* Yes.. render the glyph */ + + glyph = nxf_renderglyph(priv, fbm, ch); + } } + nxf_cache_unlock(priv); return glyph; } From 725ba1602a591378714a011209a88ef53eb859ac Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 6 Jan 2017 11:06:50 -0600 Subject: [PATCH 5/6] Font cache: misc fixes and improvements --- configs/stm3210e-eval/nxterm/defconfig | 4 +- configs/stm3240g-eval/nxterm/defconfig | 4 +- graphics/nxterm/nxterm_font.c | 2 +- libnx/nxfonts/nxfonts_cache.c | 71 ++++++++++++++------------ 4 files changed, 42 insertions(+), 39 deletions(-) diff --git a/configs/stm3210e-eval/nxterm/defconfig b/configs/stm3210e-eval/nxterm/defconfig index ffb7dc3e2d1..bbd18a5c015 100644 --- a/configs/stm3210e-eval/nxterm/defconfig +++ b/configs/stm3210e-eval/nxterm/defconfig @@ -666,7 +666,7 @@ CONFIG_SIG_SIGWORK=17 # POSIX Message Queue Options # CONFIG_PREALLOC_MQ_MSGS=8 -CONFIG_MQ_MAXMSGSIZE=32 +CONFIG_MQ_MAXMSGSIZE=64 # CONFIG_MODULE is not set # @@ -999,7 +999,7 @@ CONFIG_NXTERM=y # NxTerm Output Text/Graphics Options # CONFIG_NXTERM_BPP=16 -CONFIG_NXTERM_CURSORCHAR=137 +CONFIG_NXTERM_CURSORCHAR=95 CONFIG_NXTERM_MXCHARS=256 CONFIG_NXTERM_CACHESIZE=32 CONFIG_NXTERM_LINESEPARATION=0 diff --git a/configs/stm3240g-eval/nxterm/defconfig b/configs/stm3240g-eval/nxterm/defconfig index a83753f6520..3b6215dd536 100644 --- a/configs/stm3240g-eval/nxterm/defconfig +++ b/configs/stm3240g-eval/nxterm/defconfig @@ -713,7 +713,7 @@ CONFIG_SIG_SIGWORK=17 # POSIX Message Queue Options # CONFIG_PREALLOC_MQ_MSGS=8 -CONFIG_MQ_MAXMSGSIZE=32 +CONFIG_MQ_MAXMSGSIZE=64 # CONFIG_MODULE is not set # @@ -1189,7 +1189,7 @@ CONFIG_NXTERM=y # NxTerm Output Text/Graphics Options # CONFIG_NXTERM_BPP=16 -CONFIG_NXTERM_CURSORCHAR=137 +CONFIG_NXTERM_CURSORCHAR=95 CONFIG_NXTERM_MXCHARS=256 CONFIG_NXTERM_CACHESIZE=32 CONFIG_NXTERM_LINESEPARATION=0 diff --git a/graphics/nxterm/nxterm_font.c b/graphics/nxterm/nxterm_font.c index 1bab0e6c79c..50028459898 100644 --- a/graphics/nxterm/nxterm_font.c +++ b/graphics/nxterm/nxterm_font.c @@ -65,7 +65,7 @@ static int nxterm_fontsize(FAR struct nxterm_state_s *priv, uint8_t ch, /* Get the handle of the font managed by the font cache */ hfont = nxf_cache_getfonthandle(priv->fcache); - DEBUGASSERT(hfront != NULL); + DEBUGASSERT(hfont != NULL); /* Does the character code map to a font? */ diff --git a/libnx/nxfonts/nxfonts_cache.c b/libnx/nxfonts/nxfonts_cache.c index 3426d87fd8b..935e605bc7c 100644 --- a/libnx/nxfonts/nxfonts_cache.c +++ b/libnx/nxfonts/nxfonts_cache.c @@ -248,7 +248,7 @@ static inline void nxf_addglyph(FAR struct nxfonts_fcache_s *priv, priv->tail = glyph; } - priv->head = glyph + priv->head = glyph; /* Increment the count of glyphs in the font cache. */ @@ -269,7 +269,7 @@ static inline void nxf_addglyph(FAR struct nxfonts_fcache_s *priv, * is full and the font is not found, then the least-recently-used glyph * is deleted to make space for the new glyph that will be allocated. * - * If the glyph is found, then it is moved to the head of the list of + * (2) If the glyph is found, then it is moved to the head of the list of * glyphs since it is now the most recently used (leaving the least * recently used glyph at the tail of the list). * @@ -436,13 +436,28 @@ static inline void nxf_fillglyph(FAR struct nxfonts_fcache_s *priv, for (row = 0; row < glyph->height; row++) { - /* Just copy the color value into the glyph memory */ + /* Copy the color value into the glyph memory */ - for (col = 0; col < glyph->width; col += 3) + col = 0; + for (; ; ) { *ptr++ = pixel[0]; + if (++col >= glyph->width) + { + break; + } + *ptr++ = pixel[1]; + if (++col >= glyph->width) + { + break; + } + *ptr++ = pixel[2]; + if (++col >= glyph->width) + { + break; + } } } } @@ -653,56 +668,44 @@ FCACHE nxf_cache_connect(enum nx_fontid_e fontid, * 24). */ -#ifndef CONFIG_NX_DISABLE_1BPP - if (bpp == 1) + switch (bpp) { +#ifndef CONFIG_NX_DISABLE_1BPP + case 1: priv->renderer = (nxf_renderer_t)nxf_convert_1bpp; - } - else + break; #endif #ifndef CONFIG_NX_DISABLE_2BPP - if (bpp == 2) - { + case 2: priv->renderer = (nxf_renderer_t)nxf_convert_2bpp; - } - else + break; #endif #ifndef CONFIG_NX_DISABLE_4BPP - if (bpp == 4) - { + case 4: priv->renderer = (nxf_renderer_t)nxf_convert_4bpp; - } - else + break; #endif #ifndef CONFIG_NX_DISABLE_8BPP - if (bpp == 8) - { + case 8: priv->renderer = (nxf_renderer_t)nxf_convert_8bpp; - } - else + break; #endif #ifndef CONFIG_NX_DISABLE_16BPP - if (bpp == 16) - { + case 16: priv->renderer = (nxf_renderer_t)nxf_convert_16bpp; - } - else + break; #endif #ifndef CONFIG_NX_DISABLE_24BPP - if (bpp == 24) - { + case 24: priv->renderer = (nxf_renderer_t)nxf_convert_24bpp; - } - else + break; #endif #ifndef CONFIG_NX_DISABLE_32BPP - if (bpp == 32) - { + case 32: priv->renderer = (nxf_renderer_t)nxf_convert_32bpp; - } - else + break; #endif - { + default: gerr("ERROR: Unsupported pixel depth: %d\n", bpp); errcode = ENOSYS; goto errout_with_fcache; @@ -883,7 +886,7 @@ FAR const struct nxfonts_glyph_s *nxf_cache_getglyph(FCACHE fhandle, uint8_t ch) fbm = nxf_getbitmap(priv->font, ch); if (fbm) { - /* Yes.. render the glyph */ + /* Yes.. render the glyph for the font */ glyph = nxf_renderglyph(priv, fbm, ch); } From 4e0e18f659bae8a28be947e07f616320e362ce64 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 6 Jan 2017 11:36:05 -0600 Subject: [PATCH 6/6] Font cache: Add debug output; fix initialization of a semaphore. --- libnx/nxfonts/nxfonts_cache.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/libnx/nxfonts/nxfonts_cache.c b/libnx/nxfonts/nxfonts_cache.c index 935e605bc7c..b74df1e0f24 100644 --- a/libnx/nxfonts/nxfonts_cache.c +++ b/libnx/nxfonts/nxfonts_cache.c @@ -187,6 +187,8 @@ static inline void nxf_removeglyph(FAR struct nxfonts_fcache_s *priv, FAR struct nxfonts_glyph_s *glyph, FAR struct nxfonts_glyph_s *prev) { + ginfo("fcache=%p glyph=%p\n", priv, glyph); + /* Remove the glyph for the list. First check for removal from the head */ if (prev == NULL) @@ -239,6 +241,8 @@ static inline void nxf_removeglyph(FAR struct nxfonts_fcache_s *priv, static inline void nxf_addglyph(FAR struct nxfonts_fcache_s *priv, FAR struct nxfonts_glyph_s *glyph) { + ginfo("fcache=%p glyph=%p\n", priv, glyph); + /* Add the glyph to the head of the list */ glyph->flink = priv->head; @@ -284,6 +288,9 @@ nxf_findglyph(FAR struct nxfonts_fcache_s *priv, uint8_t ch) FAR struct nxfonts_glyph_s *glyph; FAR struct nxfonts_glyph_s *prev; + ginfo("fcache=%p ch=%c (%02x)\n", + priv, (ch >= 32 && ch < 128) ? ch : '.', ch); + /* Try to find the glyph in the list of pre-rendered glyphs */ for (prev = NULL, glyph = priv->head; @@ -509,6 +516,9 @@ nxf_renderglyph(FAR struct nxfonts_fcache_s *priv, unsigned int stride; int ret; + ginfo("fcache=%p fbm=%p ch=%c (%02x)\n", + priv, fbm, (ch >= 32 && ch < 128) ? ch : '.', ch); + /* Get the size of the glyph */ width = fbm->metric.width + fbm->metric.xoffset; @@ -575,6 +585,9 @@ nxf_findcache(enum nx_fontid_e fontid, nxgl_mxpixel_t fgcolor, { FAR struct nxfonts_fcache_s *fcache; + ginfo("fontid=%p fgcolor=%u bgcolor=%u bpp=%d\n", + fontid, fgcolor, bgcolor, bpp); + /* Search for a cache for this font characteristics */ for (fcache = g_fcaches; fcache != NULL; fcache = fcache->flink) @@ -588,10 +601,12 @@ nxf_findcache(enum nx_fontid_e fontid, nxgl_mxpixel_t fgcolor, { /* Yes... return it */ + ginfo("Returning fcache=%p\n", fcache); return fcache; } } + ginfo("Not found\n"); return NULL; } @@ -629,6 +644,9 @@ FCACHE nxf_cache_connect(enum nx_fontid_e fontid, FAR struct nxfonts_fcache_s *priv; int errcode; + ginfo("fontid=%p fgcolor=%u bgcolor=%u bpp=%d maxglyphs=%d\n", + fontid, fgcolor, bgcolor, bpp, maxglyphs); + /* Get exclusive access to the font cache list */ nxf_list_lock(); @@ -721,6 +739,10 @@ FCACHE nxf_cache_connect(enum nx_fontid_e fontid, goto errout_with_fcache; } + /* Initialize the mutual exclusion semaphore */ + + sem_init(&priv->fsem, 0, 1); + /* Add the new font cache to the list of font caches */ priv->flink = g_fcaches; @@ -739,6 +761,7 @@ FCACHE nxf_cache_connect(enum nx_fontid_e fontid, } nxf_list_unlock(); + ginfo("fhandle=%p\n", priv); return (FCACHE)priv; errout_with_fcache: @@ -773,6 +796,8 @@ void nxf_cache_disconnect(FCACHE fhandle) FAR struct nxfonts_glyph_s *glyph; FAR struct nxfonts_glyph_s *next; + ginfo("fhandle=%p\n", fhandle); + DEBUGASSERT(priv != NULL && priv->fclients > 0); /* Get exclusive access to the font cache */ @@ -872,6 +897,8 @@ FAR const struct nxfonts_glyph_s *nxf_cache_getglyph(FCACHE fhandle, uint8_t ch) FAR struct nxfonts_glyph_s *glyph; FAR const struct nx_fontbitmap_s *fbm; + ginfo("ch=%c (%02x)\n", (ch >= 32 && ch < 128) ? ch : '.', ch); + /* Get exclusive access to the font cache */ nxf_cache_lock(priv);