acid-drop- Hacking the planet from a LilyGo T-Deck using custom firmware |
git clone git://git.acid.vegas/acid-drop.git |
Log | Files | Refs | Archive | README | LICENSE |
lv_draw_sdl_composite.c (9959B)
1 /** 2 * @file lv_draw_sdl_composite.c 3 * 4 */ 5 6 /********************* 7 * INCLUDES 8 *********************/ 9 #include "../../lv_conf_internal.h" 10 11 #if LV_USE_GPU_SDL 12 13 #include "../../misc/lv_gc.h" 14 #include "../../core/lv_refr.h" 15 #include "lv_draw_sdl_composite.h" 16 #include "lv_draw_sdl_mask.h" 17 #include "lv_draw_sdl_utils.h" 18 #include "lv_draw_sdl_priv.h" 19 #include "lv_draw_sdl_texture_cache.h" 20 21 /********************* 22 * DEFINES 23 *********************/ 24 25 /********************** 26 * TYPEDEFS 27 **********************/ 28 29 typedef struct { 30 lv_sdl_cache_key_magic_t magic; 31 lv_draw_sdl_composite_texture_id_t type; 32 } composite_key_t; 33 34 /********************** 35 * STATIC PROTOTYPES 36 **********************/ 37 38 static composite_key_t mask_key_create(lv_draw_sdl_composite_texture_id_t type); 39 40 static lv_coord_t next_pow_of_2(lv_coord_t num); 41 42 static void dump_masks(SDL_Texture * texture, const lv_area_t * coords); 43 /********************** 44 * STATIC VARIABLES 45 **********************/ 46 47 /********************** 48 * MACROS 49 **********************/ 50 51 /********************** 52 * GLOBAL FUNCTIONS 53 **********************/ 54 55 bool lv_draw_sdl_composite_begin(lv_draw_sdl_ctx_t * ctx, const lv_area_t * coords_in, const lv_area_t * clip_in, 56 const lv_area_t * extension, lv_blend_mode_t blend_mode, lv_area_t * coords_out, 57 lv_area_t * clip_out, lv_area_t * apply_area) 58 { 59 lv_area_t full_coords = *coords_in; 60 61 /* Normalize full_coords */ 62 if(full_coords.x1 > full_coords.x2) { 63 lv_coord_t x2 = full_coords.x2; 64 full_coords.x2 = full_coords.x1; 65 full_coords.x1 = x2; 66 } 67 if(full_coords.y1 > full_coords.y2) { 68 lv_coord_t y2 = full_coords.y2; 69 full_coords.y2 = full_coords.y1; 70 full_coords.y1 = y2; 71 } 72 73 if(extension) { 74 full_coords.x1 -= extension->x1; 75 full_coords.x2 += extension->x2; 76 full_coords.y1 -= extension->y1; 77 full_coords.y2 += extension->y2; 78 } 79 80 if(!_lv_area_intersect(apply_area, &full_coords, clip_in)) return false; 81 bool has_mask = lv_draw_mask_is_any(apply_area); 82 83 const bool draw_mask = has_mask && LV_GPU_SDL_CUSTOM_BLEND_MODE; 84 const bool draw_blend = blend_mode != LV_BLEND_MODE_NORMAL; 85 if(draw_mask || draw_blend) { 86 lv_draw_sdl_context_internals_t * internals = ctx->internals; 87 LV_ASSERT(internals->mask == NULL && internals->composition == NULL); 88 89 lv_coord_t w = lv_area_get_width(apply_area), h = lv_area_get_height(apply_area); 90 internals->composition = lv_draw_sdl_composite_texture_obtain(ctx, LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TARGET0, w, h); 91 /* Don't need to worry about overflow */ 92 lv_coord_t ofs_x = (lv_coord_t) - apply_area->x1, ofs_y = (lv_coord_t) - apply_area->y1; 93 /* Offset draw area to start with (0,0) of coords */ 94 lv_area_move(coords_out, ofs_x, ofs_y); 95 lv_area_move(clip_out, ofs_x, ofs_y); 96 SDL_SetRenderTarget(ctx->renderer, internals->composition); 97 SDL_SetRenderDrawColor(ctx->renderer, 255, 255, 255, 0); 98 SDL_RenderClear(ctx->renderer); 99 #if LV_GPU_SDL_CUSTOM_BLEND_MODE 100 internals->mask = lv_draw_sdl_composite_texture_obtain(ctx, LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_STREAM0, w, h); 101 dump_masks(internals->mask, apply_area); 102 #endif 103 } 104 else if(has_mask) { 105 /* Fallback mask handling. This will at least make bars looks less bad */ 106 for(uint8_t i = 0; i < _LV_MASK_MAX_NUM; i++) { 107 _lv_draw_mask_common_dsc_t * comm_param = LV_GC_ROOT(_lv_draw_mask_list[i]).param; 108 if(comm_param == NULL) continue; 109 switch(comm_param->type) { 110 case LV_DRAW_MASK_TYPE_RADIUS: { 111 const lv_draw_mask_radius_param_t * param = (const lv_draw_mask_radius_param_t *) comm_param; 112 if(param->cfg.outer) break; 113 _lv_area_intersect(clip_out, apply_area, ¶m->cfg.rect); 114 break; 115 } 116 default: 117 break; 118 } 119 } 120 } 121 return has_mask; 122 } 123 124 void lv_draw_sdl_composite_end(lv_draw_sdl_ctx_t * ctx, const lv_area_t * apply_area, lv_blend_mode_t blend_mode) 125 { 126 lv_draw_sdl_context_internals_t * internals = ctx->internals; 127 SDL_Rect src_rect = {0, 0, lv_area_get_width(apply_area), lv_area_get_height(apply_area)}; 128 #if LV_GPU_SDL_CUSTOM_BLEND_MODE 129 if(internals->mask) { 130 SDL_BlendMode mode = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_ONE, 131 SDL_BLENDOPERATION_ADD, SDL_BLENDFACTOR_ZERO, 132 SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDOPERATION_ADD); 133 SDL_SetTextureBlendMode(internals->mask, mode); 134 SDL_RenderCopy(ctx->renderer, internals->mask, &src_rect, &src_rect); 135 } 136 #endif 137 138 /* Shapes are drawn on composite layer when mask or blend mode is present */ 139 if(internals->composition) { 140 SDL_Rect dst_rect; 141 lv_area_to_sdl_rect(apply_area, &dst_rect); 142 143 SDL_SetRenderTarget(ctx->renderer, ctx->base_draw.buf); 144 switch(blend_mode) { 145 case LV_BLEND_MODE_NORMAL: 146 SDL_SetTextureBlendMode(internals->composition, SDL_BLENDMODE_BLEND); 147 break; 148 case LV_BLEND_MODE_ADDITIVE: 149 SDL_SetTextureBlendMode(internals->composition, SDL_BLENDMODE_ADD); 150 break; 151 #if LV_GPU_SDL_CUSTOM_BLEND_MODE 152 case LV_BLEND_MODE_SUBTRACTIVE: { 153 SDL_BlendMode mode = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE, 154 SDL_BLENDOPERATION_SUBTRACT, SDL_BLENDFACTOR_ONE, 155 SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_SUBTRACT); 156 SDL_SetTextureBlendMode(internals->composition, mode); 157 break; 158 } 159 case LV_BLEND_MODE_MULTIPLY: { 160 SDL_BlendMode mode = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_SRC_COLOR, 161 SDL_BLENDOPERATION_ADD, SDL_BLENDFACTOR_ZERO, 162 SDL_BLENDFACTOR_DST_ALPHA, SDL_BLENDOPERATION_ADD); 163 SDL_SetTextureBlendMode(internals->composition, mode); 164 break; 165 } 166 #endif 167 default: 168 LV_LOG_WARN("Doesn't support blend mode %d", blend_mode); 169 SDL_SetTextureBlendMode(internals->composition, SDL_BLENDMODE_BLEND); 170 /* Unsupported yet */ 171 break; 172 } 173 SDL_RenderCopy(ctx->renderer, internals->composition, &src_rect, &dst_rect); 174 } 175 176 internals->mask = internals->composition = NULL; 177 } 178 179 SDL_Texture * lv_draw_sdl_composite_texture_obtain(lv_draw_sdl_ctx_t * ctx, lv_draw_sdl_composite_texture_id_t id, 180 lv_coord_t w, lv_coord_t h) 181 { 182 lv_point_t * tex_size = NULL; 183 composite_key_t mask_key = mask_key_create(id); 184 SDL_Texture * result = lv_draw_sdl_texture_cache_get_with_userdata(ctx, &mask_key, sizeof(composite_key_t), NULL, 185 (void **) &tex_size); 186 if(!result || tex_size->x < w || tex_size->y < h) { 187 lv_coord_t size = next_pow_of_2(LV_MAX(w, h)); 188 int access = SDL_TEXTUREACCESS_STREAMING; 189 if(id >= LV_DRAW_SDL_COMPOSITE_TEXTURE_ID_TARGET0) { 190 access = SDL_TEXTUREACCESS_TARGET; 191 } 192 result = SDL_CreateTexture(ctx->renderer, LV_DRAW_SDL_TEXTURE_FORMAT, access, size, size); 193 tex_size = lv_mem_alloc(sizeof(lv_point_t)); 194 tex_size->x = tex_size->y = size; 195 lv_draw_sdl_texture_cache_put_advanced(ctx, &mask_key, sizeof(composite_key_t), result, tex_size, lv_mem_free, 0); 196 } 197 return result; 198 } 199 200 /********************** 201 * STATIC FUNCTIONS 202 **********************/ 203 204 static composite_key_t mask_key_create(lv_draw_sdl_composite_texture_id_t type) 205 { 206 composite_key_t key; 207 /* VERY IMPORTANT! Padding between members is uninitialized, so we have to wipe them manually */ 208 SDL_memset(&key, 0, sizeof(key)); 209 key.magic = LV_GPU_CACHE_KEY_MAGIC_MASK; 210 key.type = type; 211 return key; 212 } 213 214 static lv_coord_t next_pow_of_2(lv_coord_t num) 215 { 216 lv_coord_t n = 128; 217 while(n < num && n < 16384) { 218 n = n << 1; 219 } 220 return n; 221 } 222 223 static void dump_masks(SDL_Texture * texture, const lv_area_t * coords) 224 { 225 lv_coord_t w = lv_area_get_width(coords), h = lv_area_get_height(coords); 226 SDL_assert(w > 0 && h > 0); 227 SDL_Rect rect = {0, 0, w, h}; 228 uint8_t * pixels; 229 int pitch; 230 if(SDL_LockTexture(texture, &rect, (void **) &pixels, &pitch) != 0) return; 231 232 lv_opa_t * line_buf = lv_mem_buf_get(rect.w); 233 for(lv_coord_t y = 0; y < rect.h; y++) { 234 lv_memset_ff(line_buf, rect.w); 235 lv_coord_t abs_x = (lv_coord_t) coords->x1, abs_y = (lv_coord_t)(y + coords->y1), len = (lv_coord_t) rect.w; 236 lv_draw_mask_res_t res; 237 res = lv_draw_mask_apply(line_buf, abs_x, abs_y, len); 238 if(res == LV_DRAW_MASK_RES_TRANSP) { 239 lv_memset_00(&pixels[y * pitch], 4 * rect.w); 240 } 241 else if(res == LV_DRAW_MASK_RES_FULL_COVER) { 242 lv_memset_ff(&pixels[y * pitch], 4 * rect.w); 243 } 244 else { 245 for(int x = 0; x < rect.w; x++) { 246 const size_t idx = y * pitch + x * 4; 247 pixels[idx] = line_buf[x]; 248 pixels[idx + 1] = pixels[idx + 2] = pixels[idx + 3] = 0xFF; 249 } 250 } 251 } 252 lv_mem_buf_release(line_buf); 253 SDL_UnlockTexture(texture); 254 } 255 256 #endif /*LV_USE_GPU_SDL*/