From d45c477d44e9d352e9d91686237e26474ab009d7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 13 Nov 2018 09:03:10 +0100 Subject: [PATCH] two-step: bgrt: Deal with quirky firmwares On laptops / tablets the LCD panel is typically brought up in its native resolution, so we can trust the x- and y-offset values provided by the firmware to be correct for a screen with the panels resolution. Moreover some laptop / tablet firmwares to do all kind of hacks wrt the y-offset. This happens especially on devices where the panel is mounted 90 degrees rotated, but also on other devices. So on devices with an internal LCD panel, we prefer to use the firmware provided offsets, to make sure we match its quirky behavior. We check that the x-offset matches what we expect for the panel's native resolution to make sure that the values are indeed for the panel's native resolution and then we correct for any difference between the (external) screen's and the panel's resolution. Signed-off-by: Hans de Goede --- src/plugins/splash/two-step/plugin.c | 79 +++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/src/plugins/splash/two-step/plugin.c b/src/plugins/splash/two-step/plugin.c index 35701828..641eb703 100644 --- a/src/plugins/splash/two-step/plugin.c +++ b/src/plugins/splash/two-step/plugin.c @@ -124,6 +124,7 @@ struct _ply_boot_splash_plugin uint32_t background_start_color; uint32_t background_end_color; + int background_bgrt_raw_width; progress_function_t progress_function; @@ -244,6 +245,41 @@ view_load_end_animation (view_t *view) view->end_animation = NULL; } +static bool +get_bgrt_sysfs_offsets(int *x_offset, int *y_offset) +{ + bool ret = false; + char buf[64]; + FILE *f; + + f = fopen("/sys/firmware/acpi/bgrt/xoffset", "r"); + if (!f) + return false; + + if (!fgets(buf, sizeof(buf), f)) + goto out; + + if (sscanf(buf, "%d", x_offset) != 1) + goto out; + + fclose(f); + + f = fopen("/sys/firmware/acpi/bgrt/yoffset", "r"); + if (!f) + return false; + + if (!fgets(buf, sizeof(buf), f)) + goto out; + + if (sscanf(buf, "%d", y_offset) != 1) + goto out; + + ret = true; +out: + fclose(f); + return ret; +} + /* The Microsoft boot logo spec says that the logo must use a black background * and have its center at 38.2% from the screen's top (golden ratio). * We reproduce this exactly here so that we get a background which is an exact @@ -286,6 +322,45 @@ view_set_bgrt_background (view_t *view) x_offset = (screen_width - width) / 2; y_offset = screen_height * 382 / 1000 - height / 2; + /* + * On laptops / tablets the LCD panel is typically brought up in + * its native resolution, so we can trust the x- and y-offset values + * provided by the firmware to be correct for a screen with the panels + * resolution. + * + * Moreover some laptop / tablet firmwares to do all kind of hacks wrt + * the y offset. This happens especially on devices where the panel is + * mounted 90 degrees rotated, but also on other devices. + * + * So on devices with an internal LCD panel, we prefer to use the + * firmware provided offsets, to make sure we match its quirky behavior. + * + * We check that the x-offset matches what we expect for the panel's + * native resolution to make sure that the values are indeed for the + * panel's native resolution and then we correct for any difference + * between the (external) screen's and the panel's resolution. + */ + if (panel_width != 0 && panel_height != 0 && + get_bgrt_sysfs_offsets(&sysfs_x_offset, &sysfs_y_offset) && + (panel_width - view->plugin->background_bgrt_raw_width) / 2 == sysfs_x_offset) { + if (panel_rotation == PLY_PIXEL_BUFFER_ROTATE_CLOCKWISE || + panel_rotation == PLY_PIXEL_BUFFER_ROTATE_COUNTER_CLOCKWISE) { + /* 90 degrees rotated, swap x and y */ + x_offset = sysfs_y_offset / panel_scale; + y_offset = sysfs_x_offset / panel_scale; + + x_offset += (screen_width - panel_height / panel_scale) / 2; + y_offset += (screen_height - panel_width / panel_scale) * 382 / 1000; + } else { + /* Normal orientation */ + x_offset = sysfs_x_offset / panel_scale; + y_offset = sysfs_y_offset / panel_scale; + + x_offset += (screen_width - panel_width / panel_scale) / 2; + y_offset += (screen_height - panel_height / panel_scale) * 382 / 1000; + } + } + ply_trace ("using %dx%d bgrt image centered at %dx%d for %dx%d screen", width, height, x_offset, y_offset, screen_width, screen_height); @@ -1173,7 +1248,9 @@ show_splash_screen (ply_boot_splash_plugin_t *plugin, if (plugin->background_bgrt_image != NULL) { ply_trace ("loading background bgrt image"); - if (!ply_image_load (plugin->background_bgrt_image)) { + if (ply_image_load (plugin->background_bgrt_image)) { + plugin->background_bgrt_raw_width = ply_image_get_width (plugin->background_bgrt_image); + } else { ply_image_free (plugin->background_bgrt_image); plugin->background_bgrt_image = NULL; }