doc(gpu): add a page for external GPU support and draw_ctx
related to: #2988
This commit is contained in:
205
docs/porting/gpu.md
Normal file
205
docs/porting/gpu.md
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
```eval_rst
|
||||||
|
.. include:: /header.rst
|
||||||
|
:github_url: |github_link_base|/porting/gpu.md
|
||||||
|
```
|
||||||
|
# Add custom GPU
|
||||||
|
|
||||||
|
LVGL has a flexible and extendable draw pipeline. You can hook it to do some rendering with a GPU or even completely replace the built-in software renderer.
|
||||||
|
|
||||||
|
## Draw context
|
||||||
|
|
||||||
|
The core structure of drawing is `lv_draw_ctx_t`.
|
||||||
|
It contains a pointer to a buffer where drawing should happen and a couple of callbacks to draw rectangles, texts, and other primitives.
|
||||||
|
|
||||||
|
### Fields
|
||||||
|
|
||||||
|
`lv_draw_ctx_t` has the following fields:
|
||||||
|
- `void * buf` Pointer to a buffer to draw into
|
||||||
|
- `lv_area_t * buf_area` The the position and size of `buf` (absolute coordinates)
|
||||||
|
- `const lv_area_t * clip_area` The current clip area with absolute coordinates, always the same or smaller than `buf_area`. All drawings should be clipped to this area.
|
||||||
|
- `void (*draw_rect)()` Draw a rectangle with shadow, gradient, border, etc.
|
||||||
|
- `void (*draw_arc)()` Draw and arc
|
||||||
|
- `void (*draw_img_decoded)()` Draw an (A)RGB image that is already decoded by LVGL.
|
||||||
|
- `lv_res_t (*draw_img)()` Draw an image before decoding it (it bypasses LVGL's internal image decoders)
|
||||||
|
- `void (*draw_letter)()` Draw a letter
|
||||||
|
- `void (*draw_line)()` Draw a line
|
||||||
|
- `void (*draw_polygon)()` Draw polygon
|
||||||
|
- `void (*draw_bg)()` Replace the buffer with a rect without decoration like radius or borders.
|
||||||
|
- `void (*wait_for_finish)()` Wait until all background operation are finished. (E.g. GPU operations)
|
||||||
|
- `void * user_data` Custom user data for arbitrary purpose
|
||||||
|
|
||||||
|
(For the sake of simplicity the parameters of the callbacks are not shown here.)
|
||||||
|
|
||||||
|
All `draw_*` callbacks receive a pointer to the current `draw_ctx` as their first parameter. Among the other parameters there is a descriptor too that tells what to draw.
|
||||||
|
E.g. for `draw_rect` it's called [lv_draw_rect_dsc_t](https://github.com/lvgl/lvgl/blob/master/src/draw/lv_draw_rect.h),
|
||||||
|
for `lv_draw_line` it's called [lv_draw_line_dsc_t](https://github.com/lvgl/lvgl/blob/master/src/draw/lv_draw_line.h).
|
||||||
|
|
||||||
|
|
||||||
|
### Initialization
|
||||||
|
|
||||||
|
The `lv_disp_drv_t` has 4 fields related to the draw context:
|
||||||
|
- `lv_draw_ctx_t * draw_ctx` Pointer to the `draw_ctx` of this display
|
||||||
|
- `void (*draw_ctx_init)(struct _lv_disp_drv_t * disp_drv, lv_draw_ctx_t * draw_ctx)` Callback to initialize a `draw_ctx`
|
||||||
|
- `void (*draw_ctx_deinit)(struct _lv_disp_drv_t * disp_drv, lv_draw_ctx_t * draw_ctx)` Callback to de-initialize a `draw_ctx`
|
||||||
|
- `size_t draw_ctx_size` Size of the draw context structure. E.g. `sizeof(lv_draw_sw_ctx_t)`
|
||||||
|
|
||||||
|
If you ignore these fields LVGL will set default values for callbacks and size in `lv_disp_drv_init()` based on the configuration in `lv_conf.h`.
|
||||||
|
`lv_disp_drv_register()` will allocate a `draw_ctx` based on `draw_ctx_size` and call `draw_ctx_init()` on it.
|
||||||
|
|
||||||
|
However, you can overwrite the callbacks and the size values before calling `lv_disp_drv_register()`.
|
||||||
|
It makes possible to use your own `draw_ctx` with your own callbacks.
|
||||||
|
|
||||||
|
|
||||||
|
## Software renderer
|
||||||
|
LVGL's built in software renderer extends the basic `lv_draw_ctx_t` structure and sets the draw callbacks. It looks like this:
|
||||||
|
```c
|
||||||
|
typedef struct {
|
||||||
|
/** Include the basic draw_ctx type*/
|
||||||
|
lv_draw_ctx_t base_draw;
|
||||||
|
|
||||||
|
/** Blend a color or image to an area*/
|
||||||
|
void (*blend)(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc);
|
||||||
|
} lv_draw_sw_ctx_t;
|
||||||
|
```
|
||||||
|
|
||||||
|
Set the draw callbacks in `draw_ctx_init()` like:
|
||||||
|
```c
|
||||||
|
draw_sw_ctx->base_draw.draw_rect = lv_draw_sw_rect;
|
||||||
|
draw_sw_ctx->base_draw.draw_letter = lv_draw_sw_letter;
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Blend callback
|
||||||
|
As you saw above the software renderer adds the `blend` callback field. It's a special callback related to how the software renderer works.
|
||||||
|
All draw operations end up in the `blend` callback which can either fill an area or copy an image to an area by considering an optional mask.
|
||||||
|
|
||||||
|
The `lv_draw_sw_blend_dsc_t` parameter describes what and how to blend. It has the following fields:
|
||||||
|
- `const lv_area_t * blend_area` The area with absolute coordinates to draw on `draw_ctx->buf`. If `src_buf` is set, it's the coordinates of the image to blend.
|
||||||
|
- `const lv_color_t * src_buf` Pointer to an image to blend. If set, `color` is ignored. If not set fill `blend_area` with `color`
|
||||||
|
- `lv_color_t color` Fill color. Used only if `src_buf == NULL`
|
||||||
|
- `lv_opa_t * mask_buf` NULL if ignored, or an alpha mask to apply on `blend_area`
|
||||||
|
- `lv_draw_mask_res_t mask_res` The result of the previous mask operation. (`LV_DRAW_MASK_RES_...`)
|
||||||
|
- `const lv_area_t * mask_area` The area of `mask_buf` with absolute coordinates
|
||||||
|
- `lv_opa_t opa` The overall opacity
|
||||||
|
- `lv_blend_mode_t blend_mode` E.g. `LV_BLEND_MODE_ADDITIVE`
|
||||||
|
|
||||||
|
|
||||||
|
## Extend the software renderer
|
||||||
|
|
||||||
|
### New blend callback
|
||||||
|
|
||||||
|
Let's take a practical example: you would like to use your MCUs GPU for color fill operations only.
|
||||||
|
|
||||||
|
As all draw callbacks call `blend` callback to fill an area in the end only the `blend` callback needs to be overwritten.
|
||||||
|
|
||||||
|
First extend `lv_draw_sw_ctx_t`:
|
||||||
|
```c
|
||||||
|
|
||||||
|
/*We don't add new fields, so just for clarity add new type*/
|
||||||
|
typedef lv_draw_sw_ctx_t my_draw_ctx_t;
|
||||||
|
|
||||||
|
void my_draw_ctx_init(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx)
|
||||||
|
{
|
||||||
|
/*Initialize the parent type first */
|
||||||
|
lv_draw_sw_init_ctx(drv, draw_ctx);
|
||||||
|
|
||||||
|
/*Change some callbacks*/
|
||||||
|
my_draw_ctx_t * my_draw_ctx = (my_draw_ctx_t *)draw_ctx;
|
||||||
|
|
||||||
|
my_draw_ctx->blend = my_draw_blend;
|
||||||
|
my_draw_ctx->base_draw.wait_for_finish = my_gpu_wait;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
After calling `lv_disp_draw_init(&drv)` you can assign the new `draw_ctx_init` callback and set `draw_ctx_size` to overwrite the defaults:
|
||||||
|
```c
|
||||||
|
static lv_disp_drv_t drv;
|
||||||
|
lv_disp_draw_init(&drv);
|
||||||
|
drv->hor_res = my_hor_res;
|
||||||
|
drv->ver_res = my_ver_res;
|
||||||
|
drv->flush_cb = my_flush_cb;
|
||||||
|
|
||||||
|
/*New draw ctx settings*/
|
||||||
|
drv->draw_ctx_init = my_draw_ctx_init;
|
||||||
|
drv->draw_ctx_size = sizeof(my_draw_ctx_t);
|
||||||
|
|
||||||
|
lv_disp_drv_register(&drv);
|
||||||
|
```
|
||||||
|
|
||||||
|
This way when LVGL calls `blend` it will call `my_draw_blend` and we can do custom GPU operations. Here is a complete example:
|
||||||
|
```c
|
||||||
|
void my_draw_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc)
|
||||||
|
{
|
||||||
|
/*Let's get the blend area which is the intersection of the area to fill and the clip area.*/
|
||||||
|
lv_area_t blend_area;
|
||||||
|
if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) return; /*Fully clipped, nothing to do*/
|
||||||
|
|
||||||
|
/*Fill only non masked, fully opaque, normal blended and not too small areas*/
|
||||||
|
if(dsc->src_buf == NULL && dsc->mask == NULL && dsc->opa >= LV_OPA_MAX &&
|
||||||
|
dsc->blend_mode == LV_BLEND_MODE_NORMAL && lv_area_get_size(&blend_area) > 100) {
|
||||||
|
|
||||||
|
/*Got the first pixel on the buffer*/
|
||||||
|
lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area); /*Width of the destination buffer*/
|
||||||
|
lv_color_t * dest_buf = draw_ctx->buf;
|
||||||
|
dest_buf += dest_stride * (blend_area.y1 - draw_ctx->buf_area->y1) + (blend_area.x1 - draw_ctx->buf_area->x1);
|
||||||
|
|
||||||
|
/*Make the blend area relative to the buffer*/
|
||||||
|
lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
|
||||||
|
|
||||||
|
/*Call your custom gou fill function to fill blend_area, on dest_buf with dsc->color*/
|
||||||
|
my_gpu_fill(dest_buf, dest_stride, &blend_area, dsc->color);
|
||||||
|
}
|
||||||
|
/*Fallback: the GPU doesn't support these settings. Call the SW renderer.*/
|
||||||
|
else {
|
||||||
|
lv_draw_sw_blend_basic(draw_ctx, dsc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The implementation of wait callback is much simpler:
|
||||||
|
```c
|
||||||
|
void my_gpu_wait(lv_draw_ctx_t * draw_ctx)
|
||||||
|
{
|
||||||
|
while(my_gpu_is_working());
|
||||||
|
|
||||||
|
/*Call SW renderer's wait callback too*/
|
||||||
|
lv_draw_sw_wait_for_finish(draw_ctx);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### New rectangle drawer
|
||||||
|
If your MCU has a more powerful GPU that can draw e.g. rounded rectangles you can replace the original software drawer too.
|
||||||
|
A custom `draw_rect` callback might look like this:
|
||||||
|
```c
|
||||||
|
void my_draw_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords)
|
||||||
|
{
|
||||||
|
if(lv_draw_mask_is_any(coords) == false && dsc->grad == NULL && dsc->bg_img_src == NULL &&
|
||||||
|
dsc->shadow_width == 0 && dsc->blend_mode = LV_BLEND_MODE_NORMAL)
|
||||||
|
{
|
||||||
|
/*Draw the background*/
|
||||||
|
my_bg_drawer(draw_ctx, coords, dsc->bg_color, dsc->radius);
|
||||||
|
|
||||||
|
/*Draw the border if any*/
|
||||||
|
if(dsc->border_width) {
|
||||||
|
my_border_drawer(draw_ctx, coords, dsc->border_width, dsc->border_color, dsc->border_opa)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Draw the outline if any*/
|
||||||
|
if(dsc->outline_width) {
|
||||||
|
my_outline_drawer(draw_ctx, coords, dsc->outline_width, dsc->outline_color, dsc->outline_opa, dsc->outline_pad)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*Fallback*/
|
||||||
|
else {
|
||||||
|
lv_draw_sw_rect(draw_ctx, dsc, coords);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`my_draw_rect` can fully bypass the use of `blend` callback if needed.
|
||||||
|
|
||||||
|
## Fully custom draw engine
|
||||||
|
|
||||||
|
For example if your MCU/MPU supports a powerful vector graphics engine you might use only that instead of LVGL's SW renderer.
|
||||||
|
In this case, you need to base the renderer on the basic `lv_draw_ctx_t` (instead of `lv_draw_sw_ctx_t`) and extend/initialize it as you wish.
|
||||||
|
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
sleep
|
sleep
|
||||||
os
|
os
|
||||||
log
|
log
|
||||||
|
gpu
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ void lv_draw_stm32_dma2d_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_
|
|||||||
|
|
||||||
bool done = false;
|
bool done = false;
|
||||||
|
|
||||||
if(dsc->mask == NULL && dsc->blend_mode == LV_BLEND_MODE_NORMAL && lv_area_get_size(&blend_area) > 100) {
|
if(dsc->mask_buf == NULL && dsc->blend_mode == LV_BLEND_MODE_NORMAL && lv_area_get_size(&blend_area) > 100) {
|
||||||
lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area);
|
lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area);
|
||||||
|
|
||||||
lv_color_t * dest_buf = draw_ctx->buf;
|
lv_color_t * dest_buf = draw_ctx->buf;
|
||||||
|
|||||||
@@ -108,10 +108,10 @@ void lv_draw_sw_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * d
|
|||||||
LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_blend_basic(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc)
|
LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_blend_basic(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc)
|
||||||
{
|
{
|
||||||
const lv_opa_t * mask;
|
const lv_opa_t * mask;
|
||||||
if(dsc->mask == NULL) mask = NULL;
|
if(dsc->mask_buf == NULL) mask = NULL;
|
||||||
if(dsc->mask && dsc->mask_res == LV_DRAW_MASK_RES_TRANSP) return;
|
if(dsc->mask_buf && dsc->mask_res == LV_DRAW_MASK_RES_TRANSP) return;
|
||||||
else if(dsc->mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask = NULL;
|
else if(dsc->mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask = NULL;
|
||||||
else mask = dsc->mask;
|
else mask = dsc->mask_buf;
|
||||||
|
|
||||||
lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area);
|
lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area);
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ typedef struct {
|
|||||||
* will be clipped to draw_`ctx->clip_area` */
|
* will be clipped to draw_`ctx->clip_area` */
|
||||||
const lv_color_t * src_buf; /**< Pointer to an image to blend. If set `fill_color is ignored`*/
|
const lv_color_t * src_buf; /**< Pointer to an image to blend. If set `fill_color is ignored`*/
|
||||||
lv_color_t color; /**< Fill color*/
|
lv_color_t color; /**< Fill color*/
|
||||||
lv_opa_t * mask; /**< NULL if ignored, or an alpha mask to apply on `blend_area`*/
|
lv_opa_t * mask_buf; /**< NULL if ignored, or an alpha mask to apply on `blend_area`*/
|
||||||
lv_draw_mask_res_t mask_res; /**< The result of the previous mask operation */
|
lv_draw_mask_res_t mask_res; /**< The result of the previous mask operation */
|
||||||
const lv_area_t * mask_area; /**< The area of `mask_buf` with absolute coordinates*/
|
const lv_area_t * mask_area; /**< The area of `mask_buf` with absolute coordinates*/
|
||||||
lv_opa_t opa; /**< The overall opacity*/
|
lv_opa_t opa; /**< The overall opacity*/
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_img_decoded(struct _lv_draw_ctx_t * draw_c
|
|||||||
uint32_t mask_buf_size = lv_area_get_size(&draw_area) > (uint32_t) hor_res ? hor_res : lv_area_get_size(&draw_area);
|
uint32_t mask_buf_size = lv_area_get_size(&draw_area) > (uint32_t) hor_res ? hor_res : lv_area_get_size(&draw_area);
|
||||||
lv_color_t * src_buf_rgb = lv_mem_buf_get(mask_buf_size * sizeof(lv_color_t));
|
lv_color_t * src_buf_rgb = lv_mem_buf_get(mask_buf_size * sizeof(lv_color_t));
|
||||||
lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size);
|
lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size);
|
||||||
blend_dsc.mask = mask_buf;
|
blend_dsc.mask_buf = mask_buf;
|
||||||
blend_dsc.mask_area = &blend_area;
|
blend_dsc.mask_area = &blend_area;
|
||||||
blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
||||||
blend_dsc.src_buf = src_buf_rgb;
|
blend_dsc.src_buf = src_buf_rgb;
|
||||||
@@ -150,7 +150,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_img_decoded(struct _lv_draw_ctx_t * draw_c
|
|||||||
uint32_t mask_buf_size = lv_area_get_size(&draw_area) > hor_res ? hor_res : lv_area_get_size(&draw_area);
|
uint32_t mask_buf_size = lv_area_get_size(&draw_area) > hor_res ? hor_res : lv_area_get_size(&draw_area);
|
||||||
lv_color_t * src_buf_rgb = lv_mem_buf_get(mask_buf_size * sizeof(lv_color_t));
|
lv_color_t * src_buf_rgb = lv_mem_buf_get(mask_buf_size * sizeof(lv_color_t));
|
||||||
lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size);
|
lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size);
|
||||||
blend_dsc.mask = mask_buf;
|
blend_dsc.mask_buf = mask_buf;
|
||||||
blend_dsc.mask_area = &blend_area;
|
blend_dsc.mask_area = &blend_area;
|
||||||
blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
||||||
blend_dsc.src_buf = src_buf_rgb;
|
blend_dsc.src_buf = src_buf_rgb;
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_letter_normal(lv_draw_ctx_t * draw_ctx, c
|
|||||||
lv_coord_t hor_res = lv_disp_get_hor_res(_lv_refr_get_disp_refreshing());
|
lv_coord_t hor_res = lv_disp_get_hor_res(_lv_refr_get_disp_refreshing());
|
||||||
uint32_t mask_buf_size = box_w * box_h > hor_res ? hor_res : box_w * box_h;
|
uint32_t mask_buf_size = box_w * box_h > hor_res ? hor_res : box_w * box_h;
|
||||||
lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size);
|
lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size);
|
||||||
blend_dsc.mask = mask_buf;
|
blend_dsc.mask_buf = mask_buf;
|
||||||
int32_t mask_p = 0;
|
int32_t mask_p = 0;
|
||||||
|
|
||||||
lv_area_t fill_area;
|
lv_area_t fill_area;
|
||||||
@@ -412,7 +412,7 @@ static void draw_letter_subpx(lv_draw_ctx_t * draw_ctx, const lv_draw_label_dsc_
|
|||||||
blend_dsc.blend_area = &map_area;
|
blend_dsc.blend_area = &map_area;
|
||||||
blend_dsc.mask_area = &map_area;
|
blend_dsc.mask_area = &map_area;
|
||||||
blend_dsc.src_buf = color_buf;
|
blend_dsc.src_buf = color_buf;
|
||||||
blend_dsc.mask = mask_buf;
|
blend_dsc.mask_buf = mask_buf;
|
||||||
blend_dsc.opa = opa;
|
blend_dsc.opa = opa;
|
||||||
blend_dsc.blend_mode = dsc->blend_mode;
|
blend_dsc.blend_mode = dsc->blend_mode;
|
||||||
|
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_line_hor(struct _lv_draw_ctx_t * draw_ctx
|
|||||||
}
|
}
|
||||||
|
|
||||||
lv_opa_t * mask_buf = lv_mem_buf_get(blend_area_w);
|
lv_opa_t * mask_buf = lv_mem_buf_get(blend_area_w);
|
||||||
blend_dsc.mask = mask_buf;
|
blend_dsc.mask_buf = mask_buf;
|
||||||
blend_dsc.mask_area = &blend_area;
|
blend_dsc.mask_area = &blend_area;
|
||||||
int32_t h;
|
int32_t h;
|
||||||
for(h = blend_area.y1; h <= y2; h++) {
|
for(h = blend_area.y1; h <= y2; h++) {
|
||||||
@@ -237,7 +237,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_line_ver(struct _lv_draw_ctx_t * draw_ctx
|
|||||||
blend_area.y2 = blend_area.y1;
|
blend_area.y2 = blend_area.y1;
|
||||||
|
|
||||||
lv_opa_t * mask_buf = lv_mem_buf_get(draw_area_w);
|
lv_opa_t * mask_buf = lv_mem_buf_get(draw_area_w);
|
||||||
blend_dsc.mask = mask_buf;
|
blend_dsc.mask_buf = mask_buf;
|
||||||
blend_dsc.mask_area = &blend_area;
|
blend_dsc.mask_area = &blend_area;
|
||||||
|
|
||||||
lv_coord_t dash_start = 0;
|
lv_coord_t dash_start = 0;
|
||||||
@@ -390,7 +390,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_line_skew(struct _lv_draw_ctx_t * draw_ct
|
|||||||
blend_dsc.blend_area = &blend_area;
|
blend_dsc.blend_area = &blend_area;
|
||||||
blend_dsc.color = dsc->color;
|
blend_dsc.color = dsc->color;
|
||||||
blend_dsc.opa = dsc->opa;
|
blend_dsc.opa = dsc->opa;
|
||||||
blend_dsc.mask = mask_buf;
|
blend_dsc.mask_buf = mask_buf;
|
||||||
blend_dsc.mask_area = &blend_area;
|
blend_dsc.mask_area = &blend_area;
|
||||||
|
|
||||||
/*Fill the first row with 'color'*/
|
/*Fill the first row with 'color'*/
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ static void draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, co
|
|||||||
lv_memset_00(&blend_dsc, sizeof(lv_draw_sw_blend_dsc_t));
|
lv_memset_00(&blend_dsc, sizeof(lv_draw_sw_blend_dsc_t));
|
||||||
blend_dsc.blend_mode = dsc->blend_mode;
|
blend_dsc.blend_mode = dsc->blend_mode;
|
||||||
blend_dsc.color = dsc->bg_color;
|
blend_dsc.color = dsc->bg_color;
|
||||||
blend_dsc.mask = mask_buf;
|
blend_dsc.mask_buf = mask_buf;
|
||||||
blend_dsc.opa = LV_OPA_COVER;
|
blend_dsc.opa = LV_OPA_COVER;
|
||||||
blend_dsc.blend_area = &blend_area;
|
blend_dsc.blend_area = &blend_area;
|
||||||
blend_dsc.mask_area = &blend_area;
|
blend_dsc.mask_area = &blend_area;
|
||||||
@@ -238,7 +238,7 @@ static void draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, co
|
|||||||
blend_area.y1 = bg_coords.y1 + rout;
|
blend_area.y1 = bg_coords.y1 + rout;
|
||||||
blend_area.y2 = bg_coords.y2 - rout;
|
blend_area.y2 = bg_coords.y2 - rout;
|
||||||
blend_dsc.opa = opa;
|
blend_dsc.opa = opa;
|
||||||
blend_dsc.mask = NULL;
|
blend_dsc.mask_buf = NULL;
|
||||||
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
||||||
}
|
}
|
||||||
/*With gradient and/or mask draw line by line*/
|
/*With gradient and/or mask draw line by line*/
|
||||||
@@ -484,7 +484,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(lv_draw_ctx_t * draw_ctx, const lv
|
|||||||
lv_memset_00(&blend_dsc, sizeof(blend_dsc));
|
lv_memset_00(&blend_dsc, sizeof(blend_dsc));
|
||||||
blend_dsc.blend_area = &blend_area;
|
blend_dsc.blend_area = &blend_area;
|
||||||
blend_dsc.mask_area = &blend_area;
|
blend_dsc.mask_area = &blend_area;
|
||||||
blend_dsc.mask = mask_buf;
|
blend_dsc.mask_buf = mask_buf;
|
||||||
blend_dsc.color = dsc->shadow_color;
|
blend_dsc.color = dsc->shadow_color;
|
||||||
blend_dsc.opa = dsc->shadow_opa;
|
blend_dsc.opa = dsc->shadow_opa;
|
||||||
blend_dsc.blend_mode = dsc->blend_mode;
|
blend_dsc.blend_mode = dsc->blend_mode;
|
||||||
@@ -514,7 +514,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(lv_draw_ctx_t * draw_ctx, const lv
|
|||||||
if(simple && _lv_area_is_out(&clip_area_sub, &bg_area, r_bg)) simple_sub = true;
|
if(simple && _lv_area_is_out(&clip_area_sub, &bg_area, r_bg)) simple_sub = true;
|
||||||
else simple_sub = simple;
|
else simple_sub = simple;
|
||||||
if(w > 0) {
|
if(w > 0) {
|
||||||
blend_dsc.mask = mask_buf;
|
blend_dsc.mask_buf = mask_buf;
|
||||||
blend_area.x1 = clip_area_sub.x1;
|
blend_area.x1 = clip_area_sub.x1;
|
||||||
blend_area.x2 = clip_area_sub.x2;
|
blend_area.x2 = clip_area_sub.x2;
|
||||||
blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; /*In simple mode it won't be overwritten*/
|
blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; /*In simple mode it won't be overwritten*/
|
||||||
@@ -528,7 +528,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(lv_draw_ctx_t * draw_ctx, const lv
|
|||||||
if(blend_dsc.mask_res == LV_DRAW_MASK_RES_FULL_COVER) blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
if(blend_dsc.mask_res == LV_DRAW_MASK_RES_FULL_COVER) blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
blend_dsc.mask = sh_buf_tmp;
|
blend_dsc.mask_buf = sh_buf_tmp;
|
||||||
}
|
}
|
||||||
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
||||||
sh_buf_tmp += corner_size;
|
sh_buf_tmp += corner_size;
|
||||||
@@ -557,7 +557,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(lv_draw_ctx_t * draw_ctx, const lv
|
|||||||
else simple_sub = simple;
|
else simple_sub = simple;
|
||||||
|
|
||||||
if(w > 0) {
|
if(w > 0) {
|
||||||
blend_dsc.mask = mask_buf;
|
blend_dsc.mask_buf = mask_buf;
|
||||||
blend_area.x1 = clip_area_sub.x1;
|
blend_area.x1 = clip_area_sub.x1;
|
||||||
blend_area.x2 = clip_area_sub.x2;
|
blend_area.x2 = clip_area_sub.x2;
|
||||||
blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; /*In simple mode it won't be overwritten*/
|
blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED; /*In simple mode it won't be overwritten*/
|
||||||
@@ -571,7 +571,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(lv_draw_ctx_t * draw_ctx, const lv
|
|||||||
if(blend_dsc.mask_res == LV_DRAW_MASK_RES_FULL_COVER) blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
if(blend_dsc.mask_res == LV_DRAW_MASK_RES_FULL_COVER) blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
blend_dsc.mask = sh_buf_tmp;
|
blend_dsc.mask_buf = sh_buf_tmp;
|
||||||
}
|
}
|
||||||
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
||||||
sh_buf_tmp += corner_size;
|
sh_buf_tmp += corner_size;
|
||||||
@@ -598,10 +598,10 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(lv_draw_ctx_t * draw_ctx, const lv
|
|||||||
|
|
||||||
if(w > 0) {
|
if(w > 0) {
|
||||||
if(!simple_sub) {
|
if(!simple_sub) {
|
||||||
blend_dsc.mask = mask_buf;
|
blend_dsc.mask_buf = mask_buf;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
blend_dsc.mask = NULL;
|
blend_dsc.mask_buf = NULL;
|
||||||
}
|
}
|
||||||
blend_area.x1 = clip_area_sub.x1;
|
blend_area.x1 = clip_area_sub.x1;
|
||||||
blend_area.x2 = clip_area_sub.x2;
|
blend_area.x2 = clip_area_sub.x2;
|
||||||
@@ -645,10 +645,10 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(lv_draw_ctx_t * draw_ctx, const lv
|
|||||||
else simple_sub = simple;
|
else simple_sub = simple;
|
||||||
|
|
||||||
if(!simple_sub) {
|
if(!simple_sub) {
|
||||||
blend_dsc.mask = mask_buf;
|
blend_dsc.mask_buf = mask_buf;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
blend_dsc.mask = NULL;
|
blend_dsc.mask_buf = NULL;
|
||||||
}
|
}
|
||||||
blend_area.x1 = clip_area_sub.x1;
|
blend_area.x1 = clip_area_sub.x1;
|
||||||
blend_area.x2 = clip_area_sub.x2;
|
blend_area.x2 = clip_area_sub.x2;
|
||||||
@@ -699,7 +699,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(lv_draw_ctx_t * draw_ctx, const lv
|
|||||||
/*Do not mask if out of the bg*/
|
/*Do not mask if out of the bg*/
|
||||||
if(simple && _lv_area_is_out(&clip_area_sub, &bg_area, r_bg)) simple_sub = true;
|
if(simple && _lv_area_is_out(&clip_area_sub, &bg_area, r_bg)) simple_sub = true;
|
||||||
else simple_sub = simple;
|
else simple_sub = simple;
|
||||||
blend_dsc.mask = simple_sub ? sh_buf_tmp : mask_buf;
|
blend_dsc.mask_buf = simple_sub ? sh_buf_tmp : mask_buf;
|
||||||
|
|
||||||
if(w > 0) {
|
if(w > 0) {
|
||||||
blend_area.x1 = clip_area_sub.x1;
|
blend_area.x1 = clip_area_sub.x1;
|
||||||
@@ -756,7 +756,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(lv_draw_ctx_t * draw_ctx, const lv
|
|||||||
/*Do not mask if out of the bg*/
|
/*Do not mask if out of the bg*/
|
||||||
if(simple && _lv_area_is_out(&clip_area_sub, &bg_area, r_bg)) simple_sub = true;
|
if(simple && _lv_area_is_out(&clip_area_sub, &bg_area, r_bg)) simple_sub = true;
|
||||||
else simple_sub = simple;
|
else simple_sub = simple;
|
||||||
blend_dsc.mask = simple_sub ? sh_buf_tmp : mask_buf;
|
blend_dsc.mask_buf = simple_sub ? sh_buf_tmp : mask_buf;
|
||||||
if(w > 0) {
|
if(w > 0) {
|
||||||
blend_area.x1 = clip_area_sub.x1;
|
blend_area.x1 = clip_area_sub.x1;
|
||||||
blend_area.x2 = clip_area_sub.x2;
|
blend_area.x2 = clip_area_sub.x2;
|
||||||
@@ -795,7 +795,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(lv_draw_ctx_t * draw_ctx, const lv
|
|||||||
/*Do not mask if out of the bg*/
|
/*Do not mask if out of the bg*/
|
||||||
if(simple && _lv_area_is_out(&clip_area_sub, &bg_area, r_bg)) simple_sub = true;
|
if(simple && _lv_area_is_out(&clip_area_sub, &bg_area, r_bg)) simple_sub = true;
|
||||||
else simple_sub = simple;
|
else simple_sub = simple;
|
||||||
blend_dsc.mask = mask_buf;
|
blend_dsc.mask_buf = mask_buf;
|
||||||
|
|
||||||
if(w > 0) {
|
if(w > 0) {
|
||||||
blend_area.x1 = clip_area_sub.x1;
|
blend_area.x1 = clip_area_sub.x1;
|
||||||
@@ -811,7 +811,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(lv_draw_ctx_t * draw_ctx, const lv
|
|||||||
if(blend_dsc.mask_res == LV_DRAW_MASK_RES_FULL_COVER) blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
if(blend_dsc.mask_res == LV_DRAW_MASK_RES_FULL_COVER) blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
blend_dsc.mask = sh_buf_tmp;
|
blend_dsc.mask_buf = sh_buf_tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
||||||
@@ -840,7 +840,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(lv_draw_ctx_t * draw_ctx, const lv
|
|||||||
/*Do not mask if out of the bg*/
|
/*Do not mask if out of the bg*/
|
||||||
if(simple && _lv_area_is_out(&clip_area_sub, &bg_area, r_bg)) simple_sub = true;
|
if(simple && _lv_area_is_out(&clip_area_sub, &bg_area, r_bg)) simple_sub = true;
|
||||||
else simple_sub = simple;
|
else simple_sub = simple;
|
||||||
blend_dsc.mask = mask_buf;
|
blend_dsc.mask_buf = mask_buf;
|
||||||
if(w > 0) {
|
if(w > 0) {
|
||||||
blend_area.x1 = clip_area_sub.x1;
|
blend_area.x1 = clip_area_sub.x1;
|
||||||
blend_area.x2 = clip_area_sub.x2;
|
blend_area.x2 = clip_area_sub.x2;
|
||||||
@@ -855,7 +855,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(lv_draw_ctx_t * draw_ctx, const lv
|
|||||||
if(blend_dsc.mask_res == LV_DRAW_MASK_RES_FULL_COVER) blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
if(blend_dsc.mask_res == LV_DRAW_MASK_RES_FULL_COVER) blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
blend_dsc.mask = sh_buf_tmp;
|
blend_dsc.mask_buf = sh_buf_tmp;
|
||||||
}
|
}
|
||||||
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
||||||
sh_buf_tmp += corner_size;
|
sh_buf_tmp += corner_size;
|
||||||
@@ -868,7 +868,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(lv_draw_ctx_t * draw_ctx, const lv
|
|||||||
blend_area.x2 = shadow_area.x2 - corner_size;
|
blend_area.x2 = shadow_area.x2 - corner_size;
|
||||||
blend_area.y1 = shadow_area.y1 + corner_size;
|
blend_area.y1 = shadow_area.y1 + corner_size;
|
||||||
blend_area.y2 = shadow_area.y2 - corner_size;
|
blend_area.y2 = shadow_area.y2 - corner_size;
|
||||||
blend_dsc.mask = mask_buf;
|
blend_dsc.mask_buf = mask_buf;
|
||||||
|
|
||||||
if(_lv_area_intersect(&clip_area_sub, &blend_area, draw_ctx->clip_area) &&
|
if(_lv_area_intersect(&clip_area_sub, &blend_area, draw_ctx->clip_area) &&
|
||||||
!_lv_area_is_in(&clip_area_sub, &bg_area, r_bg)) {
|
!_lv_area_is_in(&clip_area_sub, &bg_area, r_bg)) {
|
||||||
@@ -1126,7 +1126,7 @@ void draw_border_generic(lv_draw_ctx_t * draw_ctx, const lv_area_t * outer_area,
|
|||||||
|
|
||||||
lv_draw_sw_blend_dsc_t blend_dsc;
|
lv_draw_sw_blend_dsc_t blend_dsc;
|
||||||
lv_memset_00(&blend_dsc, sizeof(blend_dsc));
|
lv_memset_00(&blend_dsc, sizeof(blend_dsc));
|
||||||
blend_dsc.mask = lv_mem_buf_get(draw_area_w);;
|
blend_dsc.mask_buf = lv_mem_buf_get(draw_area_w);;
|
||||||
|
|
||||||
|
|
||||||
/*Create mask for the outer area*/
|
/*Create mask for the outer area*/
|
||||||
@@ -1172,8 +1172,8 @@ void draw_border_generic(lv_draw_ctx_t * draw_ctx, const lv_area_t * outer_area,
|
|||||||
blend_area.y1 = h;
|
blend_area.y1 = h;
|
||||||
blend_area.y2 = h;
|
blend_area.y2 = h;
|
||||||
|
|
||||||
lv_memset_ff(blend_dsc.mask, draw_area_w);
|
lv_memset_ff(blend_dsc.mask_buf, draw_area_w);
|
||||||
blend_dsc.mask_res = lv_draw_mask_apply(blend_dsc.mask, draw_area.x1, h, draw_area_w);
|
blend_dsc.mask_res = lv_draw_mask_apply(blend_dsc.mask_buf, draw_area.x1, h, draw_area_w);
|
||||||
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1183,7 +1183,7 @@ void draw_border_generic(lv_draw_ctx_t * draw_ctx, const lv_area_t * outer_area,
|
|||||||
lv_draw_mask_free_param(&mask_rout_param);
|
lv_draw_mask_free_param(&mask_rout_param);
|
||||||
lv_draw_mask_remove_id(mask_rout_id);
|
lv_draw_mask_remove_id(mask_rout_id);
|
||||||
}
|
}
|
||||||
lv_mem_buf_release(blend_dsc.mask);
|
lv_mem_buf_release(blend_dsc.mask_buf);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1245,8 +1245,8 @@ void draw_border_generic(lv_draw_ctx_t * draw_ctx, const lv_area_t * outer_area,
|
|||||||
lv_coord_t bottom_y = outer_area->y2 - h;
|
lv_coord_t bottom_y = outer_area->y2 - h;
|
||||||
if(top_y < draw_area.y1 && bottom_y > draw_area.y2) continue; /*This line is clipped now*/
|
if(top_y < draw_area.y1 && bottom_y > draw_area.y2) continue; /*This line is clipped now*/
|
||||||
|
|
||||||
lv_memset_ff(blend_dsc.mask, draw_area_w);
|
lv_memset_ff(blend_dsc.mask_buf, draw_area_w);
|
||||||
blend_dsc.mask_res = lv_draw_mask_apply(blend_dsc.mask, blend_area.x1, top_y, draw_area_w);
|
blend_dsc.mask_res = lv_draw_mask_apply(blend_dsc.mask_buf, blend_area.x1, top_y, draw_area_w);
|
||||||
|
|
||||||
if(top_y >= draw_area.y1) {
|
if(top_y >= draw_area.y1) {
|
||||||
blend_area.y1 = top_y;
|
blend_area.y1 = top_y;
|
||||||
@@ -1272,8 +1272,8 @@ void draw_border_generic(lv_draw_ctx_t * draw_ctx, const lv_area_t * outer_area,
|
|||||||
blend_area.y1 = h;
|
blend_area.y1 = h;
|
||||||
blend_area.y2 = h;
|
blend_area.y2 = h;
|
||||||
|
|
||||||
lv_memset_ff(blend_dsc.mask, blend_w);
|
lv_memset_ff(blend_dsc.mask_buf, blend_w);
|
||||||
blend_dsc.mask_res = lv_draw_mask_apply(blend_dsc.mask, blend_area.x1, h, blend_w);
|
blend_dsc.mask_res = lv_draw_mask_apply(blend_dsc.mask_buf, blend_area.x1, h, blend_w);
|
||||||
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1283,8 +1283,8 @@ void draw_border_generic(lv_draw_ctx_t * draw_ctx, const lv_area_t * outer_area,
|
|||||||
blend_area.y1 = h;
|
blend_area.y1 = h;
|
||||||
blend_area.y2 = h;
|
blend_area.y2 = h;
|
||||||
|
|
||||||
lv_memset_ff(blend_dsc.mask, blend_w);
|
lv_memset_ff(blend_dsc.mask_buf, blend_w);
|
||||||
blend_dsc.mask_res = lv_draw_mask_apply(blend_dsc.mask, blend_area.x1, h, blend_w);
|
blend_dsc.mask_res = lv_draw_mask_apply(blend_dsc.mask_buf, blend_area.x1, h, blend_w);
|
||||||
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1301,8 +1301,8 @@ void draw_border_generic(lv_draw_ctx_t * draw_ctx, const lv_area_t * outer_area,
|
|||||||
blend_area.y1 = h;
|
blend_area.y1 = h;
|
||||||
blend_area.y2 = h;
|
blend_area.y2 = h;
|
||||||
|
|
||||||
lv_memset_ff(blend_dsc.mask, blend_w);
|
lv_memset_ff(blend_dsc.mask_buf, blend_w);
|
||||||
blend_dsc.mask_res = lv_draw_mask_apply(blend_dsc.mask, blend_area.x1, h, blend_w);
|
blend_dsc.mask_res = lv_draw_mask_apply(blend_dsc.mask_buf, blend_area.x1, h, blend_w);
|
||||||
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1312,8 +1312,8 @@ void draw_border_generic(lv_draw_ctx_t * draw_ctx, const lv_area_t * outer_area,
|
|||||||
blend_area.y1 = h;
|
blend_area.y1 = h;
|
||||||
blend_area.y2 = h;
|
blend_area.y2 = h;
|
||||||
|
|
||||||
lv_memset_ff(blend_dsc.mask, blend_w);
|
lv_memset_ff(blend_dsc.mask_buf, blend_w);
|
||||||
blend_dsc.mask_res = lv_draw_mask_apply(blend_dsc.mask, blend_area.x1, h, blend_w);
|
blend_dsc.mask_res = lv_draw_mask_apply(blend_dsc.mask_buf, blend_area.x1, h, blend_w);
|
||||||
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
lv_draw_sw_blend(draw_ctx, &blend_dsc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1324,7 +1324,7 @@ void draw_border_generic(lv_draw_ctx_t * draw_ctx, const lv_area_t * outer_area,
|
|||||||
lv_draw_mask_remove_id(mask_rin_id);
|
lv_draw_mask_remove_id(mask_rin_id);
|
||||||
lv_draw_mask_free_param(&mask_rout_param);
|
lv_draw_mask_free_param(&mask_rout_param);
|
||||||
lv_draw_mask_remove_id(mask_rout_id);
|
lv_draw_mask_remove_id(mask_rout_id);
|
||||||
lv_mem_buf_release(blend_dsc.mask);
|
lv_mem_buf_release(blend_dsc.mask_buf);
|
||||||
|
|
||||||
#else /*LV_DRAW_COMPLEX*/
|
#else /*LV_DRAW_COMPLEX*/
|
||||||
LV_UNUSED(blend_mode);
|
LV_UNUSED(blend_mode);
|
||||||
|
|||||||
Reference in New Issue
Block a user