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
|
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
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user