Skip to content

Commit

Permalink
Replace use of array in working buffers.
Browse files Browse the repository at this point in the history
This now just uses plain bytearrays throughout, which can be allocated
extremely efficiently and without the penalty of memory copies.
  • Loading branch information
corranwebster committed Nov 1, 2024
1 parent c2a3118 commit 9b17aa2
Show file tree
Hide file tree
Showing 16 changed files with 49 additions and 45 deletions.
2 changes: 1 addition & 1 deletion ci/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def test():
os.environ["MICROPYPATH"] = "src:" + os.environ.get(
"MICROPYPATH", ":examples:.frozen:~/.micropython/lib:/usr/lib/micropython"
)
for path in sorted(test_dir.glob("*.py")):
for path in sorted(test_dir.glob("test_*.py")):
print(path.name, "... ", end="", flush=True)
result = run_test(path)
if result:
Expand Down
6 changes: 3 additions & 3 deletions examples/hello_world.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

"""Example showing basic display of text."""

from array import array


from tempe.surface import Surface
from tempe.text import Text
Expand All @@ -14,8 +14,8 @@
from tempe.fonts import roboto16bold


# a buffer one quarter the size of the screen
working_buffer = array("H", bytearray(2 * 320 * 61))
# a buffer one half the size of the screen
working_buffer = bytearray(2 * 320 * 121)

surface = Surface()

Expand Down
6 changes: 3 additions & 3 deletions examples/line_plot_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

"""Example showing how to create a line plot from Tempe Shapes."""

from array import array

import gc

from tempe import colors
Expand All @@ -17,7 +17,7 @@
surface = Surface()

# a buffer one half the size of the screen
working_buffer = array("H", range(320 * 121))
working_buffer = bytearray(2 * 320 * 121)


# fill the background with off-white pixels
Expand Down Expand Up @@ -162,7 +162,7 @@ async def init_display():

display = PimoroniDisplay(size = (240, 320))
display.backlight_pin(1)
await display.init(270)
await display.init()
return display


Expand Down
8 changes: 4 additions & 4 deletions examples/lines_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"""Example showing support for thick lines."""

import asyncio
from array import array

import framebuf
import random
import math
Expand All @@ -24,8 +24,8 @@

surface = Surface()

# a buffer one quarter the size of the screen
working_buffer = array("H", bytearray(2 * 320 * 61))
# a buffer one half the size of the screen
working_buffer = bytearray(2 * 320 * 121)

# fill the background with white pixels
background = Rectangles([(0, 0, 320, 240)], [0xFFFF])
Expand Down Expand Up @@ -93,7 +93,7 @@ async def init_display():

display = PimoroniDisplay(size = (240, 320))
display.backlight_pin(1)
await display.init(270)
await display.init()
return display


Expand Down
8 changes: 4 additions & 4 deletions examples/polar_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"""Example showing support for polar geometries."""

import asyncio
from array import array

import framebuf
import random
import math
Expand All @@ -29,8 +29,8 @@

surface = Surface()

# a buffer one quarter the size of the screen
working_buffer = array("H", bytearray(2 * 320 * 61))
# a buffer one half the size of the screen
working_buffer = bytearray(2 * 320 * 121)

# fill the background with white pixels
background = Rectangles([(0, 0, 320, 240)], [0xFFFF])
Expand Down Expand Up @@ -219,7 +219,7 @@ async def init_display():

display = PimoroniDisplay(size = (240, 320))
display.backlight_pin(1)
await display.init(270)
await display.init()
return display


Expand Down
8 changes: 4 additions & 4 deletions examples/polar_plot_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

"""Example showing how to build a polar plot from Tempe Shapes."""

from array import array

import gc
from math import sqrt, log

Expand All @@ -19,8 +19,8 @@

surface = Surface()

# a buffer one third the size of the screen
working_buffer = array("H", range(320 * 81))
# a buffer one half the size of the screen
working_buffer = bytearray(2 * 320 * 121)


# fill the background with off-black pixels
Expand Down Expand Up @@ -203,7 +203,7 @@ async def init_display():

display = PimoroniDisplay(size = (240, 320))
display.backlight_pin(1)
await display.init(270)
await display.init()
return display


Expand Down
6 changes: 3 additions & 3 deletions examples/scatter_plot_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

"""Example showing how to create a scatter plot from Tempe Shapes."""

from array import array

import gc
from math import sqrt, log

Expand All @@ -20,7 +20,7 @@
surface = Surface()

# a buffer one half the size of the screen
working_buffer = array("H", bytearray(2 * 320 * 121))
working_buffer = bytearray(2 * 320 * 121)


# fill the background with off-white pixels
Expand Down Expand Up @@ -370,7 +370,7 @@ async def init_display():

display = PimoroniDisplay(size = (240, 320))
display.backlight_pin(1)
await display.init(270)
await display.init()
return display


Expand Down
8 changes: 4 additions & 4 deletions examples/shapes_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"""Example showing core Tempe Shapes."""

import asyncio
from array import array

import framebuf
import random
import math
Expand Down Expand Up @@ -36,8 +36,8 @@

surface = Surface()

# a buffer one quarter the size of the screen
working_buffer = array("H", bytearray(2 * 320 * 61))
# a buffer one half the size of the screen
working_buffer = bytearray(2 * 320 * 121)

# fill the background with white pixels
background = Rectangles([(0, 0, 320, 240)], [0xFFFF])
Expand Down Expand Up @@ -328,7 +328,7 @@ async def init_display():

