summaryrefslogtreecommitdiff
path: root/fb
diff options
context:
space:
mode:
Diffstat (limited to 'fb')
-rw-r--r--fb/fb.go228
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
+// }