Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "External/edk2"]
path = External/edk2
url = https://github.com/tianocore/edk2.git
[submodule "External/lvgl"]
path = External/lvgl
url = https://github.com/lvgl/lvgl.git
61 changes: 61 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,67 @@ this file as both a release log and a lightweight development progress record.

### Added

- DisplayEngine per-opcode control affordances: each editable FormBrowser
statement now shows a distinct, non-semantic cue glyph keyed on its control
kind — checkbox box, numeric `+`, one-of/choice `▼`, ordered-list up/down,
string caret, date/time segment ticks, and reference/action `▶`. Cues are
drawn purely from renderer primitives, so they render identically through the
GOP and LVGL backends, and are composited by a post-text overlay
(`ModernDisplayDrawStatementRowCue`, called at the end of `DisplayOneMenu`) so
the native highlight text background no longer overpaints them. Read-only and
grayed/disabled rows intentionally get no cue. edk2 keeps all HII/value/storage
ownership; the cue helpers are smoke-guarded against
`ConfigAccess`/`RouteConfig`/`ExtractConfig`/`SetVariable`/`HiiGetString`.
- Unified control-affordance vocabulary across the front-page App and the
in-setup DisplayEngine: the per-control cue shapes now live in one shared
function, `ModernUiEngineDrawControlCue` (`ModernUiEngineLib`), keyed on
`MODERN_UI_VALUE_TYPE` and built from a new shared `ModernUiFillTriangle`
renderer primitive plus `ModernUiFillRect`/`ModernUiStrokeRect`. The App value
lane (`ModernUiEngineDrawValue`) now paints the matching cue just left of the
value box, and the DisplayEngine row overlay maps its row kind to the value
type (`ModernDisplayKindToValueType`) and delegates to the same function — so a
checkbox/drop-down/numeric/date-time/password/string/ordered-list/action
control reads identically in both surfaces. The DisplayEngine's former private
`ModernDisplayDrawKindCue`/`ModernDisplayCueTriangle` shape copies are removed.
- `build-ovmf-x64.sh` gains `MODERN_SETUP_DEMO_DRIVER_SAMPLE=0|1` (default `0`):
when `1`, edk2 `DriverSampleDxe` is added to the OVMF overlay (reachable via
Device Manager) as a control-rich VFR for exercising the DisplayEngine control
affordances. Off by default; never in a shipped overlay.
- Experimental LVGL renderer-swap mode (`experimental/lvgl-spike` branch only):
`MODERN_SETUP_DISPLAY_ENGINE=lvgl` now keeps the existing
`ModernDisplayEngineDxe` (all FormBrowser/HII/interaction ownership unchanged)
but resolves the `ModernUiRendererLib` class to a new LVGL-backed
implementation, `Library/ModernUiLvglRendererLib`. Every primitive composites
through LVGL's software draw pipeline into a persistent full-screen XRGB8888
shadow canvas, then BLTs only the touched region to GOP: geometry (fills,
borders, panels, rows, cards, progress, value boxes, drop-downs) via
`lv_draw_rect`, ASCII text via `lv_draw_label` (Montserrat), and non-ASCII
(CJK) runs via the firmware HII font composited into the same canvas (LVGL
bundles no CJK coverage). The library keeps the exact `ModernUiRenderer.h` API
and the original 8 px-cell text-measurement model, so layouts in the display
engine and `ModernSetupApp` are unchanged. Verified on OVMF X64: the live UiApp
FormBrowser front page renders end-to-end through LVGL. `LvglCoreLib` +
`IntrinsicLib` are force-linked only into the lvgl-mode overlay; never in a
default overlay. The earlier standalone `LvglDisplayEngineDxe` remains as a
separate from-scratch reference and is no longer wired into the OVMF overlay.
CJK is handled by compositing the package's embedded bitmap glyphs
(`ModernUiGlyphs.c`) into the LVGL canvas, with the firmware HII font as a
secondary fallback for code points without an embedded glyph. `lvgl` mode also
composes with `MODERN_SETUP_REPLACE_UIAPP=1`: the `ModernSetupApp` front-page
shell then renders through the same LVGL pipeline (IntrinsicLib is force-linked
into the app component in lvgl mode). Verified on OVMF X64 — both the UiApp
FormBrowser front page and the full ModernSetupApp dashboard (zh labels +
English values + all chrome) render end-to-end through LVGL.
- Experimental LVGL rendering-backend spike (`experimental/lvgl-spike` branch only;
`Experimental/LvglSpikePkg`, never in a default overlay or `ModernSetupApp`).
Pins `External/lvgl` at a tagged v9.5.0-derived baseline and validates that
LVGL core + software renderer + its upstream UEFI port build under edk2 GCC on
a hard architecture: `LvglSpikeProbe.efi` compiles for LoongArch64 and was run
on real LoongArch hardware, drawing an LVGL UI straight to GOP (standalone-app
path, not via any DisplayEngine). The ~3-site LoongArch64/RISC-V64 UEFI
arch-gate change was contributed upstream and is now in the pinned baseline, so
`External/lvgl` is consumed pristine (no local patch, no build-time patching).
See `Experimental/LvglSpikePkg/README.md`.
- ModernSetupApp header clock now updates live while the front page is idle. The
app loop arms a one-second periodic timer and waits on it alongside the
keyboard/pointer sources, repainting only the header clock text in place on
Expand Down
47 changes: 47 additions & 0 deletions Docs/MODULE_BOUNDARIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,53 @@ ModernSetupPkg is easiest to maintain when each layer keeps a small, concrete co
| HII bridge | Stay isolated as experimental parser/adapter research | Become the default compatibility path, force writes, treat unsupported opcodes as safe |
| Platform/CI | Build scripts, overlays, QEMU/manual validation, release packaging | Hide behavior changes inside scripts or docs-only PRs |

