wasp: draw565: Optimize the 2-bit RLE drawing functions

There's a bunch of different changes here but there are only really three
big wins. The biggest win comes from restructuring the 2-bit RLE decode
loop to avoid the inner function (~20%) but the switch to 16-bit writes in
_fill() and adoption of quick_write (e.g. no CS toggling) are also
note worthy (and about 5% each).
This commit is contained in:
Daniel Thompson 2020-04-08 21:50:42 +01:00
parent ac61d8a1c1
commit fd64abe882
3 changed files with 55 additions and 40 deletions

View file

@ -11,9 +11,13 @@ def viper(fn):
def ptr8(buf): def ptr8(buf):
return buf return buf
def ptr16(buf):
return memoryview(buf).cast('H')
# This is a bit of a hack since the scope for ptr8 won't be right # This is a bit of a hack since the scope for ptr8 won't be right
# but it does mean no changes to the client # but it does mean no changes to the client
fn.__globals__['ptr8'] = ptr8 fn.__globals__['ptr8'] = ptr8
fn.__globals__['ptr16'] = ptr16
return fn return fn

View file

@ -1,6 +1,7 @@
# SPDX-License-Identifier: LGPL-3.0-or-later # SPDX-License-Identifier: LGPL-3.0-or-later
# Copyright (C) 2020 Daniel Thompson # Copyright (C) 2020 Daniel Thompson
import array
import fonts.sans24 import fonts.sans24
import micropython import micropython
@ -45,13 +46,10 @@ def _expand_rgb(eightbit: int) -> int:
@micropython.viper @micropython.viper
def _fill(mv, color: int, count: int, offset: int): def _fill(mv, color: int, count: int, offset: int):
p = ptr8(mv) p = ptr16(mv)
colorhi = color >> 8
colorlo = color & 0xff
for x in range(count): for x in range(offset, offset+count):
p[2*(x+offset) ] = colorhi p[x] = color
p[2*(x+offset) + 1] = colorlo
def _bounding_box(s, font): def _bounding_box(s, font):
w = 0 w = 0
@ -110,6 +108,7 @@ class Draw565(object):
def rleblit(self, image, pos=(0, 0), fg=0xffff, bg=0): def rleblit(self, image, pos=(0, 0), fg=0xffff, bg=0):
"""Decode and draw a 1-bit RLE image.""" """Decode and draw a 1-bit RLE image."""
display = self._display display = self._display
write_data = display.write_data
(sx, sy, rle) = image (sx, sy, rle) = image
display.set_window(pos[0], pos[1], sx, sy) display.set_window(pos[0], pos[1], sx, sy)
@ -126,7 +125,7 @@ class Draw565(object):
rl -= count rl -= count
if bp >= sx: if bp >= sx:
display.write_data(buf) write_data(buf)
bp = 0 bp = 0
if color == bg: if color == bg:
@ -138,48 +137,50 @@ class Draw565(object):
def rle2bit(self, image, x, y): def rle2bit(self, image, x, y):
"""Decode and draw a 2-bit RLE image.""" """Decode and draw a 2-bit RLE image."""
display = self._display display = self._display
quick_write = display.quick_write
(sx, sy, rle) = image (sx, sy, rle) = image
display.set_window(x, y, sx, sy) display.set_window(x, y, sx, sy)
palette = array.array('H', (0, 0xfffe, 0x7bef, 0xffff))
next_color = 1
rl = 0
buf = memoryview(display.linebuffer)[0:2*sx] buf = memoryview(display.linebuffer)[0:2*sx]
bp = 0 bp = 0
rl = 0
palette = [ 0, 0xfffe, 0x7bef, 0xffff ]
next_color = 1
def blit_run(color, rl):
nonlocal bp
while rl:
count = min(sx - bp, rl)
_fill(buf, color, count, bp)
bp += count
rl -= count
if bp >= sx:
display.write_data(buf)
bp = 0
display.quick_start()
for op in rle: for op in rle:
if rl == 0: if rl == 0:
px = op >> 6 px = op >> 6
rl = op & 0x3f rl = op & 0x3f
if 0 == rl: if 0 == rl:
rl = -1 rl = -1
elif rl < 63: continue
blit_run(palette[px], rl) if rl >= 63:
rl = 0 continue
elif rl > 0: elif rl > 0:
rl += op rl += op
if op < 255: if op >= 255:
blit_run(palette[px], rl) continue
rl = 0
else: else:
palette[next_color] = _expand_rgb(op) palette[next_color] = _expand_rgb(op)
next_color += 1 if next_color < 3:
if next_color >= len(palette): next_color += 1
else:
next_color = 1 next_color = 1
rl = 0 rl = 0
continue
while rl:
count = min(sx - bp, rl)
_fill(buf, palette[px], count, bp)
bp += count
rl -= count
if bp >= sx:
quick_write(buf)
bp = 0
display.quick_end()
def set_color(self, color, bg=0): def set_color(self, color, bg=0):
"""Set the foreground (color) and background (bg) color. """Set the foreground (color) and background (bg) color.

View file

@ -121,13 +121,13 @@ class ST7789(object):
class ST7789_SPI(ST7789): class ST7789_SPI(ST7789):
def __init__(self, width, height, spi, cs, dc, res=None, rate=8000000): def __init__(self, width, height, spi, cs, dc, res=None, rate=8000000):
self.spi = spi self.quick_write = spi.write
self.dc = dc self.cs = cs.value
self.dc = dc.value
self.res = res self.res = res
self.cs = cs
self.rate = rate self.rate = rate
#self.spi.init(baudrate=self.rate, polarity=1, phase=1) #spi.init(baudrate=self.rate, polarity=1, phase=1)
cs.init(cs.OUT, value=1) cs.init(cs.OUT, value=1)
dc.init(dc.OUT, value=0) dc.init(dc.OUT, value=0)
if res: if res:
@ -145,13 +145,23 @@ class ST7789_SPI(ST7789):
sleep_ms(125) sleep_ms(125)
def write_cmd(self, cmd): def write_cmd(self, cmd):
self.dc(0) dc = self.dc
self.cs(0) cs = self.cs
self.spi.write(bytearray([cmd]))
self.cs(1) dc(0)
self.dc(1) cs(0)
self.quick_write(bytearray([cmd]))
cs(1)
dc(1)
def write_data(self, buf): def write_data(self, buf):
cs = self.cs
cs(0)
self.quick_write(buf)
cs(1)
def quick_start(self):
self.cs(0) self.cs(0)
self.spi.write(buf)
def quick_end(self):
self.cs(1) self.cs(1)