Consistently cache display device Bounds()

Improve Draw() performance.
pull/1/head
Marc-Antoine Ruel 8 years ago
parent 0a22d3193e
commit 6f8bd69f03

@ -78,6 +78,7 @@ func New(p spi.Port, o *Opts) (*Dev, error) {
numPixels: o.NumPixels,
rawBuf: buf,
pixels: buf[4 : 4+4*o.NumPixels],
rect: image.Rect(0, 0, o.NumPixels, 1),
}, nil
}
@ -96,11 +97,12 @@ type Dev struct {
// It can be changed, it will take effect on the next Draw() or Write() call.
Temperature uint16
s spi.Conn //
l lut // Updated at each .Write() call.
numPixels int //
rawBuf []byte // Raw buffer sent over SPI. Cached to reduce heap fragmentation.
pixels []byte // Double buffer of pixels, to enable partial painting via Draw(). Effectively points inside rawBuf.
s spi.Conn //
l lut // Updated at each .Write() call.
numPixels int //
rawBuf []byte // Raw buffer sent over SPI. Cached to reduce heap fragmentation.
pixels []byte // Double buffer of pixels, to enable partial painting via Draw(). Effectively points inside rawBuf.
rect image.Rectangle // Device bounds
}
func (d *Dev) String() string {
@ -115,7 +117,7 @@ func (d *Dev) ColorModel() color.Model {
// Bounds implements devices.Display. Min is guaranteed to be {0, 0}.
func (d *Dev) Bounds() image.Rectangle {
return image.Rectangle{Max: image.Point{X: d.numPixels, Y: 1}}
return d.rect
}
// Draw implements devices.Display.
@ -123,7 +125,7 @@ func (d *Dev) Bounds() image.Rectangle {
// Using something else than image.NRGBA is 10x slower. When using image.NRGBA,
// the alpha channel is ignored.
func (d *Dev) Draw(r image.Rectangle, src image.Image, sp image.Point) {
r = r.Intersect(d.Bounds())
r = r.Intersect(d.rect)
srcR := src.Bounds()
srcR.Min = srcR.Min.Add(sp)
if dX := r.Dx(); dX < srcR.Dx() {

@ -189,7 +189,7 @@ func (d *Dev) Bounds() image.Rectangle {
// It discards any failure.
func (d *Dev) Draw(r image.Rectangle, src image.Image, sp image.Point) {
var next []byte
if img, ok := src.(*image1bit.VerticalLSB); ok && r == d.Bounds() && src.Bounds() == d.rect && sp.X == 0 && sp.Y == 0 {
if img, ok := src.(*image1bit.VerticalLSB); ok && r == d.rect && src.Bounds() == d.rect && sp.X == 0 && sp.Y == 0 {
// Exact size, full frame, image1bit encoding: fast path!
next = img.Pix
} else {

@ -82,6 +82,7 @@ func New(p gpiostream.PinOut, opts *Opts) (*Dev, error) {
Bits: make([]byte, opts.NumPixels*3*opts.Channels),
LSBF: false,
},
rect: image.Rect(0, 0, opts.NumPixels, 1),
}, nil
}
@ -92,6 +93,7 @@ type Dev struct {
channels int // Number of channels per pixel
b gpiostream.BitStream // NRZ encoded bits; cached to reduce heap fragmentation
buf []byte // Double buffer of RGB/RGBW pixels; enables partial Draw()
rect image.Rectangle // Device bounds
}
func (d *Dev) String() string {
@ -126,7 +128,7 @@ func (d *Dev) ColorModel() color.Model {
// Bounds implements devices.Display. Min is guaranteed to be {0, 0}.
func (d *Dev) Bounds() image.Rectangle {
return image.Rectangle{Max: image.Point{X: d.numPixels, Y: 1}}
return d.rect
}
// Draw implements devices.Display.
@ -138,7 +140,7 @@ func (d *Dev) Bounds() image.Rectangle {
// A back buffer is kept so that partial updates are supported, albeit the full
// LED strip is updated synchronously.
func (d *Dev) Draw(r image.Rectangle, src image.Image, sp image.Point) {
r = r.Intersect(d.Bounds())
r = r.Intersect(d.rect)
srcR := src.Bounds()
srcR.Min = srcR.Min.Add(sp)
if dX := r.Dx(); dX < srcR.Dx() {

Loading…
Cancel
Save