## Renderer backends

`ModernUiRendererLib` is a class with two interchangeable implementations selected
by the build (`MODERN_SETUP_DISPLAY_ENGINE`); both expose the identical
`Include/ModernUi/ModernUiRenderer.h` API:

- **GOP backend** (`Library/ModernUiRendererLib`) — the default. Draws straight to
`EFI_GRAPHICS_OUTPUT_PROTOCOL` (BLT fills, HII-font text, built-in bitmap glyphs).
- **LVGL backend** (`Library/ModernUiLvglRendererLib`, `=lvgl`, experimental) — every
primitive is composited by LVGL's software renderer into a persistent full-screen
XRGB8888 **shadow canvas**, then only the touched region is BLT'd to GOP. Geometry
uses `lv_draw_rect`; ASCII text uses `lv_draw_label` (Montserrat); non-ASCII (CJK)
runs use the package's embedded bitmap glyphs (`ModernUiGlyphs.c`), with the
firmware HII font as a secondary fallback (LVGL ships no CJK font).

Both backends share, verbatim, the backend-agnostic surface
`Library/ModernUiRendererLib/ModernUiRendererCommon.c` (geometry compositions, text
measurement, themed widgets, the `ModernUiFillTriangle` shape primitive) and the
glyph table `ModernUiGlyphs.c`. A backend provides only three primitives —
`ModernUiRendererInit`, `ModernUiFillRect`, `ModernUiDrawText` — declared with the
shared helpers in `ModernUiRendererInternal.h`. Keep the 8 px-cell /
fixed-CJK-cell measurement model identical across backends so caller layouts are
backend-stable.

## Control-affordance vocabulary

The per-control cue shapes (checkbox box, one-of `▼`, ordered-list up/down,
numeric `+`, date/time segment ticks, password dots, string caret, action `▶`)
are defined **once**, in `ModernUiEngineDrawControlCue` (`ModernUiEngineLib`),
keyed on `MODERN_UI_VALUE_TYPE` and built only from renderer primitives
(`ModernUiFillRect` / `ModernUiStrokeRect` / `ModernUiFillTriangle`). Both
surfaces that show controls delegate to it, so a given control type reads
identically in each:

- **Front-page App value lane** — `ModernUiEngineDrawValue` paints the cue just
left of the value box.
- **In-setup DisplayEngine row** — `ModernDisplayDrawStatementRowCue` maps its
`MODERN_DISPLAY_FORM_ROW_KIND` to the value type via
`ModernDisplayKindToValueType` and draws the cue at the row's right edge,
**after** native FormBrowser prints the row text (so it composites on top
instead of being overpainted). It classifies already-materialized statement
data only and never touches HII/config/storage; read-only and disabled rows
get no cue.

Do not add a second copy of these shapes in either consumer — extend the shared
vocabulary and add the value-type mapping instead.

## What not to do

