Skip to content

Commit bccf825

Browse files
committed
busdisplay: refresh rotated displays in bands of columns
At rotation 90 and 270 a panel row is a column of the source bitmap. Refreshing in panel rows made TileGrid read every source pixel from a different source row. Refresh in bands of panel columns instead, so the sources are read along their rows. This matters most for OnDiskBitmap, which reads the file in that order.
1 parent 520805e commit bccf825

1 file changed

Lines changed: 31 additions & 28 deletions

File tree

‎shared-module/busdisplay/BusDisplay.c‎

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are
233233
return true;
234234
}
235235
uint16_t rows_per_buffer = displayio_area_height(&clipped);
236+
uint16_t cols_per_buffer = displayio_area_width(&clipped);
236237
uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->core.colorspace.depth;
237238
uint16_t pixels_per_buffer = displayio_area_size(&clipped);
238239

@@ -243,26 +244,29 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are
243244
subrectangles = rows_per_buffer / 8; // page addressing mode writes 8 rows at a time
244245
rows_per_buffer = 8;
245246
} else if (displayio_area_size(&clipped) > buffer_size * pixels_per_word) {
246-
rows_per_buffer = buffer_size * pixels_per_word / displayio_area_width(&clipped);
247-
if (rows_per_buffer == 0) {
248-
rows_per_buffer = 1;
249-
}
250-
// If pixels are packed by column then ensure rows_per_buffer is on a byte boundary.
251-
if (self->core.colorspace.depth < 8 && !self->core.colorspace.pixels_in_byte_share_row) {
252-
uint8_t pixels_per_byte = 8 / self->core.colorspace.depth;
253-
if (rows_per_buffer % pixels_per_byte != 0) {
254-
rows_per_buffer -= rows_per_buffer % pixels_per_byte;
247+
uint16_t buffer_pixels = buffer_size * pixels_per_word;
248+
if (self->core.transform.transpose_xy && self->core.colorspace.depth >= 8) {
249+
// Rotated 90 or 270: a panel column is a source row. Send bands of columns so sources
250+
// are read along their rows, which OnDiskBitmap needs to avoid a file seek per pixel.
251+
rows_per_buffer = MIN(rows_per_buffer, buffer_pixels);
252+
cols_per_buffer = buffer_pixels / rows_per_buffer;
253+
} else {
254+
rows_per_buffer = buffer_pixels / cols_per_buffer;
255+
if (rows_per_buffer == 0) {
256+
rows_per_buffer = 1;
257+
}
258+
// If pixels are packed by column then ensure rows_per_buffer is on a byte boundary.
259+
if (self->core.colorspace.depth < 8 && !self->core.colorspace.pixels_in_byte_share_row) {
260+
uint8_t pixels_per_byte = 8 / self->core.colorspace.depth;
261+
if (rows_per_buffer % pixels_per_byte != 0) {
262+
rows_per_buffer -= rows_per_buffer % pixels_per_byte;
263+
}
255264
}
256265
}
257-
subrectangles = displayio_area_height(&clipped) / rows_per_buffer;
258-
if (displayio_area_height(&clipped) % rows_per_buffer != 0) {
259-
subrectangles++;
260-
}
261-
pixels_per_buffer = rows_per_buffer * displayio_area_width(&clipped);
262-
buffer_size = pixels_per_buffer / pixels_per_word;
263-
if (pixels_per_buffer % pixels_per_word) {
264-
buffer_size += 1;
265-
}
266+
subrectangles = ((displayio_area_height(&clipped) + rows_per_buffer - 1) / rows_per_buffer) *
267+
((displayio_area_width(&clipped) + cols_per_buffer - 1) / cols_per_buffer);
268+
pixels_per_buffer = rows_per_buffer * cols_per_buffer;
269+
buffer_size = (pixels_per_buffer + pixels_per_word - 1) / pixels_per_word;
266270
}
267271

268272
// Allocated and shared as a uint32_t array so the compiler knows the
@@ -271,19 +275,17 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are
271275
uint32_t buffer[buffer_size];
272276
uint32_t mask[mask_length];
273277

274-
uint16_t remaining_rows = displayio_area_height(&clipped);
278+
displayio_area_t subrectangle = clipped;
279+
subrectangle.next = NULL;
275280

276281
for (uint16_t j = 0; j < subrectangles; j++) {
277-
displayio_area_t subrectangle = {
278-
.x1 = clipped.x1,
279-
.y1 = clipped.y1 + rows_per_buffer * j,
280-
.x2 = clipped.x2,
281-
.y2 = clipped.y1 + rows_per_buffer * (j + 1)
282-
};
283-
if (remaining_rows < rows_per_buffer) {
284-
subrectangle.y2 = subrectangle.y1 + remaining_rows;
282+
// Down the rows of a band first, then to the next band of columns.
283+
if (subrectangle.y1 >= clipped.y2) {
284+
subrectangle.y1 = clipped.y1;
285+
subrectangle.x1 += cols_per_buffer;
285286
}
286-
remaining_rows -= rows_per_buffer;
287+
subrectangle.x2 = MIN(subrectangle.x1 + cols_per_buffer, clipped.x2);
288+
subrectangle.y2 = MIN(subrectangle.y1 + rows_per_buffer, clipped.y2);
287289

288290
uint16_t subrectangle_size_bytes;
289291
if (self->core.colorspace.depth >= 8) {
@@ -305,6 +307,7 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are
305307
}
306308
_send_pixels(self, (uint8_t *)buffer, subrectangle_size_bytes);
307309
displayio_display_bus_end_transaction(&self->bus);
310+
subrectangle.y1 = subrectangle.y2;
308311

309312
// Run background tasks so they can run during an explicit refresh.
310313
// Auto-refresh won't run background tasks here because it is a background task itself.

0 commit comments

Comments
 (0)