/* * @author xamidev * @brief Screen/framebuffer system calls * @license GPL-3.0-only */ // This is not part of POSIX or anything btw #include #include extern struct boot_context boot_ctx; /* * pack_rbga_to_fb - Convert rgb values to rgba pixel for framebuffer * @r: red value * @g: green value * @b: blue value * * This function uses the mask sizes and shifts of the Limine * framebuffer to convert raw rgb values into usable pixels. * * Return: * - usable pixel */ static uint32_t pack_rgba_to_fb(uint8_t r, uint8_t g, uint8_t b) { uint32_t pixel = 0; if (boot_ctx.fb->red_mask_size) { pixel |= ((uint32_t)(r >> (8 - boot_ctx.fb->red_mask_size)) << boot_ctx.fb->red_mask_shift); } if (boot_ctx.fb->green_mask_size) { pixel |= ((uint32_t)(g >> (8 - boot_ctx.fb->green_mask_size)) << boot_ctx.fb->green_mask_shift); } if (boot_ctx.fb->blue_mask_size) { pixel |= ((uint32_t)(b >> (8 - boot_ctx.fb->blue_mask_size)) << boot_ctx.fb->blue_mask_shift); } return pixel; } /* * sys_draw_fb - Draw a framebuffer subset * @src: Source frame * @width: width of the frame * @height: height of the frame * @channels: how many channels (RGB, RGBA) * * This system call draws the frame @src, having some * @width and @height, in the top right of the Limine * framebuffer. (Used for DOOM) * * Return: * %0 - on success * On error, a negative value with an error code is returned. */ int sys_draw_fb(const uint8_t* src, int width, int height, int channels) { if (!boot_ctx.fb || !src) { return -EINVAL; } if (channels != 4 || width <= 0 || height <= 0) { return -EINVAL; } if (boot_ctx.fb->bpp < 24) { return -EIO; } uint32_t* dst = (uint32_t*)boot_ctx.fb->address; uint64_t dst_w = boot_ctx.fb->width; uint64_t dst_h = boot_ctx.fb->height; uint64_t dst_pitch_px = boot_ctx.fb->pitch / 4; uint64_t scale = 2; uint64_t scaled_w = (uint64_t)width * scale; uint64_t scaled_h = (uint64_t)height * scale; if (scaled_w > dst_w || scaled_h > dst_h) { return -EINVAL; } uint64_t dst_x = dst_w - scaled_w; uint64_t dst_y = 0; for (uint64_t y = 0; y < (uint64_t)height; ++y) { const uint8_t* src_row = src + y * (uint64_t)width * 4ULL; uint32_t* dst_row0 = dst + (dst_y + y * scale) * dst_pitch_px + dst_x; uint32_t* dst_row1 = dst_row0 + dst_pitch_px; for (uint64_t x = 0; x < (uint64_t)width; ++x) { const uint8_t* p = src_row + x * 4ULL; uint32_t pixel = pack_rgba_to_fb(p[0], p[1], p[2]); uint64_t dx = x * scale; // Write 2x2 block. This is because source DOOM frame (320x200) // is quite small. dst_row0[dx + 0] = pixel; dst_row0[dx + 1] = pixel; dst_row1[dx + 0] = pixel; dst_row1[dx + 1] = pixel; } } return 0; }