mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-24 00:07:03 +08:00
feat(refr): use transform matrix to realize display rotation (#6911)
Signed-off-by: pengyiqiang <pengyiqiang@xiaomi.com> Co-authored-by: pengyiqiang <pengyiqiang@xiaomi.com>
This commit is contained in:
+42
-11
@@ -547,6 +547,11 @@ static void refr_sync_areas(void)
|
||||
* @todo Resize SDL window will trigger crash because of sync_area is larger than disp_area
|
||||
*/
|
||||
lv_area_intersect(sync_area, sync_area, &disp_area);
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
if(lv_display_get_matrix_rotation(disp_refr)) {
|
||||
lv_display_rotate_area(disp_refr, sync_area);
|
||||
}
|
||||
#endif
|
||||
lv_draw_buf_copy(off_screen, sync_area, on_screen, sync_area);
|
||||
}
|
||||
|
||||
@@ -666,23 +671,18 @@ static void refr_area(const lv_area_t * area_p, int32_t y_offset)
|
||||
layer->phy_clip_area = *area_p;
|
||||
layer->partial_y_offset = y_offset;
|
||||
|
||||
if(disp_refr->render_mode == LV_DISPLAY_RENDER_MODE_FULL) {
|
||||
/*In full mode the area is always the full screen, so the buffer area to it too*/
|
||||
layer->buf_area = *area_p;
|
||||
layer_reshape_draw_buf(layer, layer->draw_buf->header.stride);
|
||||
|
||||
}
|
||||
else if(disp_refr->render_mode == LV_DISPLAY_RENDER_MODE_PARTIAL) {
|
||||
if(disp_refr->render_mode == LV_DISPLAY_RENDER_MODE_PARTIAL) {
|
||||
/*In partial mode render this area to the buffer*/
|
||||
layer->buf_area = *area_p;
|
||||
layer_reshape_draw_buf(layer, LV_STRIDE_AUTO);
|
||||
}
|
||||
else if(disp_refr->render_mode == LV_DISPLAY_RENDER_MODE_DIRECT) {
|
||||
/*In direct mode the the buffer area is always the whole screen*/
|
||||
else if(disp_refr->render_mode == LV_DISPLAY_RENDER_MODE_DIRECT ||
|
||||
disp_refr->render_mode == LV_DISPLAY_RENDER_MODE_FULL) {
|
||||
/*In direct mode and full mode the the buffer area is always the whole screen, not considering rotation*/
|
||||
layer->buf_area.x1 = 0;
|
||||
layer->buf_area.y1 = 0;
|
||||
layer->buf_area.x2 = lv_display_get_horizontal_resolution(disp_refr) - 1;
|
||||
layer->buf_area.y2 = lv_display_get_vertical_resolution(disp_refr) - 1;
|
||||
layer->buf_area.x2 = lv_display_get_original_horizontal_resolution(disp_refr) - 1;
|
||||
layer->buf_area.y2 = lv_display_get_original_vertical_resolution(disp_refr) - 1;
|
||||
layer_reshape_draw_buf(layer, layer->draw_buf->header.stride);
|
||||
}
|
||||
|
||||
@@ -767,6 +767,37 @@ static void refr_configured_layer(lv_layer_t * layer)
|
||||
|
||||
lv_layer_reset(layer);
|
||||
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
if(lv_display_get_matrix_rotation(disp_refr)) {
|
||||
const lv_display_rotation_t rotation = lv_display_get_rotation(disp_refr);
|
||||
if(rotation != LV_DISPLAY_ROTATION_0) {
|
||||
lv_display_rotate_area(disp_refr, &layer->phy_clip_area);
|
||||
|
||||
/* The screen rotation direction defined by LVGL is opposite to the drawing angle */
|
||||
switch(rotation) {
|
||||
case LV_DISPLAY_ROTATION_90:
|
||||
lv_matrix_rotate(&layer->matrix, 270);
|
||||
lv_matrix_translate(&layer->matrix, -disp_refr->ver_res, 0);
|
||||
break;
|
||||
|
||||
case LV_DISPLAY_ROTATION_180:
|
||||
lv_matrix_rotate(&layer->matrix, 180);
|
||||
lv_matrix_translate(&layer->matrix, -disp_refr->hor_res, -disp_refr->ver_res);
|
||||
break;
|
||||
|
||||
case LV_DISPLAY_ROTATION_270:
|
||||
lv_matrix_rotate(&layer->matrix, 90);
|
||||
lv_matrix_translate(&layer->matrix, 0, -disp_refr->hor_res);
|
||||
break;
|
||||
|
||||
default:
|
||||
LV_LOG_WARN("Invalid rotation: %d", rotation);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* LV_DRAW_TRANSFORM_USE_MATRIX */
|
||||
|
||||
/* In single buffered mode wait here until the buffer is freed.
|
||||
* Else we would draw into the buffer while it's still being transferred to the display*/
|
||||
if(!lv_display_is_double_buffered(disp_refr)) {
|
||||
|
||||
@@ -322,6 +322,26 @@ int32_t lv_display_get_vertical_resolution(const lv_display_t * disp)
|
||||
}
|
||||
}
|
||||
|
||||
int32_t lv_display_get_original_horizontal_resolution(const lv_display_t * disp)
|
||||
{
|
||||
if(disp == NULL) disp = lv_display_get_default();
|
||||
if(disp == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return disp->hor_res;
|
||||
}
|
||||
|
||||
int32_t lv_display_get_original_vertical_resolution(const lv_display_t * disp)
|
||||
{
|
||||
if(disp == NULL) disp = lv_display_get_default();
|
||||
if(disp == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return disp->ver_res;
|
||||
}
|
||||
|
||||
int32_t lv_display_get_physical_horizontal_resolution(const lv_display_t * disp)
|
||||
{
|
||||
if(disp == NULL) disp = lv_display_get_default();
|
||||
@@ -426,9 +446,8 @@ void lv_display_set_buffers(lv_display_t * disp, void * buf1, void * buf2, uint3
|
||||
{
|
||||
LV_ASSERT_MSG(buf1 != NULL, "Null buffer");
|
||||
lv_color_format_t cf = lv_display_get_color_format(disp);
|
||||
uint32_t w = lv_display_get_horizontal_resolution(disp);
|
||||
uint32_t h = lv_display_get_vertical_resolution(disp);
|
||||
|
||||
uint32_t w = lv_display_get_original_horizontal_resolution(disp);
|
||||
uint32_t h = lv_display_get_original_vertical_resolution(disp);
|
||||
LV_ASSERT_MSG(w != 0 && h != 0, "display resolution is 0");
|
||||
|
||||
/* buf1 or buf2 is not aligned according to LV_DRAW_BUF_ALIGN */
|
||||
@@ -457,8 +476,8 @@ void lv_display_set_buffers_with_stride(lv_display_t * disp, void * buf1, void *
|
||||
{
|
||||
LV_ASSERT_MSG(buf1 != NULL, "Null buffer");
|
||||
lv_color_format_t cf = lv_display_get_color_format(disp);
|
||||
uint32_t w = lv_display_get_horizontal_resolution(disp);
|
||||
uint32_t h = lv_display_get_vertical_resolution(disp);
|
||||
uint32_t w = lv_display_get_original_horizontal_resolution(disp);
|
||||
uint32_t h = lv_display_get_original_vertical_resolution(disp);
|
||||
LV_ASSERT_MSG(w != 0 && h != 0, "display resolution is 0");
|
||||
|
||||
if(render_mode == LV_DISPLAY_RENDER_MODE_PARTIAL) {
|
||||
@@ -874,6 +893,32 @@ lv_display_rotation_t lv_display_get_rotation(lv_display_t * disp)
|
||||
return disp->rotation;
|
||||
}
|
||||
|
||||
void lv_display_set_matrix_rotation(lv_display_t * disp, bool enable)
|
||||
{
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
if(disp == NULL) disp = lv_display_get_default();
|
||||
if(disp == NULL) return;
|
||||
|
||||
if(!(disp->render_mode == LV_DISPLAY_RENDER_MODE_DIRECT || disp->render_mode == LV_DISPLAY_RENDER_MODE_FULL)) {
|
||||
LV_LOG_WARN("Unsupported rendering mode: %d", disp->render_mode);
|
||||
return;
|
||||
}
|
||||
|
||||
disp->matrix_rotation = enable;
|
||||
#else
|
||||
(void)disp;
|
||||
(void)enable;
|
||||
LV_LOG_WARN("LV_DRAW_TRANSFORM_USE_MATRIX was not enabled");
|
||||
#endif
|
||||
}
|
||||
|
||||
bool lv_display_get_matrix_rotation(lv_display_t * disp)
|
||||
{
|
||||
if(disp == NULL) disp = lv_display_get_default();
|
||||
if(disp == NULL) return false;
|
||||
return disp->matrix_rotation;
|
||||
}
|
||||
|
||||
void lv_display_set_theme(lv_display_t * disp, lv_theme_t * th)
|
||||
{
|
||||
if(!disp) disp = lv_display_get_default();
|
||||
@@ -1048,12 +1093,12 @@ void lv_display_rotate_area(lv_display_t * disp, lv_area_t * area)
|
||||
{
|
||||
lv_display_rotation_t rotation = lv_display_get_rotation(disp);
|
||||
|
||||
if(rotation == LV_DISPLAY_ROTATION_0) return;
|
||||
|
||||
int32_t w = lv_area_get_width(area);
|
||||
int32_t h = lv_area_get_height(area);
|
||||
|
||||
switch(rotation) {
|
||||
case LV_DISPLAY_ROTATION_0:
|
||||
return;
|
||||
case LV_DISPLAY_ROTATION_90:
|
||||
area->y2 = disp->ver_res - area->x1 - 1;
|
||||
area->x1 = area->y1;
|
||||
@@ -1072,6 +1117,8 @@ void lv_display_rotate_area(lv_display_t * disp, lv_area_t * area)
|
||||
area->x2 = area->x1 + h - 1;
|
||||
area->y1 = area->y2 - w + 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -158,6 +158,13 @@ void lv_display_set_offset(lv_display_t * disp, int32_t x, int32_t y);
|
||||
*/
|
||||
void lv_display_set_rotation(lv_display_t * disp, lv_display_rotation_t rotation);
|
||||
|
||||
/**
|
||||
* Use matrix rotation for the display. This function is depended on `LV_DRAW_TRANSFORM_USE_MATRIX`
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @param enable true: enable matrix rotation, false: disable
|
||||
*/
|
||||
void lv_display_set_matrix_rotation(lv_display_t * disp, bool enable);
|
||||
|
||||
/**
|
||||
* Set the DPI (dot per inch) of the display.
|
||||
* dpi = sqrt(hor_res^2 + ver_res^2) / diagonal"
|
||||
@@ -180,6 +187,20 @@ int32_t lv_display_get_horizontal_resolution(const lv_display_t * disp);
|
||||
*/
|
||||
int32_t lv_display_get_vertical_resolution(const lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Get the original horizontal resolution of a display without considering rotation
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @return the horizontal resolution of the display.
|
||||
*/
|
||||
int32_t lv_display_get_original_horizontal_resolution(const lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Get the original vertical resolution of a display without considering rotation
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @return the vertical resolution of the display
|
||||
*/
|
||||
int32_t lv_display_get_original_vertical_resolution(const lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Get the physical horizontal resolution of a display
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
@@ -215,6 +236,13 @@ int32_t lv_display_get_offset_y(const lv_display_t * disp);
|
||||
*/
|
||||
lv_display_rotation_t lv_display_get_rotation(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Get if matrix rotation is enabled for a display or not
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
* @return true: matrix rotation is enabled; false: disabled
|
||||
*/
|
||||
bool lv_display_get_matrix_rotation(lv_display_t * disp);
|
||||
|
||||
/**
|
||||
* Get the DPI of the display
|
||||
* @param disp pointer to a display (NULL to use the default display)
|
||||
|
||||
@@ -145,6 +145,8 @@ struct _lv_display_t {
|
||||
|
||||
uint32_t rotation : 3; /**< Element of lv_display_rotation_t*/
|
||||
|
||||
uint32_t matrix_rotation : 1; /**< 1: Use matrix for display rotation*/
|
||||
|
||||
lv_theme_t * theme; /**< The theme assigned to the screen*/
|
||||
|
||||
/** A timer which periodically checks the dirty areas and refreshes them*/
|
||||
|
||||
@@ -75,8 +75,8 @@ static void buf_changed_event_cb(lv_event_t * e)
|
||||
{
|
||||
lv_display_t * disp = lv_event_get_target(e);
|
||||
lv_color_format_t cf = lv_display_get_color_format(disp);
|
||||
int32_t hor_res = lv_display_get_horizontal_resolution(disp);
|
||||
int32_t ver_res = lv_display_get_vertical_resolution(disp);
|
||||
int32_t hor_res = lv_display_get_original_horizontal_resolution(disp);
|
||||
int32_t ver_res = lv_display_get_original_vertical_resolution(disp);
|
||||
|
||||
free(_state.draw_buf.unaligned_data);
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.0 KiB |
@@ -2,6 +2,9 @@
|
||||
#include "../lvgl.h"
|
||||
#include "unity/unity.h"
|
||||
|
||||
/*Bypassing resolution check*/
|
||||
#define TEST_DISPLAY_ASSERT_EQUAL_SCREENSHOT(path) TEST_ASSERT_MESSAGE(lv_test_screenshot_compare(path), path);
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
/* Function run before every test */
|
||||
@@ -9,7 +12,8 @@ void setUp(void)
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
/* Function run after every test */
|
||||
lv_display_set_matrix_rotation(NULL, false);
|
||||
lv_obj_clean(lv_screen_active());
|
||||
}
|
||||
|
||||
struct display_area_test_set {
|
||||
@@ -36,6 +40,7 @@ void test_get_drawbuf_size_double_buffered(void)
|
||||
LV_COLOR_FORMAT_RGB888), 200, LV_DISPLAY_RENDER_MODE_PARTIAL);
|
||||
|
||||
TEST_ASSERT_EQUAL(200, lv_display_get_draw_buf_size(disp));
|
||||
lv_display_delete(disp);
|
||||
}
|
||||
|
||||
void test_get_drawbuf_size_single_buffered(void)
|
||||
@@ -49,6 +54,7 @@ void test_get_drawbuf_size_single_buffered(void)
|
||||
LV_DISPLAY_RENDER_MODE_PARTIAL);
|
||||
|
||||
TEST_ASSERT_EQUAL(200, lv_display_get_draw_buf_size(disp));
|
||||
lv_display_delete(disp);
|
||||
}
|
||||
|
||||
static void exec_invalidated_drawbuf_size_test(const struct display_area_test_set * test_set)
|
||||
@@ -126,5 +132,41 @@ void test_get_invalidated_drawbuf_size_i1_partial()
|
||||
exec_invalidated_drawbuf_size_test(&test_set);
|
||||
}
|
||||
|
||||
void test_display_matrix_rotation(void)
|
||||
{
|
||||
#if LV_DRAW_TRANSFORM_USE_MATRIX
|
||||
lv_obj_t * obj = lv_obj_create(lv_screen_active());
|
||||
lv_obj_set_size(obj, 300, 200);
|
||||
lv_obj_set_pos(obj, 30, 20);
|
||||
lv_obj_t * label = lv_label_create(obj);
|
||||
|
||||
lv_display_t * disp = lv_obj_get_display(obj);
|
||||
lv_display_set_matrix_rotation(disp, true);
|
||||
TEST_ASSERT_TRUE(lv_display_get_matrix_rotation(disp));
|
||||
|
||||
lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_0);
|
||||
lv_label_set_text(label, "Rotation: 0 degrees");
|
||||
TEST_DISPLAY_ASSERT_EQUAL_SCREENSHOT("display_matrix_rotation_0.png");
|
||||
|
||||
lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_90);
|
||||
lv_label_set_text(label, "Rotation: 90 degrees");
|
||||
TEST_DISPLAY_ASSERT_EQUAL_SCREENSHOT("display_matrix_rotation_90.png");
|
||||
|
||||
lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_180);
|
||||
lv_label_set_text(label, "Rotation: 180 degrees");
|
||||
TEST_DISPLAY_ASSERT_EQUAL_SCREENSHOT("display_matrix_rotation_180.png");
|
||||
|
||||
lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_270);
|
||||
lv_label_set_text(label, "Rotation: 270 degrees");
|
||||
TEST_DISPLAY_ASSERT_EQUAL_SCREENSHOT("display_matrix_rotation_270.png");
|
||||
|
||||
lv_display_set_matrix_rotation(disp, false);
|
||||
lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_0);
|
||||
lv_label_set_text(label, "Rotation: 0 degrees");
|
||||
TEST_DISPLAY_ASSERT_EQUAL_SCREENSHOT("display_matrix_rotation_0.png");
|
||||
#else
|
||||
TEST_PASS();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user