- App code must not parse IFR or write HII varstores. Real setup pages should enter native FormBrowser with `EFI_FORM_BROWSER2_PROTOCOL.SendForm()`.
Expand Down
18 changes: 18 additions & 0 deletions Experimental/LvglSpikePkg/Include/Library/LvglCoreLib.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/** @file
LvglCoreLib -- convenience umbrella header for the shared LVGL build (core +
software renderer + upstream UEFI port). Consumers include this to get the LVGL
and lv_uefi APIs. experimental/lvgl-spike only.

Copyright (c) 2026, MarsDoge. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/

#ifndef LVGL_CORE_LIB_H_
#define LVGL_CORE_LIB_H_

#include "lvgl/lvgl.h"
#include "lvgl/src/drivers/uefi/lv_uefi.h"
#include "lvgl/src/drivers/uefi/lv_uefi_context.h"
#include "lvgl/src/drivers/uefi/lv_uefi_display.h"

#endif // LVGL_CORE_LIB_H_
69 changes: 69 additions & 0 deletions Experimental/LvglSpikePkg/Include/Library/LvglLib.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/** @file
LvglLib class with APIs from the openssl project

Copyright (c) 2024, Yang Gang. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#ifndef __LVGL_LIB_H__
#define __LVGL_LIB_H__

#if defined(_MSC_VER)
#pragma warning(disable: 4244) // workaround for misc/lv_color.h(355), remove after lvgl update
#endif

#include <lvgl.h>

//
// Custom LVGL key codes for EFI function keys F1-F12.
// EFI SCAN_F1..F12 (0x000B-0x0016) overlap with LVGL reserved key values,
// so we remap them to a safe range above 0x0100.
//
#define LV_KEY_F1 0x0101U
#define LV_KEY_F2 0x0102U
#define LV_KEY_F3 0x0103U
#define LV_KEY_F4 0x0104U
#define LV_KEY_F5 0x0105U
#define LV_KEY_F6 0x0106U
#define LV_KEY_F7 0x0107U
#define LV_KEY_F8 0x0108U
#define LV_KEY_F9 0x0109U
#define LV_KEY_F10 0x010AU
#define LV_KEY_F11 0x010BU
#define LV_KEY_F12 0x010CU

typedef
VOID
(EFIAPI *EFI_LVGL_APP_FUNCTION)(
VOID
);

EFI_STATUS
EFIAPI
UefiLvglInit (
VOID
);

EFI_STATUS
EFIAPI
UefiLvglDeinit (
VOID
);

EFI_STATUS
EFIAPI
UefiLvglAppRegister (
IN EFI_LVGL_APP_FUNCTION AppRegister
);

/**
Drain the EFI keyboard buffer and reset the LVGL keypad indev state so that
no pending key-press leaks into the next event loop.
**/
void
lv_uefi_keypad_drain (
void
);

#endif
157 changes: 157 additions & 0 deletions Experimental/LvglSpikePkg/Include/LvglTheme.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/** @file
LvglTheme.h - User-customizable theme for LvglDisplayEngineDxe.

Edit the macros in this file and rebuild to restyle the LVGL HII form
renderer. All colors, fonts, padding, and radius values used by
LvglFormRenderer.c flow through these macros.

Fonts referenced here must be enabled in LvglPkg/lv_conf.h
(LV_FONT_MONTSERRAT_*).
**/

#ifndef LVGL_THEME_H_
#define LVGL_THEME_H_

#include <lvgl.h>

//
// Background colors (24-bit RGB; passed to lv_color_hex())
//
// NovaCore palette: near-black canvas, blue-tinted panels, accent blue.
//
#define THEME_COLOR_BG_SCREEN 0x0F141A
#define THEME_COLOR_BG_PANEL 0x182328
#define THEME_COLOR_BG_PANEL_ELEV 0x23304A
#define THEME_COLOR_BG_DIALOG 0x1B2A3A
#define THEME_COLOR_BG_SEPARATOR 0x2A3A52

//
// Text colors
//
#define THEME_COLOR_TEXT_TITLE 0xFFFFFF
#define THEME_COLOR_TEXT_PRIMARY 0xEAF2FF
#define THEME_COLOR_TEXT_SECONDARY 0x9FB0C8
#define THEME_COLOR_TEXT_DISABLED 0x6A7B92
#define THEME_COLOR_TEXT_LABEL THEME_COLOR_TEXT_PRIMARY
#define THEME_COLOR_TEXT_POPUP THEME_COLOR_TEXT_PRIMARY

//
// Row colors (default vs focused).
//
#define THEME_COLOR_ROW_BG THEME_COLOR_BG_PANEL
#define THEME_COLOR_ROW_TEXT THEME_COLOR_TEXT_PRIMARY
#define THEME_COLOR_ROW_TEXT_FOCUSED 0xFFFFFF
#define THEME_COLOR_ROW_TEXT_DISABLED THEME_COLOR_TEXT_DISABLED

