feat(sw): Add method to convert a htiled I1 buffer to vtiled (#7129)

This commit is contained in:
Fabian Blatz
2024-10-30 09:18:28 +01:00
committed by GitHub
parent 3f3de6ac71
commit be85ad7369
4 changed files with 200 additions and 0 deletions

View File

@@ -488,6 +488,31 @@ meaning ``(horizontal_resolution x vertical_resolution / 8) + 8`` bytes.
As LVGL can not handle fractional width make sure to round the horizontal resolution As LVGL can not handle fractional width make sure to round the horizontal resolution
to 8 bits (for example 90 to 96). to 8 bits (for example 90 to 96).
The :cpp:func:`lv_draw_sw_i1_convert_to_vtiled` function is used to convert a draw buffer in I1 color format from a row-wise (htiled) to a column-wise (vtiled) buffer layout.
This conversion is necessary for certain display controllers that require a different draw buffer mapping. The function assumes that the buffer width and height are rounded to a multiple of 8.
The bit order of the resulting vtiled buffer can be specified using the `bit_order_lsb` parameter.
For more details, refer to the implementation in :cpp:func:`lv_draw_sw_i1_convert_to_vtiled` in :file:`src/draw/sw/lv_draw_sw.c`.
To ensure that the redrawn areas start and end on byte boundaries, you can add a rounder callback to your display driver. This callback will round the width and height to the nearest multiple of 8.
Here is an example of how to implement and set a rounder callback:
.. code:: c
static void my_rounder_cb(lv_event_t *e)
{
lv_area_t *area = lv_event_get_param(e);
/* Round the height to the nearest multiple of 8 */
area->y1 = (area->y1 & ~0x7);
area->y2 = (area->y2 | 0x7);
}
lv_display_add_event_cb(display, my_rounder_cb, LV_EVENT_INVALIDATE_AREA, display);
In this example, the `my_rounder_cb` function rounds the coordinates of the redrawn area to the nearest multiple of 8.
The `x1` and `y1` coordinates are rounded down, while the `x2` and `y2` coordinates are rounded up. This ensures that the
width and height of the redrawn area are always multiples of 8.
Constraints on Redrawn Area Constraints on Redrawn Area
--------------------------- ---------------------------

View File

@@ -282,6 +282,35 @@ void lv_draw_sw_i1_invert(void * buf, uint32_t buf_size)
} }
} }
void lv_draw_sw_i1_convert_to_vtiled(const void * buf, uint32_t buf_size, uint32_t width, uint32_t height,
void * out_buf,
uint32_t out_buf_size, bool bit_order_lsb)
{
LV_ASSERT(buf && out_buf);
LV_ASSERT(width % 8 == 0 && height % 8 == 0);
LV_ASSERT(buf_size == (width / 8) * height);
LV_ASSERT(out_buf_size >= buf_size);
lv_memset(out_buf, 0, out_buf_size);
const uint8_t * src_buf = (uint8_t *)buf;
uint8_t * dst_buf = (uint8_t *)out_buf;
for(uint32_t y = 0; y < height; y++) {
for(uint32_t x = 0; x < width; x++) {
uint32_t src_index = y * width + x;
uint32_t dst_index = x * height + y;
uint8_t bit = (src_buf[src_index / 8] >> (7 - (src_index % 8))) & 0x01;
if(bit_order_lsb) {
dst_buf[dst_index / 8] |= (bit << (dst_index % 8));
}
else {
dst_buf[dst_index / 8] |= (bit << (7 - (dst_index % 8)));
}
}
}
}
void lv_draw_sw_rotate(const void * src, void * dest, int32_t src_width, int32_t src_height, int32_t src_stride, void lv_draw_sw_rotate(const void * src, void * dest, int32_t src_width, int32_t src_height, int32_t src_stride,
int32_t dest_stride, lv_display_rotation_t rotation, lv_color_format_t color_format) int32_t dest_stride, lv_display_rotation_t rotation, lv_color_format_t color_format)
{ {

View File

@@ -171,6 +171,23 @@ void lv_draw_sw_rgb565_swap(void * buf, uint32_t buf_size_px);
*/ */
void lv_draw_sw_i1_invert(void * buf, uint32_t buf_size); void lv_draw_sw_i1_invert(void * buf, uint32_t buf_size);
/**
* Convert a draw buffer in I1 color format from htiled (row-wise)
* to vtiled (column-wise) buffer layout. The conversion assumes that the buffer width
* and height is rounded to a multiple of 8.
* @param buf pointer to the buffer to be converted
* @param buf_size size of the buffer in bytes
* @param width width of the buffer
* @param height height of the buffer
* @param out_buf pointer to the output buffer
* @param out_buf_size size of the output buffer in bytes
* @param bit_order_lsb bit order of the resulting vtiled buffer
*/
void lv_draw_sw_i1_convert_to_vtiled(const void * buf, uint32_t buf_size, uint32_t width, uint32_t height,
void * out_buf,
uint32_t out_buf_size, bool bit_order_lsb);
/** /**
* Rotate a buffer into another buffer * Rotate a buffer into another buffer
* @param src the source buffer * @param src the source buffer

View File

@@ -315,4 +315,133 @@ void test_invert(void)
TEST_ASSERT_EQUAL_UINT8_ARRAY(&expected_buf[3], &buf3[3], 2); TEST_ASSERT_EQUAL_UINT8_ARRAY(&expected_buf[3], &buf3[3], 2);
} }
void test_vtile_small(void)
{
uint8_t src_buf[8] = {0x3C, 0x42, 0x81, 0xA5, 0x81, 0x81, 0x42, 0x3C};
uint8_t dst_buf[8] = {0};
uint8_t expected_buf_msb[8] = {0x3C, 0x42, 0x91, 0x81, 0x81, 0x91, 0x42, 0x3C};
uint8_t expected_buf_lsb[8] = {0x3C, 0x42, 0x89, 0x81, 0x81, 0x89, 0x42, 0x3C};
lv_draw_sw_i1_convert_to_vtiled(src_buf, 8, 8, 8, dst_buf, 8, false);
TEST_ASSERT_EQUAL_UINT8_ARRAY(expected_buf_msb, dst_buf, 8);
lv_draw_sw_i1_convert_to_vtiled(src_buf, 8, 8, 8, dst_buf, 8, true);
TEST_ASSERT_EQUAL_UINT8_ARRAY(expected_buf_lsb, dst_buf, 8);
}
void test_vtile_rectangular(void)
{
uint8_t src_buf[80] = {
0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x80, 0x83, 0xE1, 0x00,
0x40, 0x80, 0x84, 0x01, 0x00,
0x40, 0x41, 0x08, 0x01, 0x00,
0x40, 0x41, 0x10, 0x01, 0x00,
0x40, 0x41, 0x20, 0x01, 0x00,
0x40, 0x41, 0x20, 0x01, 0x00,
0x40, 0x41, 0x20, 0x01, 0x00,
0x40, 0x41, 0x20, 0x01, 0x00,
0x40, 0x23, 0x20, 0x01, 0x00,
0x40, 0x22, 0x20, 0xF1, 0x00,
0x40, 0x14, 0x20, 0x11, 0x00,
0x40, 0x14, 0x10, 0x11, 0x00,
0x40, 0x08, 0x08, 0x11, 0x00,
0x7E, 0x08, 0x07, 0xF1, 0xF8,
0x00, 0x00, 0x00, 0x00, 0x00,
};
uint8_t dst_buf[80] = {0};
uint8_t expected_buf_msb[80] = {
0x00, 0x00,
0x7F, 0xFE,
0x00, 0x02,
0x00, 0x02,
0x00, 0x02,
0x00, 0x02,
0x00, 0x02,
0x00, 0x00,
0x60, 0x00,
0x1F, 0x80,
0x00, 0x60,
0x00, 0x18,
0x00, 0x06,
0x00, 0x18,
0x00, 0x60,
0x3F, 0x80,
0xC0, 0x00,
0x00, 0x00,
0x07, 0xF0,
0x08, 0x08,
0x10, 0x04,
0x20, 0x02,
0x80, 0x02,
0x80, 0x02,
0x80, 0x22,
0x80, 0x22,
0x80, 0x22,
0x00, 0x3E,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0xFF, 0xFE,
0x00, 0x02,
0x00, 0x02,
0x00, 0x02,
0x00, 0x02,
0x00, 0x02,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
};
uint8_t expected_buf_lsb[80] = {
0x00, 0x00,
0xFE, 0x7F,
0x00, 0x40,
0x00, 0x40,
0x00, 0x40,
0x00, 0x40,
0x00, 0x40,
0x00, 0x00,
0x06, 0x00,
0xF8, 0x01,
0x00, 0x06,
0x00, 0x18,
0x00, 0x60,
0x00, 0x18,
0x00, 0x06,
0xF8, 0x03,
0x06, 0x00,
0x00, 0x00,
0xE0, 0x0F,
0x10, 0x10,
0x08, 0x20,
0x04, 0x40,
0x02, 0x40,
0x02, 0x40,
0x02, 0x44,
0x02, 0x44,
0x02, 0x44,
0x00, 0x7C,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
0xFE, 0x7F,
0x00, 0x40,
0x00, 0x40,
0x00, 0x40,
0x00, 0x40,
0x00, 0x40,
0x00, 0x00,
0x00, 0x00,
0x00, 0x00,
};
lv_draw_sw_i1_convert_to_vtiled(src_buf, 80, 40, 16, dst_buf, 80, false);
TEST_ASSERT_EQUAL_UINT8_ARRAY(expected_buf_msb, dst_buf, 8);
lv_draw_sw_i1_convert_to_vtiled(src_buf, 80, 40, 16, dst_buf, 80, true);
TEST_ASSERT_EQUAL_UINT8_ARRAY(expected_buf_lsb, dst_buf, 8);
}
#endif #endif