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 // }