feat(sw): Add method to convert a htiled I1 buffer to vtiled (#7129)
This commit is contained in:
@@ -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
|
||||
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
|
||||
---------------------------
|
||||
|
||||
@@ -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,
|
||||
int32_t dest_stride, lv_display_rotation_t rotation, lv_color_format_t color_format)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param src the source buffer
|
||||
|
||||
@@ -315,4 +315,133 @@ void test_invert(void)
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user