Smaller, faster writer.py. Requires fw V1.17 or later.

pull/8/head
Peter Hinch 2021-09-07 10:55:37 +01:00
rodzic 7010e931f1
commit 6ff7206e72
2 zmienionych plików z 32 dodań i 70 usunięć

Wyświetl plik

@ -60,8 +60,9 @@ Code has been tested on ESP32, Pi Pico and Pyboard. The API shuld be stable.
Code is new and issues are likely: please report any found. The project is Code is new and issues are likely: please report any found. The project is
under development so check for updates. under development so check for updates.
A recent firmware update [PR7682](https://github.com/micropython/micropython/pull/7682) Firmware V1.17 has provided a major boost to text rendering speed on color
has provided a major boost to text rendering speed on color displays. See display. V1.17 or later is now a requirement for color displays, although
there is a workround if it's impossible to upgrade. See
[section 1.8](./README.md#18-performance-and-hardware-notes) for details. [section 1.8](./README.md#18-performance-and-hardware-notes) for details.
# 0. Contents # 0. Contents
@ -127,6 +128,7 @@ has provided a major boost to text rendering speed on color displays. See
     23.3.1 [Class Curve](./README.md#2331-class-curve)      23.3.1 [Class Curve](./README.md#2331-class-curve)
     23.3.2 [Class PolarCurve](./README.md#2332-class-polarcurve)      23.3.2 [Class PolarCurve](./README.md#2332-class-polarcurve)
23.4 [Class TSequence](./README.md#234-class-tsequence) Plotting realtime, time sequential data. 23.4 [Class TSequence](./README.md#234-class-tsequence) Plotting realtime, time sequential data.
24. [Old firmware](./README.md#24-old-firmware) For users of color displays who can't run current firmware.
[Appendix 1 Application design](./README.md#appendix-1-application-design) Tab order, button layout, encoder interface, use of graphics primitives [Appendix 1 Application design](./README.md#appendix-1-application-design) Tab order, button layout, encoder interface, use of graphics primitives
# 1. Basic concepts # 1. Basic concepts
@ -414,21 +416,20 @@ RAM usage. A smaller display or a Pyboard D would offer more headroom.
#### A performance boost #### A performance boost
As of Aug 2021 a firmware update A firmware change in V1.17 has enabled the code size to be reduced. It has also
[PR7682](https://github.com/micropython/micropython/pull/7682) means that color accelerated text rendering on color displays. Use of color displays now
displays can benefit from a substantial performance boost in rendering text. To requires firmware V1.17 or later. Existing users should update the display
take advantage of this, firmware should be dated after 26 Aug 21. The display driver and GUI core files and should ensure that the new file
driver and GUI core files should be updated. Ensure that the new file `drivers/boolpalette.py` exists.
`drivers/boolpalette.py` exists on the target hardware.
###### [Contents](./README.md#0-contents) ###### [Contents](./README.md#0-contents)
## 1.9 Firmware and dependencies ## 1.9 Firmware and dependencies
Firmware should be V1.15 or later. For fast text rendering a daily build or Users of color displays should ensure that firmware is V1.17 or later. If this
a release build >= 1.17 should be used. The source tree includes all cannot be met, there is a [workround](./README.md#24-old-firmware). The source
dependencies. These are listed to enable users to check for newer versions or tree includes all dependencies. These are listed to enable users to check for
to read docs: newer versions or to read docs:
* [writer.py](https://github.com/peterhinch/micropython-font-to-py/blob/master/writer/writer.py) * [writer.py](https://github.com/peterhinch/micropython-font-to-py/blob/master/writer/writer.py)
Provides text rendering of Python font files. Provides text rendering of Python font files.
@ -2612,6 +2613,15 @@ class TSeq(Screen):
await asyncio.sleep_ms(400) await asyncio.sleep_ms(400)
t += 1 t += 1
``` ```
###### [Contents](./README.md#0-contents)
# 24. Old firmware
Current firmware is highly recommended. For users of color displays who cannot
run V1.17 or later it is possible to run under V1.15+. This involves copying
[this file](https://github.com/peterhinch/micropython-font-to-py/blob/master/writer/old_versions/writer_fw_compatible.py)
to `gui/core/writer.py`. This uses Python code to render text if the firmware
or driver are unable to support fast rendering.
###### [Contents](./README.md#0-contents) ###### [Contents](./README.md#0-contents)

Wyświetl plik

@ -1,6 +1,7 @@
# writer.py Implements the Writer class. # writer.py Implements the Writer class.
# Handles colour, word wrap and tab stops # Handles colour, word wrap and tab stops
# V0.5.0 Sep 2021 Color now requires firmware >= 1.17.
# V0.4.3 Aug 2021 Support for fast blit to color displays (PR7682). # V0.4.3 Aug 2021 Support for fast blit to color displays (PR7682).
# V0.4.0 Jan 2021 Improved handling of word wrap and line clip. Upside-down # V0.4.0 Jan 2021 Improved handling of word wrap and line clip. Upside-down
# rendering no longer supported: delegate to device driver. # rendering no longer supported: delegate to device driver.
@ -24,27 +25,9 @@ from uctypes import bytearray_at, addressof
from sys import implementation from sys import implementation
import os import os
__version__ = (0, 4, 3) __version__ = (0, 5, 0)
def buildcheck(device): fast_mode = True # Does nothing. Kept to avoid breaking code.
if not hasattr(device, 'palette'):
return False
i0, i1, _ = implementation[1]
if i0 > 1 or i1 > 16:
return True
# After release of V1.17 require that build. Until then check for date.
# TODO simplify this once V1.17 is released.
try:
datestring = os.uname()[3]
date = datestring.split(' on')[1]
date = date.lstrip()[:10]
idate = tuple([int(x) for x in date.split('-')])
return idate >= (2021, 8, 25)
except AttributeError:
return False
fast_mode = False # False for mono displays although actually these render fast
class DisplayState(): class DisplayState():
def __init__(self): def __init__(self):
@ -202,7 +185,7 @@ class Writer():
break break
if mc + 1 == wd: if mc + 1 == wd:
break # All done: no trailing space break # All done: no trailing space
print('Truelen', char, wd, mc + 1) # TEST # print('Truelen', char, wd, mc + 1) # TEST
return mc + 1 return mc + 1
def _get_char(self, char, recurse): def _get_char(self, char, recurse):
@ -272,19 +255,20 @@ class CWriter(Writer):
def __init__(self, device, font, fgcolor=None, bgcolor=None, verbose=True): def __init__(self, device, font, fgcolor=None, bgcolor=None, verbose=True):
if not hasattr(device, 'palette'):
raise OSError('Incompatible device driver.')
if implementation[1] < (1, 17, 0):
raise OSError('Firmware must be >= 1.17.')
super().__init__(device, font, verbose) super().__init__(device, font, verbose)
global fast_mode
fast_mode = buildcheck(device)
if bgcolor is not None: # Assume monochrome. if bgcolor is not None: # Assume monochrome.
self.bgcolor = bgcolor self.bgcolor = bgcolor
if fgcolor is not None: if fgcolor is not None:
self.fgcolor = fgcolor self.fgcolor = fgcolor
self.def_bgcolor = self.bgcolor self.def_bgcolor = self.bgcolor
self.def_fgcolor = self.fgcolor self.def_fgcolor = self.fgcolor
self._printchar = self._pchfast if fast_mode else self._pchslow
verbose and print('Render {} using fast mode'.format('is' if fast_mode else 'not'))
def _pchfast(self, char, invert=False, recurse=False): def _printchar(self, char, invert=False, recurse=False):
s = self._getstate() s = self._getstate()
self._get_char(char, recurse) self._get_char(char, recurse)
if self.glyph is None: if self.glyph is None:
@ -294,42 +278,10 @@ class CWriter(Writer):
palette = self.device.palette palette = self.device.palette
palette.bg(self.fgcolor if invert else self.bgcolor) palette.bg(self.fgcolor if invert else self.bgcolor)
palette.fg(self.bgcolor if invert else self.fgcolor) palette.fg(self.bgcolor if invert else self.fgcolor)
self.device.blit(fbc, s.text_col, s.text_row, -1, palette) self.device.blit(fbc, s.text_col, s.text_row, -1, palette)
s.text_col += self.char_width s.text_col += self.char_width
self.cpos += 1 self.cpos += 1
def _pchslow(self, char, invert=False, recurse=False):
s = self._getstate()
self._get_char(char, recurse)
if self.glyph is None:
return # All done
char_height = self.char_height
char_width = self.char_width
clip_width = self.clip_width
div, mod = divmod(char_width, 8)
gbytes = div + 1 if mod else div # No. of bytes per row of glyph
device = self.device
fgcolor = self.bgcolor if invert else self.fgcolor
bgcolor = self.fgcolor if invert else self.bgcolor
drow = s.text_row # Destination row
wcol = s.text_col # Destination column of character start
for srow in range(char_height): # Source row
for scol in range(clip_width): # Source column
# Destination column: add writer column
dcol = wcol + scol
gbyte, gbit = divmod(scol, 8)
if gbit == 0: # Next glyph byte
data = self.glyph[srow * gbytes + gbyte]
pixel = fgcolor if data & (1 << (7 - gbit)) else bgcolor
device.pixel(dcol, drow, pixel)
drow += 1
if drow >= self.screenheight or drow < 0:
break
s.text_col += char_width
self.cpos += 1
def setcolor(self, fgcolor=None, bgcolor=None): def setcolor(self, fgcolor=None, bgcolor=None):
if fgcolor is None and bgcolor is None: if fgcolor is None and bgcolor is None:
self.fgcolor = self.def_fgcolor self.fgcolor = self.def_fgcolor