fix(sdl): add transformation support for the SDL backend (#3403)

* sdl transform wip

* sdl transform wip

* working transform (scale, rotate)

* fixed transform with masks

* fixing includes

* removed lv_obj_t references in draw backend

* update the API to work with SW layers too

* update lv_conf_internal.h

* makefile fixes

* updated sdl transform implementation

Co-authored-by: Gabor Kiss-Vamosi <kisvegabor@gmail.com>
This commit is contained in:
Mariotaku 2022-06-15 17:36:47 +09:00 committed by GitHub
parent ca9aff6119
commit f575935180
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 749 additions and 174 deletions

View File

@ -125,8 +125,6 @@
* and blend it as an image with the given opacity.
* Note that `bg_opa`, `text_opa` etc don't require buffering into layer)
* The widget can be buffered in smaller chunks to avoid using large buffers.
* `draw_area` (`lv_area_t` meaning the area to draw and `px_size` (size of a pixel in bytes)
* can be used the set the buffer size adaptively.
*
* - LV_LAYER_SIMPLE_BUF_SIZE: [bytes] the optimal target buffer size. LVGL will try to allocate it
* - LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE: [bytes] used if `LV_LAYER_SIMPLE_BUF_SIZE` couldn't be allocated.
@ -136,7 +134,7 @@
* and can't be drawn in chunks. So these settings affects only widgets with opacity.
*/
#define LV_LAYER_SIMPLE_BUF_SIZE (24 * 1024)
#define LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE LV_MAX(lv_area_get_width(&draw_area) * px_size, 2048)
#define LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE (3 * 1024)
/*Default image cache size. Image caching keeps the images opened.
*If only the built-in image formats are used there is no real advantage of caching. (I.e. if no new image decoder is added)

View File

@ -812,204 +812,159 @@ static void refr_obj_and_children(lv_draw_ctx_t * draw_ctx, lv_obj_t * top_obj)
}
}
static lv_res_t layer_get_area(lv_draw_ctx_t * draw_ctx, lv_obj_t * obj, lv_layer_type_t layer_type,
lv_area_t * layer_area_out)
{
lv_coord_t ext_draw_size = _lv_obj_get_ext_draw_size(obj);
lv_area_t obj_coords_ext;
lv_obj_get_coords(obj, &obj_coords_ext);
lv_area_increase(&obj_coords_ext, ext_draw_size, ext_draw_size);
if(layer_type == LV_LAYER_TYPE_TRANSFORM) {
/*Get the transformed area and clip it to the current clip area.
*This area needs to be updated on the screen.*/
lv_area_t clip_coords_for_obj;
lv_area_t tranf_coords = obj_coords_ext;
lv_obj_get_transformed_area(obj, &tranf_coords, false, false);
if(!_lv_area_intersect(&clip_coords_for_obj, draw_ctx->clip_area, &tranf_coords)) {
return LV_RES_INV;
}
/*Transform back (inverse) the transformed area.
*It will tell which area of the non-transformed widget needs to be redrawn
*in order to cover transformed area after transformation.*/
lv_area_t inverse_clip_coords_for_obj = clip_coords_for_obj;
lv_obj_get_transformed_area(obj, &inverse_clip_coords_for_obj, false, true);
if(!_lv_area_intersect(&inverse_clip_coords_for_obj, &inverse_clip_coords_for_obj, &obj_coords_ext)) {
return LV_RES_INV;
}
*layer_area_out = inverse_clip_coords_for_obj;
}
else if(layer_type == LV_LAYER_TYPE_SIMPLE) {
lv_area_t clip_coords_for_obj;
if(!_lv_area_intersect(&clip_coords_for_obj, draw_ctx->clip_area, &obj_coords_ext)) {
return LV_RES_INV;
}
*layer_area_out = clip_coords_for_obj;
}
else {
LV_LOG_WARN("Unhandled intermediate layer type");
return LV_RES_INV;
}
return LV_RES_OK;
}
static void layer_alpha_test(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * layer_ctx,
lv_draw_layer_flags_t flags)
{
bool has_alpha;
/*If globally the layer has alpha maybe this smaller section has not (e.g. not on a rounded corner)
*If turns out that this section has no alpha renderer can choose faster algorithms*/
if(flags & LV_DRAW_LAYER_FLAG_HAS_ALPHA) {
/*Test for alpha by assuming there is no alpha. If it fails, fall back to rendering with alpha*/
has_alpha = true;
if(_lv_area_is_in(&layer_ctx->area_act, &obj->coords, 0)) {
lv_cover_check_info_t info;
info.res = LV_COVER_RES_COVER;
info.area = &layer_ctx->area_act;
lv_event_send(obj, LV_EVENT_COVER_CHECK, &info);
if(info.res == LV_COVER_RES_COVER) has_alpha = false;
}
if(has_alpha) {
layer_ctx->area_act.y2 = layer_ctx->area_act.y1 + layer_ctx->max_row_with_alpha - 1;
}
}
else {
has_alpha = false;
}
if(layer_ctx->area_act.y2 > layer_ctx->area_full.y2) layer_ctx->area_act.y2 = layer_ctx->area_full.y2;
lv_draw_layer_adjust(draw_ctx, layer_ctx, has_alpha ? LV_DRAW_LAYER_FLAG_HAS_ALPHA : LV_DRAW_LAYER_FLAG_NONE);
}
void refr_obj(lv_draw_ctx_t * draw_ctx, lv_obj_t * obj)
{
/*Do not refresh hidden objects*/
if(lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN)) return;
lv_layer_type_t inlayer = _lv_obj_get_layer_type(obj);
if(inlayer == LV_LAYER_TYPE_NONE) {
lv_layer_type_t layer_type = _lv_obj_get_layer_type(obj);
if(layer_type == LV_LAYER_TYPE_NONE) {
lv_obj_redraw(draw_ctx, obj);
}
else {
lv_opa_t opa = lv_obj_get_style_opa(obj, 0);
if(opa < LV_OPA_MIN) return;
lv_area_t draw_area;
const lv_area_t * clip_area_ori = draw_ctx->clip_area;
lv_coord_t ext_draw_size = _lv_obj_get_ext_draw_size(obj);
lv_area_t obj_coords_ext;
lv_obj_get_coords(obj, &obj_coords_ext);
lv_area_increase(&obj_coords_ext, ext_draw_size, ext_draw_size);
uint32_t buf_size_sub;
lv_area_t layer_area_full;
lv_res_t res = layer_get_area(draw_ctx, obj, layer_type, &layer_area_full);
if(res != LV_RES_OK) return;
if(inlayer == LV_LAYER_TYPE_TRANSFORM) {
lv_area_t clip_coords_for_obj;
lv_area_t tranf_coords = obj_coords_ext;
lv_obj_get_transformed_area(obj, &tranf_coords, false, false);
if(!_lv_area_intersect(&clip_coords_for_obj, clip_area_ori, &tranf_coords)) {
return;
}
lv_draw_layer_flags_t flags = LV_DRAW_LAYER_FLAG_HAS_ALPHA;
lv_area_t inverse_clip_coords_for_obj = clip_coords_for_obj;
lv_obj_get_transformed_area(obj, &inverse_clip_coords_for_obj, false, true);
if(!_lv_area_intersect(&inverse_clip_coords_for_obj, &inverse_clip_coords_for_obj, &obj_coords_ext)) {
return;
}
draw_area = inverse_clip_coords_for_obj;
}
else if(inlayer == LV_LAYER_TYPE_SIMPLE) {
lv_area_t clip_coords_for_obj;
if(!_lv_area_intersect(&clip_coords_for_obj, clip_area_ori, &obj_coords_ext)) {
return;
}
draw_area = clip_coords_for_obj;
}
else {
LV_LOG_WARN("Unhandled intermediate layer type");
return;
}
bool full_cover = false;
if(_lv_area_is_in(&draw_area, &obj->coords, 0)) {
if(_lv_area_is_in(&layer_area_full, &obj->coords, 0)) {
lv_cover_check_info_t info;
info.res = LV_COVER_RES_COVER;
info.area = &draw_area;
info.area = &layer_area_full;
lv_event_send(obj, LV_EVENT_COVER_CHECK, &info);
if(info.res == LV_COVER_RES_COVER) full_cover = true;
if(info.res == LV_COVER_RES_COVER) flags &= ~LV_DRAW_LAYER_FLAG_HAS_ALPHA;
}
if(LV_COLOR_SCREEN_TRANSP == 0 && !full_cover) {
LV_LOG_WARN("Rendering this widget needs LV_COLOR_SCREEN_TRANSP 1");
if(layer_type == LV_LAYER_TYPE_SIMPLE) flags |= LV_DRAW_LAYER_FLAG_CAN_SUBDIVIDE;
lv_draw_layer_ctx_t * layer_ctx = lv_draw_layer_create(draw_ctx, &layer_area_full, flags);
if(layer_ctx == NULL) {
LV_LOG_WARN("Couldn't create a new layer context");
return;
}
uint32_t px_size = full_cover ? sizeof(lv_color_t) : LV_IMG_PX_SIZE_ALPHA_BYTE;
if(inlayer == LV_LAYER_TYPE_SIMPLE) {
buf_size_sub = LV_LAYER_SIMPLE_BUF_SIZE;
}
else {
buf_size_sub = lv_area_get_size(&draw_area) * px_size;
}
uint32_t buf_size_full = lv_area_get_size(&draw_area) * px_size;
if(buf_size_sub > buf_size_full) buf_size_sub = buf_size_full;
uint8_t * layer_buf = lv_mem_alloc(buf_size_sub);
/*Try again with a smaller buf size*/
if(inlayer == LV_LAYER_TYPE_SIMPLE) {
if(layer_buf == NULL) {
LV_LOG_WARN("Cannot allocate %"LV_PRIu32" bytes for layer buffer. Allocating %"LV_PRIu32" bytes instead. (Reduced performance)",
(uint32_t)buf_size_sub * px_size, (uint32_t)LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE * px_size);
buf_size_sub = LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE;
if(buf_size_sub > buf_size_full) buf_size_sub = buf_size_full;
layer_buf = lv_mem_alloc(buf_size_sub);
}
}
if(layer_buf == NULL) {
LV_LOG_ERROR("Out of memory: couldn't allocate %"LV_PRIu32" bytes for layer buffer.", (uint32_t)buf_size_sub * px_size);
LV_ASSERT_MALLOC(layer_buf);
return;
}
int32_t row_cnt = 0;
lv_draw_ctx_t * new_draw_ctx = lv_mem_alloc(disp_refr->driver->draw_ctx_size);
LV_ASSERT_MALLOC(new_draw_ctx);
if(new_draw_ctx == NULL) {
LV_LOG_ERROR("Out of memory: couldn't allocate new draw context.");
lv_mem_free(layer_buf);
return;
}
lv_area_t draw_area_sub = draw_area;
/*Set-up a new draw_ctx*/
bool old_scr_transp = disp_refr->driver->screen_transp;
disp_refr->driver->draw_ctx_init(disp_refr->driver, new_draw_ctx);
new_draw_ctx->clip_area = &draw_area_sub;
new_draw_ctx->buf_area = &draw_area_sub;
new_draw_ctx->buf = (void *)layer_buf;
lv_point_t pivot = {
.x = lv_obj_get_style_transform_pivot_x(obj, 0),
.y = lv_obj_get_style_transform_pivot_y(obj, 0)
};
lv_draw_img_dsc_t draw_dsc;
lv_draw_img_dsc_init(&draw_dsc);
draw_dsc.opa = opa;
draw_dsc.angle = lv_obj_get_style_transform_angle(obj, 0);
if(draw_dsc.angle > 3600) draw_dsc.angle -= 3600;
if(draw_dsc.angle < 0) draw_dsc.angle += 3600;
else if(draw_dsc.angle < 0) draw_dsc.angle += 3600;
draw_dsc.zoom = lv_obj_get_style_transform_zoom(obj, 0);
draw_dsc.blend_mode = lv_obj_get_style_blend_mode(obj, 0);
draw_dsc.antialias = disp_refr->driver->antialiasing;
lv_point_t pivot;
pivot.x = lv_obj_get_style_transform_pivot_x(obj, 0);
pivot.y = lv_obj_get_style_transform_pivot_y(obj, 0);
lv_img_dsc_t img;
img.data = layer_buf;
img.header.always_zero = 0;
img.header.w = lv_area_get_width(&draw_area);
/*If the whole area is covers calculate the row count only once*/
if(full_cover) {
row_cnt = buf_size_sub / (sizeof(lv_color_t) * lv_area_get_width(&draw_area));
draw_area_sub.y2 = draw_area_sub.y1 + row_cnt - 1;
if(draw_area_sub.y2 > draw_area.y2) draw_area_sub.y2 = draw_area.y2;
if(flags & LV_DRAW_LAYER_FLAG_CAN_SUBDIVIDE) {
layer_ctx->area_act = layer_ctx->area_full;
layer_ctx->area_act.y2 = layer_ctx->area_act.y1 + layer_ctx->max_row_with_no_alpha - 1;
if(layer_ctx->area_act.y2 > layer_ctx->area_full.y2) layer_ctx->area_act.y2 = layer_ctx->area_full.y2;
}
while(draw_area_sub.y1 <= draw_area.y2) {
/* If the widget covers the area of as many rows as an RGB buffer provides,
* draw it as RGB instead of ARGB because it's much faster
* `full_cover_global == true` indicates that the widget covers the whole draw_area anyway*/
if(!full_cover) {
row_cnt = buf_size_sub / (sizeof(lv_color_t) * lv_area_get_width(&draw_area));
while(layer_ctx->area_act.y1 <= layer_area_full.y2) {
if(flags & LV_DRAW_LAYER_FLAG_CAN_SUBDIVIDE) {
layer_alpha_test(obj, draw_ctx, layer_ctx, flags);
}
draw_area_sub.y2 = draw_area_sub.y1 + row_cnt - 1;
if(draw_area_sub.y2 > draw_area.y2) draw_area_sub.y2 = draw_area.y2;
lv_obj_redraw(draw_ctx, obj);
bool full_cover_sub = false;
if(_lv_area_is_in(&draw_area_sub, &obj->coords, 0)) {
lv_cover_check_info_t info;
info.res = LV_COVER_RES_COVER;
info.area = &draw_area_sub;
lv_event_send(obj, LV_EVENT_COVER_CHECK, &info);
if(info.res == LV_COVER_RES_COVER) full_cover_sub = true;
}
draw_dsc.pivot.x = obj->coords.x1 + pivot.x - draw_ctx->buf_area->x1;
draw_dsc.pivot.y = obj->coords.y1 + pivot.y - draw_ctx->buf_area->y1;
/* In the area is not covered by the widget recalculate the row count using ARGB pixel size
* It can happen that this smaller area is already covered by the widget but ignore this case
* in favor of fewer LV_EVENT_COVER_CHECK calls */
if(!full_cover_sub) {
row_cnt = buf_size_sub / (LV_IMG_PX_SIZE_ALPHA_BYTE * lv_area_get_width(&draw_area));
draw_area_sub.y2 = draw_area_sub.y1 + row_cnt - 1;
if(draw_area_sub.y2 > draw_area.y2) draw_area_sub.y2 = draw_area.y2;
disp_refr->driver->screen_transp = 1;
img.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
}
else {
disp_refr->driver->screen_transp = 0;
img.header.cf = LV_IMG_CF_TRUE_COLOR;
}
/*With LV_DRAW_LAYER_FLAG_CAN_SUBDIVIDE it should also go the next chunk*/
lv_draw_layer_blend(draw_ctx, layer_ctx, &draw_dsc);
draw_dsc.pivot.x = obj->coords.x1 + pivot.x - draw_area_sub.x1;
draw_dsc.pivot.y = obj->coords.y1 + pivot.y - draw_area_sub.y1;
if((flags & LV_DRAW_LAYER_FLAG_CAN_SUBDIVIDE) == 0) break;
if(!full_cover_sub) lv_memset_00(layer_buf, buf_size_sub);
lv_obj_redraw(new_draw_ctx, obj);
lv_img_cache_invalidate_src(&img);
img.header.h = lv_area_get_height(&draw_area_sub);
disp_refr->driver->screen_transp = old_scr_transp;
lv_draw_img(draw_ctx, &draw_dsc, &draw_area_sub, &img);
draw_area_sub.y1 = draw_area_sub.y2 + 1;
if(draw_area_sub.y2 > draw_area.y2) draw_area_sub.y2 = draw_area.y2;
lv_area_move(&layer_ctx->area_act, 0, layer_ctx->max_row_with_no_alpha);
}
disp_refr->driver->draw_ctx_deinit(disp_refr->driver, new_draw_ctx);
lv_mem_free(layer_buf);
lv_mem_free(new_draw_ctx);
disp_refr->driver->screen_transp = old_scr_transp;
lv_draw_layer_destroy(draw_ctx, layer_ctx);
}
}
static uint32_t get_max_row(lv_disp_t * disp, lv_coord_t area_w, lv_coord_t area_h)
{
int32_t max_row = (uint32_t)disp->driver->draw_buf->size / area_w;

View File

@ -42,6 +42,11 @@ void lv_draw_init(void)
/*Nothing to init now*/
}
void lv_draw_wait_for_finish(lv_draw_ctx_t * draw_ctx)
{
if(draw_ctx->wait_for_finish) draw_ctx->wait_for_finish(draw_ctx);
}
/**********************
* STATIC FUNCTIONS
**********************/

View File

@ -28,6 +28,7 @@ extern "C" {
#include "lv_draw_arc.h"
#include "lv_draw_mask.h"
#include "lv_draw_transform.h"
#include "lv_draw_layer.h"
/*********************
* DEFINES
@ -41,6 +42,19 @@ typedef struct {
void * user_data;
} lv_draw_mask_t;
typedef struct _lv_draw_layer_ctx_t {
lv_area_t area_full;
lv_area_t area_act;
lv_coord_t max_row_with_alpha;
lv_coord_t max_row_with_no_alpha;
void * buf;
struct {
const lv_area_t * clip_area;
lv_area_t * buf_area;
void * buf;
bool screen_transp;
} original;
} lv_draw_layer_ctx_t;
typedef struct _lv_draw_ctx_t {
/**
@ -126,6 +140,50 @@ typedef struct _lv_draw_ctx_t {
void (*buffer_copy)(struct _lv_draw_ctx_t * draw_ctx, void * dest_buf, lv_coord_t dest_stride,
const lv_area_t * dest_area,
void * src_buf, lv_coord_t src_stride, const lv_area_t * src_area);
/**
* Initialize a new layer context.
* The original buffer and area data are already saved from `draw_ctx` to `layer_ctx`
* @param draw_ctx pointer to the current draw context
* @param layer_area the coordinates of the layer
* @param flags OR-ed flags from @lv_draw_layer_flags_t
* @return pointer to the layer context, or NULL on error
*/
struct _lv_draw_layer_ctx_t * (*layer_init)(struct _lv_draw_ctx_t * draw_ctx, struct _lv_draw_layer_ctx_t * layer_ctx,
lv_draw_layer_flags_t flags);
/**
* Adjust the layer_ctx and/or draw_ctx based on the `layer_ctx->area_act`.
* It's called only if flags has `LV_DRAW_LAYER_FLAG_CAN_SUBDIVIDE`
* @param draw_ctx pointer to the current draw context
* @param layer_ctx pointer to a layer context
* @param flags OR-ed flags from @lv_draw_layer_flags_t
*/
void (*layer_adjust)(struct _lv_draw_ctx_t * draw_ctx, struct _lv_draw_layer_ctx_t * layer_ctx,
lv_draw_layer_flags_t flags);
/**
* Blend a rendered layer to `layer_ctx->area_act`
* @param draw_ctx pointer to the current draw context
* @param layer_ctx pointer to a layer context
* @param draw_dsc pointer to an image draw descriptor
*/
void (*layer_blend)(struct _lv_draw_ctx_t * draw_ctx, struct _lv_draw_layer_ctx_t * layer_ctx,
const lv_draw_img_dsc_t * draw_dsc);
/**
* Destroy a layer context. The original buffer and area data of the `draw_ctx` will be restored
* and the `layer_ctx` itself will be freed automatically.
* @param draw_ctx pointer to the current draw context
* @param layer_ctx pointer to a layer context
*/
void (*layer_destroy)(struct _lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * layer_ctx);
/**
* Size of a layer context in bytes.
*/
size_t layer_instance_size;
#if LV_USE_USER_DATA
void * user_data;
#endif
@ -138,6 +196,9 @@ typedef struct _lv_draw_ctx_t {
void lv_draw_init(void);
void lv_draw_wait_for_finish(lv_draw_ctx_t * draw_ctx);
/**********************
* GLOBAL VARIABLES
**********************/

View File

@ -6,6 +6,7 @@ CSRCS += lv_draw_line.c
CSRCS += lv_draw_mask.c
CSRCS += lv_draw_rect.c
CSRCS += lv_draw_transform.c
CSRCS += lv_draw_layer.c
CSRCS += lv_draw_triangle.c
CSRCS += lv_img_buf.c
CSRCS += lv_img_cache.c

89
src/draw/lv_draw_layer.c Normal file
View File

@ -0,0 +1,89 @@
/**
* @file lv_draw_layer.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw.h"
#include "lv_draw_arc.h"
#include "../core/lv_refr.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_draw_layer_ctx_t * lv_draw_layer_create(lv_draw_ctx_t * draw_ctx, const lv_area_t * layer_area,
lv_draw_layer_flags_t flags)
{
if(draw_ctx->layer_init == NULL) return NULL;
lv_draw_layer_ctx_t * layer_ctx = lv_mem_alloc(draw_ctx->layer_instance_size);
LV_ASSERT_MALLOC(layer_ctx);
if(layer_ctx == NULL) {
LV_LOG_WARN("Couldn't allocate a new layer context");
return NULL;
}
lv_memset_00(layer_ctx, draw_ctx->layer_instance_size);
lv_disp_t * disp_refr = _lv_refr_get_disp_refreshing();
layer_ctx->original.buf = draw_ctx->buf;
layer_ctx->original.buf_area = draw_ctx->buf_area;
layer_ctx->original.clip_area = draw_ctx->clip_area;
layer_ctx->original.screen_transp = disp_refr->driver->screen_transp;
layer_ctx->area_full = *layer_area;
return draw_ctx->layer_init(draw_ctx, layer_ctx, flags);
}
void lv_draw_layer_adjust(struct _lv_draw_ctx_t * draw_ctx, struct _lv_draw_layer_ctx_t * layer_ctx,
lv_draw_layer_flags_t flags)
{
if(draw_ctx->layer_adjust) draw_ctx->layer_adjust(draw_ctx, layer_ctx, flags);
}
void lv_draw_layer_blend(struct _lv_draw_ctx_t * draw_ctx, struct _lv_draw_layer_ctx_t * layer_ctx,
lv_draw_img_dsc_t * draw_dsc)
{
if(draw_ctx->layer_blend) draw_ctx->layer_blend(draw_ctx, layer_ctx, draw_dsc);
}
void lv_draw_layer_destroy(lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * layer_ctx)
{
lv_draw_wait_for_finish(draw_ctx);
draw_ctx->buf = layer_ctx->original.buf;
draw_ctx->buf_area = layer_ctx->original.buf_area;
draw_ctx->clip_area = layer_ctx->original.clip_area;
lv_disp_t * disp_refr = _lv_refr_get_disp_refreshing();
disp_refr->driver->screen_transp = layer_ctx->original.screen_transp;
if(draw_ctx->layer_destroy) draw_ctx->layer_destroy(draw_ctx, layer_ctx);
lv_mem_free(layer_ctx);
}
/**********************
* STATIC FUNCTIONS
**********************/

83
src/draw/lv_draw_layer.h Normal file
View File

@ -0,0 +1,83 @@
/**
* @file lv_draw_layer.h
*
*/
#ifndef LV_DRAW_LAYER_H
#define LV_DRAW_LAYER_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../lv_conf_internal.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
struct _lv_draw_ctx_t;
struct _lv_draw_layer_ctx_t;
typedef enum {
LV_DRAW_LAYER_FLAG_NONE,
LV_DRAW_LAYER_FLAG_HAS_ALPHA,
LV_DRAW_LAYER_FLAG_CAN_SUBDIVIDE,
} lv_draw_layer_flags_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create a new layer context. It is used to start and independent rendering session
* with the current draw_ctx
* @param draw_ctx pointer to the current draw context
* @param layer_area the coordinates of the layer
* @param flags OR-ed flags from @lv_draw_layer_flags_t
* @return pointer to the layer context, or NULL on error
*/
struct _lv_draw_layer_ctx_t * lv_draw_layer_create(struct _lv_draw_ctx_t * draw_ctx, const lv_area_t * layer_area,
lv_draw_layer_flags_t flags);
/**
* Adjust the layer_ctx and/or draw_ctx based on the `layer_ctx->area_act`.
* It's called only if flags has `LV_DRAW_LAYER_FLAG_CAN_SUBDIVIDE`
* @param draw_ctx pointer to the current draw context
* @param layer_ctx pointer to a layer context
* @param flags OR-ed flags from @lv_draw_layer_flags_t
*/
void lv_draw_layer_adjust(struct _lv_draw_ctx_t * draw_ctx, struct _lv_draw_layer_ctx_t * layer_ctx,
lv_draw_layer_flags_t flags);
/**
* Blend a rendered layer to `layer_ctx->area_act`
* @param draw_ctx pointer to the current draw context
* @param layer_ctx pointer to a layer context
* @param draw_dsc pointer to an image draw descriptor
*/
void lv_draw_layer_blend(struct _lv_draw_ctx_t * draw_ctx, struct _lv_draw_layer_ctx_t * layer_ctx,
lv_draw_img_dsc_t * draw_dsc);
/**
* Destroy a layer context.
* @param draw_ctx pointer to the current draw context
* @param layer_ctx pointer to a layer context
*/
void lv_draw_layer_destroy(struct _lv_draw_ctx_t * draw_ctx, struct _lv_draw_layer_ctx_t * layer_ctx);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_DRAW_LAYER_H*/

View File

@ -15,6 +15,7 @@
#include "lv_draw_sdl.h"
#include "lv_draw_sdl_utils.h"
#include "lv_draw_sdl_texture_cache.h"
#include "lv_draw_sdl_layer.h"
/*********************
* DEFINES
@ -69,6 +70,10 @@ void lv_draw_sdl_init_ctx(lv_disp_drv_t * disp_drv, lv_draw_ctx_t * draw_ctx)
draw_ctx->draw_arc = lv_draw_sdl_draw_arc;
draw_ctx->draw_polygon = lv_draw_sdl_polygon;
draw_ctx->draw_bg = lv_draw_sdl_draw_bg;
draw_ctx->layer_init = lv_draw_sdl_layer_init;
draw_ctx->layer_blend = lv_draw_sdl_layer_blend;
draw_ctx->layer_destroy = lv_draw_sdl_layer_destroy;
draw_ctx->layer_instance_size = sizeof(lv_draw_sdl_layer_ctx_t);
lv_draw_sdl_ctx_t * draw_ctx_sdl = (lv_draw_sdl_ctx_t *) draw_ctx;
draw_ctx_sdl->renderer = ((lv_draw_sdl_drv_param_t *) disp_drv->user_data)->renderer;
draw_ctx_sdl->internals = lv_mem_alloc(sizeof(lv_draw_sdl_context_internals_t));

View File

@ -11,6 +11,7 @@ CSRCS += lv_draw_sdl_rect.c
CSRCS += lv_draw_sdl_stack_blur.c
CSRCS += lv_draw_sdl_texture_cache.c
CSRCS += lv_draw_sdl_utils.c
CSRCS += lv_draw_sdl_layer.c
DEPPATH += --dep-path $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/draw/sdl
VPATH += :$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/draw/sdl

View File

@ -13,7 +13,6 @@
#include "../../misc/lv_gc.h"
#include "../../core/lv_refr.h"
#include "lv_draw_sdl_composite.h"
#include "lv_draw_sdl_mask.h"
#include "lv_draw_sdl_utils.h"
#include "lv_draw_sdl_priv.h"
#include "lv_draw_sdl_texture_cache.h"
@ -84,15 +83,16 @@ bool lv_draw_sdl_composite_begin(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coor
const bool draw_blend = blend_mode != LV_BLEND_MODE_NORMAL;
if(draw_mask || draw_blend) {
lv_draw_sdl_context_internals_t * internals = ctx->internals;
LV_ASSERT(internals->mask == NULL && internals->composition == NULL);
LV_ASSERT(internals->mask == NULL && internals->composition == NULL && internals->target_backup == NULL);
lv_coord_t w = lv_area_get_width(apply_area), h = lv_area_get_height(apply_area);
internals->composition = lv_draw_sdl_composite_texture_obtain(ctx, LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TARGET0, w, h);
/* Don't need to worry about overflow */
/* Don't need to worry about integral overflow */
lv_coord_t ofs_x = (lv_coord_t) - apply_area->x1, ofs_y = (lv_coord_t) - apply_area->y1;
/* Offset draw area to start with (0,0) of coords */
lv_area_move(coords_out, ofs_x, ofs_y);
lv_area_move(clip_out, ofs_x, ofs_y);
internals->target_backup = SDL_GetRenderTarget(ctx->renderer);
SDL_SetRenderTarget(ctx->renderer, internals->composition);
SDL_SetRenderDrawColor(ctx->renderer, 255, 255, 255, 0);
SDL_RenderClear(ctx->renderer);
@ -140,7 +140,7 @@ void lv_draw_sdl_composite_end(lv_draw_sdl_ctx_t * ctx, const lv_area_t * apply_
SDL_Rect dst_rect;
lv_area_to_sdl_rect(apply_area, &dst_rect);
SDL_SetRenderTarget(ctx->renderer, ctx->base_draw.buf);
SDL_SetRenderTarget(ctx->renderer, internals->target_backup);
switch(blend_mode) {
case LV_BLEND_MODE_NORMAL:
SDL_SetTextureBlendMode(internals->composition, SDL_BLENDMODE_BLEND);
@ -173,7 +173,7 @@ void lv_draw_sdl_composite_end(lv_draw_sdl_ctx_t * ctx, const lv_area_t * apply_
SDL_RenderCopy(ctx->renderer, internals->composition, &src_rect, &dst_rect);
}
internals->mask = internals->composition = NULL;
internals->mask = internals->composition = internals->target_backup = NULL;
}
SDL_Texture * lv_draw_sdl_composite_texture_obtain(lv_draw_sdl_ctx_t * ctx, lv_draw_sdl_composite_texture_id_t id,
@ -186,7 +186,10 @@ SDL_Texture * lv_draw_sdl_composite_texture_obtain(lv_draw_sdl_ctx_t * ctx, lv_d
if(!result || tex_size->x < w || tex_size->y < h) {
lv_coord_t size = next_pow_of_2(LV_MAX(w, h));
int access = SDL_TEXTUREACCESS_STREAMING;
if(id >= LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TARGET0) {
if(id >= LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TRANSFORM0) {
access = SDL_TEXTUREACCESS_TARGET;
}
else if(id >= LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TARGET0) {
access = SDL_TEXTUREACCESS_TARGET;
}
result = SDL_CreateTexture(ctx->renderer, LV_DRAW_SDL_TEXTURE_FORMAT, access, size, size);

View File

@ -35,6 +35,7 @@ typedef enum lv_draw_sdl_composite_texture_id_t {
LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_STREAM1,
LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TARGET0,
LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TARGET1,
LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TRANSFORM0,
} lv_draw_sdl_composite_texture_id_t;
/**********************

View File

@ -22,6 +22,7 @@
#include "lv_draw_sdl_texture_cache.h"
#include "lv_draw_sdl_composite.h"
#include "lv_draw_sdl_rect.h"
#include "lv_draw_sdl_layer.h"
/*********************
* DEFINES
@ -123,11 +124,15 @@ lv_res_t lv_draw_sdl_img_core(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t
/* Coords will be translated so coords will start at (0,0) */
lv_area_t t_coords = zoomed_cords, t_clip = *clip, apply_area;
bool has_composite = false;
if(!check_mask_simple_radius(&t_coords, &radius)) {
lv_draw_sdl_composite_begin(ctx, &zoomed_cords, clip, NULL, draw_dsc->blend_mode,
&t_coords, &t_clip, &apply_area);
has_composite = lv_draw_sdl_composite_begin(ctx, &zoomed_cords, clip, NULL, draw_dsc->blend_mode,
&t_coords, &t_clip, &apply_area);
}
lv_draw_sdl_transform_areas_offset(ctx, has_composite, &apply_area, &t_coords, &t_clip);
SDL_Rect clip_rect, coords_rect;
lv_area_to_sdl_rect(&t_clip, &clip_rect);
lv_area_to_sdl_rect(&t_coords, &coords_rect);

View File

@ -19,6 +19,7 @@
#include "lv_draw_sdl_utils.h"
#include "lv_draw_sdl_texture_cache.h"
#include "lv_draw_sdl_composite.h"
#include "lv_draw_sdl_layer.h"
/*********************
* DEFINES
@ -134,8 +135,10 @@ void lv_draw_sdl_draw_letter(lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_t
}
lv_area_t t_letter = letter_area, t_clip = *clip_area, apply_area;
bool has_mask = lv_draw_sdl_composite_begin(ctx, &letter_area, clip_area, NULL, dsc->blend_mode, &t_letter, &t_clip,
&apply_area);
bool has_composite = lv_draw_sdl_composite_begin(ctx, &letter_area, clip_area, NULL, dsc->blend_mode, &t_letter,
&t_clip, &apply_area);
lv_draw_sdl_transform_areas_offset(ctx, has_composite, &apply_area, &t_letter, &t_clip);
/*If the letter is completely out of mask don't draw it*/
if(!_lv_area_intersect(&draw_area, &t_letter, &t_clip)) {

View File

@ -0,0 +1,132 @@
/**
* @file lv_draw_sdl_refr.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include "../../core/lv_refr.h"
#include "lv_draw_sdl.h"
#include "lv_draw_sdl_priv.h"
#include "lv_draw_sdl_composite.h"
#include "lv_draw_sdl_utils.h"
#include "lv_draw_sdl_layer.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_draw_layer_ctx_t * lv_draw_sdl_layer_init(lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * layer_ctx,
lv_draw_layer_flags_t flags)
{
lv_draw_sdl_ctx_t * ctx = (lv_draw_sdl_ctx_t *) draw_ctx;
SDL_Renderer * renderer = ctx->renderer;
lv_draw_sdl_layer_ctx_t * transform_ctx = (lv_draw_sdl_layer_ctx_t *) layer_ctx;
transform_ctx->flags = flags;
transform_ctx->orig_target = SDL_GetRenderTarget(renderer);
lv_coord_t target_w = lv_area_get_width(&layer_ctx->area_full);
lv_coord_t target_h = lv_area_get_height(&layer_ctx->area_full);
enum lv_draw_sdl_composite_texture_id_t texture_id = LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TRANSFORM0 +
ctx->internals->transform_count;
transform_ctx->target = lv_draw_sdl_composite_texture_obtain(ctx, texture_id, target_w, target_h);
transform_ctx->target_rect.x = 0;
transform_ctx->target_rect.y = 0;
transform_ctx->target_rect.w = target_w;
transform_ctx->target_rect.h = target_h;
SDL_SetTextureBlendMode(transform_ctx->target, SDL_BLENDMODE_BLEND);
SDL_SetRenderTarget(renderer, transform_ctx->target);
SDL_RenderClear(renderer);
/* Set proper drawing context for transform layer */
ctx->internals->transform_count += 1;
draw_ctx->buf_area = &layer_ctx->area_full;
draw_ctx->clip_area = &layer_ctx->area_full;
return layer_ctx;
}
void lv_draw_sdl_layer_blend(lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * layer_ctx,
const lv_draw_img_dsc_t * draw_dsc)
{
lv_draw_sdl_ctx_t * ctx = (lv_draw_sdl_ctx_t *) draw_ctx;
lv_draw_sdl_layer_ctx_t * transform_ctx = (lv_draw_sdl_layer_ctx_t *) layer_ctx;
SDL_Renderer * renderer = ctx->renderer;
SDL_Rect trans_rect;
if(transform_ctx->flags & LV_DRAW_LAYER_FLAG_CAN_SUBDIVIDE) {
lv_area_zoom_to_sdl_rect(&layer_ctx->area_act, &trans_rect, draw_dsc->zoom, &draw_dsc->pivot);
}
else {
lv_area_zoom_to_sdl_rect(&layer_ctx->area_full, &trans_rect, draw_dsc->zoom, &draw_dsc->pivot);
}
SDL_SetRenderTarget(renderer, transform_ctx->orig_target);
/*Render off-screen texture, transformed*/
SDL_Rect clip_rect;
lv_area_to_sdl_rect(layer_ctx->original.clip_area, &clip_rect);
SDL_Point center = {.x = draw_dsc->pivot.x, .y = draw_dsc->pivot.y};
SDL_RenderSetClipRect(renderer, &clip_rect);
SDL_RenderCopyEx(renderer, transform_ctx->target, &transform_ctx->target_rect, &trans_rect,
draw_dsc->angle, &center, SDL_FLIP_NONE);
SDL_RenderSetClipRect(renderer, NULL);
}
void lv_draw_sdl_layer_destroy(lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * layer_ctx)
{
lv_draw_sdl_ctx_t * ctx = (lv_draw_sdl_ctx_t *) draw_ctx;
ctx->internals->transform_count -= 1;
}
void lv_draw_sdl_transform_areas_offset(lv_draw_sdl_ctx_t * ctx, bool has_composite, lv_area_t * apply_area,
lv_area_t * coords, lv_area_t * clip)
{
if(ctx->internals->transform_count == 0) {
return;
}
lv_area_t * area = ctx->base_draw.buf_area;
lv_area_move(coords, -area->x1, -area->y1);
lv_area_move(clip, -area->x1, -area->y1);
if(has_composite) {
lv_area_move(apply_area, -area->x1, -area->y1);
}
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_GPU_SDL*/

View File

@ -0,0 +1,55 @@
/**
* @file lv_draw_sdl_refr.h
*
*/
#ifndef LV_TEMPL_H
#define LV_TEMPL_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lv_draw_sdl.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct _lv_draw_sdl_layer_ctx_t {
lv_draw_layer_ctx_t base;
SDL_Texture * orig_target;
SDL_Texture * target;
SDL_Rect target_rect;
lv_draw_layer_flags_t flags;
} lv_draw_sdl_layer_ctx_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
lv_draw_layer_ctx_t * lv_draw_sdl_layer_init(lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * layer_ctx,
lv_draw_layer_flags_t flags);
void lv_draw_sdl_layer_blend(lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * transform_ctx,
const lv_draw_img_dsc_t * draw_dsc);
void lv_draw_sdl_layer_destroy(lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * layer_ctx);
void lv_draw_sdl_transform_areas_offset(lv_draw_sdl_ctx_t * ctx, bool has_composite, lv_area_t * apply_area,
lv_area_t * coords, lv_area_t * clip);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_TEMPL_H*/

View File

@ -35,6 +35,8 @@ typedef struct lv_draw_sdl_context_internals_t {
lv_lru_t * texture_cache;
SDL_Texture * mask;
SDL_Texture * composition;
SDL_Texture * target_backup;
uint8_t transform_count;
} lv_draw_sdl_context_internals_t;
/**********************

View File

@ -21,7 +21,7 @@
#include "lv_draw_sdl_composite.h"
#include "lv_draw_sdl_mask.h"
#include "lv_draw_sdl_stack_blur.h"
#include "lv_draw_sdl_img.h"
#include "lv_draw_sdl_layer.h"
/*********************
* DEFINES
@ -124,7 +124,11 @@ void lv_draw_sdl_draw_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t *
}
/* Coords will be translated so coords will start at (0,0) */
lv_area_t t_coords = *coords, t_clip = *clip, apply_area, t_area;
lv_draw_sdl_composite_begin(ctx, coords, clip, &extension, dsc->blend_mode, &t_coords, &t_clip, &apply_area);
bool has_composite = lv_draw_sdl_composite_begin(ctx, coords, clip, &extension, dsc->blend_mode, &t_coords, &t_clip,
&apply_area);
lv_draw_sdl_transform_areas_offset(ctx, has_composite, &apply_area, &t_coords, &t_clip);
bool has_content = _lv_area_intersect(&t_area, &t_coords, &t_clip);
SDL_Rect clip_rect;

View File

@ -56,7 +56,12 @@ void lv_draw_sw_init_ctx(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx)
#endif
draw_sw_ctx->base_draw.wait_for_finish = lv_draw_sw_wait_for_finish;
draw_sw_ctx->base_draw.buffer_copy = lv_draw_sw_buffer_copy;
draw_sw_ctx->base_draw.layer_init = lv_draw_sw_layer_create;
draw_sw_ctx->base_draw.layer_adjust = lv_draw_sw_layer_adjust;
draw_sw_ctx->base_draw.layer_blend = lv_draw_sw_layer_blend;
draw_sw_ctx->base_draw.layer_destroy = lv_draw_sw_layer_destroy;
draw_sw_ctx->blend = lv_draw_sw_blend_basic;
draw_ctx->layer_instance_size = sizeof(lv_draw_sw_layer_ctx_t);
}
void lv_draw_sw_deinit_ctx(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx)
@ -96,7 +101,6 @@ void lv_draw_sw_buffer_copy(lv_draw_ctx_t * draw_ctx,
dest_bufc += dest_stride;
src_bufc += src_stride;
}
}
/**********************

View File

@ -36,6 +36,13 @@ typedef struct {
void (*blend)(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc);
} lv_draw_sw_ctx_t;
typedef struct {
lv_draw_layer_ctx_t base_draw;
uint32_t buf_size_bytes: 31;
uint32_t has_alpha : 1;
} lv_draw_sw_layer_ctx_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
@ -67,11 +74,21 @@ void lv_draw_sw_buffer_copy(lv_draw_ctx_t * draw_ctx,
void * dest_buf, lv_coord_t dest_stride, const lv_area_t * dest_area,
void * src_buf, lv_coord_t src_stride, const lv_area_t * src_area);
void lv_draw_sw_transform(lv_draw_ctx_t * draw_ctx, const lv_area_t * dest_area, const void * src_buf,
lv_coord_t src_w, lv_coord_t src_h, lv_coord_t src_stride,
const lv_draw_img_dsc_t * draw_dsc, lv_img_cf_t cf, lv_color_t * cbuf, lv_opa_t * abuf);
struct _lv_draw_layer_ctx_t * lv_draw_sw_layer_create(struct _lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * layer_ctx,
lv_draw_layer_flags_t flags);
void lv_draw_sw_layer_adjust(struct _lv_draw_ctx_t * draw_ctx, struct _lv_draw_layer_ctx_t * layer_ctx,
lv_draw_layer_flags_t flags);
void lv_draw_sw_layer_blend(struct _lv_draw_ctx_t * draw_ctx, struct _lv_draw_layer_ctx_t * layer_ctx,
const lv_draw_img_dsc_t * draw_dsc);
void lv_draw_sw_layer_destroy(lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * layer_ctx);
/***********************
* GLOBAL VARIABLES
***********************/

View File

@ -9,6 +9,7 @@ CSRCS += lv_draw_sw_line.c
CSRCS += lv_draw_sw_polygon.c
CSRCS += lv_draw_sw_rect.c
CSRCS += lv_draw_sw_transform.c
CSRCS += lv_draw_sw_layer.c
DEPPATH += --dep-path $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/draw/sw
VPATH += :$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/draw/sw

View File

@ -0,0 +1,152 @@
/**
* @file lv_draw_sw_layer.h
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_sw.h"
#include "../../hal/lv_hal_disp.h"
#include "../../misc/lv_area.h"
#include "../../core/lv_refr.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* GLOBAL VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
struct _lv_draw_layer_ctx_t * lv_draw_sw_layer_create(struct _lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * layer_ctx,
lv_draw_layer_flags_t flags)
{
if(LV_COLOR_SCREEN_TRANSP == 0 && (flags & LV_DRAW_LAYER_FLAG_HAS_ALPHA)) {
LV_LOG_WARN("Rendering this widget needs LV_COLOR_SCREEN_TRANSP 1");
return NULL;
}
lv_draw_sw_layer_ctx_t * layer_sw_ctx = (lv_draw_sw_layer_ctx_t *) layer_ctx;
uint32_t px_size = flags & LV_DRAW_LAYER_FLAG_HAS_ALPHA ? LV_IMG_PX_SIZE_ALPHA_BYTE : sizeof(lv_color_t);
if(flags & LV_DRAW_LAYER_FLAG_CAN_SUBDIVIDE) {
layer_sw_ctx->buf_size_bytes = LV_LAYER_SIMPLE_BUF_SIZE;
uint32_t full_size = lv_area_get_size(&layer_sw_ctx->base_draw.area_full) * px_size;
if(layer_sw_ctx->buf_size_bytes > full_size) layer_sw_ctx->buf_size_bytes = full_size;
layer_sw_ctx->base_draw.buf = lv_mem_alloc(layer_sw_ctx->buf_size_bytes);
if(layer_sw_ctx->base_draw.buf == NULL) {
LV_LOG_WARN("Cannot allocate %"LV_PRIu32" bytes for layer buffer. Allocating %"LV_PRIu32" bytes instead. (Reduced performance)",
(uint32_t)layer_sw_ctx->buf_size_bytes, (uint32_t)LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE * px_size);
layer_sw_ctx->buf_size_bytes = LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE;
layer_sw_ctx->base_draw.buf = lv_mem_alloc(layer_sw_ctx->buf_size_bytes);
if(layer_sw_ctx->base_draw.buf == NULL) {
lv_mem_free(layer_ctx);
return NULL;
}
}
layer_sw_ctx->base_draw.area_act = layer_sw_ctx->base_draw.area_full;
layer_sw_ctx->base_draw.area_act.y2 = layer_sw_ctx->base_draw.area_full.y1;
lv_coord_t w = lv_area_get_width(&layer_sw_ctx->base_draw.area_act);
layer_sw_ctx->base_draw.max_row_with_alpha = layer_sw_ctx->buf_size_bytes / w / LV_IMG_PX_SIZE_ALPHA_BYTE;
layer_sw_ctx->base_draw.max_row_with_no_alpha = layer_sw_ctx->buf_size_bytes / w / sizeof(lv_color_t);
}
else {
layer_sw_ctx->base_draw.area_act = layer_sw_ctx->base_draw.area_full;
layer_sw_ctx->buf_size_bytes = lv_area_get_size(&layer_sw_ctx->base_draw.area_full) * px_size;
layer_sw_ctx->base_draw.buf = lv_mem_alloc(layer_sw_ctx->buf_size_bytes);
lv_memset_00(layer_sw_ctx->base_draw.buf, layer_sw_ctx->buf_size_bytes);
layer_sw_ctx->has_alpha = flags & LV_DRAW_LAYER_FLAG_HAS_ALPHA ? 1 : 0;
if(layer_sw_ctx->base_draw.buf == NULL) {
lv_mem_free(layer_ctx);
return NULL;
}
draw_ctx->buf = layer_sw_ctx->base_draw.buf;
draw_ctx->buf_area = &layer_sw_ctx->base_draw.area_act;
draw_ctx->clip_area = &layer_sw_ctx->base_draw.area_act;
lv_disp_t * disp_refr = _lv_refr_get_disp_refreshing();
disp_refr->driver->screen_transp = flags & LV_DRAW_LAYER_FLAG_HAS_ALPHA ? 1 : 0;
}
return layer_ctx;
}
void lv_draw_sw_layer_adjust(struct _lv_draw_ctx_t * draw_ctx, struct _lv_draw_layer_ctx_t * layer_ctx,
lv_draw_layer_flags_t flags)
{
lv_draw_sw_layer_ctx_t * layer_sw_ctx = (lv_draw_sw_layer_ctx_t *) layer_ctx;
lv_disp_t * disp_refr = _lv_refr_get_disp_refreshing();
if(flags & LV_DRAW_LAYER_FLAG_HAS_ALPHA) {
lv_memset_00(layer_ctx->buf, layer_sw_ctx->buf_size_bytes);
layer_sw_ctx->has_alpha = 1;
disp_refr->driver->screen_transp = 1;
}
else {
layer_sw_ctx->has_alpha = 0;
disp_refr->driver->screen_transp = 0;
}
draw_ctx->buf = layer_ctx->buf;
draw_ctx->buf_area = &layer_ctx->area_act;
draw_ctx->clip_area = &layer_ctx->area_act;
}
void lv_draw_sw_layer_blend(struct _lv_draw_ctx_t * draw_ctx, struct _lv_draw_layer_ctx_t * layer_ctx,
const lv_draw_img_dsc_t * draw_dsc)
{
lv_draw_sw_layer_ctx_t * layer_sw_ctx = (lv_draw_sw_layer_ctx_t *) layer_ctx;
lv_img_dsc_t img;
img.data = draw_ctx->buf;
img.header.always_zero = 0;
img.header.w = lv_area_get_width(draw_ctx->buf_area);
img.header.h = lv_area_get_height(draw_ctx->buf_area);
img.header.cf = layer_sw_ctx->has_alpha ? LV_IMG_CF_TRUE_COLOR_ALPHA : LV_IMG_CF_TRUE_COLOR;
lv_img_cache_invalidate_src(&img);
/*Restore the original draw_ctx*/
draw_ctx->buf = layer_ctx->original.buf;
draw_ctx->buf_area = layer_ctx->original.buf_area;
draw_ctx->clip_area = layer_ctx->original.clip_area;
lv_disp_t * disp_refr = _lv_refr_get_disp_refreshing();
disp_refr->driver->screen_transp = layer_ctx->original.screen_transp;
/*Blend the layer*/
lv_draw_img(draw_ctx, draw_dsc, &layer_ctx->area_act, &img);
lv_draw_wait_for_finish(draw_ctx);
}
void lv_draw_sw_layer_destroy(lv_draw_ctx_t * draw_ctx, lv_draw_layer_ctx_t * layer_ctx)
{
LV_UNUSED(draw_ctx);
lv_mem_free(layer_ctx->buf);
}
/**********************
* STATIC FUNCTIONS
**********************/

View File

@ -317,8 +317,6 @@
* and blend it as an image with the given opacity.
* Note that `bg_opa`, `text_opa` etc don't require buffering into layer)
* The widget can be buffered in smaller chunks to avoid using large buffers.
* `draw_area` (`lv_area_t` meaning the area to draw and `px_size` (size of a pixel in bytes)
* can be used the set the buffer size adaptively.
*
* - LV_LAYER_SIMPLE_BUF_SIZE: [bytes] the optimal target buffer size. LVGL will try to allocate it
* - LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE: [bytes] used if `LV_LAYER_SIMPLE_BUF_SIZE` couldn't be allocated.
@ -338,7 +336,7 @@
#ifdef CONFIG_LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE
#define LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE CONFIG_LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE
#else
#define LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE LV_MAX(lv_area_get_width(&draw_area) * px_size, 2048)
#define LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE (3 * 1024)
#endif
#endif