code wiki / _hdl_build / nx_gop_present.nx
nx_gop_present.nx source
↩ module page · 67 lines · 3781 B
1// nx_gop_present.nx -- LIB: the UEFI GOP linear-framebuffer PRESENTATION SINK (the x86 on-metal display path).
2// SF1/SF2/SF4 put pixels on the sovereign SILICON (fabric + behavioral RV64IM). This is the OTHER half of
3// "both": delivering the games' framebuffer to a REAL x86 screen via the UEFI Graphics Output Protocol's
4// linear framebuffer -- the destination the nx_swapchain roadmap queued as NX_SWAP_DEST_KMS_DIRECT /
5// NX_SWAP_DEST_NISHI_OS (honestly stubbed NOT_IMPL there). This is that backend, implemented.
6//
7// A GOP linear framebuffer (EFI_GRAPHICS_OUTPUT_PROTOCOL->Mode->FrameBufferBase) is 32 bits/pixel with:
8// - a STRIDE in PIXELS (PixelsPerScanLine) that may EXCEED the visible width -> rows are padded; writing
9// `width` pixels per row instead of advancing by `pitch` shears the image (the swapchain hazard
10// "stride-vs-width-confusion").
11// - a PIXEL FORMAT: PixelRedGreenBlueReserved8BitPerColor (RGBX) or, the common one on real HW / OVMF /
12// QEMU, PixelBlueGreenRedReserved8BitPerColor (BGRX) -- writing the wrong channel order swaps red/blue
13// (the hazard "rgba-vs-rgb-channel-order"). BitMask / BltOnly are honestly refused (NOT_IMPL), never a
14// silent no-op (the hazard "silent-stub-no-op").
15//
16// NEVER-BRICK (#26): a pixel BLIT to a GOP linear framebuffer is volatile VRAM = a `gui`-axis capability
17// that cannot corrupt firmware/CMOS/NVRAM BY CONSTRUCTION. (The GOP MODE-SET -- SetMode, which picks the
18// resolution -- is the firmware-adjacent part; that is a SEPARATE rung registered firmware-axis with an
19// idempotent / read-back-verify / never-flash guarantee. This sink only BLITS into an already-configured
20// framebuffer.) Bounded (exactly w*h pixel writes), total, deterministic.
21// license_tier: ORIGINAL
22import "nx_syscalls.nx"
23
24// EFI_GRAPHICS_PIXEL_FORMAT (the two direct-write 32bpp formats; BitMask/BltOnly handled by NOT_IMPL).
25const NX_GOP_FMT_RGBX: i64 = 0 // PixelRedGreenBlueReserved8BitPerColor
26const NX_GOP_FMT_BGRX: i64 = 1 // PixelBlueGreenRedReserved8BitPerColor (common on real HW / OVMF)
27
28// status (mirrors nx_swapchain's honest-error convention).
29const NX_GOP_ERR_BAD_SIZE: i64 = -101
30const NX_GOP_ERR_NOT_IMPL: i64 = -103
31
32// Present the games' packed-RGB framebuffer (fb[y*w+x] = R | G<<8 | B<<16) to a GOP linear framebuffer.
33// lfb = FrameBufferBase (a *u8 of at least pitch_px*h*4 bytes)
34// pitch_px = PixelsPerScanLine (the row STRIDE in pixels; must be >= w)
35// pixfmt = NX_GOP_FMT_RGBX or NX_GOP_FMT_BGRX
36// Returns the number of pixels written (w*h) on success, or a negative honest error.
37func nx_gop_present(fb: *i64, w: i64, h: i64, lfb: *u8, pitch_px: i64, pixfmt: i64) -> i64 {
38 if w <= 0 { return NX_GOP_ERR_BAD_SIZE }
39 if h <= 0 { return NX_GOP_ERR_BAD_SIZE }
40 if pitch_px < w { return NX_GOP_ERR_BAD_SIZE } // stride must cover the visible width
41 if pixfmt != NX_GOP_FMT_RGBX { if pixfmt != NX_GOP_FMT_BGRX { return NX_GOP_ERR_NOT_IMPL } }
42 var y: i64 = 0
43 while y < h {
44 var x: i64 = 0
45 while x < w {
46 let cell: i64 = fb[y*w + x]
47 let r: i64 = cell & 0xFF
48 let g: i64 = (cell >> 8) & 0xFF
49 let b: i64 = (cell >> 16) & 0xFF
50 let o: i64 = (y*pitch_px + x) * 4 // 32 bpp, stride in PIXELS (the padded LFB)
51 if pixfmt == NX_GOP_FMT_BGRX {
52 lfb[o] = b as u8
53 lfb[o+1] = g as u8
54 lfb[o+2] = r as u8
55 lfb[o+3] = 0 as u8
56 } else {
57 lfb[o] = r as u8
58 lfb[o+1] = g as u8
59 lfb[o+2] = b as u8
60 lfb[o+3] = 0 as u8
61 }
62 x = x + 1
63 }
64 y = y + 1
65 }
66 return w * h
67}