Stride adjust in place (#5423)
Signed-off-by: Xu Xingliang <xuxingliang@xiaomi.com>
This commit is contained in:
@@ -270,12 +270,12 @@ void * lv_draw_buf_goto_xy(const lv_draw_buf_t * buf, uint32_t x, uint32_t y)
|
|||||||
return data + x * lv_color_format_get_size(buf->header.cf);
|
return data + x * lv_color_format_get_size(buf->header.cf);
|
||||||
}
|
}
|
||||||
|
|
||||||
lv_draw_buf_t * lv_draw_buf_adjust_stride(const lv_draw_buf_t * src, uint32_t stride)
|
lv_result_t lv_draw_buf_adjust_stride(lv_draw_buf_t * src, uint32_t stride)
|
||||||
{
|
{
|
||||||
LV_ASSERT_NULL(src);
|
LV_ASSERT_NULL(src);
|
||||||
LV_ASSERT_NULL(src->data);
|
LV_ASSERT_NULL(src->data);
|
||||||
if(src == NULL) return NULL;
|
if(src == NULL) return LV_RESULT_INVALID;
|
||||||
if(src->data == NULL) return NULL;
|
if(src->data == NULL) return LV_RESULT_INVALID;
|
||||||
|
|
||||||
const lv_image_header_t * header = &src->header;
|
const lv_image_header_t * header = &src->header;
|
||||||
|
|
||||||
@@ -283,32 +283,48 @@ lv_draw_buf_t * lv_draw_buf_adjust_stride(const lv_draw_buf_t * src, uint32_t st
|
|||||||
if(stride == 0) stride = lv_draw_buf_width_to_stride(header->w, header->cf);
|
if(stride == 0) stride = lv_draw_buf_width_to_stride(header->w, header->cf);
|
||||||
|
|
||||||
/*Check if stride already match*/
|
/*Check if stride already match*/
|
||||||
if(header->stride == stride) return NULL;
|
if(header->stride == stride) return LV_RESULT_OK;
|
||||||
|
|
||||||
/*Calculate the minimal stride allowed from bpp*/
|
/*Calculate the minimal stride allowed from bpp*/
|
||||||
uint32_t bpp = lv_color_format_get_bpp(header->cf);
|
uint32_t bpp = lv_color_format_get_bpp(header->cf);
|
||||||
uint32_t min_stride = (header->w * bpp + 7) >> 3;
|
uint32_t min_stride = (header->w * bpp + 7) >> 3;
|
||||||
if(stride < min_stride) {
|
if(stride < min_stride) {
|
||||||
LV_LOG_WARN("New stride is too small. min: %" LV_PRId32, min_stride);
|
LV_LOG_WARN("New stride is too small. min: %" LV_PRId32, min_stride);
|
||||||
return NULL;
|
return LV_RESULT_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
lv_draw_buf_t * dst = lv_draw_buf_create(header->w, header->h, header->cf, stride);
|
/*Check if buffer has enough space. */
|
||||||
if(dst == NULL) return NULL;
|
uint32_t new_size = _calculate_draw_buf_size(header->w, header->h, header->cf, stride);
|
||||||
|
if(new_size > src->data_size) {
|
||||||
|
return LV_RESULT_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t offset = LV_COLOR_INDEXED_PALETTE_SIZE(header->cf) * 4;
|
uint32_t offset = LV_COLOR_INDEXED_PALETTE_SIZE(header->cf) * 4;
|
||||||
if(offset) lv_memcpy(dst->data, src->data, offset);
|
|
||||||
uint8_t * dst_data = dst->data;
|
if(stride > header->stride) {
|
||||||
dst_data += offset;
|
/*Copy from the last line to the first*/
|
||||||
const uint8_t * src_data = src->data;
|
uint8_t * src_data = src->data + offset + header->stride * (header->h - 1);
|
||||||
src_data += offset;
|
uint8_t * dst_data = src->data + offset + stride * (header->h - 1);
|
||||||
for(int32_t y = 0; y < src->header.h; y++) {
|
for(; src_data != src->data;) {
|
||||||
lv_memcpy(dst_data, src_data, min_stride);
|
lv_memmove(dst_data, src_data, min_stride);
|
||||||
src_data += src->header.stride;
|
src_data -= header->stride;
|
||||||
dst_data += dst->header.stride;
|
dst_data -= stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/*Copy from the first line to the last*/
|
||||||
|
uint8_t * src_data = src->data + offset;
|
||||||
|
uint8_t * dst_data = src->data + offset;
|
||||||
|
for(uint32_t y = 0; y < header->h; y++) {
|
||||||
|
lv_memmove(dst_data, src_data, min_stride);
|
||||||
|
src_data += header->stride;
|
||||||
|
dst_data += stride;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dst;
|
src->header.stride = stride;
|
||||||
|
|
||||||
|
return LV_RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
lv_result_t lv_draw_buf_premultiply(lv_draw_buf_t * draw_buf)
|
lv_result_t lv_draw_buf_premultiply(lv_draw_buf_t * draw_buf)
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ LV_EXPORT_CONST_INT(LV_STRIDE_AUTO);
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
lv_image_header_t header;
|
lv_image_header_t header;
|
||||||
uint32_t data_size; /*Total buf size in bytes*/
|
uint32_t data_size; /*Total buf size in bytes*/
|
||||||
void * data;
|
uint8_t * data;
|
||||||
void * unaligned_data; /*Unaligned address of `data`, used internally by lvgl*/
|
void * unaligned_data; /*Unaligned address of `data`, used internally by lvgl*/
|
||||||
} lv_draw_buf_t;
|
} lv_draw_buf_t;
|
||||||
|
|
||||||
@@ -206,9 +206,12 @@ void lv_draw_buf_destroy(lv_draw_buf_t * buf);
|
|||||||
void * lv_draw_buf_goto_xy(const lv_draw_buf_t * buf, uint32_t x, uint32_t y);
|
void * lv_draw_buf_goto_xy(const lv_draw_buf_t * buf, uint32_t x, uint32_t y);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adjust the stride of a draw buf.
|
* Adjust the stride of a draw buf in place.
|
||||||
|
* @param src pointer to a draw buffer
|
||||||
|
* @param stride the new stride in bytes for image. Use LV_STRIDE_AUTO for automatic calculation.
|
||||||
|
* @return LV_RESULT_OK: success or LV_RESULT_INVALID: failed
|
||||||
*/
|
*/
|
||||||
lv_draw_buf_t * lv_draw_buf_adjust_stride(const lv_draw_buf_t * src, uint32_t stride);
|
lv_result_t lv_draw_buf_adjust_stride(lv_draw_buf_t * src, uint32_t stride);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Premultiply draw buffer color with alpha channel.
|
* Premultiply draw buffer color with alpha channel.
|
||||||
|
|||||||
@@ -256,13 +256,17 @@ lv_draw_buf_t * lv_image_decoder_post_process(lv_image_decoder_dsc_t * dsc, lv_d
|
|||||||
uint32_t stride_expect = lv_draw_buf_width_to_stride(decoded->header.w, decoded->header.cf);
|
uint32_t stride_expect = lv_draw_buf_width_to_stride(decoded->header.w, decoded->header.cf);
|
||||||
if(decoded->header.stride != stride_expect) {
|
if(decoded->header.stride != stride_expect) {
|
||||||
LV_LOG_TRACE("Stride mismatch");
|
LV_LOG_TRACE("Stride mismatch");
|
||||||
lv_draw_buf_t * aligned = lv_draw_buf_adjust_stride(decoded, stride_expect);
|
lv_result_t res = lv_draw_buf_adjust_stride(decoded, stride_expect);
|
||||||
if(aligned == NULL) {
|
if(res != LV_RESULT_OK) {
|
||||||
LV_LOG_ERROR("No memory for Stride adjust.");
|
lv_draw_buf_t * aligned = lv_draw_buf_create(decoded->header.w, decoded->header.h, decoded->header.cf, stride_expect);
|
||||||
return NULL;
|
if(aligned == NULL) {
|
||||||
}
|
LV_LOG_ERROR("No memory for Stride adjust.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
decoded = aligned;
|
lv_draw_buf_copy(aligned, NULL, decoded, NULL);
|
||||||
|
decoded = aligned;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
74
tests/src/test_cases/test_draw_buf_stride.c
Normal file
74
tests/src/test_cases/test_draw_buf_stride.c
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#if LV_BUILD_TEST
|
||||||
|
#include "../lvgl.h"
|
||||||
|
|
||||||
|
#include "unity/unity.h"
|
||||||
|
#include "lv_test_helpers.h"
|
||||||
|
|
||||||
|
void setUp(void)
|
||||||
|
{
|
||||||
|
/* Function run before every test */
|
||||||
|
}
|
||||||
|
|
||||||
|
void tearDown(void)
|
||||||
|
{
|
||||||
|
/* Function run after every test */
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_draw_buf_stride_adjust(void)
|
||||||
|
{
|
||||||
|
#if LV_BIN_DECODER_RAM_LOAD == 1
|
||||||
|
const char * img_src = "A:test_images/stride_align64/UNCOMPRESSED/test_ARGB8888.bin";
|
||||||
|
lv_obj_t * img = lv_image_create(lv_screen_active());
|
||||||
|
lv_obj_center(img);
|
||||||
|
lv_image_set_src(img, img_src);
|
||||||
|
TEST_ASSERT_EQUAL_SCREENSHOT("draw/temp.o"); /*Generate the reference image, use .o so git ignore it*/
|
||||||
|
|
||||||
|
lv_image_decoder_args_t args = {
|
||||||
|
.no_cache = false,
|
||||||
|
.premultiply = false,
|
||||||
|
.stride_align = false,
|
||||||
|
.use_indexed = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
lv_image_decoder_dsc_t decoder_dsc;
|
||||||
|
lv_result_t res = lv_image_decoder_open(&decoder_dsc, img_src, &args);
|
||||||
|
TEST_ASSERT_EQUAL(LV_RESULT_OK, res);
|
||||||
|
|
||||||
|
const lv_image_header_t header = decoder_dsc.decoded->header;
|
||||||
|
/*The test image must have aligned stride different with width * bpp*/
|
||||||
|
TEST_ASSERT_NOT_EQUAL(header.w * 4, header.stride);
|
||||||
|
|
||||||
|
lv_draw_buf_t * dup = lv_draw_buf_dup(decoder_dsc.decoded);
|
||||||
|
TEST_ASSERT_NOT_NULL(dup);
|
||||||
|
|
||||||
|
/*Close the decoder since we copied out the decoded draw buffer*/
|
||||||
|
lv_image_decoder_close(&decoder_dsc);
|
||||||
|
|
||||||
|
/* Shrink stride to below minimal stride(by -1 in code below) should fail */
|
||||||
|
res = lv_draw_buf_adjust_stride(dup, header.w * 4 - 1);
|
||||||
|
TEST_ASSERT_EQUAL(LV_RESULT_INVALID, res);
|
||||||
|
|
||||||
|
res = lv_draw_buf_adjust_stride(dup, header.stride + 1);
|
||||||
|
TEST_ASSERT_EQUAL(LV_RESULT_INVALID, res);
|
||||||
|
|
||||||
|
/*Expand the stride should fail if stride is too large that buffer size overflow*/
|
||||||
|
res = lv_draw_buf_adjust_stride(dup, header.stride + 1);
|
||||||
|
TEST_ASSERT_EQUAL(LV_RESULT_INVALID, res);
|
||||||
|
|
||||||
|
/* Expand the stride should work, use a proper stride value should succeed*/
|
||||||
|
res = lv_draw_buf_adjust_stride(dup, (header.stride + header.w * 4) / 2);
|
||||||
|
TEST_ASSERT_EQUAL(LV_RESULT_OK, res);
|
||||||
|
lv_image_set_src(img, dup);
|
||||||
|
TEST_ASSERT_EQUAL_SCREENSHOT("draw/temp.o"); /*The image should still looks same*/
|
||||||
|
|
||||||
|
/* Shrink stride to minimal stride should succeed */
|
||||||
|
res = lv_draw_buf_adjust_stride(dup, header.w * 4);
|
||||||
|
TEST_ASSERT_EQUAL(LV_RESULT_OK, res);
|
||||||
|
lv_image_set_src(img, dup);
|
||||||
|
TEST_ASSERT_EQUAL_SCREENSHOT("draw/temp.o"); /*Test against with above reference image*/
|
||||||
|
|
||||||
|
lv_draw_buf_destroy(dup);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user