perf(sdl): optimize the use of SDL_RenderSetClipRect (#2941)

* reduce SDL_RenderSetClipRect as much as possible

* added some comments

* removing draw_sw usage

* fixed import

* implemented polygon drawing

* supports subimage for sdl texture based images

* fixed formatting

* removed unused code

* cleanup

* cleanup

* formatted code
This commit is contained in:
Mariotaku
2022-01-05 18:01:18 +09:00
committed by GitHub
parent edb207e27c
commit 9bbf661dd4
14 changed files with 387 additions and 208 deletions

View File

@@ -28,6 +28,7 @@ extern "C" {
void lv_example_event_1(void);
void lv_example_event_2(void);
void lv_example_event_3(void);
void lv_example_event_4(void);
/**********************
* MACROS

View File

@@ -0,0 +1,65 @@
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES
static int n = 3;
static lv_obj_t * label = NULL;
static void timer_cb(lv_timer_t * timer)
{
if (n < 3 || n > 32) {
n = 3;
} else {
static uint32_t old_tick = 0;
uint32_t tick = lv_tick_get();
if (!old_tick) {
old_tick = tick;
}
if (tick - old_tick > 3000) {
n++;
lv_label_set_text_fmt(label, "%d sides", n);
old_tick = tick;
}
}
lv_obj_invalidate(timer->user_data);
}
static void event_cb(lv_event_t * e)
{
/*The original target of the event. Can be the buttons or the container*/
lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e);
lv_draw_rect_dsc_t draw_dsc;
lv_draw_rect_dsc_init(&draw_dsc);
draw_dsc.bg_color = lv_palette_main(LV_PALETTE_LIGHT_GREEN);
draw_dsc.bg_opa = LV_OPA_COVER;
lv_point_t points[32];
int i, r = 150;
uint32_t tick = lv_tick_get();
for (i = 0; i < n; i++) {
int angle = i * 360 / n + ((tick % 36000) / 100);
lv_coord_t x = 150 + (r * lv_trigo_cos(angle) >> LV_TRIGO_SHIFT), y =
150 + (r * lv_trigo_sin(angle) >> LV_TRIGO_SHIFT);
points[i].x = x;
points[i].y = y;
}
lv_draw_polygon(draw_ctx, &draw_dsc, points, n);
}
/**
* Demonstrate event bubbling
*/
void lv_example_event_4(void)
{
lv_obj_t * cont = lv_obj_create(lv_scr_act());
lv_obj_remove_style_all(cont);
lv_obj_set_size(cont, 300, 300);
label = lv_label_create(cont);
lv_label_set_text_fmt(label, "%d sides", n);
lv_obj_center(label);
lv_obj_add_event_cb(cont, event_cb, LV_EVENT_DRAW_MAIN, NULL);
lv_timer_create(timer_cb, 17, cont);
}
#endif

View File

