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
This commit is contained in:
parent
c01da939b0
commit
becaac3972
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user