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}