]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[efi] Support Unicode character output via framebuffer console
authorMichael Brown <mcb30@ipxe.org>
Tue, 15 Mar 2022 15:04:22 +0000 (15:04 +0000)
committerMichael Brown <mcb30@ipxe.org>
Tue, 15 Mar 2022 17:30:52 +0000 (17:30 +0000)
Extend the glyph cache to include a number of dynamic entries that are
populated on demand whenever a non-ASCII character needs to be drawn.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/interface/efi/efi_fbcon.c

index d9e3e69e64b1365ef3d46c962b7a46f294368bb9..d388e03171eca317764401e9b5cb11974b5aad6a 100644 (file)
@@ -65,6 +65,9 @@ struct console_driver efi_console __attribute__ (( weak ));
 /** Number of ASCII glyphs in cache */
 #define EFIFB_ASCII 128
 
+/** Number of dynamic non-ASCII glyphs in cache */
+#define EFIFB_DYNAMIC 32
+
 /* Forward declaration */
 struct console_driver efifb_console __console_driver;
 
@@ -89,6 +92,10 @@ struct efifb {
        struct fbcon_font font;
        /** Character glyph cache */
        userptr_t glyphs;
+       /** Dynamic characters in cache */
+       unsigned int dynamic[EFIFB_DYNAMIC];
+       /** Next dynamic character cache entry to evict */
+       unsigned int next;
 };
 
 /** The EFI frame buffer */
@@ -177,6 +184,41 @@ static int efifb_draw_unknown ( unsigned int index ) {
        return efifb_draw ( '?', index, -1U );
 }
 
+/**
+ * Get dynamic glyph index
+ *
+ * @v character                Unicode character
+ * @ret index          Glyph cache index
+ */
+static unsigned int efifb_dynamic ( unsigned int character ) {
+       unsigned int dynamic;
+       unsigned int index;
+       unsigned int i;
+       int height;
+
+       /* Search existing cached entries */
+       for ( i = 0 ; i < EFIFB_DYNAMIC ; i++ ) {
+               if ( character == efifb.dynamic[i] )
+                       return ( EFIFB_ASCII + i );
+       }
+
+       /* Overwrite the oldest cache entry */
+       dynamic = ( efifb.next++ % EFIFB_DYNAMIC );
+       index = ( EFIFB_ASCII + dynamic );
+       DBGC2 ( &efifb, "EFIFB dynamic %#02x is glyph %#02x\n",
+               dynamic, character );
+
+       /* Draw glyph */
+       height = efifb_draw ( character, index, 0 );
+       if ( height < 0 )
+               efifb_draw_unknown ( index );
+
+       /* Record cached character */
+       efifb.dynamic[dynamic] = character;
+
+       return index;
+}
+
 /**
  * Get character glyph
  *
@@ -195,8 +237,8 @@ static void efifb_glyph ( unsigned int character, uint8_t *glyph ) {
 
        } else {
 
-               /* Non-ASCII character: use an "unknown" glyph */
-               index = 0;
+               /* Non-ASCII character: use dynamic glyph cache */
+               index = efifb_dynamic ( character );
        }
 
        /* Copy cached glyph */
@@ -248,7 +290,7 @@ static int efifb_glyphs ( void ) {
        efifb.font.height = max;
 
        /* Allocate glyph data */
-       len = ( EFIFB_ASCII * efifb.font.height );
+       len = ( ( EFIFB_ASCII + EFIFB_DYNAMIC ) * efifb.font.height );
        efifb.glyphs = umalloc ( len );
        if ( ! efifb.glyphs ) {
                rc = -ENOMEM;
@@ -273,6 +315,9 @@ static int efifb_glyphs ( void ) {
                }
        }
 
+       /* Clear dynamic glyph character cache */
+       memset ( efifb.dynamic, 0, sizeof ( efifb.dynamic ) );
+
        efifb.font.glyph = efifb_glyph;
        return 0;