//
// Accent (focus ring + active selection).
//
#define THEME_COLOR_ACCENT 0x1A6FD8
#define THEME_COLOR_ACCENT_HOVER 0x2A85F0
#define THEME_COLOR_SUCCESS 0x2BC79F
#define THEME_COLOR_WARNING 0xE9A23B
#define THEME_COLOR_DANGER 0xE25555

//
// Accent (subtitle / focus highlight) — LV_PALETTE_* enum value
//
#define THEME_ACCENT_PALETTE LV_PALETTE_BLUE

//
// Fonts — must be enabled in lv_conf.h
//
#define THEME_FONT_TITLE (&lv_font_montserrat_20)
#define THEME_FONT_BODY (&lv_font_montserrat_16)
#define THEME_FONT_POPUP (&lv_font_montserrat_16)

//
// Spacing & shape (pixels)
//
#define THEME_PAD_SCREEN 16
#define THEME_PAD_PANEL 8
#define THEME_PAD_ROW 4
#define THEME_PAD_ROW_TIGHT 2
#define THEME_PAD_DIALOG 16
#define THEME_PAD_DIALOG_ROW_GAP 10
#define THEME_PAD_DIALOG_COL_GAP 8
#define THEME_PAD_SCREEN_ROW_GAP 6
#define THEME_PAD_PANEL_ROW_GAP 4
#define THEME_PAD_LABEL_TOP 8
#define THEME_RADIUS 8
#define THEME_OVERLAY_OPA LV_OPA_50

//
// Aptio-style chrome (header / subtitle / footer / wallpaper).
// Used by LvglDisplayEngineDxe/LvglAptioChrome.c.
//
#define THEME_COLOR_HEADER_BG_TOP 0x0B1218
#define THEME_COLOR_HEADER_BG_BOTTOM 0x16263F
#define THEME_COLOR_HEADER_TEXT 0xFFFFFF
#define THEME_COLOR_HEADER_DIM 0x9FB0C8
#define THEME_COLOR_SUBTITLE_BG 0x182328
#define THEME_COLOR_SUBTITLE_TEXT 0xEAF2FF
#define THEME_COLOR_FOOTER_BG 0x0B1218
#define THEME_COLOR_FOOTER_TEXT 0xEAF2FF
#define THEME_COLOR_FOOTER_DIM 0x6A7B92
#define THEME_COLOR_HIGHLIGHT_ROW THEME_COLOR_ACCENT

#define THEME_HEADER_HEIGHT 44
#define THEME_SUBTITLE_HEIGHT 28
#define THEME_FOOTER_HEIGHT 32

//
// Chrome — help pane (right column).
//
#define THEME_HELPPANE_WIDTH 240
#define THEME_PAD_HELPPANE_X 14
#define THEME_PAD_HELPPANE_Y 12
#define THEME_PAD_HELPPANE_ROW_GAP 8

//
// Chrome — header / subtitle / content / footer paddings.
//
#define THEME_PAD_HEADER_X 16
#define THEME_PAD_SUBTITLE_X 16
#define THEME_PAD_CONTENT_LEFT 24
#define THEME_PAD_CONTENT_RIGHT 16
#define THEME_PAD_CONTENT_Y 12
#define THEME_PAD_CONTENT_ROW_GAP 6
#define THEME_PAD_FOOTER_X 12
#define THEME_PAD_FOOTER_Y 2
#define THEME_PAD_FOOTER_COL_GAP 6

//
// Footer "chip" widgets (one per registered hotkey + nav primitives).
//
#define THEME_PAD_CHIP_X 8
#define THEME_PAD_CHIP_Y 4
#define THEME_PAD_CHIP_COL_GAP 6
#define THEME_RADIUS_CHIP 4

//
// Form rows (StyleRow).
//
#define THEME_RADIUS_ROW 4
#define THEME_PAD_ROW_X 16
#define THEME_PAD_ROW_Y 10
#define THEME_BORDER_FOCUS 3

//
// Generic 1 px separator/border thickness used between panes.
//
#define THEME_BORDER_PANE 1

//
// Confirm/discard dialog card width as a percentage of the screen.
//
#define THEME_DIALOG_WIDTH_PCT 50

//
// Static strings shown in the chrome (no SMBIOS lookup yet).
//
#define APTIO_HEADER_TITLE "EDK II Boot Manager"
#define APTIO_HEADER_VENDOR "UEFI v2.90 | EDK II"
#define APTIO_FOOTER_NAV_HINTS LV_SYMBOL_UP LV_SYMBOL_DOWN " Select Enter Confirm Esc Exit F9 Defaults F10 Save"
#define APTIO_FOOTER_SYSINFO "QEMU x86_64 | OVMF"

#endif // LVGL_THEME_H_
Loading
Loading