1
0
Fork 0

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).
pull/24/head
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):
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
# but it does mean no changes to the client
fn.__globals__['ptr8'] = ptr8
fn.__globals__['ptr16'] = ptr16
return fn

View File

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

View File

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