The branch main has been updated by tsoome:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=becaac3972f1fde4e3c44516399468ba5ca65c9b

commit becaac3972f1fde4e3c44516399468ba5ca65c9b
Author:     Toomas Soome <tso...@freebsd.org>
AuthorDate: 2021-02-20 08:51:28 +0000
Commit:     Toomas Soome <tso...@freebsd.org>
CommitDate: 2021-02-27 09:26:02 +0000

    loader: use display pixel density for font autoselection
    
    Calculate font size from 16 density independent pixels (dp) by using:
    size = 16 * ppi/160 * display_factor
    
    We are specifying font size 16dp, and assuming 1dp = 160ppi.
    Also apply scaling factor 2 (display_factor).
    
    MFC after: 1 week
    Differential Revision: https://reviews.freebsd.org/D28849
---
 stand/common/gfx_fb.c          | 110 +++++++++++++++++++++++++++++++++++++++++
 stand/common/gfx_fb.h          |   2 +
 stand/efi/libefi/efi_console.c |  23 ++++++---
 stand/efi/loader/framebuffer.c |  96 +++++++++++++++++++++++++++++++++--
 stand/i386/libi386/vbe.c       |  25 ++++++----
 5 files changed, 237 insertions(+), 19 deletions(-)

diff --git a/stand/common/gfx_fb.c b/stand/common/gfx_fb.c
index 02a0a3d2be22..77cf1d39854f 100644
--- a/stand/common/gfx_fb.c
+++ b/stand/common/gfx_fb.c
@@ -1863,6 +1863,113 @@ reset_font_flags(void)
        }
 }
 
+/* Return  w^2 + h^2 or 0, if the dimensions are unknown */
+static unsigned
+edid_diagonal_squared(void)
+{
+       unsigned w, h;
+
+       if (edid_info == NULL)
+               return (0);
+
+       w = edid_info->display.max_horizontal_image_size;
+       h = edid_info->display.max_vertical_image_size;
+
+       /* If either one is 0, we have aspect ratio, not size */
+       if (w == 0 || h == 0)
+               return (0);
+
+       /*
+        * some monitors encode the aspect ratio instead of the physical size.
+        */
+       if ((w == 16 && h == 9) || (w == 16 && h == 10) ||
+           (w == 4 && h == 3) || (w == 5 && h == 4))
+               return (0);
+
+       /*
+        * translate cm to inch, note we scale by 100 here.
+        */
+       w = w * 100 / 254;
+       h = h * 100 / 254;
+
+       /* Return w^2 + h^2 */
+       return (w * w + h * h);
+}
+
+/*
+ * calculate pixels per inch.
+ */
+static unsigned
+gfx_get_ppi(void)
+{
+       unsigned dp, di;
+
+       di = edid_diagonal_squared();
+       if (di == 0)
+               return (0);
+
+       dp = gfx_state.tg_fb.fb_width *
+           gfx_state.tg_fb.fb_width +
+           gfx_state.tg_fb.fb_height *
+           gfx_state.tg_fb.fb_height;
+
+       return (isqrt(dp / di));
+}
+
+/*
+ * Calculate font size from density independent pixels (dp):
+ * ((16dp * ppi) / 160) * display_factor.
+ * Here we are using fixed constants: 1dp == 160 ppi and
+ * display_factor 2.
+ *
+ * We are rounding font size up and are searching for font which is
+ * not smaller than calculated size value.
+ */
+static vt_font_bitmap_data_t *
+gfx_get_font(void)
+{
+       unsigned ppi, size;
+       vt_font_bitmap_data_t *font = NULL;
+       struct fontlist *fl, *next;
+
+       /* Text mode is not supported here. */
+       if (gfx_state.tg_fb_type == FB_TEXT)
+               return (NULL);
+
+       ppi = gfx_get_ppi();
+       if (ppi == 0)
+               return (NULL);
+
+       /*
+        * We will search for 16dp font.
+        * We are using scale up by 10 for roundup.
+        */
+       size = (16 * ppi * 10) / 160;
+       /* Apply display factor 2.  */
+       size = roundup(size * 2, 10) / 10;
+
+       STAILQ_FOREACH(fl, &fonts, font_next) {
+               next = STAILQ_NEXT(fl, font_next);
+
+               /*
+                * If this is last font or, if next font is smaller,
+                * we have our font. Make sure, it actually is loaded.
+                */
+               if (next == NULL || next->font_data->vfbd_height < size) {
+                       font = fl->font_data;
+                       if (font->vfbd_font == NULL ||
+                           fl->font_flags == FONT_RELOAD) {
+                               if (fl->font_load != NULL &&
+                                   fl->font_name != NULL)
+                                       font = fl->font_load(fl->font_name);
+                       }
+                       break;
+               }
+       }
+
+       return (font);
+}
+
 static vt_font_bitmap_data_t *
 set_font(teken_unit_t *rows, teken_unit_t *cols, teken_unit_t h, teken_unit_t 
w)
 {
@@ -1887,6 +1994,9 @@ set_font(teken_unit_t *rows, teken_unit_t *cols, 
teken_unit_t h, teken_unit_t w)
                }
        }
 
