Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tile palette mapper module and class #10113

Open
wants to merge 15 commits into
base: main
Choose a base branch
from

Conversation

FoamyGuy
Copy link
Collaborator

@FoamyGuy FoamyGuy commented Mar 5, 2025

All testing was performed on a pyportal titano with this script:

import time

from displayio import Palette
from tilepalettemapper import TilePaletteMapper
import board
import terminalio
import displayio

time.sleep(1)
p = Palette(2)
p[0] = 0x000000
p[1] = 0xffffff

bbox = terminalio.FONT.get_bounding_box()
main_group = displayio.Group()
board.DISPLAY.root_group = main_group

tpm = TilePaletteMapper(p, 10,4)

tg = displayio.TileGrid(terminalio.FONT.bitmap, pixel_shader=tpm,
                        tile_width=bbox[0], tile_height=bbox[1],
                        width=10, height=4, default_tile=0)
#tg.pixel_shader = tpm
main_group.append(tg)

for i in range(40):
    tg[i] = i

# print(tpm.width)
# print(tpm.palette[1])
tpm[1,0] = [1,0]
# print(tpm[1,0])

while True:
    for y in range(tg.height):
        for x in range(tg.width):
            cur = (x, y)
            tpm[cur] = [1,0] if tpm[cur] == [0,1] else [0,1]
            time.sleep(0.025)

@FoamyGuy
Copy link
Collaborator Author

FoamyGuy commented Mar 5, 2025

a handful of atmel boards overflowed and I disabled the new module in them. I am not sure how to fix the zephyr builds that failed.

Copy link

@RetiredWizard RetiredWizard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The palette and the ansi code is pushing the same boards so it probably makes sense to link the parameter flags

@@ -555,6 +555,9 @@ CFLAGS += -DCIRCUITPY_TERMINALIO=$(CIRCUITPY_TERMINALIO)
CIRCUITPY_FONTIO ?= $(call enable-if-all,$(CIRCUITPY_DISPLAYIO) $(CIRCUITPY_TERMINALIO))
CFLAGS += -DCIRCUITPY_FONTIO=$(CIRCUITPY_FONTIO)

