starkernel: item 4.3.1 -- framebuffer orientation test, found and fixed a real color-swap bug

Adds fb_draw_orientation_test() (framebuffer.c/.h): fills the four raster
corners RED/GREEN/BLUE/YELLOW via fb_fill_rect. Wired into kernel_main.c
calling fb_init() directly -- console_fb_init()/vt100_init() removed from
the boot path, since vt100.c/console.c are superseded by the Console
drawing-fabric redesign (FABRIC.md ss27) and should not be exercised even
incidentally.

The diagnostic caught a real, pre-existing bug on its first run: framebuffer.c's
pack_pixel() had its FB_PIXEL_RGBX32/FB_PIXEL_BGRX32 branches swapped relative
to UEFI GOP's own byte-order naming convention, producing a clean R<->B channel
swap (G unaffected). Spatial placement was already correct -- no flip/rotation.
Fixed by swapping pack_pixel's two return bodies to match framebuffer.h's
already-correct doc comments; kernel_main.c's GOP-format switch needed no change.

Also item 4.3.2 -- QEMU screenshot capability. scripts/qemu_screenshot.sh
already existed (monitor socket + socat + HMP screendump), just unwired and
unused this session. Redirected its PNG output to a new top-level fb/
directory (tracked in git, not logs/, not a gitignored temp dir) and added a
python3+PIL fallback for PPM->PNG conversion since imagemagick isn't
installed here. Left as a standalone script for now, not wired into a
Makefile target.

FABRIC.md items 4.3.1 and 4.3.2 marked done with acceptance evidence.
This commit is contained in:
Robert Allan James
2026-08-07 11:38:33 -04:00
parent f3acfb9b47
commit ab96ac0970
11 changed files with 54516 additions and 15 deletions
+50 -4
View File
@@ -66,17 +66,27 @@ static FbState g_fb;
* Internal helpers
* --------------------------------------------------------------------- */
/* Convert our 0x00RRGGBB to the hardware BGRX / RGBX 32-bit word */
/*
* Convert our 0x00RRGGBB to the hardware 32-bit word.
*
* GOP format names describe increasing byte address in memory (little-endian
* uint32 store), e.g. PixelRedGreenBlueReserved8BitPerColor means byte0=R,
* byte1=G, byte2=B, byte3=X -- which as a little-endian uint32 puts R in
* bits[7:0], G in bits[15:8], B in bits[23:16]. The two branches below were
* previously swapped relative to that (found via FABRIC.md item 4.3.1's
* orientation test: corners rendered with R and B channels exchanged).
*/
static uint32_t pack_pixel(uint32_t rgb)
{
uint32_t r = FB_R(rgb);
uint32_t g = FB_G(rgb);
uint32_t b = FB_B(rgb);
if (g_fb.fmt == FB_PIXEL_RGBX32) {
return (r << 16) | (g << 8) | b; /* RGBX: R@[23:16] */
/* RGBX byte order R,G,B: byte0=R@[7:0] byte1=G@[15:8] byte2=B@[23:16] */
return (b << 16) | (g << 8) | r;
}
/* BGRX (default): B@[23:16] G@[15:8] R@[7:0] */
return (b << 16) | (g << 8) | r;
/* BGRX (default), byte order B,G,R: byte0=B@[7:0] byte1=G@[15:8] byte2=R@[23:16] */
return (r << 16) | (g << 8) | b;
}
/* -----------------------------------------------------------------------
@@ -197,6 +207,42 @@ void fb_draw_glyph(uint32_t px, uint32_t py, uint8_t ch,
}
}
/* -----------------------------------------------------------------------
* Boot diagnostic: orientation test pattern
* --------------------------------------------------------------------- */
/**
* fb_draw_orientation_test — one-time boot diagnostic (FABRIC.md item 4.3.1).
*
* Fills each raster corner with a distinct solid color so a screendump
* immediately reveals whether the image is flipped or rotated. Not part of
* the Console drawing fabric itself -- diagnostic-only, analogous to item
* 4.2's self-test scaffolding.
*
* Corner colors (raster/top-left-origin coordinates, pre-Cartesian-flip):
* top-left RED
* top-right GREEN
* bottom-left BLUE
* bottom-right YELLOW
*/
void fb_draw_orientation_test(void)
{
uint32_t block_w, block_h;
if (!g_fb.ready) return;
block_w = g_fb.width / 8u;
block_h = g_fb.height / 8u;
if (block_w == 0) block_w = 1;
if (block_h == 0) block_h = 1;
fb_fill_rect(0, 0, block_w, block_h, FB_RGB(0xFF, 0x00, 0x00)); /* top-left: RED */
fb_fill_rect(g_fb.width - block_w, 0, block_w, block_h, FB_RGB(0x00, 0xFF, 0x00)); /* top-right: GREEN */
fb_fill_rect(0, g_fb.height - block_h, block_w, block_h, FB_RGB(0x00, 0x00, 0xFF)); /* bottom-left: BLUE */
fb_fill_rect(g_fb.width - block_w, g_fb.height - block_h, block_w, block_h,
FB_RGB(0xFF, 0xFF, 0x00)); /* bottom-right: YELLOW */
}
/* -----------------------------------------------------------------------
* Scrolling
* --------------------------------------------------------------------- */