+       if (font == NULL)
+               font = gfx_get_font();
+
        if (font != NULL) {
                *rows = height / font->vfbd_height;
                *cols = width / font->vfbd_width;
diff --git a/stand/common/gfx_fb.h b/stand/common/gfx_fb.h
index 04076a2c6d38..ac63d7939cef 100644
--- a/stand/common/gfx_fb.h
+++ b/stand/common/gfx_fb.h
@@ -109,6 +109,8 @@ struct vesa_edid_info {
        uint8_t checksum;
 } __packed;
 
+extern struct vesa_edid_info *edid_info;
+
 #define        STD_TIMINGS     8
 #define        DET_TIMINGS     4
 
diff --git a/stand/efi/libefi/efi_console.c b/stand/efi/libefi/efi_console.c
index 3cbd121c41da..0c40b362f276 100644
--- a/stand/efi/libefi/efi_console.c
+++ b/stand/efi/libefi/efi_console.c
@@ -952,13 +952,24 @@ cons_update_mode(bool use_gfx_mode)
 
                        /*
                         * setup_font() can adjust terminal size.
-                        * Note, we do use UEFI terminal dimensions first,
-                        * this is because the font selection will attempt
-                        * to achieve at least this terminal dimension and
-                        * we do not end up with too small font.
+                        * We can see two kind of bad happening.
+                        * We either can get too small console font - requested
+                        * terminal size is large, display resolution is
+                        * large, and we get very small font.
+                        * Or, we can get too large font - requested
+                        * terminal size is small and this will cause large
+                        * font to be selected.
+                        * Now, the setup_font() is updated to consider
+                        * display density and this should give us mostly
+                        * acceptable font. However, the catch is, not all
+                        * display devices will give us display density.
+                        * Still, we do hope, external monitors do - this is
+                        * where the display size will matter the most.
+                        * And for laptop screens, we should still get good
+                        * results by requesting 80x25 terminal.
                         */
-                       gfx_state.tg_tp.tp_row = rows;
-                       gfx_state.tg_tp.tp_col = cols;
+                       gfx_state.tg_tp.tp_row = 25;
+                       gfx_state.tg_tp.tp_col = 80;
                        setup_font(&gfx_state, fb_height, fb_width);
                        rows = gfx_state.tg_tp.tp_row;
                        cols = gfx_state.tg_tp.tp_col;
diff --git a/stand/efi/loader/framebuffer.c b/stand/efi/loader/framebuffer.c
index 509c41844dcb..adb9dfb62cee 100644
--- a/stand/efi/loader/framebuffer.c
+++ b/stand/efi/loader/framebuffer.c
@@ -38,6 +38,8 @@ __FBSDID("$FreeBSD$");
 #include <efilib.h>
 #include <efiuga.h>
 #include <efipciio.h>
+#include <Protocol/EdidActive.h>
+#include <Protocol/EdidDiscovered.h>
 #include <machine/metadata.h>
 
 #include "bootstrap.h"
@@ -47,6 +49,12 @@ static EFI_GUID conout_guid = EFI_CONSOLE_OUT_DEVICE_GUID;
 EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
 static EFI_GUID pciio_guid = EFI_PCI_IO_PROTOCOL_GUID;
 static EFI_GUID uga_guid = EFI_UGA_DRAW_PROTOCOL_GUID;
+static EFI_GUID active_edid_guid = EFI_EDID_ACTIVE_PROTOCOL_GUID;
+static EFI_GUID discovered_edid_guid = EFI_EDID_DISCOVERED_PROTOCOL_GUID;
+static EFI_HANDLE gop_handle;
+
+/* Cached EDID. */
+struct vesa_edid_info *edid_info = NULL;
 
 static EFI_GRAPHICS_OUTPUT *gop;
 static EFI_UGA_DRAW_PROTOCOL *uga;
@@ -467,10 +475,71 @@ efifb_from_uga(struct efi_fb *efifb)
        return (0);
 }
 
