latest round of changes

This commit is contained in:
Michael Bishop 2023-09-01 01:03:00 -03:00
parent dc415872e6
commit e549bd915c
10 changed files with 183 additions and 16 deletions

View File

@ -6,7 +6,11 @@
#include "bindings/videocore/Sprite.h"
#include "shared-bindings/displayio/Bitmap.h"
#include "shared-module/displayio/Group.h"
#include "shared-bindings/displayio/Group.h"
#include "py/runtime.h"
#include "shared-bindings/displayio/TileGrid.h"
#include "shared-bindings/displayio/Palette.h"
#include "bindings/videocore/hvs.h"
#include "bindings/videocore/Hvs.h"
@ -17,7 +21,6 @@ volatile uint32_t* dlist_memory = (volatile uint32_t*)SCALER5_LIST_MEMORY;
volatile uint32_t* dlist_memory = (volatile uint32_t*)SCALER_LIST_MEMORY;
#endif
extern const mp_obj_type_t hvs_channel_type;
volatile struct hvs_channel *hvs_hw_channels = (volatile struct hvs_channel*)SCALER_DISPCTRL0;
uint32_t dlist_slot = 128; // start a bit in, to not trash the firmware list
@ -37,12 +40,21 @@ hvs_channel_t hvs_channels[3] = {
};
static mp_obj_t c_set_sprite_list(mp_obj_t self_in, mp_obj_t list) {
mp_obj_t *unique_palettes = mp_obj_new_set(0, NULL);
hvs_channel_t *self = MP_OBJ_TO_PTR(self_in);
mp_obj_t sprite_list = mp_arg_validate_type(list, &mp_type_list, MP_QSTR_sprites);
size_t len = 0;
mp_obj_t *items;
mp_obj_list_get(sprite_list, &len, &items);
// first loop, find unique palettes
for (uint32_t i=0; i<len; i++) {
mp_obj_t sprite = mp_arg_validate_type(items[i], &hvs_sprite_type, MP_QSTR_todo);
sprite_t *s = MP_OBJ_TO_PTR(sprite);
if (s->palette) mp_obj_set_store(unique_palettes, s->palette);
}
// TODO, copy each palette to the dlist memory and set sprite->palette_addr to the addr its copied to
uint32_t needed_slots = 1; // one more, to terminate the list
// second loop, regenerate any display lists and count the total size
for (uint32_t i=0; i<len; i++) {
mp_obj_t sprite = mp_arg_validate_type(items[i], &hvs_sprite_type, MP_QSTR_todo);
sprite_t *s = MP_OBJ_TO_PTR(sprite);
@ -54,10 +66,10 @@ static mp_obj_t c_set_sprite_list(mp_obj_t self_in, mp_obj_t list) {
mp_raise_ValueError(translate("too many sprites, unable to pageflip reliably"));
}
if ((dlist_slot + needed_slots) > 4096) {
// early loop)
dlist_slot = 128;
}
uint32_t starting_slot = dlist_slot;
// third loop, copy dlist fragments to hw
for (uint32_t i=0; i<len; i++) {
mp_obj_t sprite = mp_arg_validate_type(items[i], &hvs_sprite_type, MP_QSTR_todo);
sprite_t *s = MP_OBJ_TO_PTR(sprite);
@ -80,7 +92,71 @@ static mp_obj_t c_set_sprite_list(mp_obj_t self_in, mp_obj_t list) {
}
return mp_const_none;
}
static mp_obj_t c_hvs_show(mp_obj_t self_in, mp_obj_t root_group_in) {
mp_obj_list_t *sprites = mp_obj_new_list(0, NULL);
hvs_channel_t *self = MP_OBJ_TO_PTR(self_in);
displayio_group_t *root_group = mp_arg_validate_type(root_group_in, &displayio_group_type, MP_QSTR_bitmap);
printf("hvs channel: %ld\n", self->channel);
printf("root group x: %d y: %d\n", root_group->x, root_group->y);
printf("group scale (not implemented): %d\n", root_group->scale);
size_t len = 0;
mp_obj_t *items;
mp_obj_list_get(root_group->members, &len, &items);
printf("%d elements\n", len);
for (uint i=0; i<len; i++) {
printf("%d: %p\n", i, mp_obj_get_type(items[i]));
if (mp_obj_get_type(items[i]) == &displayio_tilegrid_type) {
displayio_tilegrid_t *tg = mp_arg_validate_type(items[i], &displayio_tilegrid_type, MP_QSTR_tilegrid);
displayio_bitmap_t *bitmap = mp_arg_validate_type(tg->bitmap, &displayio_bitmap_type, MP_QSTR_bitmap);
uint8_t *arr;
if (tg->inline_tiles) arr = (uint8_t*)&tg->tiles;
else arr = tg->tiles;
/*
printf("found tilegrid: %p\n", tg);
printf("x %d, y %d\n", tg->x, tg->y);
printf("w %d, h %d\n", tg->width_in_tiles, tg->height_in_tiles);
printf("w %d, h %d\n", tg->pixel_width, tg->pixel_height);
printf("w %d, h %d\n", tg->tile_width, tg->tile_height);
printf("shader type: %p\n", mp_obj_get_type(tg->pixel_shader));
*/
enum hvs_pixel_format format = HVS_PIXEL_FORMAT_RGB332;
int order = HVS_PIXEL_ORDER_ABGR;
if (mp_obj_get_type(tg->pixel_shader) == &displayio_palette_type) {
puts("tg uses a palette");
format = HVS_PIXEL_FORMAT_PALETTE;
}
for (uint row=0; row < tg->height_in_tiles; row++) {
for (uint col=0; col < tg->width_in_tiles; col++) {
uint tile_offset = col + (row * tg->width_in_tiles);
sprite_t *sprite = mp_obj_malloc(sprite_t, &hvs_sprite_type);
sprite->bitmap = bitmap;
if (format == HVS_PIXEL_FORMAT_PALETTE) sprite->palette = tg->pixel_shader;
else sprite->palette = NULL;
sprite->x = root_group->x + tg->x + (col * tg->tile_width);
sprite->y = root_group->y + tg->y + (row * tg->tile_height);
uint tile = arr[tile_offset];
sprite->x_offset = (tile % tg->bitmap_width_in_tiles) * tg->tile_width;
sprite->y_offset = (tile / tg->bitmap_width_in_tiles) * tg->tile_height;
sprite->width = tg->tile_width;
sprite->height = tg->tile_height;
sprite->dirty = true;
sprite->color_order = order;
sprite->pixel_format = format;
mp_obj_list_append(sprites, sprite);
}
}
} else {
puts("unexpected item in group");
}
}
c_set_sprite_list(self_in, sprites);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(fun_set_sprite_list, c_set_sprite_list);
MP_DEFINE_CONST_FUN_OBJ_2(fun_hvs_show, c_hvs_show);
#define simpleprop(name) \
static MP_DEFINE_CONST_FUN_OBJ_1(fun_get_##name, c_getter_##name); \
@ -104,15 +180,32 @@ static mp_obj_t c_getter_enabled(mp_obj_t self_in) {
return mp_obj_new_bool(ctrl & SCALER_DISPCTRLX_ENABLE);
}
static mp_obj_t c_getter_frame(mp_obj_t self_in) {
hvs_channel_t *self = MP_OBJ_TO_PTR(self_in);
uint32_t stat = hvs_hw_channels[self->channel].dispstat;
return MP_OBJ_NEW_SMALL_INT((stat >> 12) & 0x3f);
}
static mp_obj_t c_getter_scanline(mp_obj_t self_in) {
hvs_channel_t *self = MP_OBJ_TO_PTR(self_in);
uint32_t stat = hvs_hw_channels[self->channel].dispstat;
return MP_OBJ_NEW_SMALL_INT(stat & 0xfff);
}
simpleprop(width);
simpleprop(height);
simpleprop(enabled);
simpleprop(frame);
simpleprop(scanline);
static const mp_rom_map_elem_t hvs_channel_locals_dict_table[] = {
prop_entry(width),
prop_entry(height),
prop_entry(enabled),
prop_entry(frame),
prop_entry(scanline),
{ MP_ROM_QSTR(MP_QSTR_set_sprite_list), MP_ROM_PTR(&fun_set_sprite_list) },
{ MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&fun_hvs_show) },
};
static MP_DEFINE_CONST_DICT(hvs_channel_locals_dict, hvs_channel_locals_dict_table);

View File

@ -6,3 +6,4 @@ typedef struct {
} hvs_channel_t;
extern hvs_channel_t hvs_channels[3];
extern const mp_obj_type_t hvs_channel_type;

View File

@ -31,27 +31,58 @@ enum hvs_pixel_format bitmap_to_hvs(const displayio_bitmap_t *bitmap) {
#error not implemented yet
#else
void hvs_regen_noscale_noviewport(sprite_t *s) {
printf("xoffset: %ld yoffset: %ld\n", s->x_offset, s->y_offset);
uint32_t *d = s->dlist;
uint32_t phys_addr = (uint32_t)s->bitmap->data; // assumes identity map, should be physical addr
int bytes_per_pixel = s->bitmap->bits_per_value / 8;
uint stride = s->bitmap->stride * 4;
phys_addr += bytes_per_pixel * s->x_offset;
phys_addr += stride * s->y_offset;
uint size = 7;
if (s->pixel_format == HVS_PIXEL_FORMAT_PALETTE) size = 8;
// CTL0
d[0] = CONTROL_VALID
| CONTROL_PIXEL_ORDER(s->color_order)
| CONTROL_UNITY
| CONTROL_FORMAT(s->pixel_format)
| CONTROL_WORDS(7);
| CONTROL_WORDS(size);
// POS0
d[1] = POS0_X(s->x) | POS0_Y(s->y) | POS0_ALPHA(0xff);
// POS2, input size
d[2] = POS2_H(s->bitmap->height) | POS2_W(s->bitmap->width) | (s->alpha_mode << 30);
d[2] = POS2_H(s->height) | POS2_W(s->width) | (s->alpha_mode << 30);
// POS3, context
d[3] = 0xDEADBEEF;
// PTR0
d[4] = ((uint32_t)s->bitmap->data) // assumes identity map, should be physical addr
d[4] = phys_addr
| 0xc0000000; // and tell HVS to do uncached reads
// context 0
d[5] = 0xDEADBEEF;
// pitch 0
d[6] = s->bitmap->stride * 4;
d[6] = stride;
if (s->pixel_format == HVS_PIXEL_FORMAT_PALETTE) {
// https://github.com/librerpi/rpi-open-firmware/blob/93dc394d33f54a59a25a087213f46a20f5aad327/docs/hvs.txt#L107-L112
uint bitsize;
switch (s->bitmap->bits_per_value) {
case 1:
bitsize = 0;
break;
case 2:
bitsize = 1;
break;
case 4:
bitsize = 2;
break;
case 8:
bitsize = 3;
break;
default:
d[0] = 0;
return;
}
uint initial_pixel_offset = 0;
uint order = 0;
d[7] = (bitsize << 30) | (initial_pixel_offset << 27) | (order << 26) | (s->palette_addr << 2);
}
//printf("w: %d, h: %d, stride: %d, bits per value: %d\n", s->bitmap->width, s->bitmap->height, s->bitmap->stride, s->bitmap->bits_per_value);
}
#endif

View File

@ -11,10 +11,14 @@ typedef struct {
uint32_t height;
uint32_t x;
uint32_t y;
uint32_t x_offset;
uint32_t y_offset;
uint32_t dlist[32];
enum alpha_mode alpha_mode;
uint32_t color_order;
uint32_t palette_addr;
enum hvs_pixel_format pixel_format;
mp_obj_t palette;
} sprite_t;
extern const mp_obj_type_t hvs_sprite_type;

View File

@ -23,9 +23,19 @@ def gif_animate():
x = 5
y = 5
lastframe = videocore.HvsChannel1.frame
start = time.monotonic()
while True:
framedelta = videocore.HvsChannel1.frame - lastframe
lastframe = videocore.HvsChannel1.frame
#print(f"delta: {framedelta} scanline: {videocore.HvsChannel1.scanline}/{videocore.HvsChannel1.height} overhead: {overhead} next: {next_delay}")
end = time.monotonic()
overhead = end - start
time.sleep(max(0, next_delay - overhead))
start = time.monotonic()
next_delay = gif.next_frame()
if (x > 0) and (x < xmax):
x += xinc
@ -45,10 +55,7 @@ def gif_animate():
y = 0
sprite.x = x
sprite.y = y
start = time.monotonic()
videocore.HvsChannel1.set_sprite_list([sprite])
end = time.monotonic()
refresh = end-start
#print("refresh time:")
#print(refresh)
@ -80,7 +87,29 @@ def many_formats():
format4 = make_color_sweep(4, dist * 3, color_order=3, red_start=0, red_max=31, green_start=5, green_max=63, blue_start = 11, blue_max=31)
videocore.HvsChannel1.set_sprite_list([format1, format2, format3, format4])
#many_formats()
gif_animate()
def tilegrid():
import adafruit_imageload
import displayio
import board
# https://learn.adafruit.com/circuitpython-display-support-using-displayio/sprite-sheet
sprite_sheet, palette = adafruit_imageload.load("/cp_sprite_sheet.bmp", bitmap=displayio.Bitmap, palette=displayio.Palette)
sprite = displayio.TileGrid(sprite_sheet, pixel_shader=palette, width=2, height=2, tile_width=16, tile_height=16)
group = displayio.Group(scale=8)
group.append(sprite)
display = board.DISPLAY
group.x = 30
group.y = 30
for i in range(30):
sprite[0] = i % 6
sprite[1] = (i+1) % 6
sprite[2] = (i+2) % 6
sprite[3] = (i+3) % 6
for j in range(100):
group.x = j
display.show(group)
return
time.sleep(0.01)
print("Hello World!")
#many_formats()
#gif_animate()
tilegrid()

View File

@ -30,8 +30,14 @@
#include "bindings/videocore/Framebuffer.h"
#include "shared-module/displayio/__init__.h"
#include "shared-bindings/framebufferio/FramebufferDisplay.h"
#include "bindings/videocore/Hvs.h"
void board_init(void) {
hvs_channel_t *display = &allocate_display()->hvs_display;
display->channel = 1;
display->base.type = &hvs_channel_type;
return;
/*
videocore_framebuffer_obj_t *fb = &allocate_display_bus()->videocore;
fb->base.type = &videocore_framebuffer_type;
common_hal_videocore_framebuffer_construct(fb, 640, 480);
@ -43,6 +49,7 @@ void board_init(void) {
MP_OBJ_FROM_PTR(fb),
0,
true);
*/
}
// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here.

View File

@ -60,7 +60,7 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) {
// there is room for a 6bit int to be smuggled across reset, look into using that
}
// https://learn.adafruit.com/circuitpython-essentials/circuitpython-resetting
void common_hal_mcu_reset(void) {
common_hal_mcu_disable_interrupts();
*REG32(PM_WDOG) = PM_PASSWORD | (1 & PM_WDOG_MASK);

View File

@ -38,7 +38,7 @@ void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_
mp_obj_t pixel_shader, uint16_t width, uint16_t height,
uint16_t tile_width, uint16_t tile_height, uint16_t x, uint16_t y, uint8_t default_tile) {
uint32_t total_tiles = width * height;
// Sprites will only have one tile so save a little memory by inlining values in the pointer.
// Sprites with only have one tile so save a little memory by inlining values in the pointer.
uint8_t inline_tiles = sizeof(uint8_t *);
if (total_tiles <= inline_tiles) {
self->tiles = 0;

View File

@ -40,7 +40,7 @@ typedef struct {
mp_obj_t pixel_shader;
int16_t x;
int16_t y;
uint16_t pixel_width;
uint16_t pixel_width; // of the entire grid, covering width_in_tiles tiles
uint16_t pixel_height;
uint16_t bitmap_width_in_tiles;
;

View File

@ -50,6 +50,7 @@
// Port unique frame buffers.
#if CIRCUITPY_VIDEOCORE
#include "bindings/videocore/Framebuffer.h"
#include "bindings/videocore/Hvs.h"
#endif
#if CIRCUITPY_PICODVI
#include "bindings/picodvi/Framebuffer.h"
@ -88,6 +89,7 @@ typedef struct {
displayio_epaperdisplay_obj_t epaper_display;
#if CIRCUITPY_FRAMEBUFFERIO
framebufferio_framebufferdisplay_obj_t framebuffer_display;
hvs_channel_t hvs_display;
#endif
};
} primary_display_t;