CIRCUITPY_TILEPALETTEMAPPER ?= $(CIRCUITPY_DISPLAYIO)
CFLAGS += -DCIRCUITPY_TILEPALETTEMAPPER=$(CIRCUITPY_TILEPALETTEMAPPER)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than setting two parameters in the atmel-samd/boards mpconfigboard.mk files, I think the CIRCUITPY_TERMINALIO_VT100 I recently created should default to your new parameter. (After #10108 was merged, it's being set immediately following CIRCUITPY_TERMINALIO, but doesn't show up here?). I'm also setting the VT100 parameter to 0 for all samd21 boards in the atmel-samd mpconfigport.mk which could be removed if you make this change and decide to disable the new palette for all samd21 boards 😁

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I think about it, the two features aren't technically, necessarily linked so perhaps two parameters is appropriate. Trade-offs... 🤷

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think keeping them separate makes sense, but I also don't have a strong preference one way or the other. If it's possible to set it in one spot as disabled for all SAMD21 boards that sounds more convenient than adding to each of board individually though.

Copy link

@RetiredWizard RetiredWizard Mar 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Putting your assignment here will turn it off for all samd21 boards by default. The board files can still turn it back on if needed.

# Turn off a few more things that don't fit in 192kB
CIRCUITPY_TERMINALIO_VT100 = 0

Edit: There were a couple of SAMD51 boards you overflowed as well though 😁 If you want to turn it off for all samd21 & samd51 boards you can use the same file and just move it outside the if block.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! I do want to keep it on for any samd51s that have room. The pyportal titano for instance is what all my testing was on and it seems fine on that device.

Copy link
Member

@tannewt tannewt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking this on!

I'm thinking over how to organize the memory internally. The array of uint16_t for every tile is nice because it has a bunch of small allocations instead of one large one. It does cost the array of pointers though. This could be optimized to allocate the tile mapping only when changed. If the pointer is null then it'd just map 1:1 (or have a default mapping).

Definitely try with a palette larger than the input bitmap has. We'll want that for coloring text in addition to just inverting the colors.

To fix Zephyr you'll need to add tilepalettemapper = false to all of the autogen_board_info.tomls. Adding a python script may actually be quickest. https://github.com/adafruit/circuitpython/blob/main/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml#L92

self->needs_refresh = false;
int mappings_len = width * height;
self->tile_mappings = (uint16_t **)m_malloc(mappings_len * sizeof(uint16_t *));
uint32_t palette_len = common_hal_displayio_palette_get_len(self->palette);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! Let's take in the number of input indices and then adjust the value length based on the number of colors in the palette.

FoamyGuy added 3 commits March 6, 2025 08:30
# Conflicts:
#	ports/atmel-samd/boards/openbook_m4/mpconfigboard.mk
#	ports/atmel-samd/boards/uartlogger2/mpconfigboard.mk
…t_color to work with more than 2 colors, disable for samd21 instead of individaul boards, input_color_count arg.
@FoamyGuy
Copy link
Collaborator Author

FoamyGuy commented Mar 6, 2025

The latest commit contains a bunch of the requested changes, as well as fixing the functionality for more colors, it turned out that was not behaving correctly before.

This is the updated test script i've been using the test the color functionality:

import time
from displayio import Palette
from tilepalettemapper import TilePaletteMapper
import board
import terminalio
import displayio
import rainbowio


time.sleep(1)
p = Palette(258)
p[0] = 0x000000
p[1] = 0xffffff
for i in range(256):
    p[i+2] = rainbowio.colorwheel(i)

# for i in range(258):
#     print(f"color {i}: {p[i]:06x}")
bbox = terminalio.FONT.get_bounding_box()
main_group = displayio.Group(scale=4)
board.DISPLAY.root_group = main_group

#tpm = TilePaletteMapper(p, 2, 20,3)
#tpm = TilePaletteMapper(p, 2, 9,3)
tpm = TilePaletteMapper(p, 2,10,4)

FONT_BMP = terminalio.FONT.bitmap

tg = displayio.TileGrid(FONT_BMP, pixel_shader=tpm,
                        tile_width=bbox[0], tile_height=bbox[1],
                        width=10, height=4, default_tile=0)
#tg.pixel_shader = tpm
main_group.append(tg)

for i in range(40):
    tg[i] = i

# print(tpm.width)
# print(tpm.palette[1])
print(tpm[1,0])
tpm[1,0] = [1,0]
print(tpm[1,0])


cur_offset = 2
while True:

    for y in range(tg.height):
        for x in range(tg.width):
            cur = (x, y)
            try:
                tpm[cur] = [0, cur_offset]
            except IndexError:
                pass
            cur_offset = max(2, (cur_offset + 2) % 258)
            time.sleep(0.005)
    for y in range(tg.height-1, -1, -1):
        for x in range(tg.width-1, -1, -1):
            cur = (x, y)
            try:
                tpm[cur] = [0, cur_offset]
            except IndexError:
                pass
            cur_offset = max(2, (cur_offset + 2) % 258)
            time.sleep(0.005)

There are also commented out lines that I've used to test the functionality when the TPM size does not match the TileGrid size.

@tannewt I think the two remaining things that you mentioned that haven't been implemented yet are ColorConverter support, and optimizing by using null to mean "no mapping" for a tile. I'm wondering if it's okay to work on those as a followup to this? I'd love to get the palette support solidified and exercised more with user code before venturing into ColorConverter if possible.

The null for no mapping efficiency improvement I'd like to attempt as well, but I don't have high confidence that I'll do it successfully without wrecking the functionality a bit first. I'll probably start that on a new branch anyhow. In addition to keeping this one functional it would also let me reset my local repo state which seems to have gotten some unrelated changes intermixed in that I'm having to uncheck boxes for every time I commit.

@tannewt
Copy link
Member

tannewt commented Mar 6, 2025

I'm wondering if it's okay to work on those as a followup to this?

Yup, totally!

Copy link
Member

@tannewt tannewt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few more small things. Thanks for the iteration! It's getting close.

FoamyGuy and others added 3 commits March 6, 2025 14:05
Co-authored-by: Scott Shawcroft <[email protected]>
Co-authored-by: Scott Shawcroft <[email protected]>
@FoamyGuy
Copy link
Collaborator Author

FoamyGuy commented Mar 6, 2025

Thank you, updated all of those in the latest commits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants