move to self repo

This commit is contained in:
Jay 2019-12-10 04:49:40 +00:00
commit 169b79d0cb
2 changed files with 298 additions and 0 deletions

166
framebuffer.go Normal file
View 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
View 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)
}
}