From 2c7b11b1af8559135ae47792b27ff276ed9f39b3 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Sat, 3 Aug 2024 20:35:54 +0200 Subject: [PATCH] displayio.Bitmap is now byte-aligned for depth < 8 The traditional layout of pixels in bitmaps of depth less than eight is with the order of values in a byte reversed, but with bytes in the same order as the pixels on the line. Before now, displayio.Bitmap did reverse the values, but did it on a word (four bytes) basis, not byte, which resulted in groups of four bytes being in the order opposite to the screen order. This patch fixes this, by making processing of pixels in bitmaps of depth less than 8 bits based on bytes, not words. Since the internal details are changing, any code that accessed bitmaps through the memoryview buffer, or that created bitmaps directly from raw data, and that used depth of less than 8 bits will be affected. Therefore, the gen_display_resources.py script also had to be modified to account for the changes. --- shared-module/displayio/Bitmap.c | 29 ++++++------- tools/gen_display_resources.py | 70 ++++++++++++++++---------------- 2 files changed, 50 insertions(+), 49 deletions(-) diff --git a/shared-module/displayio/Bitmap.c b/shared-module/displayio/Bitmap.c index d0060edae543..d5236f6b4f61 100644 --- a/shared-module/displayio/Bitmap.c +++ b/shared-module/displayio/Bitmap.c @@ -49,7 +49,7 @@ void common_hal_displayio_bitmap_construct_from_buffer(displayio_bitmap_t *self, self->x_shift = 0; // Used to divide the index by the number of pixels per word. Its used in a // shift which effectively divides by 2 ** x_shift. uint32_t power_of_two = 1; - while (power_of_two < ALIGN_BITS / bits_per_value) { + while (power_of_two < 8 / bits_per_value) { self->x_shift++; power_of_two <<= 1; } @@ -90,13 +90,14 @@ uint32_t common_hal_displayio_bitmap_get_pixel(displayio_bitmap_t *self, int16_t return 0; } int32_t row_start = y * self->stride; - uint32_t bytes_per_value = self->bits_per_value / 8; + uint32_t *row = self->data + row_start; + uint8_t bytes_per_value = self->bits_per_value / 8; + uint8_t values_per_byte = 8 / self->bits_per_value; if (bytes_per_value < 1) { - uint32_t word = self->data[row_start + (x >> self->x_shift)]; - - return (word >> (sizeof(uint32_t) * 8 - ((x & self->x_mask) + 1) * self->bits_per_value)) & self->bitmask; + uint8_t bits = ((uint8_t *)row)[x >> self->x_shift]; + uint8_t bit_position = (values_per_byte - (x & self->x_mask) - 1) * self->bits_per_value; + return (bits >> bit_position) & self->bitmask; } else { - uint32_t *row = self->data + row_start; if (bytes_per_value == 1) { return ((uint8_t *)row)[x]; } else if (bytes_per_value == 2) { @@ -134,16 +135,16 @@ void displayio_bitmap_write_pixel(displayio_bitmap_t *self, int16_t x, int16_t y // Update one pixel of data int32_t row_start = y * self->stride; - uint32_t bytes_per_value = self->bits_per_value / 8; + uint32_t *row = self->data + row_start; + uint8_t bytes_per_value = self->bits_per_value / 8; + uint8_t values_per_byte = 8 / self->bits_per_value; if (bytes_per_value < 1) { - uint32_t bit_position = (sizeof(uint32_t) * 8 - ((x & self->x_mask) + 1) * self->bits_per_value); - uint32_t index = row_start + (x >> self->x_shift); - uint32_t word = self->data[index]; - word &= ~(self->bitmask << bit_position); - word |= (value & self->bitmask) << bit_position; - self->data[index] = word; + uint8_t bits = ((uint8_t *)row)[x >> self->x_shift]; + uint8_t bit_position = (values_per_byte - (x & self->x_mask) - 1) * self->bits_per_value; + bits &= ~(self->bitmask << bit_position); + bits |= (value & self->bitmask) << bit_position; + ((uint8_t *)row)[x >> self->x_shift] = bits; } else { - uint32_t *row = self->data + row_start; if (bytes_per_value == 1) { ((uint8_t *)row)[x] = value; } else if (bytes_per_value == 2) { diff --git a/tools/gen_display_resources.py b/tools/gen_display_resources.py index 350988bab0c0..dbf3f9a99467 100644 --- a/tools/gen_display_resources.py +++ b/tools/gen_display_resources.py @@ -122,22 +122,22 @@ def _load_row(self, y, row): c_file.write( """\ const uint32_t blinka_bitmap_data[32] = { - 0x00000011, 0x11000000, - 0x00000111, 0x53100000, - 0x00000111, 0x56110000, - 0x00000111, 0x11140000, - 0x00000111, 0x20002000, - 0x00000011, 0x13000000, - 0x00000001, 0x11200000, - 0x00000000, 0x11330000, - 0x00000000, 0x01122000, - 0x00001111, 0x44133000, - 0x00032323, 0x24112200, - 0x00111114, 0x44113300, - 0x00323232, 0x34112200, - 0x11111144, 0x44443300, - 0x11111111, 0x11144401, - 0x23232323, 0x21111110 + 0x11000000, 0x00000011, + 0x11010000, 0x00001053, + 0x11010000, 0x00001156, + 0x11010000, 0x00001411, + 0x11010000, 0x00200020, + 0x11000000, 0x00000013, + 0x01000000, 0x00002011, + 0x00000000, 0x00003311, + 0x00000000, 0x00201201, + 0x11110000, 0x00301344, + 0x23230300, 0x00221124, + 0x14111100, 0x00331144, + 0x32323200, 0x00221134, + 0x44111111, 0x00334444, + 0x11111111, 0x01441411, + 0x23232323, 0x10111121 }; """ ) @@ -146,18 +146,18 @@ def _load_row(self, y, row): c_file.write( """\ const uint32_t blinka_bitmap_data[28] = { - 0x00000111, 0x00000000, - 0x00001153, 0x10000000, - 0x00001156, 0x11000000, - 0x00001111, 0x14000000, - 0x00000112, 0x00200000, - 0x00000011, 0x30000000, - 0x00000011, 0x20000000, - 0x00011144, 0x13000000, - 0x00232324, 0x12000000, - 0x01111444, 0x13000000, - 0x32323234, 0x12010000, - 0x11111144, 0x44100000 + 0x11010000, 0x00000000, + 0x53110000, 0x00000010, + 0x56110000, 0x00000011, + 0x11110000, 0x00000014, + 0x12010000, 0x00002000, + 0x11000000, 0x00000030, + 0x11000000, 0x00000020, + 0x44110100, 0x00000013, + 0x24232300, 0x00000012, + 0x44141101, 0x00000013, + 0x34323232, 0x00000112, + 0x44111111, 0x00001044 }; """ ) @@ -171,9 +171,9 @@ def _load_row(self, y, row): .data = (uint32_t*) blinka_bitmap_data, .stride = 2, .bits_per_value = 4, - .x_shift = 3, - .x_mask = 0x7, - .bitmask = 0xf, + .x_shift = 1, + .x_mask = 0x01, + .bitmask = 0x0f, .read_only = true }}; @@ -328,7 +328,7 @@ def _load_row(self, y, row): ) ) -for i, word in enumerate(struct.iter_unpack(">I", b)): +for i, word in enumerate(struct.iter_unpack("