display = PimoroniDisplay(size = (240, 320))
display.backlight_pin(1)
await display.init(270)
await display.init()
return display


Expand Down
4 changes: 2 additions & 2 deletions examples/temperature_screen.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
Note: this is currently not working as it uses earlier version of code.
"""

from array import array

import asyncio
import gc
from machine import SPI, Pin, ADC, RTC
Expand Down Expand Up @@ -35,7 +35,7 @@
h = 240

gc.collect()
DRAWING_BUFFER = array("H", bytearray(2 * w * 31))
DRAWING_BUFFER = bytearray(2 * w * 31)


async def init_display():
Expand Down
4 changes: 2 additions & 2 deletions examples/update_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"""Example showing asyncio updating of a surface."""

import asyncio
from array import array

from machine import ADC, RTC

from tempe import colors
Expand All @@ -14,7 +14,7 @@


# a buffer one half the size of the screen
WORKING_BUFFER = array('H', range(240*161))
WORKING_BUFFER = bytearray(2*240*161)



Expand Down
11 changes: 6 additions & 5 deletions src/tempe/display.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,30 @@ def blit(self, buffer, x, y, w, h):
class FileDisplay(Display):
"""Display that renders raw RGB565 data to a file."""

def __init__(self, name, size=(320, 240)):
def __init__(self, name, size=(320, 240), pixel_size=2):
self.name = name
self.size = size
self.pixel_size = pixel_size
self._io = None

def clear(self):
self._io.seek(0)
row = b"\x00\x00" * (self.size[0])
row = b"\x00" * (self.pixel_size * self.size[0])
for i in range(self.size[1]):
self._io.write(row)

def blit(self, buffer, x, y, w, h):
cols, rows = self.size
print(x, w, cols, y, h, rows)
if x + w > cols or y + h > rows:
raise ValueError("Buffer too large")
if self._io is None:
raise RuntimeError("File is not open")

# write out a row at a time
ps = self.pixel_size
for i in range(h):
self._io.seek(2 * (cols * (y + i) + x))
self._io.write(memoryview(buffer)[w * i : w * (i + 1)])
self._io.seek(ps * (cols * (y + i) + x))
self._io.write(memoryview(buffer)[ps * w * i : ps * w * (i + 1)])

def __enter__(self):
if self._io is None:
Expand Down
2 changes: 1 addition & 1 deletion src/tempe/font.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

"""Font ABCs and support for bitmapped fonts."""

from array import array

import framebuf


Expand Down
8 changes: 5 additions & 3 deletions src/tempe/raster.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@
class Raster:
"""A rectangular buffer that can be drawn on by a surface."""

def __init__(self, buf, x, y, w, h, stride=None, offset=0):
def __init__(self, buf, x, y, w, h, stride=None, offset=0, format=framebuf.RGB565):
stride = stride if stride is not None else w
self.buf = buf
self.x = x
self.y = y
self.w = w
self.h = h
self.pixel_size = 2
self.offset = offset
self.stride = stride
self.format = format
self.fbuf = framebuf.FrameBuffer(
memoryview(buf)[offset:], w, h, framebuf.RGB565, stride
memoryview(buf)[self.pixel_size * offset:], w, h, self.format, stride
)

@classmethod
Expand All @@ -34,4 +36,4 @@ def clip(self, x, y, w, h):
if w1 <= 0 or h1 <= 0:
return None
offset = self.offset + self.stride * (y1 - self.y) + (x1 - self.x)
return Raster(self.buf, x1, y1, w1, h1, self.stride, offset)
return Raster(self.buf, x1, y1, w1, h1, self.stride, offset, self.format)
4 changes: 3 additions & 1 deletion src/tempe/surface.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ def __init__(self):
self.layers = {layer: [] for layer in LAYERS}
self._damage = []
self.refresh_needed = asyncio.Event()
self.format = framebuf.RGB565
self.pixel_size = 2

def draw(self, raster):
"""Draw into a raster."""
Expand All @@ -41,7 +43,7 @@ def refresh(self, display, working_buffer):
for rect in self._damage:
x, y, w, h = rect
# handle buffer too small
buffer_rows = (len(working_buffer) // w) - 1
buffer_rows = (len(working_buffer) // (w * self.pixel_size) ) - 1
for start_row in range(0, h, buffer_rows):
raster_rows = min(buffer_rows, h - start_row)
raster = Raster(working_buffer, x, y + start_row, w, raster_rows)
Expand Down
6 changes: 3 additions & 3 deletions src/tempe_displays/st7789/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,15 +361,15 @@ def _blit565(self, buf, x, y, w, h, stride=None):
self.window(x, y, w, h)
if stride is None:
# fast path for contiguous memory
self.write_to_memory(buf[:w * h])
self.write_to_memory(buf[:2 * w * h])
else:
buf = memoryview(buf)
self.window(x, y, w, h)
self.write_to_memory(b"")
self.send_iterator(
1,
(
buf[offset : offset + w]
for offset in range(0, stride * h, stride)
buf[offset : offset + 2 * w]
for offset in range(0, 2 * stride * h, 2 * stride)
)
)
3 changes: 1 addition & 2 deletions tests/tempe/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@
#
# SPDX-License-Identifier: MIT

import array
import gc
import unittest

from tempe.display import FileDisplay

working_buffer = array.array("H", bytearray(320 * 61 * 2))
working_buffer = bytearray(320 * 61 * 2)


class TestExamples(unittest.TestCase):
Expand Down

0 comments on commit 9b17aa2

Please sign in to comment.