move to self repo
This commit is contained in:
commit
169b79d0cb
166
framebuffer.go
Normal file
166
framebuffer.go
Normal file
@ -0,0 +1,166 @@
|
||||
package gofb
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/fb.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
int OpenFrameBuffer(char * name) {
|
||||
return open(name, O_RDWR);
|
||||
}
|
||||
|
||||
static int GetFixedScreenInformation(int fd,struct fb_fix_screeninfo *finfo)
|
||||
{
|
||||
|
||||
return ioctl(fd, FBIOGET_FSCREENINFO, finfo);
|
||||
}
|
||||
|
||||
|
||||
static int GetVarScreenInformation(int fd,struct fb_var_screeninfo *vinfo) {
|
||||
return ioctl(fd, FBIOGET_VSCREENINFO, vinfo);
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"os/exec"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type Framebuffer struct {
|
||||
Fd int
|
||||
BitsPerPixel int
|
||||
Xres int
|
||||
Yres int
|
||||
Data []byte
|
||||
Xoffset int
|
||||
Yoffset int
|
||||
LineLength int
|
||||
Screensize int
|
||||
}
|
||||
|
||||
func NewFramebuffer() *Framebuffer {
|
||||
return &Framebuffer{}
|
||||
}
|
||||
|
||||
func _HideCursor() {
|
||||
fmt.Print("\033[?25l")
|
||||
exec.Command(`kill `)
|
||||
}
|
||||
|
||||
func _ShowCursor() {
|
||||
fmt.Printf("\033[?25h")
|
||||
}
|
||||
|
||||
func (f *Framebuffer) Init() {
|
||||
_HideCursor()
|
||||
dev_file := C.CString("/dev/fb0")
|
||||
fd, err := C.OpenFrameBuffer(dev_file)
|
||||
C.free(unsafe.Pointer(dev_file))
|
||||
|
||||
if err != nil {
|
||||
panic(errors.New("Open the framebuffer failed"))
|
||||
}
|
||||
|
||||
var finfo C.struct_fb_fix_screeninfo
|
||||
if _, err := C.GetFixedScreenInformation(fd, &finfo); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
var vinfo C.struct_fb_var_screeninfo
|
||||
if _, err := C.GetVarScreenInformation(fd, &vinfo); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
f.Xres = int(vinfo.xres)
|
||||
f.Yres = int(vinfo.yres)
|
||||
f.BitsPerPixel = int(vinfo.bits_per_pixel)
|
||||
f.Xoffset = int(vinfo.xoffset)
|
||||
f.Yoffset = int(vinfo.yoffset)
|
||||
f.LineLength = int(finfo.line_length)
|
||||
|
||||
f.Screensize = int(finfo.smem_len)
|
||||
|
||||
addr := uintptr(C.mmap(nil, C.size_t(f.Screensize), C.PROT_READ|C.PROT_WRITE, C.MAP_SHARED, fd, 0))
|
||||
|
||||
var sl = struct {
|
||||
addr uintptr
|
||||
len int
|
||||
cap int
|
||||
}{addr, f.Screensize, f.Screensize}
|
||||
|
||||
f.Data = *(*[]byte)(unsafe.Pointer(&sl))
|
||||
|
||||
}
|
||||
|
||||
func (f *Framebuffer) Release() {
|
||||
C.munmap(unsafe.Pointer(&f.Data[0]), C.size_t(f.Screensize))
|
||||
C.close(C.int(f.Fd))
|
||||
_ShowCursor()
|
||||
}
|
||||
|
||||
func (f *Framebuffer) SetPixel(x int, y int, r uint32, g uint32, b uint32, a uint32) {
|
||||
if x < 0 || x > f.Xres {
|
||||
panic(errors.New("X is too big or is negative"))
|
||||
}
|
||||
|
||||
if y < 0 || y > f.Yres {
|
||||
panic(errors.New("Y is too big or is negative"))
|
||||
}
|
||||
|
||||
location := (x+f.Xoffset)*(f.BitsPerPixel/8) + (y+f.Yoffset)*f.LineLength
|
||||
|
||||
f.Data[location+3] = byte(a & 0xff)
|
||||
f.Data[location+2] = byte(r & 0xff)
|
||||
f.Data[location+1] = byte(g & 0xff)
|
||||
f.Data[location] = byte(b & 0xff)
|
||||
}
|
||||
|
||||
func (f *Framebuffer) DrawImage(xoffset int, yoffset int, image image.Image) {
|
||||
|
||||
b := image.Bounds()
|
||||
|
||||
for y := 0; y < b.Max.Y; y++ {
|
||||
for x := 0; x < b.Max.X; x++ {
|
||||
r, g, b, a := image.At(x, y).RGBA()
|
||||
f.SetPixel(x+xoffset, y+yoffset, r&0xff, g&0xff, b&0xff, a&0xff)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Framebuffer) DrawData(xoffset int, yoffset int, data []byte, w int, h int) {
|
||||
|
||||
if w > f.Xres {
|
||||
panic(errors.New("The width of data must NOT be bigger the Xres of the framebuffer"))
|
||||
}
|
||||
|
||||
for y := 0; y < h; y++ {
|
||||
if (y+1)*w > len(data) {
|
||||
panic(errors.New("The length of image data is too small or w(h) argument is wrong"))
|
||||
}
|
||||
|
||||
line_start := (xoffset+f.Xoffset)*(f.BitsPerPixel/8) + (y+yoffset+f.Yoffset)*f.LineLength
|
||||
line_end := (xoffset+f.Xoffset)*(f.BitsPerPixel/8) + (y+1+yoffset+f.Yoffset)*f.LineLength - 1
|
||||
|
||||
if line_start+w > line_end {
|
||||
panic(errors.New("The lines is too long beyond the framebuffer"))
|
||||
}
|
||||
|
||||
data_line := data[y*w*4 : (y+1)*w*4]
|
||||
copy(f.Data[line_start:line_start+w*4], data_line)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (f *Framebuffer) Fill(r, g, b, a uint32) {
|
||||
for y := 0; y < f.Yres; y++ {
|
||||
for x := 0; x < f.Xres; x++ {
|
||||
f.SetPixel(x, y, r, g, b, a)
|
||||
}
|
||||
}
|
||||
}
|
132
framebuffer_test.go
Normal file
132
framebuffer_test.go
Normal file
@ -0,0 +1,132 @@
|
||||
package gofb
|
||||
|
||||
import (
|
||||
"image"
|
||||
"testing"
|
||||
|
||||
"github.com/ungerik/go-cairo"
|
||||
)
|
||||
|
||||
func BenchmarkFill(b *testing.B) {
|
||||
fb := NewFramebuffer()
|
||||
|
||||
fb.Init()
|
||||
defer fb.Release()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
fb.Fill(0, 0, 255, 0)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func BenchmarkMakeSurfaceImage(b *testing.B) {
|
||||
surface := cairo.NewSurface(cairo.FORMAT_ARGB32, 1680, 1050)
|
||||
defer surface.Finish()
|
||||
for i := 0; i < b.N; i++ {
|
||||
surface.SetSourceRGBA(1, 1, 1, 1)
|
||||
surface.Rectangle(0, 0, 240, 80)
|
||||
surface.Fill()
|
||||
surface.SelectFontFace("serif", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD)
|
||||
surface.SetFontSize(32.0)
|
||||
surface.SetSourceRGBA(0, 0, 0, .1)
|
||||
surface.MoveTo(10.0, 50.0)
|
||||
surface.ShowText("Hello World")
|
||||
surface.GetImage()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func BenchmarkDrawImage(b *testing.B) {
|
||||
fb := NewFramebuffer()
|
||||
|
||||
fb.Init()
|
||||
defer fb.Release()
|
||||
|
||||
image := image.NewRGBA(image.Rect(0, 0, fb.Xres, fb.Yres))
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
fb.DrawImage(0, 0, image)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func BenchmarkCairoGetData(b *testing.B) {
|
||||
fb := NewFramebuffer()
|
||||
|
||||
fb.Init()
|
||||
defer fb.Release()
|
||||
|
||||
surface := cairo.NewSurface(cairo.FORMAT_ARGB32, fb.Xres, fb.Yres)
|
||||
defer surface.Finish()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
surface.GetData()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func BenchmarkDrawData(b *testing.B) {
|
||||
fb := NewFramebuffer()
|
||||
|
||||
fb.Init()
|
||||
defer fb.Release()
|
||||
|
||||
data := make([]byte, fb.Xres*fb.Yres*4, fb.Xres*fb.Yres*4)
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
fb.DrawData(0, 0, data, fb.Xres, fb.Yres)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCopyDataByLine(b *testing.B) {
|
||||
fb := NewFramebuffer()
|
||||
|
||||
fb.Init()
|
||||
defer fb.Release()
|
||||
|
||||
data1 := make([]byte, fb.Xres*fb.Yres*4, fb.Xres*fb.Yres*4)
|
||||
data2 := make([]byte, fb.Xres*fb.Yres*4, fb.Xres*fb.Yres*4)
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
for y := 0; y < fb.Yres; y++ {
|
||||
copy(data1[y*fb.Xres*4:(y+1)*fb.Xres*4], data2[y*fb.Xres*4:(y+1)*fb.Xres*4])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCopyDataAllInOne(b *testing.B) {
|
||||
fb := NewFramebuffer()
|
||||
|
||||
fb.Init()
|
||||
defer fb.Release()
|
||||
|
||||
data1 := make([]byte, fb.Xres*fb.Yres*4, fb.Xres*fb.Yres*4)
|
||||
data2 := make([]byte, fb.Xres*fb.Yres*4, fb.Xres*fb.Yres*4)
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
copy(data1, data2)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAnimation(b *testing.B) {
|
||||
fb := NewFramebuffer()
|
||||
|
||||
fb.Init()
|
||||
defer fb.Release()
|
||||
|
||||
surface := cairo.NewSurface(cairo.FORMAT_ARGB32, fb.Xres, fb.Yres)
|
||||
defer surface.Finish()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
surface.SetSourceRGBA(0, 0, 0, 1)
|
||||
surface.Rectangle(0, 0, float64(fb.Xres), float64(fb.Yres))
|
||||
surface.Fill()
|
||||
surface.SelectFontFace("serif", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD)
|
||||
surface.SetFontSize(32.0)
|
||||
surface.SetSourceRGBA(1, 1, 1, 1)
|
||||
surface.MoveTo(10.0+float64(i), 50.0)
|
||||
surface.ShowText("道可道 非常道")
|
||||
data := surface.GetData()
|
||||
fb.DrawData(0, 0, data, fb.Xres, fb.Yres)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user