// Kernel display manager. This file owns provider registration, framebuffer routing, dirty rectangles, text console state, and cursor delegation. #include #include #include #include #include #include #include #include #include #include #include #define DISPLAY_DEFAULT_FG 0x00CCCCCCu #define DISPLAY_DEFAULT_BG 0x00012456u #define DISPLAY_MAX_DIRTY_RECTS 64u #define DISPLAY_CURSOR_W DISPLAY_DEFAULT_CURSOR_W #define DISPLAY_CURSOR_H DISPLAY_DEFAULT_CURSOR_H #define FONT_W 8 #define FONT_H 16 #define DISPLAY_CONSOLE_MAX_COLS 256 #define DISPLAY_CONSOLE_MAX_ROWS 128 #define DISPLAY_CONSOLE_MAX_CELLS (DISPLAY_CONSOLE_MAX_COLS * DISPLAY_CONSOLE_MAX_ROWS) #define DISPLAY_CONSOLE_DEFAULT_ATTR 0x07u typedef struct BOOTFB_CONTEXT { const HAL_API* Hal; uint32_t* Framebuffer; uint32_t* Backbuffer; uint32_t Width; uint32_t Height; uint32_t Stride; DISPLAY_STATS Stats; } BOOTFB_CONTEXT; static const HAL_API* gDisplayHal; static DISPLAY_DEVICE* gDisplayList; static DISPLAY_DEVICE* gPrimaryDisplay; static SPINLOCK gDisplayLock = SPINLOCK_INIT; static DISPLAY_DEVICE gBootFbDevice; static BOOTFB_CONTEXT gBootFb; static DISPLAY_RECT gDirtyRects[DISPLAY_MAX_DIRTY_RECTS]; static size_t gDirtyRectCount; static bool gDirtyAll; static uint32_t gDrawDepth; static DISPLAY_STATS gDisplayStats; static bool gCursorVisible; static bool gCursorDrawn; static int gCursorX; static int gCursorY; static int gCursorDrawX; static int gCursorDrawY; static int gConsoleX; static int gConsoleY; static uint16_t gConsoleAttribute; static char gConsoleCells[DISPLAY_CONSOLE_MAX_CELLS]; static uint8_t gConsoleAttrs[DISPLAY_CONSOLE_MAX_CELLS]; static volatile long gDisplayConsoleSuspended; static KSTATUS BootFbGetMode(DISPLAY_DEVICE* device, DISPLAY_MODE* outMode); static KSTATUS BootFbBlit(DISPLAY_DEVICE* device, int x, int y, int w, int h, const uint32_t* pixels); static KSTATUS BootFbFillRect(DISPLAY_DEVICE* device, int x, int y, int w, int h, uint32_t color); static KSTATUS BootFbCopyRect(DISPLAY_DEVICE* device, int dstX, int dstY, int srcX, int srcY, int w, int h); static KSTATUS BootFbReadRect(DISPLAY_DEVICE* device, int x, int y, int w, int h, uint32_t* outPixels, uint32_t outStride); static KSTATUS BootFbPresent(DISPLAY_DEVICE* device, const DISPLAY_RECT* rects, size_t rectCount); static KSTATUS BootFbSync(DISPLAY_DEVICE* device); static KSTATUS BootFbSetCursorImage(DISPLAY_DEVICE* device, int width, int height, int hotX, int hotY, const uint32_t* argbPixels); static KSTATUS BootFbSetCursorPosition(DISPLAY_DEVICE* device, int x, int y); static KSTATUS BootFbShowCursor(DISPLAY_DEVICE* device, bool show); static KSTATUS BootFbQueryStats(DISPLAY_DEVICE* device, DISPLAY_STATS* outStats); static const DISPLAY_DEVICE_OPS gBootFbOps = { .GetMode = BootFbGetMode, .Blit = BootFbBlit, .FillRect = BootFbFillRect, .CopyRect = BootFbCopyRect, .ReadRect = BootFbReadRect, .Present = BootFbPresent, .Sync = BootFbSync, .SetCursorImage = BootFbSetCursorImage, .SetCursorPosition = BootFbSetCursorPosition, .ShowCursor = BootFbShowCursor, .QueryStats = BootFbQueryStats, }; // Checks whether a primary display provider is available. static bool KiDisplayHasDevice(void) { return gPrimaryDisplay && gPrimaryDisplay->Ops; } // Checks whether the active provider expects the manager to draw the cursor into the framebuffer. static bool KiDisplayUsesSoftwareCursor(void) { return KiDisplayHasDevice() && (gPrimaryDisplay->Caps & DISPLAY_CAP_SOFTWARE_CURSOR) && gPrimaryDisplay->Ops->ShowCursor; } // Checks whether the active provider owns cursor presentation in hardware or device firmware. static bool KiDisplayUsesHardwareCursor(void) { return KiDisplayHasDevice() && (gPrimaryDisplay->Caps & DISPLAY_CAP_HARDWARE_CURSOR) && gPrimaryDisplay->Ops->ShowCursor; } // Checks whether the active provider exposes any cursor-control path. static bool KiDisplayHasCursorOps(void) { return KiDisplayHasDevice() && (gPrimaryDisplay->Caps & (DISPLAY_CAP_SOFTWARE_CURSOR | DISPLAY_CAP_HARDWARE_CURSOR)) && gPrimaryDisplay->Ops->ShowCursor; } // Clips a rectangle to a display mode so providers never see negative or out-of-bounds regions. static bool KiDisplayClipRect(const DISPLAY_MODE* mode, DISPLAY_RECT* rect) { if (!mode || !rect || rect->W <= 0 || rect->H <= 0) return false; int64_t x0 = rect->X; int64_t y0 = rect->Y; int64_t x1 = x0 + rect->W; int64_t y1 = y0 + rect->H; if (x0 < 0) x0 = 0; if (y0 < 0) y0 = 0; if (x1 > (int64_t)mode->Width) x1 = mode->Width; if (y1 > (int64_t)mode->Height) y1 = mode->Height; if (x0 >= x1 || y0 >= y1) return false; rect->X = (int32_t)x0; rect->Y = (int32_t)y0; rect->W = (int32_t)(x1 - x0); rect->H = (int32_t)(y1 - y0); return true; } // Implements the display Dirty All operation. static void KiDisplayDirtyAll(void) { gDisplayStats.DirtyAllCount++; gDirtyAll = true; gDirtyRectCount = 0; } // Implements the display Add Dirty operation. static void KiDisplayAddDirty(int x, int y, int w, int h) { if (!KiDisplayHasDevice() || gDirtyAll || w <= 0 || h <= 0) return; DISPLAY_MODE mode; if (!KSUCCESS(gPrimaryDisplay->Ops->GetMode(gPrimaryDisplay, &mode))) return; DISPLAY_RECT rect = { x, y, w, h }; if (!KiDisplayClipRect(&mode, &rect)) return; if (rect.X == 0 && rect.Y == 0 && rect.W == (int32_t)mode.Width && rect.H == (int32_t)mode.Height) { KiDisplayDirtyAll(); return; } if (gDirtyRectCount >= DISPLAY_MAX_DIRTY_RECTS) { KiDisplayDirtyAll(); return; } gDisplayStats.DirtyRectCount++; gDirtyRects[gDirtyRectCount++] = rect; } // Implements the display Flush Dirty operation. static KSTATUS KiDisplayFlushDirty(void) { if (!KiDisplayHasDevice() || !gPrimaryDisplay->Ops->Present) return STATUS_SUCCESS; if (!gDirtyAll && gDirtyRectCount == 0) return STATUS_SUCCESS; DISPLAY_RECT full; const DISPLAY_RECT* rects = gDirtyRects; size_t count = gDirtyRectCount; if (gDirtyAll) { DISPLAY_MODE mode; KSTATUS s = gPrimaryDisplay->Ops->GetMode(gPrimaryDisplay, &mode); if (!KSUCCESS(s)) return s; full.X = 0; full.Y = 0; full.W = (int32_t)mode.Width; full.H = (int32_t)mode.Height; rects = &full; count = 1; } gDisplayStats.PresentCount++; gDisplayStats.PresentRectCount += count; KSTATUS s = gPrimaryDisplay->Ops->Present(gPrimaryDisplay, rects, count); if (KSUCCESS(s)) { gDirtyAll = false; gDirtyRectCount = 0; } return s; } // Implements the display Hide Cursor For Draw operation. static void KiDisplayHideCursorForDraw(void) { if (!gCursorDrawn || !KiDisplayUsesSoftwareCursor()) return; (void)gPrimaryDisplay->Ops->ShowCursor(gPrimaryDisplay, false); gCursorDrawn = false; } // Implements the display Restore Cursor After Draw operation. static void KiDisplayRestoreCursorAfterDraw(void) { if (!gCursorVisible || gCursorDrawn || !KiDisplayHasCursorOps()) return; if (gPrimaryDisplay->Ops->SetCursorPosition) (void)gPrimaryDisplay->Ops->SetCursorPosition(gPrimaryDisplay, gCursorX, gCursorY); if (KSUCCESS(gPrimaryDisplay->Ops->ShowCursor(gPrimaryDisplay, true))) gCursorDrawn = true; } // Implements the display Begin Draw operation. static void KiDisplayBeginDraw(void) { if (gDrawDepth++ == 0) KiDisplayHideCursorForDraw(); } // Implements the display End Draw operation. static KSTATUS KiDisplayEndDraw(void) { KSTATUS s = STATUS_SUCCESS; if (gDrawDepth > 0) gDrawDepth--; if (gDrawDepth == 0) { s = KiDisplayFlushDirty(); KiDisplayRestoreCursorAfterDraw(); } return s; } // Implements the display Draw Blit No Cursor operation. static KSTATUS KiDisplayDrawBlitNoCursor(int x, int y, int w, int h, const uint32_t* pixels) { if (!pixels || w <= 0 || h <= 0) return STATUS_INVALID_PARAMETER; if (!KiDisplayHasDevice() || !gPrimaryDisplay->Ops->Blit) return STATUS_NOT_SUPPORTED; KSTATUS s = gPrimaryDisplay->Ops->Blit(gPrimaryDisplay, x, y, w, h, pixels); if (KSUCCESS(s)) { gDisplayStats.BlitCount++; gDisplayStats.BytesCopied += (uint64_t)(uint32_t)w * (uint64_t)(uint32_t)h * sizeof(uint32_t); KiDisplayAddDirty(x, y, w, h); } return s; } // Implements the display Fill Rect No Cursor operation. static KSTATUS KiDisplayFillRectNoCursor(int x, int y, int w, int h, uint32_t color) { if (w <= 0 || h <= 0) return STATUS_INVALID_PARAMETER; if (!KiDisplayHasDevice() || !gPrimaryDisplay->Ops->FillRect) return STATUS_NOT_SUPPORTED; KSTATUS s = gPrimaryDisplay->Ops->FillRect(gPrimaryDisplay, x, y, w, h, color); if (KSUCCESS(s)) { gDisplayStats.FillRectCount++; gDisplayStats.BytesCopied += (uint64_t)(uint32_t)w * (uint64_t)(uint32_t)h * sizeof(uint32_t); KiDisplayAddDirty(x, y, w, h); } return s; } // Implements the display Copy Rect No Cursor operation. static KSTATUS KiDisplayCopyRectNoCursor(int dstX, int dstY, int srcX, int srcY, int w, int h) { if (w <= 0 || h <= 0) return STATUS_INVALID_PARAMETER; if (!KiDisplayHasDevice() || !gPrimaryDisplay->Ops->CopyRect) return STATUS_NOT_SUPPORTED; KSTATUS s = gPrimaryDisplay->Ops->CopyRect(gPrimaryDisplay, dstX, dstY, srcX, srcY, w, h); if (KSUCCESS(s)) { gDisplayStats.CopyRectCount++; gDisplayStats.BytesCopied += (uint64_t)(uint32_t)w * (uint64_t)(uint32_t)h * sizeof(uint32_t); KiDisplayAddDirty(dstX, dstY, w, h); } return s; } // Implements the display Console Index operation. static size_t KiDisplayConsoleIndex(int col, int row) { return (size_t)row * DISPLAY_CONSOLE_MAX_COLS + (size_t)col; } // Implements the display Console Color operation. static uint32_t KiDisplayConsoleColor(uint8_t index) { static const uint32_t colors[16] = { 0x00000000u, 0x000000AAu, 0x0000AA00u, 0x0000AAAAu, 0x00AA0000u, 0x00AA00AAu, 0x00AA5500u, 0x00AAAAAAu, 0x00555555u, 0x005555FFu, 0x0055FF55u, 0x0055FFFFu, 0x00FF5555u, 0x00FF55FFu, 0x00FFFF55u, 0x00FFFFFFu, }; return colors[index & 0x0Fu]; } // Implements the display Console Fg operation. static uint32_t KiDisplayConsoleFg(uint16_t attr) { return KiDisplayConsoleColor((uint8_t)(attr & 0x0Fu)); } // Implements the display Console Bg operation. static uint32_t KiDisplayConsoleBg(uint16_t attr) { return KiDisplayConsoleColor((uint8_t)((attr >> 4) & 0x0Fu)); } // Implements the display Get Console Grid Locked operation. static bool KiDisplayGetConsoleGridLocked(int* outCols, int* outRows) { DISPLAY_MODE mode; if (!KiDisplayHasDevice() || !gPrimaryDisplay->Ops->GetMode) return false; if (!KSUCCESS(gPrimaryDisplay->Ops->GetMode(gPrimaryDisplay, &mode))) return false; int cols = (int)mode.Width / FONT_W; int rows = (int)mode.Height / FONT_H; if (cols > DISPLAY_CONSOLE_MAX_COLS) cols = DISPLAY_CONSOLE_MAX_COLS; if (rows > DISPLAY_CONSOLE_MAX_ROWS) rows = DISPLAY_CONSOLE_MAX_ROWS; if (cols <= 0 || rows <= 0) return false; if (outCols) *outCols = cols; if (outRows) *outRows = rows; return true; } // Implements the display Console Reset Cells Locked operation. static void KiDisplayConsoleResetCellsLocked(void) { for (size_t i = 0; i < DISPLAY_CONSOLE_MAX_CELLS; i++) { gConsoleCells[i] = ' '; gConsoleAttrs[i] = (uint8_t)DISPLAY_CONSOLE_DEFAULT_ATTR; } gConsoleAttribute = DISPLAY_CONSOLE_DEFAULT_ATTR; } // Implements the display Console Scroll Cells Locked operation. static void KiDisplayConsoleScrollCellsLocked(int cols, int rows, int cellLines) { if (cols <= 0 || rows <= 0 || cellLines <= 0) return; if (cellLines >= rows) { for (int y = 0; y < rows; y++) { for (int x = 0; x < cols; x++) { size_t i = KiDisplayConsoleIndex(x, y); gConsoleCells[i] = ' '; gConsoleAttrs[i] = (uint8_t)gConsoleAttribute; } } return; } for (int y = 0; y < rows - cellLines; y++) { for (int x = 0; x < cols; x++) { size_t dst = KiDisplayConsoleIndex(x, y); size_t src = KiDisplayConsoleIndex(x, y + cellLines); gConsoleCells[dst] = gConsoleCells[src]; gConsoleAttrs[dst] = gConsoleAttrs[src]; } } for (int y = rows - cellLines; y < rows; y++) { for (int x = 0; x < cols; x++) { size_t i = KiDisplayConsoleIndex(x, y); gConsoleCells[i] = ' '; gConsoleAttrs[i] = (uint8_t)gConsoleAttribute; } } } // Implements the display Draw Char Pixels Locked operation. static KSTATUS KiDisplayDrawCharPixelsLocked(char c, int x, int y, uint32_t fg, uint32_t bg) { uint32_t glyphPixels[FONT_W * FONT_H]; const uint8_t* glyph = Font8x16 + ((uint8_t)c * 16u); for (int row = 0; row < FONT_H; row++) { uint8_t bits = glyph[row]; for (int col = 0; col < FONT_W; col++) glyphPixels[row * FONT_W + col] = (bits & (0x80u >> col)) ? fg : bg; } return KiDisplayDrawBlitNoCursor(x, y, FONT_W, FONT_H, glyphPixels); } // Implements the display Draw Console Cell Locked operation. static KSTATUS KiDisplayDrawConsoleCellLocked(int col, int row, char c, uint16_t attr, bool updateCell) { if (updateCell) { size_t i = KiDisplayConsoleIndex(col, row); gConsoleCells[i] = c; gConsoleAttrs[i] = (uint8_t)attr; } return KiDisplayDrawCharPixelsLocked(c, col * FONT_W, row * FONT_H, KiDisplayConsoleFg(attr), KiDisplayConsoleBg(attr)); } // Implements the display Serial Write Char operation. static void KiDisplaySerialWriteChar(char c) { while ((__inbyte(0x3FD) & 0x20) == 0) { } if (c == '\n') __outbyte(0x3F8, '\r'); __outbyte(0x3F8, (uint8_t)c); } // Implements the display Initialize operation. void KeDisplayInitialize(const HAL_API* hal) { gDisplayHal = hal; gDisplayList = NULL; gPrimaryDisplay = NULL; gDirtyRectCount = 0; gDirtyAll = false; gDrawDepth = 0; memset(&gDisplayStats, 0, sizeof(gDisplayStats)); gCursorVisible = false; gCursorDrawn = false; gCursorX = 0; gCursorY = 0; gCursorDrawX = -1; gCursorDrawY = -1; gConsoleX = 0; gConsoleY = 0; KiDisplayConsoleResetCellsLocked(); _InterlockedExchange((volatile long*)&gDisplayConsoleSuspended, 0); memset(&gBootFb, 0, sizeof(gBootFb)); memset(&gBootFbDevice, 0, sizeof(gBootFbDevice)); if (!hal || !hal->Screen.GetFramebuffer) return; HAL_FRAMEBUFFER_INFO fb; memset(&fb, 0, sizeof(fb)); if (!KSUCCESS(hal->Screen.GetFramebuffer(&fb)) || !fb.Base || fb.Width == 0 || fb.Height == 0 || fb.Stride == 0) return; gBootFb.Hal = hal; gBootFb.Framebuffer = (uint32_t*)fb.Base; gBootFb.Width = fb.Width; gBootFb.Height = fb.Height; gBootFb.Stride = fb.Stride; size_t pixels = (size_t)gBootFb.Stride * (size_t)gBootFb.Height; size_t bytes = pixels * sizeof(uint32_t); if (gBootFb.Stride > 0 && gBootFb.Height > 0 && pixels / (size_t)gBootFb.Stride == (size_t)gBootFb.Height && bytes / sizeof(uint32_t) == pixels) { gBootFb.Backbuffer = (uint32_t*)MmAllocatePool(bytes); if (gBootFb.Backbuffer) memcpy(gBootFb.Backbuffer, gBootFb.Framebuffer, bytes); } gBootFbDevice.Name = "bootfb"; gBootFbDevice.Caps = DISPLAY_CAP_FRAMEBUFFER; if (gBootFb.Backbuffer) gBootFbDevice.Caps |= DISPLAY_CAP_SOFTWARE_CURSOR; gBootFbDevice.DriverContext = &gBootFb; gBootFbDevice.Ops = &gBootFbOps; KSTATUS s = KeDisplayRegisterDevice(&gBootFbDevice); if (KSUCCESS(s)) { (void)KeDisplaySetPrimary(&gBootFbDevice); DISPLAY_MODE mode; if (KSUCCESS(KeDisplayGetMode(&mode))) { DbgPrint("Display: bootfb primary %ux%u stride=%u\n", mode.Width, mode.Height, mode.Stride); } // KeDisplayInitialize runs while the debug console still points at the // HAL early console, so the registration messages above are written // directly through HAL_SCREEN. Resync the bootfb backbuffer once before // kmain switches DbgPrint to KeDisplayDebugPrintChar. if (gBootFb.Backbuffer) { size_t pixels2 = (size_t)gBootFb.Stride * (size_t)gBootFb.Height; memcpy(gBootFb.Backbuffer, gBootFb.Framebuffer, pixels2 * sizeof(uint32_t)); } } } DISPLAY_API KSTATUS KeDisplayRegisterDevice(DISPLAY_DEVICE* device) { if (!device || !device->Name || !device->Ops || !device->Ops->GetMode) return STATUS_INVALID_PARAMETER; KSTATUS result = STATUS_SUCCESS; uintptr_t flags = KeAcquireSpinlock(&gDisplayLock); for (DISPLAY_DEVICE* it = gDisplayList; it; it = it->Next) { if (it == device) { result = STATUS_ALREADY_EXISTS; break; } } if (KSUCCESS(result)) { device->Next = gDisplayList; gDisplayList = device; } KeReleaseSpinlock(&gDisplayLock, flags); if (KSUCCESS(result)) DbgPrint("Display: registered device %s caps=0x%x\n", device->Name, device->Caps); return result; } // Implements the display Seed New Primary operation. static KSTATUS KiDisplaySeedNewPrimary(DISPLAY_DEVICE* oldDevice, DISPLAY_DEVICE* newDevice) { if (!oldDevice || !newDevice || oldDevice == newDevice) return STATUS_SUCCESS; if (!oldDevice->Ops || !oldDevice->Ops->ReadRect || !newDevice->Ops || !newDevice->Ops->GetMode || !newDevice->Ops->Blit) return STATUS_NOT_SUPPORTED; DISPLAY_MODE oldMode; DISPLAY_MODE newMode; KSTATUS s = oldDevice->Ops->GetMode(oldDevice, &oldMode); if (!KSUCCESS(s)) return s; s = newDevice->Ops->GetMode(newDevice, &newMode); if (!KSUCCESS(s)) return s; if (oldMode.Format != DisplayPixelFormatX8R8G8B8 || newMode.Format != DisplayPixelFormatX8R8G8B8 || oldMode.Width != newMode.Width || oldMode.Height != newMode.Height) return STATUS_NOT_SUPPORTED; uint32_t* row = (uint32_t*)MmAllocatePool((size_t)newMode.Width * sizeof(uint32_t)); if (!row) return STATUS_NO_MEMORY; for (uint32_t y = 0; y < newMode.Height; y++) { s = oldDevice->Ops->ReadRect(oldDevice, 0, (int)y, (int)newMode.Width, 1, row, newMode.Width); if (!KSUCCESS(s)) break; s = newDevice->Ops->Blit(newDevice, 0, (int)y, (int)newMode.Width, 1, row); if (!KSUCCESS(s)) break; } MmFreePool(row); return s; } DISPLAY_API void KeDisplaySuspendConsole(bool suspend) { _InterlockedExchange((volatile long*)&gDisplayConsoleSuspended, suspend ? 1 : 0); } // Implements the display Output Suspended operation. static bool KiDisplayOutputSuspended(void) { return _InterlockedCompareExchange((volatile long*)&gDisplayConsoleSuspended, 0, 0) != 0; } DISPLAY_API KSTATUS KeDisplaySetPrimary(DISPLAY_DEVICE* device) { if (!device || !device->Ops || !device->Ops->GetMode) return STATUS_INVALID_PARAMETER; const char* name = device->Name ? device->Name : "?"; KSTATUS result = STATUS_SUCCESS; KSTATUS seedResult = STATUS_SUCCESS; const char* seedOldName = NULL; uintptr_t flags = KeAcquireSpinlock(&gDisplayLock); bool found = false; for (DISPLAY_DEVICE* it = gDisplayList; it; it = it->Next) { if (it == device) { found = true; break; } } if (!found) { KeReleaseSpinlock(&gDisplayLock, flags); return STATUS_NOT_FOUND; } DISPLAY_DEVICE* oldDevice = gPrimaryDisplay; bool cursorWasVisible = gCursorVisible; if (oldDevice && gCursorDrawn && oldDevice->Ops && oldDevice->Ops->ShowCursor) (void)oldDevice->Ops->ShowCursor(oldDevice, false); if (oldDevice && oldDevice != device) { seedOldName = oldDevice->Name; seedResult = KiDisplaySeedNewPrimary(oldDevice, device); } gPrimaryDisplay = device; gCursorDrawn = false; gDirtyAll = false; gDirtyRectCount = 0; if (device->Ops->Present) { DISPLAY_MODE mode; if (KSUCCESS(device->Ops->GetMode(device, &mode))) { DISPLAY_RECT full = { 0, 0, (int32_t)mode.Width, (int32_t)mode.Height }; (void)device->Ops->Present(device, &full, 1); } } if (cursorWasVisible) KiDisplayRestoreCursorAfterDraw(); KeReleaseSpinlock(&gDisplayLock, flags); if (!KSUCCESS(seedResult) && seedResult != STATUS_NOT_SUPPORTED) { DbgPrint("Display: primary handoff seed %s -> %s failed st=0x%x\n", seedOldName ? seedOldName : "?", name, seedResult); } if (KSUCCESS(result)) DbgPrint("Display: primary is %s\n", name); return result; } DISPLAY_API KSTATUS KeDisplayGetMode(DISPLAY_MODE* outMode) { if (!outMode) return STATUS_INVALID_PARAMETER; uintptr_t flags = KeAcquireSpinlock(&gDisplayLock); KSTATUS s = (!KiDisplayHasDevice() || !gPrimaryDisplay->Ops->GetMode) ? STATUS_INVALID_PARAMETER : gPrimaryDisplay->Ops->GetMode(gPrimaryDisplay, outMode); KeReleaseSpinlock(&gDisplayLock, flags); return s; } DISPLAY_API KSTATUS KeDisplayGetSize(int* outWidth, int* outHeight) { DISPLAY_MODE mode; KSTATUS s = KeDisplayGetMode(&mode); if (!KSUCCESS(s)) return s; if (outWidth) *outWidth = (int)mode.Width; if (outHeight) *outHeight = (int)mode.Height; return STATUS_SUCCESS; } DISPLAY_API KSTATUS KeDisplayBlit(int x, int y, int w, int h, const uint32_t* pixels) { uintptr_t flags = KeAcquireSpinlock(&gDisplayLock); KiDisplayBeginDraw(); KSTATUS s = KiDisplayDrawBlitNoCursor(x, y, w, h, pixels); KSTATUS ps = KiDisplayEndDraw(); KeReleaseSpinlock(&gDisplayLock, flags); return KSUCCESS(s) ? ps : s; } DISPLAY_API KSTATUS KeDisplayFillRect(int x, int y, int w, int h, uint32_t color) { uintptr_t flags = KeAcquireSpinlock(&gDisplayLock); KiDisplayBeginDraw(); KSTATUS s = KiDisplayFillRectNoCursor(x, y, w, h, color); KSTATUS ps = KiDisplayEndDraw(); KeReleaseSpinlock(&gDisplayLock, flags); return KSUCCESS(s) ? ps : s; } // Implements the display Clear Locked operation. static KSTATUS KiDisplayClearLocked(uint32_t color) { DISPLAY_MODE mode; if (!KiDisplayHasDevice() || !gPrimaryDisplay->Ops->GetMode) return STATUS_NOT_SUPPORTED; KSTATUS s = gPrimaryDisplay->Ops->GetMode(gPrimaryDisplay, &mode); if (!KSUCCESS(s)) return s; KiDisplayBeginDraw(); s = KiDisplayFillRectNoCursor(0, 0, (int)mode.Width, (int)mode.Height, color); if (KSUCCESS(s)) KiDisplayConsoleResetCellsLocked(); KSTATUS ps = KiDisplayEndDraw(); return KSUCCESS(s) ? ps : s; } DISPLAY_API KSTATUS KeDisplayClear(uint32_t color) { uintptr_t flags = KeAcquireSpinlock(&gDisplayLock); KSTATUS s = KiDisplayClearLocked(color); KeReleaseSpinlock(&gDisplayLock, flags); return s; } DISPLAY_API KSTATUS KeDisplayCopyRect(int dstX, int dstY, int srcX, int srcY, int w, int h) { uintptr_t flags = KeAcquireSpinlock(&gDisplayLock); KiDisplayBeginDraw(); KSTATUS s = KiDisplayCopyRectNoCursor(dstX, dstY, srcX, srcY, w, h); KSTATUS ps = KiDisplayEndDraw(); KeReleaseSpinlock(&gDisplayLock, flags); return KSUCCESS(s) ? ps : s; } // Implements the display Scroll Locked operation. static KSTATUS KiDisplayScrollLocked(int lines) { if (lines <= 0) return STATUS_SUCCESS; if (!KiDisplayHasDevice() || !gPrimaryDisplay->Ops->GetMode) return STATUS_NOT_SUPPORTED; DISPLAY_MODE mode; KSTATUS s = gPrimaryDisplay->Ops->GetMode(gPrimaryDisplay, &mode); if (!KSUCCESS(s)) return s; if ((uint32_t)lines >= mode.Height) return KiDisplayClearLocked(DISPLAY_DEFAULT_BG); KiDisplayBeginDraw(); s = KiDisplayCopyRectNoCursor(0, 0, 0, lines, (int)mode.Width, (int)(mode.Height - (uint32_t)lines)); if (KSUCCESS(s)) { s = KiDisplayFillRectNoCursor(0, (int)(mode.Height - (uint32_t)lines), (int)mode.Width, lines, DISPLAY_DEFAULT_BG); } KSTATUS ps = KiDisplayEndDraw(); return KSUCCESS(s) ? ps : s; } DISPLAY_API KSTATUS KeDisplayScroll(int lines) { uintptr_t flags = KeAcquireSpinlock(&gDisplayLock); KSTATUS s = KiDisplayScrollLocked(lines); KeReleaseSpinlock(&gDisplayLock, flags); return s; } // Implements the display Put Char Locked operation. static KSTATUS KiDisplayPutCharLocked(char c, int x, int y, uint32_t fg, uint32_t bg) { KiDisplayBeginDraw(); KSTATUS s = KiDisplayDrawCharPixelsLocked(c, x, y, fg, bg); KSTATUS ps = KiDisplayEndDraw(); return KSUCCESS(s) ? ps : s; } DISPLAY_API KSTATUS KeDisplayPutChar(char c, int x, int y, uint32_t fg, uint32_t bg) { uintptr_t flags = KeAcquireSpinlock(&gDisplayLock); KSTATUS s = KiDisplayPutCharLocked(c, x, y, fg, bg); KeReleaseSpinlock(&gDisplayLock, flags); return s; } DISPLAY_API KSTATUS KeDisplayPrintChar(char c, uint32_t fg, uint32_t bg) { KiDisplaySerialWriteChar(c); if (KiDisplayOutputSuspended()) return STATUS_SUCCESS; uintptr_t flags = KeAcquireSpinlock(&gDisplayLock); DISPLAY_MODE mode; KSTATUS s = (!KiDisplayHasDevice() || !gPrimaryDisplay->Ops->GetMode) ? STATUS_NOT_SUPPORTED : gPrimaryDisplay->Ops->GetMode(gPrimaryDisplay, &mode); if (!KSUCCESS(s)) { const HAL_API* hal = gDisplayHal; KeReleaseSpinlock(&gDisplayLock, flags); if (hal && hal->Screen.PrintChar) hal->Screen.PrintChar(c, fg, bg); return s; } int cols = 0; int rows = 0; if (!KiDisplayGetConsoleGridLocked(&cols, &rows)) { KeReleaseSpinlock(&gDisplayLock, flags); return STATUS_DEVICE_ERROR; } if (c == '\n') { gConsoleX = 0; gConsoleY++; } else if (c == '\r') { gConsoleX = 0; } else if (c == '\b') { if (gConsoleX > 0) { gConsoleX--; } else if (gConsoleY > 0) { gConsoleY--; gConsoleX = cols - 1; } } else { s = KiDisplayPutCharLocked(c, gConsoleX * FONT_W, gConsoleY * FONT_H, fg, bg); if (!KSUCCESS(s)) { KeReleaseSpinlock(&gDisplayLock, flags); return s; } if (gConsoleX >= 0 && gConsoleX < cols && gConsoleY >= 0 && gConsoleY < rows) { size_t i = KiDisplayConsoleIndex(gConsoleX, gConsoleY); gConsoleCells[i] = c; gConsoleAttrs[i] = (uint8_t)gConsoleAttribute; } if (++gConsoleX >= cols) { gConsoleX = 0; gConsoleY++; } } if (gConsoleY >= rows) { s = KiDisplayScrollLocked(FONT_H); if (!KSUCCESS(s)) { KeReleaseSpinlock(&gDisplayLock, flags); return s; } KiDisplayConsoleScrollCellsLocked(cols, rows, 1); gConsoleY = rows - 1; } KeReleaseSpinlock(&gDisplayLock, flags); return STATUS_SUCCESS; } // Implements the display Debug Print Char operation. void KeDisplayDebugPrintChar(char c, uint32_t fg, uint32_t bg) { (void)KeDisplayPrintChar(c, fg, bg); } DISPLAY_API KSTATUS KeDisplayGetConsoleInfo(KE_CONSOLE_INFO* outInfo) { if (!outInfo) return STATUS_INVALID_PARAMETER; uintptr_t flags = KeAcquireSpinlock(&gDisplayLock); int cols = 0; int rows = 0; if (!KiDisplayGetConsoleGridLocked(&cols, &rows)) { KeReleaseSpinlock(&gDisplayLock, flags); return STATUS_NOT_SUPPORTED; } outInfo->Columns = (uint32_t)cols; outInfo->Rows = (uint32_t)rows; outInfo->CursorX = (uint32_t)gConsoleX; outInfo->CursorY = (uint32_t)gConsoleY; outInfo->Attribute = gConsoleAttribute; KeReleaseSpinlock(&gDisplayLock, flags); return STATUS_SUCCESS; } DISPLAY_API KSTATUS KeDisplaySetConsoleCursor(int col, int row) { uintptr_t flags = KeAcquireSpinlock(&gDisplayLock); int cols = 0; int rows = 0; if (!KiDisplayGetConsoleGridLocked(&cols, &rows)) { KeReleaseSpinlock(&gDisplayLock, flags); return STATUS_NOT_SUPPORTED; } if (col < 0 || row < 0 || col >= cols || row >= rows) { KeReleaseSpinlock(&gDisplayLock, flags); return STATUS_INVALID_PARAMETER; } gConsoleX = col; gConsoleY = row; KeReleaseSpinlock(&gDisplayLock, flags); return STATUS_SUCCESS; } DISPLAY_API KSTATUS KeDisplayFillConsoleChars(char c, int col, int row, size_t length, size_t* writtenOut) { uintptr_t flags = KeAcquireSpinlock(&gDisplayLock); int cols = 0; int rows = 0; if (!KiDisplayGetConsoleGridLocked(&cols, &rows)) { KeReleaseSpinlock(&gDisplayLock, flags); return STATUS_NOT_SUPPORTED; } if (col < 0 || row < 0 || col >= cols || row >= rows) { KeReleaseSpinlock(&gDisplayLock, flags); if (writtenOut) *writtenOut = 0; return STATUS_INVALID_PARAMETER; } size_t written = 0; KiDisplayBeginDraw(); KSTATUS s = STATUS_SUCCESS; int x = col; int y = row; while (written < length && y < rows) { size_t i = KiDisplayConsoleIndex(x, y); uint16_t attr = gConsoleAttrs[i]; s = KiDisplayDrawConsoleCellLocked(x, y, c, attr, true); if (!KSUCCESS(s)) break; written++; if (++x >= cols) { x = 0; y++; } } KSTATUS ps = KiDisplayEndDraw(); KeReleaseSpinlock(&gDisplayLock, flags); if (writtenOut) *writtenOut = written; return KSUCCESS(s) ? ps : s; } DISPLAY_API KSTATUS KeDisplayFillConsoleAttrs(uint16_t attr, int col, int row, size_t length, size_t* writtenOut) { uintptr_t flags = KeAcquireSpinlock(&gDisplayLock); int cols = 0; int rows = 0; if (!KiDisplayGetConsoleGridLocked(&cols, &rows)) { KeReleaseSpinlock(&gDisplayLock, flags); return STATUS_NOT_SUPPORTED; } if (col < 0 || row < 0 || col >= cols || row >= rows) { KeReleaseSpinlock(&gDisplayLock, flags); if (writtenOut) *writtenOut = 0; return STATUS_INVALID_PARAMETER; } size_t written = 0; KiDisplayBeginDraw(); KSTATUS s = STATUS_SUCCESS; int x = col; int y = row; while (written < length && y < rows) { size_t i = KiDisplayConsoleIndex(x, y); char c = gConsoleCells[i]; s = KiDisplayDrawConsoleCellLocked(x, y, c, attr, true); if (!KSUCCESS(s)) break; written++; if (++x >= cols) { x = 0; y++; } } KSTATUS ps = KiDisplayEndDraw(); KeReleaseSpinlock(&gDisplayLock, flags); if (writtenOut) *writtenOut = written; return KSUCCESS(s) ? ps : s; } DISPLAY_API KSTATUS KeDisplayPresent(const DISPLAY_RECT* rects, size_t rectCount) { uintptr_t flags = KeAcquireSpinlock(&gDisplayLock); if (!KiDisplayHasDevice() || !gPrimaryDisplay->Ops->Present) { KeReleaseSpinlock(&gDisplayLock, flags); return STATUS_NOT_SUPPORTED; } if (!rects || rectCount == 0) { KSTATUS s = KiDisplayFlushDirty(); KeReleaseSpinlock(&gDisplayLock, flags); return s; } bool hideCursor = gCursorDrawn && KiDisplayUsesSoftwareCursor(); if (hideCursor) KiDisplayHideCursorForDraw(); gDisplayStats.PresentCount++; gDisplayStats.PresentRectCount += rectCount; KSTATUS s = gPrimaryDisplay->Ops->Present(gPrimaryDisplay, rects, rectCount); if (hideCursor) KiDisplayRestoreCursorAfterDraw(); KeReleaseSpinlock(&gDisplayLock, flags); return s; } DISPLAY_API KSTATUS KeDisplaySync(void) { uintptr_t flags = KeAcquireSpinlock(&gDisplayLock); if (!KiDisplayHasDevice() || !gPrimaryDisplay->Ops->Sync) { KeReleaseSpinlock(&gDisplayLock, flags); return STATUS_NOT_SUPPORTED; } gDisplayStats.SyncCount++; KSTATUS s = gPrimaryDisplay->Ops->Sync(gPrimaryDisplay); KeReleaseSpinlock(&gDisplayLock, flags); return s; } DISPLAY_API KSTATUS KeDisplayQueryInfo(KE_DISPLAY_INFO* outInfo) { if (!outInfo) return STATUS_INVALID_PARAMETER; uintptr_t flags = KeAcquireSpinlock(&gDisplayLock); memset(outInfo, 0, sizeof(*outInfo)); uint32_t count = 0; for (DISPLAY_DEVICE* it = gDisplayList; it; it = it->Next) count++; outInfo->DeviceCount = count; outInfo->ManagerStats = gDisplayStats; if (!KiDisplayHasDevice()) { KeReleaseSpinlock(&gDisplayLock, flags); return STATUS_NOT_FOUND; } const char* name = gPrimaryDisplay->Name ? gPrimaryDisplay->Name : "?"; size_t len = strlen(name); if (len >= sizeof(outInfo->PrimaryName)) len = sizeof(outInfo->PrimaryName) - 1; memcpy(outInfo->PrimaryName, name, len); outInfo->PrimaryName[len] = '\0'; outInfo->Caps = gPrimaryDisplay->Caps; if (gPrimaryDisplay->Ops->GetMode) { KSTATUS s = gPrimaryDisplay->Ops->GetMode(gPrimaryDisplay, &outInfo->Mode); if (!KSUCCESS(s)) { KeReleaseSpinlock(&gDisplayLock, flags); return s; } } if (gPrimaryDisplay->Ops->QueryStats) (void)gPrimaryDisplay->Ops->QueryStats(gPrimaryDisplay, &outInfo->DeviceStats); KeReleaseSpinlock(&gDisplayLock, flags); return STATUS_SUCCESS; } DISPLAY_API KSTATUS KeDisplaySetCursorImage(int width, int height, int hotX, int hotY, const uint32_t* argbPixels) { uintptr_t flags = KeAcquireSpinlock(&gDisplayLock); KSTATUS s = (!KiDisplayHasDevice() || !gPrimaryDisplay->Ops->SetCursorImage) ? STATUS_NOT_SUPPORTED : gPrimaryDisplay->Ops->SetCursorImage(gPrimaryDisplay, width, height, hotX, hotY, argbPixels); KeReleaseSpinlock(&gDisplayLock, flags); return s; } DISPLAY_API KSTATUS KeDisplaySetCursorPosition(int x, int y) { uintptr_t flags = KeAcquireSpinlock(&gDisplayLock); gCursorX = x; gCursorY = y; gDisplayStats.CursorMoveCount++; if (KiDisplayOutputSuspended()) { KeReleaseSpinlock(&gDisplayLock, flags); return STATUS_SUCCESS; } if (!gCursorVisible || !KiDisplayHasCursorOps()) { KeReleaseSpinlock(&gDisplayLock, flags); return STATUS_SUCCESS; } if (gCursorDrawn && KiDisplayUsesSoftwareCursor()) (void)gPrimaryDisplay->Ops->ShowCursor(gPrimaryDisplay, false); if (gPrimaryDisplay->Ops->SetCursorPosition) (void)gPrimaryDisplay->Ops->SetCursorPosition(gPrimaryDisplay, x, y); if (gCursorDrawn && KiDisplayUsesHardwareCursor()) { KeReleaseSpinlock(&gDisplayLock, flags); return STATUS_SUCCESS; } KSTATUS s = gPrimaryDisplay->Ops->ShowCursor(gPrimaryDisplay, true); gCursorDrawn = KSUCCESS(s); KeReleaseSpinlock(&gDisplayLock, flags); return s; } DISPLAY_API KSTATUS KeDisplayShowCursor(bool show) { uintptr_t flags = KeAcquireSpinlock(&gDisplayLock); gCursorVisible = show; if (show) gDisplayStats.CursorShowCount++; else gDisplayStats.CursorHideCount++; if (KiDisplayOutputSuspended()) { KeReleaseSpinlock(&gDisplayLock, flags); return STATUS_SUCCESS; } if (!KiDisplayHasCursorOps()) { gCursorDrawn = false; KeReleaseSpinlock(&gDisplayLock, flags); return STATUS_SUCCESS; } if (!show) { if (gCursorDrawn) (void)gPrimaryDisplay->Ops->ShowCursor(gPrimaryDisplay, false); gCursorDrawn = false; KeReleaseSpinlock(&gDisplayLock, flags); return STATUS_SUCCESS; } if (gCursorDrawn) { KeReleaseSpinlock(&gDisplayLock, flags); return STATUS_SUCCESS; } if (gPrimaryDisplay->Ops->SetCursorPosition) (void)gPrimaryDisplay->Ops->SetCursorPosition(gPrimaryDisplay, gCursorX, gCursorY); KSTATUS s = gPrimaryDisplay->Ops->ShowCursor(gPrimaryDisplay, true); gCursorDrawn = KSUCCESS(s); KeReleaseSpinlock(&gDisplayLock, flags); return s; } // Implements the boot Fb Context operation. static BOOTFB_CONTEXT* BootFbContext(DISPLAY_DEVICE* device) { return device ? (BOOTFB_CONTEXT*)device->DriverContext : NULL; } // Implements the boot Fb Get Mode operation. static KSTATUS BootFbGetMode(DISPLAY_DEVICE* device, DISPLAY_MODE* outMode) { BOOTFB_CONTEXT* fb = BootFbContext(device); if (!fb || !fb->Framebuffer || !outMode) return STATUS_INVALID_PARAMETER; outMode->Width = fb->Width; outMode->Height = fb->Height; outMode->Stride = fb->Stride; outMode->Format = DisplayPixelFormatX8R8G8B8; return STATUS_SUCCESS; } // Implements the boot Fb Blit operation. static KSTATUS BootFbBlit(DISPLAY_DEVICE* device, int x, int y, int w, int h, const uint32_t* pixels) { BOOTFB_CONTEXT* fb = BootFbContext(device); if (!fb || !fb->Framebuffer || !pixels || w <= 0 || h <= 0) return STATUS_INVALID_PARAMETER; uint32_t* dstBase = fb->Backbuffer ? fb->Backbuffer : fb->Framebuffer; int startX = x < 0 ? 0 : x; int startY = y < 0 ? 0 : y; int endX = x + w > (int)fb->Width ? (int)fb->Width : x + w; int endY = y + h > (int)fb->Height ? (int)fb->Height : y + h; if (startX >= endX || startY >= endY) return STATUS_SUCCESS; int srcOffsetX = startX - x; int srcOffsetY = startY - y; size_t bytesPerRow = (size_t)(endX - startX) * sizeof(uint32_t); fb->Stats.BlitCount++; fb->Stats.BytesCopied += (uint64_t)(endX - startX) * (uint64_t)(endY - startY) * sizeof(uint32_t); for (int row = 0; row < endY - startY; row++) { uint32_t* dst = dstBase + ((size_t)(startY + row) * fb->Stride) + startX; const uint32_t* src = pixels + ((size_t)(srcOffsetY + row) * (size_t)w) + srcOffsetX; memcpy(dst, src, bytesPerRow); } return STATUS_SUCCESS; } // Implements the boot Fb Fill Rect operation. static KSTATUS BootFbFillRect(DISPLAY_DEVICE* device, int x, int y, int w, int h, uint32_t color) { BOOTFB_CONTEXT* fb = BootFbContext(device); if (!fb || !fb->Framebuffer || w <= 0 || h <= 0) return STATUS_INVALID_PARAMETER; uint32_t* dstBase = fb->Backbuffer ? fb->Backbuffer : fb->Framebuffer; int startX = x < 0 ? 0 : x; int startY = y < 0 ? 0 : y; int endX = x + w > (int)fb->Width ? (int)fb->Width : x + w; int endY = y + h > (int)fb->Height ? (int)fb->Height : y + h; if (startX >= endX || startY >= endY) return STATUS_SUCCESS; fb->Stats.FillRectCount++; fb->Stats.BytesCopied += (uint64_t)(endX - startX) * (uint64_t)(endY - startY) * sizeof(uint32_t); for (int yy = startY; yy < endY; yy++) { uint32_t* dst = dstBase + ((size_t)yy * fb->Stride) + startX; for (int xx = startX; xx < endX; xx++) *dst++ = color; } return STATUS_SUCCESS; } // Implements the boot Fb Copy Rect operation. static KSTATUS BootFbCopyRect(DISPLAY_DEVICE* device, int dstX, int dstY, int srcX, int srcY, int w, int h) { BOOTFB_CONTEXT* fb = BootFbContext(device); if (!fb || !fb->Framebuffer || w <= 0 || h <= 0) return STATUS_INVALID_PARAMETER; uint32_t* base = fb->Backbuffer ? fb->Backbuffer : fb->Framebuffer; if (srcX < 0) { int d = -srcX; srcX = 0; dstX += d; w -= d; } if (srcY < 0) { int d = -srcY; srcY = 0; dstY += d; h -= d; } if (dstX < 0) { int d = -dstX; dstX = 0; srcX += d; w -= d; } if (dstY < 0) { int d = -dstY; dstY = 0; srcY += d; h -= d; } if (srcX + w > (int)fb->Width) w = (int)fb->Width - srcX; if (dstX + w > (int)fb->Width) w = (int)fb->Width - dstX; if (srcY + h > (int)fb->Height) h = (int)fb->Height - srcY; if (dstY + h > (int)fb->Height) h = (int)fb->Height - dstY; if (w <= 0 || h <= 0) return STATUS_SUCCESS; fb->Stats.CopyRectCount++; fb->Stats.BytesCopied += (uint64_t)(uint32_t)w * (uint64_t)(uint32_t)h * sizeof(uint32_t); size_t rowBytes = (size_t)w * sizeof(uint32_t); if (dstY > srcY) { for (int row = h - 1; row >= 0; row--) { uint32_t* dst = base + ((size_t)(dstY + row) * fb->Stride) + dstX; uint32_t* src = base + ((size_t)(srcY + row) * fb->Stride) + srcX; memmove(dst, src, rowBytes); } } else { for (int row = 0; row < h; row++) { uint32_t* dst = base + ((size_t)(dstY + row) * fb->Stride) + dstX; uint32_t* src = base + ((size_t)(srcY + row) * fb->Stride) + srcX; memmove(dst, src, rowBytes); } } return STATUS_SUCCESS; } // Implements the boot Fb Read Rect operation. static KSTATUS BootFbReadRect(DISPLAY_DEVICE* device, int x, int y, int w, int h, uint32_t* outPixels, uint32_t outStride) { BOOTFB_CONTEXT* fb = BootFbContext(device); if (!fb || !fb->Framebuffer || !outPixels || outStride == 0 || w <= 0 || h <= 0) return STATUS_INVALID_PARAMETER; uint32_t* srcBase = fb->Backbuffer ? fb->Backbuffer : fb->Framebuffer; DISPLAY_MODE mode = { fb->Width, fb->Height, fb->Stride, DisplayPixelFormatX8R8G8B8 }; DISPLAY_RECT r = { x, y, w, h }; if (!KiDisplayClipRect(&mode, &r)) return STATUS_SUCCESS; fb->Stats.ReadRectCount++; fb->Stats.BytesCopied += (uint64_t)(uint32_t)r.W * (uint64_t)(uint32_t)r.H * sizeof(uint32_t); int dstOffsetX = r.X - x; int dstOffsetY = r.Y - y; for (int row = 0; row < r.H; row++) { const uint32_t* src = srcBase + ((size_t)(r.Y + row) * fb->Stride) + r.X; uint32_t* dst = outPixels + ((size_t)(dstOffsetY + row) * outStride) + dstOffsetX; memcpy(dst, src, (size_t)r.W * sizeof(uint32_t)); } return STATUS_SUCCESS; } // Implements the boot Fb Present operation. static KSTATUS BootFbPresent(DISPLAY_DEVICE* device, const DISPLAY_RECT* rects, size_t rectCount) { BOOTFB_CONTEXT* fb = BootFbContext(device); if (!fb || !fb->Framebuffer) return STATUS_INVALID_PARAMETER; if (!fb->Backbuffer || !rects || rectCount == 0) return STATUS_SUCCESS; DISPLAY_MODE mode; KSTATUS s = BootFbGetMode(device, &mode); if (!KSUCCESS(s)) return s; fb->Stats.PresentCount++; fb->Stats.PresentRectCount += rectCount; for (size_t i = 0; i < rectCount; i++) { DISPLAY_RECT r = rects[i]; if (!KiDisplayClipRect(&mode, &r)) continue; fb->Stats.BytesCopied += (uint64_t)(uint32_t)r.W * (uint64_t)(uint32_t)r.H * sizeof(uint32_t); size_t bytesPerRow = (size_t)r.W * sizeof(uint32_t); for (int row = 0; row < r.H; row++) { uint32_t* dst = fb->Framebuffer + ((size_t)(r.Y + row) * fb->Stride) + r.X; uint32_t* src = fb->Backbuffer + ((size_t)(r.Y + row) * fb->Stride) + r.X; memcpy(dst, src, bytesPerRow); } } return STATUS_SUCCESS; } // Implements the boot Fb Sync operation. static KSTATUS BootFbSync(DISPLAY_DEVICE* device) { BOOTFB_CONTEXT* fb = BootFbContext(device); if (fb) fb->Stats.SyncCount++; return STATUS_SUCCESS; } // Implements the boot Fb Set Cursor Image operation. static KSTATUS BootFbSetCursorImage(DISPLAY_DEVICE* device, int width, int height, int hotX, int hotY, const uint32_t* argbPixels) { (void)device; (void)width; (void)height; (void)hotX; (void)hotY; (void)argbPixels; return STATUS_NOT_SUPPORTED; } // Implements the boot Fb Set Cursor Position operation. static KSTATUS BootFbSetCursorPosition(DISPLAY_DEVICE* device, int x, int y) { BOOTFB_CONTEXT* fb = BootFbContext(device); if (fb) fb->Stats.CursorMoveCount++; (void)x; (void)y; return STATUS_SUCCESS; } // Implements the display Blend Pixel operation. static inline uint32_t KiDisplayBlendPixel(uint32_t dst, uint32_t src) { uint8_t a = (uint8_t)(src >> 24); if (a == 0) return dst; if (a == 255) return src & 0x00FFFFFFu; uint8_t sr = (uint8_t)(src >> 16); uint8_t sg = (uint8_t)(src >> 8); uint8_t sb = (uint8_t)src; uint8_t dr = (uint8_t)(dst >> 16); uint8_t dg = (uint8_t)(dst >> 8); uint8_t db = (uint8_t)dst; uint8_t na = (uint8_t)(255 - a); uint8_t rr = (uint8_t)((a * sr + na * dr) >> 8); uint8_t gg = (uint8_t)((a * sg + na * dg) >> 8); uint8_t bb = (uint8_t)((a * sb + na * db) >> 8); return ((uint32_t)rr << 16) | ((uint32_t)gg << 8) | bb; } // Implements the boot Fb Restore Cursor operation. static void BootFbRestoreCursor(BOOTFB_CONTEXT* fb) { if (!fb || !fb->Framebuffer || !fb->Backbuffer || gCursorDrawX < 0) return; DISPLAY_RECT r = { gCursorDrawX, gCursorDrawY, DISPLAY_CURSOR_W, DISPLAY_CURSOR_H }; DISPLAY_MODE mode = { fb->Width, fb->Height, fb->Stride, DisplayPixelFormatX8R8G8B8 }; if (KiDisplayClipRect(&mode, &r)) { for (int row = 0; row < r.H; row++) { uint32_t* dst = fb->Framebuffer + ((size_t)(r.Y + row) * fb->Stride) + r.X; uint32_t* src = fb->Backbuffer + ((size_t)(r.Y + row) * fb->Stride) + r.X; memcpy(dst, src, (size_t)r.W * sizeof(uint32_t)); } } gCursorDrawX = -1; gCursorDrawY = -1; } // Implements the boot Fb Draw Cursor operation. static void BootFbDrawCursor(BOOTFB_CONTEXT* fb, int x, int y) { if (!fb || !fb->Framebuffer || !fb->Backbuffer) return; gCursorDrawX = x; gCursorDrawY = y; for (int row = 0; row < DISPLAY_CURSOR_H; row++) { int fy = y + row; if ((unsigned)fy >= fb->Height) continue; for (int col = 0; col < DISPLAY_CURSOR_W; col++) { int fx = x + col; if ((unsigned)fx >= fb->Width) continue; uint32_t src = gDisplayDefaultCursorArgb[row][col]; if ((src >> 24) == 0) continue; uint32_t dst = fb->Backbuffer[(size_t)fy * fb->Stride + fx]; fb->Framebuffer[(size_t)fy * fb->Stride + fx] = KiDisplayBlendPixel(dst, src); } } } // Implements the boot Fb Show Cursor operation. static KSTATUS BootFbShowCursor(DISPLAY_DEVICE* device, bool show) { BOOTFB_CONTEXT* fb = BootFbContext(device); if (!fb || !fb->Framebuffer || !fb->Backbuffer) return STATUS_NOT_SUPPORTED; if (show) { fb->Stats.CursorShowCount++; BootFbDrawCursor(fb, gCursorX, gCursorY); } else { fb->Stats.CursorHideCount++; BootFbRestoreCursor(fb); } return STATUS_SUCCESS; } // Implements the boot Fb Query Stats operation. static KSTATUS BootFbQueryStats(DISPLAY_DEVICE* device, DISPLAY_STATS* outStats) { BOOTFB_CONTEXT* fb = BootFbContext(device); if (!fb || !outStats) return STATUS_INVALID_PARAMETER; *outStats = fb->Stats; return STATUS_SUCCESS; }