mirror of
https://github.com/archr-linux/Arch-R.git
synced 2026-03-31 14:41:55 -07:00
System daemons: hotkeys (volume/brightness), automount, bluetooth agent, memory manager, sleep/suspend, USB gadget mode, save-config persistence. Boot splash: initramfs SVG renderer (fbsplash + svg_parser) for 0.7s splash. Panel tools: generate-panel-dtbos.sh rewrite, convert-panel.py for ROCKNIX panel data extraction, archr-dtbo.py for runtime overlay management. Input: archr-gptokeyb.c gamepad-to-keyboard mapper via uinput. Launch wrappers: emulationstation.sh and retroarch-launch.sh updated for KMS/DRM + Mesa 26 Panfrost environment. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
158 lines
4.3 KiB
C
158 lines
4.3 KiB
C
/*
|
|
* Arch R — Framebuffer splash abstraction
|
|
* Framebuffer abstraction for initramfs boot splash
|
|
* Removed stdio.h (crashes in static glibc PID 1 initramfs)
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <sys/ioctl.h>
|
|
#include "fbsplash.h"
|
|
|
|
Framebuffer* fb_init(const char *fb_device)
|
|
{
|
|
Framebuffer *fb = calloc(1, sizeof(Framebuffer));
|
|
if (!fb)
|
|
return NULL;
|
|
|
|
fb->fd = open(fb_device, O_RDWR);
|
|
if (fb->fd == -1) {
|
|
free(fb);
|
|
return NULL;
|
|
}
|
|
|
|
if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vinfo) == -1 ||
|
|
ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->finfo) == -1) {
|
|
close(fb->fd);
|
|
free(fb);
|
|
return NULL;
|
|
}
|
|
|
|
fb->screensize = fb->vinfo.yres_virtual * fb->finfo.line_length;
|
|
|
|
fb->buffer = malloc(fb->screensize);
|
|
if (!fb->buffer) {
|
|
close(fb->fd);
|
|
free(fb);
|
|
return NULL;
|
|
}
|
|
|
|
/* Clear to black */
|
|
memset(fb->buffer, 0, fb->screensize);
|
|
|
|
return fb;
|
|
}
|
|
|
|
void set_pixel(Framebuffer *fb, uint32_t x, uint32_t y, uint32_t color)
|
|
{
|
|
if (x >= fb->vinfo.xres || y >= fb->vinfo.yres)
|
|
return;
|
|
|
|
size_t location = (x + fb->vinfo.xoffset) * (fb->vinfo.bits_per_pixel / 8) +
|
|
(y + fb->vinfo.yoffset) * fb->finfo.line_length;
|
|
|
|
if (location >= fb->screensize)
|
|
return;
|
|
|
|
if (fb->vinfo.bits_per_pixel == 32) {
|
|
*((uint32_t*)(fb->buffer + location)) = color;
|
|
} else if (fb->vinfo.bits_per_pixel == 16) {
|
|
uint8_t r = (color >> 16) & 0xFF;
|
|
uint8_t g = (color >> 8) & 0xFF;
|
|
uint8_t b = color & 0xFF;
|
|
uint16_t color16 = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
|
|
*((uint16_t*)(fb->buffer + location)) = color16;
|
|
}
|
|
}
|
|
|
|
void blend_pixel(Framebuffer *fb, uint32_t x, uint32_t y, uint32_t color, float alpha)
|
|
{
|
|
if (x >= fb->vinfo.xres || y >= fb->vinfo.yres || alpha <= 0.0f)
|
|
return;
|
|
|
|
if (alpha >= 1.0f) {
|
|
set_pixel(fb, x, y, color);
|
|
return;
|
|
}
|
|
|
|
size_t location = (x + fb->vinfo.xoffset) * (fb->vinfo.bits_per_pixel / 8) +
|
|
(y + fb->vinfo.yoffset) * fb->finfo.line_length;
|
|
|
|
if (location >= fb->screensize)
|
|
return;
|
|
|
|
uint8_t fg_r = (color >> 16) & 0xFF;
|
|
uint8_t fg_g = (color >> 8) & 0xFF;
|
|
uint8_t fg_b = color & 0xFF;
|
|
|
|
uint32_t bg_color = 0;
|
|
if (fb->vinfo.bits_per_pixel == 32) {
|
|
bg_color = *((uint32_t*)(fb->buffer + location));
|
|
} else if (fb->vinfo.bits_per_pixel == 16) {
|
|
uint16_t color16 = *((uint16_t*)(fb->buffer + location));
|
|
uint8_t r = ((color16 >> 11) & 0x1F) << 3;
|
|
uint8_t g = ((color16 >> 5) & 0x3F) << 2;
|
|
uint8_t b = (color16 & 0x1F) << 3;
|
|
bg_color = (r << 16) | (g << 8) | b;
|
|
}
|
|
|
|
uint8_t bg_r = (bg_color >> 16) & 0xFF;
|
|
uint8_t bg_g = (bg_color >> 8) & 0xFF;
|
|
uint8_t bg_b = bg_color & 0xFF;
|
|
|
|
uint8_t r = (uint8_t)(fg_r * alpha + bg_r * (1.0f - alpha));
|
|
uint8_t g = (uint8_t)(fg_g * alpha + bg_g * (1.0f - alpha));
|
|
uint8_t b = (uint8_t)(fg_b * alpha + bg_b * (1.0f - alpha));
|
|
|
|
uint32_t blended = (r << 16) | (g << 8) | b;
|
|
set_pixel(fb, x, y, blended);
|
|
}
|
|
|
|
void fb_flush(Framebuffer *fb)
|
|
{
|
|
if (fb && fb->buffer) {
|
|
lseek(fb->fd, 0, SEEK_SET);
|
|
(void)write(fb->fd, fb->buffer, fb->screensize);
|
|
}
|
|
}
|
|
|
|
void fb_cleanup(Framebuffer *fb)
|
|
{
|
|
if (fb) {
|
|
if (fb->buffer)
|
|
free(fb->buffer);
|
|
if (fb->fd >= 0)
|
|
close(fb->fd);
|
|
free(fb);
|
|
}
|
|
}
|
|
|
|
DisplayInfo* calculate_display_info(Framebuffer *fb, float base_width, float base_height)
|
|
{
|
|
DisplayInfo *info = calloc(1, sizeof(DisplayInfo));
|
|
if (!info)
|
|
return NULL;
|
|
|
|
info->screen_width = fb->vinfo.xres;
|
|
info->screen_height = fb->vinfo.yres;
|
|
info->base_svg_width = base_width;
|
|
info->base_svg_height = base_height;
|
|
|
|
float target_width = info->screen_width * 0.6f;
|
|
float target_height = target_width * (base_height / base_width);
|
|
|
|
if (target_height > info->screen_height * 0.6f) {
|
|
target_height = info->screen_height * 0.6f;
|
|
target_width = target_height * (base_width / base_height);
|
|
}
|
|
|
|
info->svg_width = (uint32_t)target_width;
|
|
info->svg_height = (uint32_t)target_height;
|
|
info->x_offset = (info->screen_width - info->svg_width) / 2;
|
|
info->y_offset = (info->screen_height - info->svg_height) / 2;
|
|
|
|
return info;
|
|
}
|