Skip to content

Commit 66ad7b4

Browse files
committed
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.
1 parent 87f7bc9 commit 66ad7b4

File tree

2 files changed

+76
-56
lines changed

2 files changed

+76
-56
lines changed

shared-module/displayio/Bitmap.c

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,28 @@
1-
// This file is part of the CircuitPython project: https://circuitpython.org
2-
//
3-
// SPDX-FileCopyrightText: Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
4-
//
5-
// SPDX-License-Identifier: MIT
1+
/*
2+
* This file is part of the Micro Python project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
626

727
#include "shared-bindings/displayio/Bitmap.h"
828

@@ -49,7 +69,7 @@ void common_hal_displayio_bitmap_construct_from_buffer(displayio_bitmap_t *self,
4969
self->x_shift = 0; // Used to divide the index by the number of pixels per word. Its used in a
5070
// shift which effectively divides by 2 ** x_shift.
5171
uint32_t power_of_two = 1;
52-
while (power_of_two < ALIGN_BITS / bits_per_value) {
72+
while (power_of_two < 8 / bits_per_value) {
5373
self->x_shift++;
5474
power_of_two <<= 1;
5575
}
@@ -90,13 +110,14 @@ uint32_t common_hal_displayio_bitmap_get_pixel(displayio_bitmap_t *self, int16_t
90110
return 0;
91111
}
92112
int32_t row_start = y * self->stride;
93-
uint32_t bytes_per_value = self->bits_per_value / 8;
113+
uint32_t *row = self->data + row_start;
114+
uint8_t bytes_per_value = self->bits_per_value / 8;
115+
uint8_t values_per_byte = 8 / self->bits_per_value;
94116
if (bytes_per_value < 1) {
95-
uint32_t word = self->data[row_start + (x >> self->x_shift)];
96-
97-
return (word >> (sizeof(uint32_t) * 8 - ((x & self->x_mask) + 1) * self->bits_per_value)) & self->bitmask;
117+
uint8_t bits = ((uint8_t *)row)[x >> self->x_shift];
118+
uint8_t bit_position = (values_per_byte - (x & self->x_mask) - 1) * self->bits_per_value;
119+
return (bits >> bit_position) & self->bitmask;
98120
} else {
99-
uint32_t *row = self->data + row_start;
100121
if (bytes_per_value == 1) {
101122
return ((uint8_t *)row)[x];
102123
} else if (bytes_per_value == 2) {
@@ -134,16 +155,16 @@ void displayio_bitmap_write_pixel(displayio_bitmap_t *self, int16_t x, int16_t y
134155

135156
// Update one pixel of data
136157
int32_t row_start = y * self->stride;
137-
uint32_t bytes_per_value = self->bits_per_value / 8;
158+
uint32_t *row = self->data + row_start;
159+
uint8_t bytes_per_value = self->bits_per_value / 8;
160+
uint8_t values_per_byte = 8 / self->bits_per_value;
138161
if (bytes_per_value < 1) {
139-
uint32_t bit_position = (sizeof(uint32_t) * 8 - ((x & self->x_mask) + 1) * self->bits_per_value);
140-
uint32_t index = row_start + (x >> self->x_shift);
141-
uint32_t word = self->data[index];
142-
word &= ~(self->bitmask << bit_position);
143-
word |= (value & self->bitmask) << bit_position;
144-
self->data[index] = word;
162+
uint8_t bits = ((uint8_t *)row)[x >> self->x_shift];
163+
uint8_t bit_position = (values_per_byte - (x & self->x_mask) - 1) * self->bits_per_value;
164+
bits &= ~(self->bitmask << bit_position);
165+
bits |= (value & self->bitmask) << bit_position;
166+
((uint8_t *)row)[x >> self->x_shift] = bits;
145167
} else {
146-
uint32_t *row = self->data + row_start;
147168
if (bytes_per_value == 1) {
148169
((uint8_t *)row)[x] = value;
149170
} else if (bytes_per_value == 2) {

tools/gen_display_resources.py

Lines changed: 36 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,7 @@ def _load_row(self, y, row):
101101

102102
c_file = args.output_c_file
103103

104-
c_file.write(
105-
"""\
104+
c_file.write( """\
106105
107106
#include "shared-bindings/displayio/Bitmap.h"
108107
#include "shared-bindings/displayio/Palette.h"
@@ -122,22 +121,22 @@ def _load_row(self, y, row):
122121
c_file.write(
123122
"""\
124123
const uint32_t blinka_bitmap_data[32] = {
125-
0x00000011, 0x11000000,
126-
0x00000111, 0x53100000,
127-
0x00000111, 0x56110000,
128-
0x00000111, 0x11140000,
129-
0x00000111, 0x20002000,
130-
0x00000011, 0x13000000,
131-
0x00000001, 0x11200000,
132-
0x00000000, 0x11330000,
133-
0x00000000, 0x01122000,
134-
0x00001111, 0x44133000,
135-
0x00032323, 0x24112200,
136-
0x00111114, 0x44113300,
137-
0x00323232, 0x34112200,
138-
0x11111144, 0x44443300,
139-
0x11111111, 0x11144401,
140-
0x23232323, 0x21111110
124+
0x11000000, 0x00000011,
125+
0x11010000, 0x00001053,
126+
0x11010000, 0x00001156,
127+
0x11010000, 0x00001411,
128+
0x11010000, 0x00200020,
129+
0x11000000, 0x00000013,
130+
0x01000000, 0x00002011,
131+
0x00000000, 0x00003311,
132+
0x00000000, 0x00201201,
133+
0x11110000, 0x00301344,
134+
0x23230300, 0x00221124,
135+
0x14111100, 0x00331144,
136+
0x32323200, 0x00221134,
137+
0x44111111, 0x00334444,
138+
0x11111111, 0x01441411,
139+
0x23232323, 0x10111121
141140
};
142141
"""
143142
)
@@ -146,18 +145,18 @@ def _load_row(self, y, row):
146145
c_file.write(
147146
"""\
148147
const uint32_t blinka_bitmap_data[28] = {
149-
0x00000111, 0x00000000,
150-
0x00001153, 0x10000000,
151-
0x00001156, 0x11000000,
152-
0x00001111, 0x14000000,
153-
0x00000112, 0x00200000,
154-
0x00000011, 0x30000000,
155-
0x00000011, 0x20000000,
156-
0x00011144, 0x13000000,
157-
0x00232324, 0x12000000,
158-
0x01111444, 0x13000000,
159-
0x32323234, 0x12010000,
160-
0x11111144, 0x44100000
148+
0x11010000, 0x00000000,
149+
0x53110000, 0x00000010,
150+
0x56110000, 0x00000011,
151+
0x11110000, 0x00000014,
152+
0x12010000, 0x00002000,
153+
0x11000000, 0x00000030,
154+
0x11000000, 0x00000020,
155+
0x44110100, 0x00000013,
156+
0x24232300, 0x00000012,
157+
0x44141101, 0x00000013,
158+
0x34323232, 0x00000112,
159+
0x44111111, 0x00001044
161160
};
162161
"""
163162
)
@@ -171,9 +170,9 @@ def _load_row(self, y, row):
171170
.data = (uint32_t*) blinka_bitmap_data,
172171
.stride = 2,
173172
.bits_per_value = 4,
174-
.x_shift = 3,
175-
.x_mask = 0x7,
176-
.bitmask = 0xf,
173+
.x_shift = 1,
174+
.x_mask = 0x01,
175+
.bitmask = 0x0f,
177176
.read_only = true
178177
}};
179178
@@ -328,7 +327,7 @@ def _load_row(self, y, row):
328327
)
329328
)
330329

331-
for i, word in enumerate(struct.iter_unpack(">I", b)):
330+
for i, word in enumerate(struct.iter_unpack("<I", b)):
332331
c_file.write("0x{:08x}, ".format(word[0]))
333332
if (i + 1) % (bytes_per_row // 4) == 0:
334333
c_file.write("\n")
@@ -348,9 +347,9 @@ def _load_row(self, y, row):
348347
.data = (uint32_t*) font_bitmap_data,
349348
.stride = {},
350349
.bits_per_value = 1,
351-
.x_shift = 5,
352-
.x_mask = 0x1f,
353-
.bitmask = 0x1,
350+
.x_shift = 3,
351+
.x_mask = 0x07,
352+
.bitmask = 0x01,
354353
.read_only = true
355354
}};
356355
""".format(

0 commit comments

Comments
 (0)