@@ -41,6 +41,9 @@ LV_ATTRIBUTE_FAST_MEM static lv_draw_mask_res_t lv_draw_mask_fade(lv_opa_t * mas
LV_ATTRIBUTE_FAST_MEM static lv_draw_mask_res_t lv_draw_mask_map(lv_opa_t * mask_buf, lv_coord_t abs_x,
lv_coord_t abs_y, lv_coord_t len,
lv_draw_mask_map_param_t * param);
LV_ATTRIBUTE_FAST_MEM static lv_draw_mask_res_t lv_draw_mask_polygon(lv_opa_t * mask_buf, lv_coord_t abs_x,
lv_coord_t abs_y, lv_coord_t len,
lv_draw_mask_polygon_param_t * param);
LV_ATTRIBUTE_FAST_MEM static lv_draw_mask_res_t line_mask_flat(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y,
lv_coord_t len,
@@ -219,6 +222,10 @@ void lv_draw_mask_free_param(void * p)
}
}
}
else if(pdsc->type == LV_DRAW_MASK_TYPE_POLYGON) {
lv_draw_mask_polygon_param_t * poly_p = (lv_draw_mask_polygon_param_t *) p;
lv_mem_free(poly_p->cfg.points);
}
}
void _lv_draw_mask_cleanup(void)
@@ -560,6 +567,31 @@ void lv_draw_mask_map_init(lv_draw_mask_map_param_t * param, const lv_area_t * c
param->dsc.type = LV_DRAW_MASK_TYPE_MAP;
}
void lv_draw_mask_polygon_init(lv_draw_mask_polygon_param_t * param, const lv_point_t * points, uint16_t point_cnt)
{
/*Join adjacent points if they are on the same coordinate*/
lv_point_t * p = lv_mem_alloc(point_cnt * sizeof(lv_point_t));
if(p == NULL) return;
uint16_t i;
uint16_t pcnt = 0;
p[0] = points[0];
for(i = 0; i < point_cnt - 1; i++) {
if(points[i].x != points[i + 1].x || points[i].y != points[i + 1].y) {
p[pcnt] = points[i];
pcnt++;
}
}
/*The first and the last points are also adjacent*/
if(points[0].x != points[point_cnt - 1].x || points[0].y != points[point_cnt - 1].y) {
p[pcnt] = points[point_cnt - 1];
pcnt++;
}
param->cfg.points = p;
param->cfg.point_cnt = pcnt;
param->dsc.cb = (lv_draw_mask_xcb_t)lv_draw_mask_polygon;
param->dsc.type = LV_DRAW_MASK_TYPE_POLYGON;
}
/**********************
* STATIC FUNCTIONS
**********************/
@@ -1218,6 +1250,79 @@ LV_ATTRIBUTE_FAST_MEM static lv_draw_mask_res_t lv_draw_mask_map(lv_opa_t * mask
return LV_DRAW_MASK_RES_CHANGED;
}
LV_ATTRIBUTE_FAST_MEM static lv_draw_mask_res_t lv_draw_mask_polygon(lv_opa_t * mask_buf, lv_coord_t abs_x,
lv_coord_t abs_y, lv_coord_t len,
lv_draw_mask_polygon_param_t * param)
{
uint16_t i;
struct {
lv_point_t p1;
lv_point_t p2;
} lines[2], tmp;
uint16_t line_cnt = 0;
lv_memset_00(&lines, sizeof(lines));
int psign_prev = 0;
for(i = 0; i < param->cfg.point_cnt; i++) {
lv_point_t p1 = param->cfg.points[i];
lv_point_t p2 = param->cfg.points[i + 1 < param->cfg.point_cnt ? i + 1 : 0];
int pdiff = p1.y - p2.y, psign = pdiff / LV_ABS(pdiff);
if(pdiff > 0) {
if(abs_y > p1.y || abs_y < p2.y) continue;
lines[line_cnt].p1 = p2;
lines[line_cnt].p2 = p1;
}
else {
if(abs_y < p1.y || abs_y > p2.y) continue;
lines[line_cnt].p1 = p1;
lines[line_cnt].p2 = p2;
}
if(psign_prev && psign_prev == psign) continue;
psign_prev = psign;
line_cnt++;
if(line_cnt == 2) break;
}
if(line_cnt != 2) return LV_DRAW_MASK_RES_TRANSP;
if(lines[0].p1.x > lines[1].p1.x || lines[0].p2.x > lines[1].p2.x) {
tmp = lines[0];
lines[0] = lines[1];
lines[1] = tmp;
}
lv_draw_mask_line_param_t line_p;
lv_draw_mask_line_points_init(&line_p, lines[0].p1.x, lines[0].p1.y, lines[0].p2.x, lines[0].p2.y,
LV_DRAW_MASK_LINE_SIDE_RIGHT);
if(line_p.steep == 0 && line_p.flat) {
lv_coord_t x1 = LV_MIN(lines[0].p1.x, lines[0].p2.x);
lv_coord_t x2 = LV_MAX(lines[0].p1.x, lines[0].p2.x);
for(i = 0; i < len; i++) {
mask_buf[i] = mask_mix(mask_buf[i], (abs_x + i >= x1 && abs_x + i <= x2) * 0xFF);
}
lv_draw_mask_free_param(&line_p);
return LV_DRAW_MASK_RES_CHANGED;
}
lv_draw_mask_res_t res1 = lv_draw_mask_line(mask_buf, abs_x, abs_y, len, &line_p);
lv_draw_mask_free_param(&line_p);
if(res1 == LV_DRAW_MASK_RES_TRANSP) {
return LV_DRAW_MASK_RES_TRANSP;
}
lv_draw_mask_line_points_init(&line_p, lines[1].p1.x, lines[1].p1.y, lines[1].p2.x, lines[1].p2.y,
LV_DRAW_MASK_LINE_SIDE_LEFT);
if(line_p.steep == 0 && line_p.flat) {
lv_coord_t x1 = LV_MIN(lines[1].p1.x, lines[1].p2.x);
lv_coord_t x2 = LV_MAX(lines[1].p1.x, lines[1].p2.x);
for(i = 0; i < len; i++) {
mask_buf[i] = mask_mix(mask_buf[i], (abs_x + i >= x1 && abs_x + i <= x2) * 0xFF);
}
lv_draw_mask_free_param(&line_p);
return LV_DRAW_MASK_RES_CHANGED;
}
lv_draw_mask_res_t res2 = lv_draw_mask_line(mask_buf, abs_x, abs_y, len, &line_p);
lv_draw_mask_free_param(&line_p);
if(res2 == LV_DRAW_MASK_RES_TRANSP) {
return LV_DRAW_MASK_RES_TRANSP;
}
if(res1 == LV_DRAW_MASK_RES_CHANGED || res2 == LV_DRAW_MASK_RES_CHANGED) return LV_DRAW_MASK_RES_CHANGED;
return res1;
}
/**
* Initialize the circle drawing
* @param c pointer to a point. The coordinates will be calculated here

View File

@@ -73,6 +73,7 @@ enum {
LV_DRAW_MASK_TYPE_RADIUS,
LV_DRAW_MASK_TYPE_FADE,
LV_DRAW_MASK_TYPE_MAP,
LV_DRAW_MASK_TYPE_POLYGON,
};
typedef uint8_t lv_draw_mask_type_t;
@@ -204,6 +205,16 @@ typedef struct _lv_draw_mask_map_param_t {
} cfg;
} lv_draw_mask_map_param_t;
typedef struct {
/*The first element must be the common descriptor*/
_lv_draw_mask_common_dsc_t dsc;
struct {
lv_point_t * points;
uint16_t point_cnt;
} cfg;
} lv_draw_mask_polygon_param_t;
/**********************
* GLOBAL PROTOTYPES
@@ -368,6 +379,8 @@ void lv_draw_mask_fade_init(lv_draw_mask_fade_param_t * param, const lv_area_t *
*/
void lv_draw_mask_map_init(lv_draw_mask_map_param_t * param, const lv_area_t * coords, const lv_opa_t * map);
void lv_draw_mask_polygon_init(lv_draw_mask_polygon_param_t * param, const lv_point_t * points, uint16_t point_cnt);
#endif /*LV_DRAW_COMPLEX*/
/**********************

View File

@@ -33,9 +33,10 @@ void lv_draw_sdl_draw_line(lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t *
void lv_draw_sdl_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center,
uint16_t radius, uint16_t start_angle, uint16_t end_angle);
void lv_draw_sdl_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords);
void lv_draw_sdl_polygon(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * draw_dsc, const lv_point_t * points,
uint16_t point_cnt);
void lv_draw_sdl_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc);
void lv_draw_sdl_draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords);
/**********************
* TYPEDEFS
@@ -61,16 +62,15 @@ void lv_draw_sdl_init_ctx(lv_disp_drv_t * disp_drv, lv_draw_ctx_t * draw_ctx)
{
_lv_draw_sdl_utils_init();
lv_memset_00(draw_ctx, sizeof(lv_draw_sdl_ctx_t));
lv_draw_sw_init_ctx(disp_drv, draw_ctx);
draw_ctx->draw_rect = lv_draw_sdl_draw_rect;
draw_ctx->draw_img = lv_draw_sdl_img_core;
draw_ctx->draw_letter = lv_draw_sdl_draw_letter;
draw_ctx->draw_line = lv_draw_sdl_draw_line;
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;
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->base_draw.blend = lv_draw_sdl_blend;
draw_ctx_sdl->internals = lv_mem_alloc(sizeof(lv_draw_sdl_context_internals_t));
lv_memset_00(draw_ctx_sdl->internals, sizeof(lv_draw_sdl_context_internals_t));
lv_draw_sdl_texture_cache_init(draw_ctx_sdl);

View File

@@ -20,7 +20,8 @@ extern "C" {
#include LV_GPU_SDL_INCLUDE_PATH
#include "../sw/lv_draw_sw.h"
#include "../lv_draw.h"
#include "../../core/lv_disp.h"
/*********************
* DEFINES
@@ -46,7 +47,7 @@ typedef struct {
} lv_draw_sdl_drv_param_t;
typedef struct {
lv_draw_sw_ctx_t base_draw;
lv_draw_ctx_t base_draw;
SDL_Renderer * renderer;
struct lv_draw_sdl_context_internals_t * internals;
} lv_draw_sdl_ctx_t;

View File

@@ -1,12 +1,12 @@
CSRCS += lv_draw_sdl.c
CSRCS += lv_draw_sdl_arc.c
CSRCS += lv_draw_sdl_bg.c
CSRCS += lv_draw_sdl_blend.c
CSRCS += lv_draw_sdl_composite.c
CSRCS += lv_draw_sdl_img.c
CSRCS += lv_draw_sdl_label.c
CSRCS += lv_draw_sdl_line.c
CSRCS += lv_draw_sdl_mask.c
CSRCS += lv_draw_sdl_polygon.c
CSRCS += lv_draw_sdl_rect.c
CSRCS += lv_draw_sdl_stack_blur.c
CSRCS += lv_draw_sdl_texture_cache.c

View File

@@ -1,5 +1,5 @@
/**
* @file lv_templ.c
* @file lv_draw_sdl_arc.c
*
*/
@@ -14,7 +14,6 @@
#include "lv_draw_sdl_utils.h"
#include "lv_draw_sdl_texture_cache.h"
#include "lv_draw_sdl_composite.h"
#include "lv_draw_sdl_mask.h"
/*********************
* DEFINES
@@ -24,14 +23,6 @@
* TYPEDEFS
**********************/
typedef struct {
lv_sdl_cache_key_magic_t magic;
uint16_t radius;
uint16_t angle;
lv_coord_t width;
uint8_t rounded;
} lv_draw_arc_key_t;
/**********************
* STATIC PROTOTYPES
**********************/
@@ -44,9 +35,6 @@ typedef struct {
* MACROS
**********************/
static lv_draw_arc_key_t arc_key_create(const lv_draw_arc_dsc_t * dsc, uint16_t radius, uint16_t start_angle,
uint16_t end_angle);
static void dump_masks(SDL_Texture * texture, const lv_area_t * coords, const int16_t * ids, int16_t ids_count,
const int16_t * caps);
@@ -60,7 +48,6 @@ void lv_draw_sdl_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * ds
uint16_t radius, uint16_t start_angle, uint16_t end_angle)
{
lv_draw_sdl_ctx_t * ctx = (lv_draw_sdl_ctx_t *) draw_ctx;
SDL_Renderer * renderer = ctx->renderer;
lv_area_t area_out;
area_out.x1 = center->x - radius;
@@ -154,19 +141,6 @@ void lv_draw_sdl_draw_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * ds
* STATIC FUNCTIONS
**********************/
static lv_draw_arc_key_t arc_key_create(const lv_draw_arc_dsc_t * dsc, uint16_t radius, uint16_t start_angle,
uint16_t end_angle)
{
lv_draw_arc_key_t key;
lv_memset_00(&key, sizeof(lv_draw_arc_key_t));
key.magic = LV_GPU_CACHE_KEY_MAGIC_ARC;
key.radius = radius;
key.angle = ((end_angle - start_angle) % 360 + 360) % 360;
key.width = dsc->width;
key.rounded = dsc->rounded;
return key;
}
static void dump_masks(SDL_Texture * texture, const lv_area_t * coords, const int16_t * ids, int16_t ids_count,
const int16_t * caps)
{
@@ -233,7 +207,7 @@ static void get_cap_area(int16_t angle, lv_coord_t thickness, uint16_t radius, c
int32_t cir_x;
int32_t cir_y;
cir_x = ((radius - thick_half) * lv_trigo_sin(90 - angle)) >> (LV_TRIGO_SHIFT - ps);
cir_x = ((radius - thick_half) * lv_trigo_sin((int16_t)(90 - angle))) >> (LV_TRIGO_SHIFT - ps);
cir_y = ((radius - thick_half) * lv_trigo_sin(angle)) >> (LV_TRIGO_SHIFT - ps);
/*Actually the center of the pixel need to be calculated so apply 1/2 px offset*/

View File

@@ -1,154 +0,0 @@
/**
* @file lv_draw_sdl_blend.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include "lv_draw_sdl_texture_cache.h"
#include "lv_draw_sdl_utils.h"
#include "lv_draw_sdl_composite.h"
#include LV_GPU_SDL_INCLUDE_PATH
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void blend_fill(lv_draw_sdl_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc);
static void blend_map(lv_draw_sdl_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_sdl_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc)
{
if(dsc->src_buf) {
blend_map((lv_draw_sdl_ctx_t *) draw_ctx, dsc);
}
else {
blend_fill((lv_draw_sdl_ctx_t *) draw_ctx, dsc);
}
}
/**********************
* STATIC FUNCTIONS
**********************/
void blend_fill(lv_draw_sdl_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc)
{
const lv_opa_t opa = dsc->opa;
const lv_color_t color = dsc->color;
/*Do not draw transparent things*/
if(opa < LV_OPA_MIN) return;
SDL_Renderer * renderer = draw_ctx->renderer;
lv_area_t fill_area;
_lv_area_intersect(&fill_area, draw_ctx->base_draw.base_draw.clip_area, dsc->blend_area);
SDL_Rect fill_rect;
lv_area_to_sdl_rect(&fill_area, &fill_rect);
if(dsc->mask) {
SDL_Texture * texture = lv_draw_sdl_composite_texture_obtain(draw_ctx, LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_STREAM0,
lv_area_get_height(&fill_area),
lv_area_get_width(&fill_area));
SDL_Rect rect = {0, 0, lv_area_get_width(&fill_area), lv_area_get_height(&fill_area)};
uint8_t * pixels = NULL;
int pitch;
SDL_LockTexture(texture, &rect, (void **) &pixels, &pitch);
SDL_assert(pixels && pitch);
for(int y = 0; y < rect.h; y++) {
SDL_memset(&pixels[y * pitch], 0xFF, 4 * rect.w);
for(int x = 0; x < rect.w; x++) {
pixels[y * pitch + x * 4] = dsc->mask[y * rect.w + x];
}
}
SDL_UnlockTexture(texture);
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
SDL_SetTextureAlphaMod(texture, opa);
SDL_SetTextureColorMod(texture, color.ch.red, color.ch.green, color.ch.blue);
SDL_RenderCopy(renderer, texture, &rect, &fill_rect);
}
else {
SDL_SetRenderDrawColor(renderer, color.ch.red, color.ch.green, color.ch.blue, opa);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
SDL_RenderFillRect(renderer, &fill_rect);
}
}
void blend_map(lv_draw_sdl_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc)
{
const lv_opa_t opa = dsc->opa;
/*Do not draw transparent things*/
if(opa < LV_OPA_MIN) return;
lv_coord_t sw = lv_area_get_width(dsc->blend_area), sh = lv_area_get_height(dsc->blend_area);
SDL_Renderer * renderer = draw_ctx->renderer;
SDL_Rect draw_area_rect;
lv_area_to_sdl_rect(draw_ctx->base_draw.base_draw.clip_area, &draw_area_rect);
Uint32 rmask = 0x00FF0000;
Uint32 gmask = 0x0000FF00;
Uint32 bmask = 0x000000FF;
Uint32 amask = 0x00000000;
SDL_Surface * surface = SDL_CreateRGBSurfaceFrom((void *) dsc->src_buf, sw, sh, LV_COLOR_DEPTH,
sw * LV_COLOR_DEPTH / 8, rmask, gmask, bmask, amask);
if(dsc->mask) {
SDL_Texture * masked = SDL_CreateTexture(renderer, LV_DRAW_SDL_TEXTURE_FORMAT, SDL_TEXTUREACCESS_TARGET,
sw, sh);
SDL_Texture * mask_texture = lv_sdl_create_opa_texture(renderer, dsc->mask, sw, sh, sw);
SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_SetRenderTarget(renderer, masked);
SDL_SetTextureAlphaMod(mask_texture, opa);
SDL_SetTextureBlendMode(mask_texture, SDL_BLENDMODE_NONE);
SDL_RenderCopy(renderer, mask_texture, NULL, NULL);
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_MOD);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_SetRenderTarget(renderer, draw_ctx->base_draw.base_draw.buf);
SDL_SetTextureBlendMode(masked, SDL_BLENDMODE_BLEND);
SDL_SetTextureAlphaMod(masked, 0xFF);
SDL_SetTextureColorMod(masked, 0xFF, 0xFF, 0xFF);
SDL_RenderCopy(renderer, masked, NULL, &draw_area_rect);
SDL_DestroyTexture(texture);
SDL_DestroyTexture(mask_texture);
SDL_DestroyTexture(masked);
}
else {
SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_SetTextureAlphaMod(texture, opa);
SDL_SetRenderTarget(renderer, draw_ctx->base_draw.base_draw.buf);
SDL_RenderCopy(renderer, texture, NULL, &draw_area_rect);
SDL_DestroyTexture(texture);
}
SDL_FreeSurface(surface);
}
#endif /*LV_USE_GPU_SDL*/

View File

@@ -141,7 +141,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.base_draw.buf);
SDL_SetRenderTarget(ctx->renderer, ctx->base_draw.buf);
switch(blend_mode) {
case LV_BLEND_MODE_NORMAL:
SDL_SetTextureBlendMode(internals->composition, SDL_BLENDMODE_BLEND);

View File

@@ -26,7 +26,10 @@
/**********************
* TYPEDEFS
**********************/
typedef struct sdl_img_header_t {
lv_img_header_t base;
SDL_Rect rect;
} sdl_img_header_t;
/**********************
* STATIC PROTOTYPES
@@ -58,15 +61,20 @@ lv_res_t lv_draw_sdl_img_core(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t
size_t key_size;
lv_draw_sdl_cache_key_head_img_t * key = lv_draw_sdl_texture_img_key_create(src, draw_dsc->frame_id, &key_size);
bool texture_found = false;
SDL_Texture * texture = lv_draw_sdl_texture_cache_get(ctx, key, key_size, &texture_found);
sdl_img_header_t * header = NULL;
SDL_Texture * texture = lv_draw_sdl_texture_cache_get_with_userdata(ctx, key, key_size, &texture_found,
(void **) &header);
if(!texture_found) {
_lv_img_cache_entry_t * cdsc = _lv_img_cache_open(src, draw_dsc->recolor, draw_dsc->frame_id);
lv_draw_sdl_cache_flag_t tex_flags = 0;
SDL_Rect rect;
SDL_memset(&rect, 0, sizeof(SDL_Rect));
if(cdsc) {
lv_img_decoder_dsc_t * dsc = &cdsc->dec_dsc;
if(dsc->user_data && SDL_memcmp(dsc->user_data, LV_DRAW_SDL_DEC_DSC_TEXTURE_HEAD, 8) == 0) {
lv_draw_sdl_dec_dsc_userdata_t * ptr = (lv_draw_sdl_dec_dsc_userdata_t *) dsc->user_data;
texture = ptr->texture;
rect = ptr->rect;
if(ptr->texture_managed) {
tex_flags |= LV_DRAW_SDL_CACHE_FLAG_MANAGED;
}
@@ -80,8 +88,9 @@ lv_res_t lv_draw_sdl_img_core(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t
#endif
}
if(texture && cdsc) {
lv_img_header_t * header = SDL_malloc(sizeof(lv_img_header_t));
SDL_memcpy(header, &cdsc->dec_dsc.header, sizeof(lv_img_header_t));
header = SDL_malloc(sizeof(sdl_img_header_t));
SDL_memcpy(&header->base, &cdsc->dec_dsc.header, sizeof(lv_img_header_t));
header->rect = rect;
lv_draw_sdl_texture_cache_put_advanced(ctx, key, key_size, texture, header, SDL_free, tex_flags);
}
else {
@@ -100,7 +109,35 @@ lv_res_t lv_draw_sdl_img_core(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t
SDL_Point pivot = {.x = draw_dsc->pivot.x, .y = draw_dsc->pivot.y};
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
SDL_Rect clipped_src = {0, 0, 0, 0}, clipped_dst = coords_rect;
const SDL_Rect * src_rect = NULL, *dst_rect = &clipped_dst;
if(_lv_area_is_in(coords, clip, 0)) {
/*Image needs to be fully drawn*/
src_rect = SDL_RectEmpty(&header->rect) ? NULL : &header->rect;
}
else if(draw_dsc->angle == 0) {
/*Image needs to be partly drawn, and we calculate the area to draw manually*/
Uint32 format = 0;
int access = 0, w, h;
if(SDL_RectEmpty(&header->rect)) {
SDL_QueryTexture(texture, &format, &access, &w, &h);
}
else {
w = header->rect.w;
h = header->rect.h;
}
SDL_IntersectRect(&clip_rect, &coords_rect, &clipped_dst);
clipped_src.x = header->rect.x + (clipped_dst.x - coords_rect.x) * w / coords_rect.x;
clipped_src.y = header->rect.y + (clipped_dst.y - coords_rect.y) * h / coords_rect.h;
clipped_src.w = w - (coords_rect.w - clipped_dst.w) * w / coords_rect.w;
clipped_src.h = h - (coords_rect.h - clipped_dst.h) * h / coords_rect.h;
src_rect = &clipped_src;
}
else {
/*Image needs to be rotated, so we have to use clip rect which is slower*/
SDL_RenderSetClipRect(renderer, &clip_rect);
}
SDL_Color recolor;
lv_color_to_sdl_color(&draw_dsc->recolor, &recolor);
@@ -108,22 +145,22 @@ lv_res_t lv_draw_sdl_img_core(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t
/* Draw fully recolored image*/
SDL_SetTextureColorMod(texture, draw_dsc->recolor.ch.red, recolor.g, recolor.b);
SDL_SetTextureAlphaMod(texture, draw_dsc->opa);
SDL_RenderCopyEx(renderer, texture, NULL, &coords_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE);
SDL_RenderCopyEx(renderer, texture, src_rect, dst_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE);
}
else if(draw_dsc->recolor_opa > LV_OPA_TRANSP) {
/* Draw blended. src: origA, dst: origA * recolorA */
SDL_SetTextureColorMod(texture, 0xFF, 0xFF, 0xFF);
SDL_SetTextureAlphaMod(texture, draw_dsc->opa);
SDL_RenderCopyEx(renderer, texture, NULL, &coords_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE);
SDL_RenderCopyEx(renderer, texture, src_rect, dst_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE);
SDL_SetTextureColorMod(texture, recolor.r, recolor.g, recolor.b);
SDL_SetTextureAlphaMod(texture, draw_dsc->opa * draw_dsc->recolor_opa / 255);
SDL_RenderCopyEx(renderer, texture, NULL, &coords_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE);
SDL_RenderCopyEx(renderer, texture, src_rect, dst_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE);
}
else {
/* Draw with no recolor */
SDL_SetTextureColorMod(texture, 0xFF, 0xFF, 0xFF);
SDL_SetTextureAlphaMod(texture, draw_dsc->opa);
SDL_RenderCopyEx(renderer, texture, NULL, &coords_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE);
SDL_RenderCopyEx(renderer, texture, src_rect, dst_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE);
}
SDL_RenderSetClipRect(renderer, NULL);
return LV_RES_OK;

View File

@@ -1,5 +1,5 @@
/**
* @file lv_templ.c
* @file lv_draw_sdl_line.c
*
*/
@@ -64,10 +64,10 @@ void lv_draw_sdl_draw_line(lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t *
}
double angle = SDL_atan2(y2 - y1, x2 - x1) * 180 / M_PI;
lv_draw_line_key_t key = line_key_create(dsc, length);
lv_draw_line_key_t key = line_key_create(dsc, (lv_coord_t) length);
SDL_Texture * texture = lv_draw_sdl_texture_cache_get(sdl_ctx, &key, sizeof(key), NULL);
if(!texture) {
texture = line_texture_create(sdl_ctx, dsc, length);
texture = line_texture_create(sdl_ctx, dsc, (lv_coord_t) length);
lv_draw_sdl_texture_cache_put(sdl_ctx, &key, sizeof(key), texture);
}
@@ -80,20 +80,23 @@ void lv_draw_sdl_draw_line(lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t *
lv_area_t t_coords = coords, t_clip = *clip, apply_area;
lv_area_t extension = {dsc->width / 2, dsc->width / 2, dsc->width / 2, dsc->width / 2};
bool has_mask = lv_draw_sdl_composite_begin(sdl_ctx, &coords, clip, &extension, dsc->blend_mode, &t_coords, &t_clip,
lv_draw_sdl_composite_begin(sdl_ctx, &coords, clip, &extension, dsc->blend_mode, &t_coords, &t_clip,
&apply_area);
SDL_Color color;
lv_color_to_sdl_color(&dsc->color, &color);
SDL_Rect clip_rect;
lv_area_to_sdl_rect(&t_clip, &clip_rect);
SDL_RenderSetClipRect(renderer, &clip_rect);
SDL_SetTextureColorMod(texture, color.r, color.g, color.b);
SDL_SetTextureAlphaMod(texture, dsc->opa);
SDL_Rect srcrect = {0, 0, length + dsc->width + 2, dsc->width + 2},
SDL_Rect srcrect = {0, 0, (int) length + dsc->width + 2, dsc->width + 2},
dstrect = {t_coords.x1 - 1 - dsc->width / 2, t_coords.y1 - 1, srcrect.w, srcrect.h};
SDL_Point center = {1 + dsc->width / 2, 1 + dsc->width / 2};
SDL_Rect clip_rect;
lv_area_to_sdl_rect(&t_clip, &clip_rect);
if(!SDL_RectEquals(&clip_rect, &dstrect) || angle != 0) {
SDL_RenderSetClipRect(renderer, &clip_rect);
}
SDL_RenderCopyEx(renderer, texture, &srcrect, &dstrect, angle, &center, 0);
SDL_RenderSetClipRect(renderer, NULL);

View File

@@ -0,0 +1,133 @@
/**
* @file lv_draw_sdl_polygon.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_GPU_SDL
#include "lv_draw_sdl.h"
#include "lv_draw_sdl_utils.h"
#include "lv_draw_sdl_texture_cache.h"
#include "lv_draw_sdl_composite.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
static void dump_masks(SDL_Texture * texture, const lv_area_t * coords);
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_sdl_polygon(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * draw_dsc, const lv_point_t * points,
uint16_t point_cnt)
{
if(point_cnt < 3) return;
if(points == NULL) return;
lv_draw_mask_polygon_param_t polygon_param;
lv_draw_mask_polygon_init(&polygon_param, points, point_cnt);
if(polygon_param.cfg.point_cnt < 3) {
lv_draw_mask_free_param(&polygon_param);
return;
}
lv_area_t poly_coords = {.x1 = LV_COORD_MAX, .y1 = LV_COORD_MAX, .x2 = LV_COORD_MIN, .y2 = LV_COORD_MIN};
uint16_t i;
for(i = 0; i < point_cnt; i++) {
poly_coords.x1 = LV_MIN(poly_coords.x1, polygon_param.cfg.points[i].x);
poly_coords.y1 = LV_MIN(poly_coords.y1, polygon_param.cfg.points[i].y);
poly_coords.x2 = LV_MAX(poly_coords.x2, polygon_param.cfg.points[i].x);
poly_coords.y2 = LV_MAX(poly_coords.y2, polygon_param.cfg.points[i].y);
}
bool is_common;
lv_area_t draw_area;
is_common = _lv_area_intersect(&draw_area, &poly_coords, draw_ctx->clip_area);
if(!is_common) {
lv_draw_mask_free_param(&polygon_param);
return;
}
lv_draw_sdl_ctx_t * ctx = (lv_draw_sdl_ctx_t *) draw_ctx;
int16_t mask_id = lv_draw_mask_add(&polygon_param, NULL);
lv_coord_t w = lv_area_get_width(&draw_area), h = lv_area_get_height(&draw_area);
SDL_Texture * texture = lv_draw_sdl_composite_texture_obtain(ctx, LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_STREAM1, w, h);
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
dump_masks(texture, &draw_area);
lv_draw_mask_remove_id(mask_id);
lv_draw_mask_free_param(&polygon_param);
SDL_Rect srcrect = {0, 0, w, h}, dstrect;
lv_area_to_sdl_rect(&draw_area, &dstrect);
SDL_Color color;
lv_color_to_sdl_color(&draw_dsc->bg_color, &color);
SDL_SetTextureColorMod(texture, color.r, color.g, color.b);
SDL_SetTextureAlphaMod(texture, draw_dsc->bg_opa);
SDL_RenderCopy(ctx->renderer, texture, &srcrect, &dstrect);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void dump_masks(SDL_Texture * texture, const lv_area_t * coords)
{
lv_coord_t w = lv_area_get_width(coords), h = lv_area_get_height(coords);
SDL_assert(w > 0 && h > 0);
SDL_Rect rect = {0, 0, w, h};
uint8_t * pixels;
int pitch;
if(SDL_LockTexture(texture, &rect, (void **) &pixels, &pitch) != 0) return;
lv_opa_t * line_buf = lv_mem_buf_get(rect.w);
for(lv_coord_t y = 0; y < rect.h; y++) {
lv_memset_ff(line_buf, rect.w);
lv_coord_t abs_x = (lv_coord_t) coords->x1, abs_y = (lv_coord_t)(y + coords->y1), len = (lv_coord_t) rect.w;
lv_draw_mask_res_t res;
res = lv_draw_mask_apply(line_buf, abs_x, abs_y, len);
if(res == LV_DRAW_MASK_RES_TRANSP) {
lv_memset_00(&pixels[y * pitch], 4 * rect.w);
}
else if(res == LV_DRAW_MASK_RES_FULL_COVER) {
lv_memset_ff(&pixels[y * pitch], 4 * rect.w);
}
else {
for(int x = 0; x < rect.w; x++) {
uint8_t * pixel = &pixels[y * pitch + x * 4];
*pixel = line_buf[x];
pixel[1] = pixel[2] = pixel[3] = 0xFF;
}
}
}
lv_mem_buf_release(line_buf);
SDL_UnlockTexture(texture);
}
#endif /*LV_USE_GPU_SDL*/

View File

@@ -37,6 +37,7 @@ extern "C" {
typedef struct {
char head[8];
SDL_Texture * texture;
SDL_Rect rect;
bool texture_managed;
bool texture_referenced;
} lv_draw_sdl_dec_dsc_userdata_t;