diff --git a/graphics/graphics.c b/graphics/graphics.c index 19b3559..4e4e459 100644 --- a/graphics/graphics.c +++ b/graphics/graphics.c @@ -1,6 +1,7 @@ #include "graphics.h" +#include "color.h" #include "unifont.h" #include "../runtime/stdio.h" #include @@ -26,14 +27,17 @@ static EFI_GRAPHICS_OUTPUT_PROTOCOL *gop; static EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info; static UINTN sizeofInfo, nModes, nativeMode; static HelosGraphics_Mode modes[128]; +HelosGraphics_Mode graphics_SystemVideoMode; void *graphics_DeviceFramebuffer; void * graphics_Framebuffer; uint64_t graphics_FramebufferSize; - uint32_t graphics_Doublebuffer[2048 * 1024]; +xcursor_ChunkHeader_Image *graphics_Cursor; +int graphics_MouseCursorX, graphics_MouseCursorY; + void graphics_Init() { assert(sizeof(HelosGraphics_Color) == sizeof(uint32_t) && "HelosGraphics_Color not packed to be 32-bit(4 bytes)"); @@ -99,8 +103,12 @@ void graphics_Init() { } #undef CASE - graphics_Framebuffer = (void *)graphics_Doublebuffer; + graphics_SystemVideoMode = modes[nativeMode]; + graphics_Framebuffer = (void *)graphics_Doublebuffer; graphics_CursorX = graphics_CursorY = 0; + + graphics_MouseCursorX = graphics_SystemVideoMode.Width / 2; + graphics_MouseCursorY = graphics_SystemVideoMode.Height / 2; } @@ -112,17 +120,17 @@ void graphics_SetPixel_RGB(int posX, int posY, const HelosGraphics_Color *color) uint8_t A; } colorRGB = {color->R, color->G, color->B, 0}; - *((uint32_t *)(graphics_Framebuffer + modes[nativeMode].PixelsPerLine * 4 * posY + 4 * posX)) = (*((uint32_t *)&colorRGB)); + *((uint32_t *)(graphics_Framebuffer + graphics_SystemVideoMode.PixelsPerLine * 4 * posY + 4 * posX)) = (*((uint32_t *)&colorRGB)); } void graphics_SetPixel_BGR(int posX, int posY, const HelosGraphics_Color *color) { - *((uint32_t *)(graphics_Framebuffer + modes[nativeMode].PixelsPerLine * 4 * posY + 4 * posX)) = (*((uint32_t *)color)) & 0x00ffffffu; + *((uint32_t *)(graphics_Framebuffer + graphics_SystemVideoMode.PixelsPerLine * 4 * posY + 4 * posX)) = (*((uint32_t *)color)) & 0x00ffffffu; } void graphics_GetSize(int *sizeX, int *sizeY, int *bitsPerPixel) { - *sizeX = modes[nativeMode].Width; - *sizeY = modes[nativeMode].Height; + *sizeX = graphics_SystemVideoMode.Width; + *sizeY = graphics_SystemVideoMode.Height; *bitsPerPixel = 24; } @@ -134,13 +142,13 @@ void graphics_ClearBuffer(const HelosGraphics_Color *color) { return; } - if (modes[nativeMode].PixelFormat == PixelRedGreenBlueReserved8BitPerColor) { + if (graphics_SystemVideoMode.PixelFormat == PixelRedGreenBlueReserved8BitPerColor) { struct { uint8_t R, G, B; uint8_t A; } colorRGB = {color->R, color->G, color->B, 0}; data = (*(uint32_t *)&colorRGB) & 0x00ffffffu; - } else if (modes[nativeMode].PixelFormat == PixelBlueGreenRedReserved8BitPerColor) { + } else if (graphics_SystemVideoMode.PixelFormat == PixelBlueGreenRedReserved8BitPerColor) { data = (*(uint32_t *)color) & 0x00ffffffu; } @@ -151,17 +159,47 @@ void graphics_ClearBuffer(const HelosGraphics_Color *color) { } } +static inline size_t min(size_t x, size_t y) { + return x < y ? x : y; +} + void graphics_SwapBuffer() { memcpy(graphics_DeviceFramebuffer, graphics_Framebuffer, graphics_FramebufferSize); + + if (graphics_Cursor) { + // TODO Optimize mouse cursor overlay render + /*if (graphics_SystemVideoMode.PixelFormat == PixelBlueGreenRedReserved8BitPerColor) { + for (int i = 0; i < graphics_Cursor->height; i++) { + if (graphics_MouseCursorY + i >= graphics_SystemVideoMode.Height) + break; + memcpy( + graphics_DeviceFramebuffer + graphics_SystemVideoMode.PixelsPerLine * 4 * graphics_CursorY + 4 * graphics_CursorX, + &graphics_Cursor->pixels[i * graphics_Cursor->width], + min(graphics_Cursor->width, graphics_SystemVideoMode.Width - graphics_MouseCursorX) * 4); + } + } else {*/ + for (int y = 0; y < graphics_Cursor->height; y++) { + if (graphics_MouseCursorY + y >= graphics_SystemVideoMode.Height) + break; + for (int x = 0; x < min(graphics_Cursor->width, graphics_SystemVideoMode.Width - graphics_MouseCursorX); x++) { + //graphics_SetPixel_RGB(x + graphics_MouseCursorX, y + graphics_MouseCursorY, &graphics_Cursor->pixels[y * graphics_Cursor->width + x]); + HelosGraphics_Color *pixel = &graphics_Cursor->pixels[y * graphics_Cursor->width + x]; + if (pixel->A <= 0x7f) + continue; + *((uint32_t *)(graphics_DeviceFramebuffer + graphics_SystemVideoMode.PixelsPerLine * 4 * (y + graphics_MouseCursorY) + 4 * (x + graphics_MouseCursorX))) = (*((uint32_t *)&graphics_Cursor->pixels[y * graphics_Cursor->width + x])) & 0x00ffffffu; + } + } + //} + } } void graphics_FillPixel(int startX, int startY, int endX, int endY, const HelosGraphics_Color *color) { // TODO Optimize this! This is too sloooow - if (gop->Mode->Info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) + if (graphics_SystemVideoMode.PixelFormat == PixelBlueGreenRedReserved8BitPerColor) for (int i = startX; i < endX; i++) for (int j = startY; j < endY; j++) - *((uint32_t *)(graphics_Framebuffer + modes[nativeMode].PixelsPerLine * 4 * j + 4 * i)) = (*((uint32_t *)color)) & 0x00ffffffu; - else if (gop->Mode->Info->PixelFormat == PixelRedGreenBlueReserved8BitPerColor) + *((uint32_t *)(graphics_Framebuffer + graphics_SystemVideoMode.PixelsPerLine * 4 * j + 4 * i)) = (*((uint32_t *)color)) & 0x00ffffffu; + else if (graphics_SystemVideoMode.PixelFormat == PixelRedGreenBlueReserved8BitPerColor) for (int i = startX; i < endX; i++) for (int j = startY; j < endY; j++) { struct { @@ -169,7 +207,7 @@ void graphics_FillPixel(int startX, int startY, int endX, int endY, const HelosG uint8_t A; } colorRGB = {color->B, color->G, color->R, 0}; - *((uint32_t *)(graphics_Framebuffer + modes[nativeMode].PixelsPerLine * 4 * j + 4 * i)) = (*((uint32_t *)&colorRGB)); + *((uint32_t *)(graphics_Framebuffer + graphics_SystemVideoMode.PixelsPerLine * 4 * j + 4 * i)) = (*((uint32_t *)&colorRGB)); } } @@ -178,24 +216,24 @@ int graphics_CursorX, graphics_CursorY; void graphics_Scroll(int scrollY) { memmove( graphics_Doublebuffer, - graphics_Doublebuffer + modes[nativeMode].PixelsPerLine * scrollY, - sizeof(uint32_t) * (modes[nativeMode].PixelsPerLine * (modes[nativeMode].Height - scrollY))); + graphics_Doublebuffer + graphics_SystemVideoMode.PixelsPerLine * scrollY, + sizeof(uint32_t) * (graphics_SystemVideoMode.PixelsPerLine * (graphics_SystemVideoMode.Height - scrollY))); // TODO proper memset instead of this sloooow FillPixel /*memset( - graphics_Doublebuffer + modes[nativeMode].PixelsPerLine * (modes[nativeMode].Height - scrollY), + graphics_Doublebuffer + graphics_SystemVideoMode.PixelsPerLine * (graphics_SystemVideoMode.Height - scrollY), 0, - sizeof(uint32_t) * modes[nativeMode].PixelsPerLine * (scrollY));*/ - graphics_FillPixel(0, modes[nativeMode].Height - scrollY, modes[nativeMode].Width, modes[nativeMode].Height, &HelosGraphics_Color_Black); + sizeof(uint32_t) * graphics_SystemVideoMode.PixelsPerLine * (scrollY));*/ + graphics_FillPixel(0, graphics_SystemVideoMode.Height - scrollY, graphics_SystemVideoMode.Width, graphics_SystemVideoMode.Height, &HelosGraphics_Color_Black); } void graphics_ElementSize(int sizeX, int sizeY) { - if (graphics_CursorX + sizeX >= modes[nativeMode].Width) { // line breaking required + if (graphics_CursorX + sizeX >= graphics_SystemVideoMode.Width) { // line breaking required graphics_CursorY += sizeY; graphics_CursorX = 0; } - if (graphics_CursorY + sizeY >= modes[nativeMode].Height) { // scrolling required - graphics_Scroll(sizeY + graphics_CursorY - modes[nativeMode].Height); - graphics_CursorY = modes[nativeMode].Height - sizeY; + if (graphics_CursorY + sizeY >= graphics_SystemVideoMode.Height) { // scrolling required + graphics_Scroll(sizeY + graphics_CursorY - graphics_SystemVideoMode.Height); + graphics_CursorY = graphics_SystemVideoMode.Height - sizeY; } } diff --git a/graphics/graphics.h b/graphics/graphics.h index b2cf83f..06062b1 100644 --- a/graphics/graphics.h +++ b/graphics/graphics.h @@ -3,6 +3,8 @@ #include "../main.h" #include "efiprot.h" +#include "color.h" +#include "xcursor/xcursor.h" #ifdef __cplusplus extern "C" { @@ -12,22 +14,6 @@ extern "C" { #define HELOS_GRAPHICS_TARGET_MODE_WIDTH 1600 #define HELOS_GRAPHICS_TARGET_MODE_HEIGHT 900 -// HelosGraphics_Color is in ARGB little-endian packed format -// (B,G,R,A in byte order) -typedef struct { - uint8_t B, G, R; - uint8_t A; -} PACKED HelosGraphics_Color; - -extern const HelosGraphics_Color - HelosGraphics_Color_Black, - HelosGraphics_Color_White, - HelosGraphics_Color_Red, - HelosGraphics_Color_Green, - HelosGraphics_Color_Blue, - HelosGraphics_Color_Cyan, - HelosGraphics_Color_Magenta, - HelosGraphics_Color_Yellow; typedef struct { int Width, Height; @@ -37,9 +23,13 @@ typedef struct { } HelosGraphics_Mode; -extern void * graphics_DeviceFramebuffer; // this is the framebuffer directly for the device via memory mapping. -extern void * graphics_Framebuffer; // this is the double-buffered framebuffer (back buffer) -extern uint64_t graphics_FramebufferSize; +extern void * graphics_DeviceFramebuffer; // this is the framebuffer directly for the device via memory mapping. +extern void * graphics_Framebuffer; // this is the double-buffered framebuffer (back buffer) +extern uint64_t graphics_FramebufferSize; +extern HelosGraphics_Mode graphics_SystemVideoMode; // system video mode + +extern xcursor_ChunkHeader_Image *graphics_Cursor; // mouse cursor image +extern int graphics_MouseCursorX, graphics_MouseCursorY; // Init() must be called prior to ExitBootServices() diff --git a/kernel/kmain.c b/kernel/kmain.c index b035a53..77689a5 100644 --- a/kernel/kmain.c +++ b/kernel/kmain.c @@ -15,6 +15,10 @@ #include "../execformat/pe/reloc.h" void execformat_pe_ReadSystemHeader(execformat_pe_PortableExecutable *pe); +#include "../graphics/graphics.h" +#include "../graphics/xcursor/xcursor.h" +#include "../embed/files.h" + static void tellRIP() { uint64_t a, b; asm volatile("leaq (%%rip), %0\n\tleaq runtime_InitPaging(%%rip), %1" @@ -22,6 +26,14 @@ static void tellRIP() { io_Printf("tellRIP(): Stack position: %llx, RIP=%llx, kMain_StackPosition:%llx(%llx), interrupt_Int128: %llx\n", &a, a, (uint64_t)&kMain_StackPosition, b, (uint64_t)interrupt_Int128); } +static inline int minmax(int val, int min, int max) { + if (val > max) + return max; + if (val < min) + return min; + return val; +} + SYSV_ABI void kMain() { io_WriteConsoleASCII("Yes! kMain survived!\n"); @@ -44,8 +56,43 @@ SYSV_ABI void kMain() { irq_pic_ps2_Init(); io_WriteConsoleASCII("PIC PS/2 OK\n"); + xcursor_Xcursor cursor; + xcursor_LoadMemory(&cursor, (void *)embed_Xcursor_Default_Data, embed_Xcursor_Default_Data_End - embed_Xcursor_Default_Data); + if (cursor.header) { + for (int i = 0; i < cursor.n; i++) { + if (cursor.toc[i].type == XCURSOR_CHUNKTYPE_IMAGE /*&& ((xcursor_ChunkHeader_Image *)(embed_Xcursor_Default_Data + cursor.toc[i].offset))->subtype == 24*/) { + xcursor_ChunkHeader_Image *image = (xcursor_ChunkHeader_Image *)(embed_Xcursor_Default_Data + cursor.toc[i].offset); + io_Printf("xcursor_Default: Loading size=%dx%d\n", image->width, image->height); + graphics_Cursor = image; + break; + } + } + } else + io_WriteConsoleASCII("xcursor_Default: failed to load\n"); + for (;;) { asm volatile("hlt"); - io_WriteConsoleASCII("kMain: Interrupt hit\n"); + + while (queue_Size(&irq_pic_ps2_QueueMouse) >= (irq_pic_ps2_Mouse4Bytes ? 4 : 3)) { + unsigned int moveX, moveY, state; + + do { + state = queue_PopByte(&irq_pic_ps2_QueueMouse); + } while (!(state & (1u << 3))); + + unsigned int d = queue_PopByte(&irq_pic_ps2_QueueMouse); + moveX = d - ((state << 4) & 0x100); + d = queue_PopByte(&irq_pic_ps2_QueueMouse); + moveY = d - ((state << 3) & 0x100); + + graphics_MouseCursorX = minmax(graphics_MouseCursorX + *((int *)&moveX), 0, graphics_SystemVideoMode.Width - 1); + graphics_MouseCursorY = minmax(graphics_MouseCursorY - *((int *)&moveY), 0, graphics_SystemVideoMode.Height - 1); + + if (irq_pic_ps2_Mouse4Bytes) + queue_PopByte(&irq_pic_ps2_QueueMouse); + } + + //io_WriteConsoleASCII("kMain: Interrupt hit\n"); + graphics_SwapBuffer(); } }