diff options
| author | Kevin Wallace <kevin@pentabarf.net> | 2026-04-25 02:32:32 -0700 |
|---|---|---|
| committer | Kevin Wallace <kevin@pentabarf.net> | 2026-04-25 02:32:32 -0700 |
| commit | 3004e4d88e55bdc2e00f7236a2b2111e4d05fd4a (patch) | |
| tree | f2d347f8b169cee4246aa7ae0568057674c6073a /fb | |
| parent | beep when you press the button (diff) | |
orca ui replica wip
Diffstat (limited to 'fb')
| -rw-r--r-- | fb/fb.go | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/fb/fb.go b/fb/fb.go new file mode 100644 index 0000000..2c28d6d --- /dev/null +++ b/fb/fb.go @@ -0,0 +1,228 @@ +package fb + +import ( + "image" + "image/color" + "image/draw" + "io" + "syscall" + + "golang.org/x/sys/unix" +) + +const ( + Width = 800 + Height = 480 +) + +type fb struct { + fd int + data []byte +} + +var _ interface { + io.Closer + draw.Image +} = &fb{} + +func Open() (*fb, error) { + fd, err := unix.Open("/dev/fb0", unix.O_RDWR, 0) + if err != nil { + return nil, err + } + data, err := syscall.Mmap(fd, 0, Width*Height*4, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED) + if err != nil { + return nil, err + } + return &fb{ + fd: fd, + data: data, + }, nil +} + +func (fb *fb) Close() error { + if err := syscall.Munmap(fb.data); err != nil { + return err + } + if err := unix.Close(fb.fd); err != nil { + return err + } + return nil +} + +func (fb *fb) ColorModel() color.Model { return color.RGBAModel } // draw.Image +func (fb *fb) Bounds() image.Rectangle { return image.Rect(0, 0, Width, Height) } // draw.Image + +func (fb *fb) At(x, y int) color.Color { // draw.Image + if x < 0 || x >= Width || y < 0 || y >= Height { + return color.RGBA{} + } + off := (y*Width + x) * 4 + bs := fb.data[off : off+4] + return color.RGBA{bs[2], bs[1], bs[0], bs[3]} +} + +func (fb *fb) Set(x, y int, c color.Color) { // draw.Image + rgba := color.RGBAModel.Convert(c).(color.RGBA) + if x < 0 || x >= Width || y < 0 || y >= Height { + return + } + off := (y*Width + x) * 4 + bs := fb.data[off : off+4] + bs[0] = rgba.B + bs[1] = rgba.G + bs[2] = rgba.R + bs[3] = rgba.A +} + +// swizzle swizzles RGBA to BGRA, or vice versa +func swizzle(bs []byte) { + for i := 0; i < len(bs); i += 4 { + bs[i], bs[i+2] = bs[i+2], bs[i] + } +} + +func (fb *fb) ReadRGBA() *image.RGBA { + img := image.NewRGBA(fb.Bounds()) + pix := img.Pix[:Width*Height*4] + copy(pix, fb.data) + swizzle(pix) + return img +} + +func (fb *fb) WriteRGBA(img *image.RGBA) { // destructive: swizzles img's RGBA to BGRA in-place + if fb.Bounds() != img.Bounds() { + panic("img bounds mismatch") + } + pix := img.Pix[:Width*Height*4] + swizzle(pix) + copy(fb.data, pix) +} + +// finfo: { +// ID:[68 73 83 80 51 32 66 71 0 0 0 0 0 0 0 0] +// SMemStart:437256192 +// SMemLen:1536000 +// Type:0 +// TypeAux:0 +// Visual:2 +// XPanStep:1 +// YPanStep:1 +// YWrapStep:1 +// LineLength:3200 +// MMIOStart:0 +// MMIOLen:0 +// Accel:0 +// Capabilities:0 +// Reserved:[0 0] +// } +// vinfo: { +// XRes:800 +// YRes:480 +// XResVirtual:800 +// YResVirtual:480 +// XOffset:0 +// YOffset:0 +// BitsPerPixel:32 +// Grayscale:0 +// R:{Offset:16 Length:8 MSBRight:0} +// G:{Offset:8 Length:8 MSBRight:0} +// B:{Offset:0 Length:8 MSBRight:0} +// A:{Offset:24 Length:8 MSBRight:0} +// Nonstd:0 +// Activate:0 +// Height:4294967295 +// Width:4294967295 +// AccelFlags:0 +// Pixclock:37037 +// LeftMargin:40 +// RightMargin:60 +// UpperMargin:10 +// LowerMargin:10 +// HSyncLen:20 +// VSyncLen:10 +// Sync:1073741824 +// VMode:0 +// Rotate:0 +// Colorspace:0 +// Reserved:[0 0 0 0] +// } + +// // include/uapi/linux/fb.h + +// type FBFInfo struct { +// ID [16]byte +// SMemStart uint32 +// SMemLen uint32 +// Type uint32 +// TypeAux uint32 +// Visual uint32 +// XPanStep uint16 +// YPanStep uint16 +// YWrapStep uint16 +// LineLength uint32 +// MMIOStart uint32 +// MMIOLen uint32 +// Accel uint32 +// Capabilities uint16 +// Reserved [2]uint16 +// } + +// type FBBitfield struct { +// Offset uint32 +// Length uint32 +// MSBRight uint32 +// } + +// type FBVInfo struct { +// XRes uint32 +// YRes uint32 +// XResVirtual uint32 +// YResVirtual uint32 +// XOffset uint32 +// YOffset uint32 + +// BitsPerPixel uint32 +// Grayscale uint32 +// R, G, B, A FBBitfield + +// Nonstd uint32 + +// Activate uint32 + +// Height uint32 +// Width uint32 + +// AccelFlags uint32 + +// Pixclock uint32 +// LeftMargin uint32 +// RightMargin uint32 +// UpperMargin uint32 +// LowerMargin uint32 +// HSyncLen uint32 +// VSyncLen uint32 +// Sync uint32 +// VMode uint32 +// Rotate uint32 +// Colorspace uint32 +// Reserved [4]uint32 +// } + +// func FBGetFInfo(fd int) (finfo FBFInfo, err error) { +// const FBIOGET_FSCREENINFO = 0x4602 +// _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), FBIOGET_FSCREENINFO, uintptr(unsafe.Pointer(&finfo))) +// if errno != 0 { +// err = errno +// } +// return +// } + +// func FBGetVInfo(fd int) (vinfo FBVInfo, err error) { +// const FBIOGET_VSCREENINFO = 0x4600 +// _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), FBIOGET_VSCREENINFO, uintptr(unsafe.Pointer(&vinfo))) +// if errno != 0 { +// err = errno +// } +// return +// } |