+/*
+ * Fetch EDID info. Caller must free the buffer.
+ */
+static struct vesa_edid_info *
+efifb_gop_get_edid(EFI_HANDLE h)
+{
+       const uint8_t magic[] = EDID_MAGIC;
+       EFI_EDID_ACTIVE_PROTOCOL *edid;
+       struct vesa_edid_info *edid_infop;
+       EFI_GUID *guid;
+       EFI_STATUS status;
+       size_t size;
+
+       guid = &active_edid_guid;
+       status = BS->OpenProtocol(h, guid, (void **)&edid, IH, NULL,
+           EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+       if (status != EFI_SUCCESS ||
+           edid->SizeOfEdid == 0) {
+               guid = &discovered_edid_guid;
+               status = BS->OpenProtocol(h, guid, (void **)&edid, IH, NULL,
+                   EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+               if (status != EFI_SUCCESS ||
+                   edid->SizeOfEdid == 0)
+                       return (NULL);
+       }
+
+       size = MAX(sizeof(*edid_infop), edid->SizeOfEdid);
+
+       edid_infop = calloc(1, size);
+       if (edid_infop == NULL)
+               return (NULL);
+
+       memcpy(edid_infop, edid->Edid, edid->SizeOfEdid);
+
+       /* Validate EDID */
+       if (memcmp(edid_infop, magic, sizeof (magic)) != 0)
+               goto error;
+
+       if (edid_infop->header.version != 1)
+               goto error;
+
+       return (edid_infop);
+error:
+       free(edid_infop);
+       return (NULL);
+}
+
+static bool
+efifb_get_edid(edid_res_list_t *res)
+{
+       bool rv = false;
+
+       if (edid_info == NULL)
+               edid_info = efifb_gop_get_edid(gop_handle);
+
+       if (edid_info != NULL)
+               rv = gfx_get_edid_resolution(edid_info, res);
+
+       return (rv);
+}
+
 int
 efi_find_framebuffer(teken_gfx_t *gfx_state)
 {
-       EFI_HANDLE h, *hlist;
+       EFI_HANDLE *hlist;
        UINTN nhandles, i, hsize;
        struct efi_fb efifb;
        EFI_STATUS status;
@@ -498,23 +567,25 @@ efi_find_framebuffer(teken_gfx_t *gfx_state)
        /*
         * Search for ConOut protocol, if not found, use first handle.
         */
-       h = *hlist;
+       gop_handle = *hlist;
        for (i = 0; i < nhandles; i++) {
                void *dummy = NULL;
 
                status = OpenProtocolByHandle(hlist[i], &conout_guid, &dummy);
                if (status == EFI_SUCCESS) {
-                       h = hlist[i];
+                       gop_handle = hlist[i];
                        break;
                }
        }
 
-       status = OpenProtocolByHandle(h, &gop_guid, (void **)&gop);
+       status = OpenProtocolByHandle(gop_handle, &gop_guid, (void **)&gop);
        free(hlist);
 
        if (status == EFI_SUCCESS) {
                gfx_state->tg_fb_type = FB_GOP;
                gfx_state->tg_private = gop;
+               if (edid_info == NULL)
+                       edid_info = efifb_gop_get_edid(gop_handle);
        } else {
                status = BS->LocateProtocol(&uga_guid, NULL, (VOID **)&uga);
                if (status == EFI_SUCCESS) {
@@ -767,9 +838,25 @@ command_gop(int argc, char *argv[])
        } else if (strcmp(argv[1], "off") == 0) {
                (void) cons_update_mode(false);
        } else if (strcmp(argv[1], "get") == 0) {
+               edid_res_list_t res;
+
                if (argc != 2)
                        goto usage;
+               TAILQ_INIT(&res);
                efifb_from_gop(&efifb, gop->Mode, gop->Mode->Info);
+               if (efifb_get_edid(&res)) {
+                       struct resolution *rp;
+
+                       printf("EDID");
+                       while ((rp = TAILQ_FIRST(&res)) != NULL) {
+                               printf(" %dx%d", rp->width, rp->height);
+                               TAILQ_REMOVE(&res, rp, next);
+                               free(rp);
+                       }
+                       printf("\n");
+               } else {
+                       printf("no EDID information\n");
+               }
                print_efifb(gop->Mode->Mode, &efifb, 1);
                printf("\n");
        } else if (!strcmp(argv[1], "list")) {
@@ -778,6 +865,7 @@ command_gop(int argc, char *argv[])
 
                if (argc != 2)
                        goto usage;
+
                pager_open();
                for (mode = 0; mode < gop->Mode->MaxMode; mode++) {
                        status = gop->QueryMode(gop, mode, &infosz, &info);
diff --git a/stand/i386/libi386/vbe.c b/stand/i386/libi386/vbe.c
index 0e9f6929ac05..ef4daffa8380 100644
--- a/stand/i386/libi386/vbe.c
+++ b/stand/i386/libi386/vbe.c
@@ -51,6 +51,7 @@ static struct modeinfoblock *vbe_mode;
 
 static uint16_t *vbe_mode_list;
 static size_t vbe_mode_list_size;
+struct vesa_edid_info *edid_info = NULL;
 
 /* The default VGA color palette format is 6 bits per primary color. */
 int palette_format = 6;
@@ -836,34 +837,40 @@ vbe_dump_mode(int modenum, struct modeinfoblock *mi)
 static bool
 vbe_get_edid(edid_res_list_t *res)
 {
-       struct vesa_edid_info *edid_info;
+       struct vesa_edid_info *edidp;
        const uint8_t magic[] = EDID_MAGIC;
        int ddc_caps;
        bool ret = false;
 
+       if (edid_info != NULL)
+               return (gfx_get_edid_resolution(edid_info, res));
+
        ddc_caps = biosvbe_ddc_caps();
        if (ddc_caps == 0) {
                return (ret);
        }
 
-       edid_info = bio_alloc(sizeof (*edid_info));
-       if (edid_info == NULL)
+       edidp = bio_alloc(sizeof(*edidp));
+       if (edidp == NULL)
                return (ret);
-       memset(edid_info, 0, sizeof (*edid_info));
+       memset(edidp, 0, sizeof(*edidp));
 
-       if (VBE_ERROR(biosvbe_ddc_read_edid(0, edid_info)))
+       if (VBE_ERROR(biosvbe_ddc_read_edid(0, edidp)))
                goto done;
 
-       if (memcmp(edid_info, magic, sizeof (magic)) != 0)
+       if (memcmp(edidp, magic, sizeof(magic)) != 0)
                goto done;
 
        /* Unknown EDID version. */
-       if (edid_info->header.version != 1)
+       if (edidp->header.version != 1)
                goto done;
 
-       ret = gfx_get_edid_resolution(edid_info, res);
+       ret = gfx_get_edid_resolution(edidp, res);
+       edid_info = malloc(sizeof(*edid_info));
+       if (edid_info != NULL)
+               memcpy(edid_info, edidp, sizeof (*edid_info));
 done:
-       bio_free(edid_info, sizeof (*edid_info));
+       bio_free(edidp, sizeof(*edidp));
        return (ret);
 }
 
_______________________________________________
dev-commits-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-all
To unsubscribe, send any mail to "dev-commits-src-all-unsubscr...@freebsd.org"

Reply via email to