Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion ports/atmel-samd/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ endif

#Debugging/Optimization
ifeq ($(DEBUG), 1)
# Turn on Python modules useful for debugging (e.g. uheap, ustack).
CFLAGS += -ggdb
# You may want to disable -flto if it interferes with debugging.
CFLAGS += -flto
Expand Down
1 change: 1 addition & 0 deletions shared-bindings/displayio/Display.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ void common_hal_displayio_display_refresh_soon(displayio_display_obj_t* self);
bool displayio_display_begin_transaction(displayio_display_obj_t* self);
void displayio_display_end_transaction(displayio_display_obj_t* self);

// The second point of the region is exclusive.
void displayio_display_set_region_to_update(displayio_display_obj_t* self, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
bool displayio_display_frame_queued(displayio_display_obj_t* self);

Expand Down
34 changes: 16 additions & 18 deletions shared-module/displayio/Group.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,32 +134,30 @@ void displayio_group_construct(displayio_group_t* self, displayio_group_child_t*
self->scale = scale;
}

bool displayio_group_get_pixel(displayio_group_t *self, int16_t x, int16_t y, uint16_t* pixel) {
x -= self->x;
y -= self->y;
// When we are scaled we need to substract all but one to ensure -scale to 0 divide down to -1.
// Normally -scale to scale both divide down to 0 because 0 is unsigned.
if (x < 0) {
x -= self->scale - 1;
}
if (y < 0) {
y -= self->scale - 1;
}
x /= self->scale;
y /= self->scale;
bool displayio_group_get_area(displayio_group_t *self, displayio_buffer_transform_t* transform, displayio_area_t* area, uint32_t* mask, uint32_t* buffer) {
displayio_area_shift(area, -self->x * transform->scale, -self->y * transform->scale);
transform->scale *= self->scale;

// Track if any of the layers finishes filling in the given area. We can ignore any remaining
// layers at that point.
bool full_coverage = false;
for (int32_t i = self->size - 1; i >= 0 ; i--) {
mp_obj_t layer = self->children[i].native;
if (MP_OBJ_IS_TYPE(layer, &displayio_tilegrid_type)) {
if (displayio_tilegrid_get_pixel(layer, x, y, pixel)) {
return true;
if (displayio_tilegrid_get_area(layer, transform, area, mask, buffer)) {
full_coverage = true;
break;
}
} else if (MP_OBJ_IS_TYPE(layer, &displayio_group_type)) {
if (displayio_group_get_pixel(layer, x, y, pixel)) {
return true;
if (displayio_group_get_area(layer, transform, area, mask, buffer)) {
full_coverage = true;
break;
}
}
}
return false;
transform->scale /= self->scale;
displayio_area_shift(area, self->x * transform->scale, self->y * transform->scale);
return full_coverage;
}

bool displayio_group_needs_refresh(displayio_group_t *self) {
Expand Down
3 changes: 2 additions & 1 deletion shared-module/displayio/Group.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <stdint.h>

#include "py/obj.h"
#include "shared-module/displayio/area.h"

typedef struct {
mp_obj_t native;
Expand All @@ -49,7 +50,7 @@ typedef struct {
} displayio_group_t;

void displayio_group_construct(displayio_group_t* self, displayio_group_child_t* child_array, uint32_t max_size, uint32_t scale, mp_int_t x, mp_int_t y);
bool displayio_group_get_pixel(displayio_group_t *group, int16_t x, int16_t y, uint16_t *pixel);
bool displayio_group_get_area(displayio_group_t *group, displayio_buffer_transform_t* transform, displayio_area_t* area, uint32_t* mask, uint32_t *buffer);
bool displayio_group_needs_refresh(displayio_group_t *self);
void displayio_group_finish_refresh(displayio_group_t *self);

Expand Down
153 changes: 118 additions & 35 deletions shared-module/displayio/TileGrid.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,31 +56,39 @@ void common_hal_displayio_tilegrid_construct(displayio_tilegrid_t *self, mp_obj_
self->bitmap_width_in_tiles = bitmap_width_in_tiles;
self->width_in_tiles = width;
self->height_in_tiles = height;
self->total_width = width * tile_width;
self->total_height = height * tile_height;
self->area.x1 = x;
self->area.y1 = y;
self->area.x2 = x + width * tile_width;
self->area.y2 = y + height * tile_height;
self->tile_width = tile_width;
self->tile_height = tile_height;
self->bitmap = bitmap;
self->pixel_shader = pixel_shader;
self->x = x;
self->y = y;
}


mp_int_t common_hal_displayio_tilegrid_get_x(displayio_tilegrid_t *self) {
return self->x;
return self->area.x1;
}
void common_hal_displayio_tilegrid_set_x(displayio_tilegrid_t *self, mp_int_t x) {
self->needs_refresh = self->x != x;
self->x = x;
if (self->area.x1 == x) {
return;
}
self->needs_refresh = true;
self->area.x2 += (self->area.x1 - x);
self->area.x1 = x;
}
mp_int_t common_hal_displayio_tilegrid_get_y(displayio_tilegrid_t *self) {
return self->y;
return self->area.y1;
}

void common_hal_displayio_tilegrid_set_y(displayio_tilegrid_t *self, mp_int_t y) {
self->needs_refresh = self->y != y;
self->y = y;
if (self->area.y1 == y) {
return;
}
self->needs_refresh = true;
self->area.y2 += (self->area.y1 - y);
self->area.y1 = y;
}

mp_obj_t common_hal_displayio_tilegrid_get_pixel_shader(displayio_tilegrid_t *self) {
Expand Down Expand Up @@ -128,45 +136,120 @@ void common_hal_displayio_tilegrid_set_tile(displayio_tilegrid_t *self, uint16_t
void common_hal_displayio_tilegrid_set_top_left(displayio_tilegrid_t *self, uint16_t x, uint16_t y) {
self->top_left_x = x;
self->top_left_y = y;
self->needs_refresh = true;
}
bool displayio_tilegrid_get_pixel(displayio_tilegrid_t *self, int16_t x, int16_t y, uint16_t* pixel) {
x -= self->x;
y -= self->y;
if (y < 0 || y >= self->total_height || x >= self->total_width || x < 0) {
return false;
}

bool displayio_tilegrid_get_area(displayio_tilegrid_t *self, displayio_buffer_transform_t* transform, displayio_area_t* area, uint32_t* mask, uint32_t *buffer) {
// If no tiles are present we have no impact.
uint8_t* tiles = self->tiles;
if (self->inline_tiles) {
tiles = (uint8_t*) &self->tiles;
}
if (tiles == NULL) {
return false;
}
uint16_t tile_location = ((y / self->tile_height + self->top_left_y) % self->height_in_tiles) * self->width_in_tiles + (x / self->tile_width + self->top_left_x) % self->width_in_tiles;
uint8_t tile = tiles[tile_location];
uint16_t tile_x = tile_x = (tile % self->bitmap_width_in_tiles) * self->tile_width + x % self->tile_width;
uint16_t tile_y = tile_y = (tile / self->bitmap_width_in_tiles) * self->tile_height + y % self->tile_height;

uint32_t value = 0;
if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_bitmap_type)) {
value = common_hal_displayio_bitmap_get_pixel(self->bitmap, tile_x, tile_y);
} else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_shape_type)) {
value = common_hal_displayio_shape_get_pixel(self->bitmap, tile_x, tile_y);
} else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_ondiskbitmap_type)) {
value = common_hal_displayio_ondiskbitmap_get_pixel(self->bitmap, tile_x, tile_y);
displayio_area_t overlap;
displayio_area_t scaled_area = {
.x1 = self->area.x1 * transform->scale,
.y1 = self->area.y1 * transform->scale,
.x2 = self->area.x2 * transform->scale,
.y2 = self->area.y2 * transform->scale
};
if (!displayio_area_compute_overlap(area, &scaled_area, &overlap)) {
return false;
}

if (self->pixel_shader == mp_const_none) {
*pixel = value;
return true;
} else if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_palette_type) && displayio_palette_get_color(self->pixel_shader, value, pixel)) {
return true;
} else if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_colorconverter_type) && common_hal_displayio_colorconverter_convert(self->pixel_shader, value, pixel)) {
return true;
int16_t x_stride = 1;
int16_t y_stride = displayio_area_width(area);
if (transform->transpose_xy) {
x_stride = displayio_area_height(area);
y_stride = 1;
}
uint16_t start = 0;
if (transform->mirror_x) {
start += (area->x2 - area->x1 - 1) * x_stride;
x_stride *= -1;
}
if (transform->mirror_y) {
start += (area->y2 - area->y1 - 1) * y_stride;
y_stride *= -1;
}

return false;
// Track if this layer finishes filling in the given area. We can ignore any remaining
// layers at that point.
bool full_coverage = displayio_area_equal(area, &overlap);

// TODO(tannewt): Skip coverage tracking if all pixels outside the overlap have already been
// set and our palette is all opaque.

// TODO(tannewt): Check to see if the pixel_shader has any transparency. If it doesn't then we
// can either return full coverage or bulk update the mask.
int16_t y = overlap.y1 - scaled_area.y1;
if (y < 0) {
y = 0;
}
int16_t x_shift = area->x1 - scaled_area.x1;
int16_t y_shift = area->y1 - scaled_area.y1;
for (; y < overlap.y2 - scaled_area.y1; y++) {
int16_t x = overlap.x1 - scaled_area.x1;
if (x < 0) {
x = 0;
}
int16_t row_start = start + (y - y_shift) * y_stride;
int16_t local_y = y / transform->scale;
for (; x < overlap.x2 - scaled_area.x1; x++) {
// Compute the destination pixel in the buffer and mask based on the transformations.
uint16_t offset = row_start + (x - x_shift) * x_stride;

// This is super useful for debugging out range accesses. Uncomment to use.
// if (offset < 0 || offset >= displayio_area_size(area)) {
// asm("bkpt");
// }

// Check the mask first to see if the pixel has already been set.
if ((mask[offset / 32] & (1 << (offset % 32))) != 0) {
continue;
}
int16_t local_x = x / transform->scale;
uint16_t tile_location = ((local_y / self->tile_height + self->top_left_y) % self->height_in_tiles) * self->width_in_tiles + (local_x / self->tile_width + self->top_left_x) % self->width_in_tiles;
uint8_t tile = tiles[tile_location];
uint16_t tile_x = (tile % self->bitmap_width_in_tiles) * self->tile_width + local_x % self->tile_width;
uint16_t tile_y = (tile / self->bitmap_width_in_tiles) * self->tile_height + local_y % self->tile_height;

uint32_t value = 0;
// We always want to read bitmap pixels by row first and then transpose into the destination
// buffer because most bitmaps are row associated.
if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_bitmap_type)) {
value = common_hal_displayio_bitmap_get_pixel(self->bitmap, tile_x, tile_y);
} else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_shape_type)) {
value = common_hal_displayio_shape_get_pixel(self->bitmap, tile_x, tile_y);
} else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_ondiskbitmap_type)) {
value = common_hal_displayio_ondiskbitmap_get_pixel(self->bitmap, tile_x, tile_y);
}

uint16_t* pixel = ((uint16_t*) buffer) + offset;
if (self->pixel_shader == mp_const_none) {
*pixel = value;
return true;
} else if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_palette_type)) {
if (!displayio_palette_get_color(self->pixel_shader, value, pixel)) {
// A pixel is transparent so we haven't fully covered the area ourselves.
full_coverage = false;
} else {
mask[offset / 32] |= 1 << (offset % 32);
}
} else if (MP_OBJ_IS_TYPE(self->pixel_shader, &displayio_colorconverter_type)) {
if (!common_hal_displayio_colorconverter_convert(self->pixel_shader, value, pixel)) {
// A pixel is transparent so we haven't fully covered the area ourselves.
full_coverage = false;
} else {
mask[offset / 32] |= 1 << (offset % 32);
}
}
}
}
return full_coverage;
}

bool displayio_tilegrid_needs_refresh(displayio_tilegrid_t *self) {
Expand Down
8 changes: 3 additions & 5 deletions shared-module/displayio/TileGrid.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,16 @@
#include <stdint.h>

#include "py/obj.h"
#include "shared-module/displayio/area.h"

typedef struct {
mp_obj_base_t base;
mp_obj_t bitmap;
mp_obj_t pixel_shader;
uint16_t x;
uint16_t y;
displayio_area_t area;
uint16_t bitmap_width_in_tiles;
uint16_t width_in_tiles;
uint16_t height_in_tiles;
uint16_t total_width;
uint16_t total_height;
uint16_t tile_width;
uint16_t tile_height;
uint16_t top_left_x;
Expand All @@ -52,7 +50,7 @@ typedef struct {
bool inline_tiles;
} displayio_tilegrid_t;

bool displayio_tilegrid_get_pixel(displayio_tilegrid_t *self, int16_t x, int16_t y, uint16_t *pixel);
bool displayio_tilegrid_get_area(displayio_tilegrid_t *self, displayio_buffer_transform_t* transform, displayio_area_t* area, uint32_t* mask, uint32_t *buffer);
bool displayio_tilegrid_needs_refresh(displayio_tilegrid_t *self);
void displayio_tilegrid_finish_refresh(displayio_tilegrid_t *self);

Expand Down
Loading