feat(EVE): add asset pre-upload functions (#8710)

This commit is contained in:
Liam Howatt
2025-08-25 03:56:14 -04:00
committed by GitHub
parent 75a24301fa
commit ff7cc00ade
7 changed files with 312 additions and 90 deletions
@@ -165,6 +165,36 @@ Efficient display rotation is fully supported through :cpp:func:`lv_display_set_
Touch input rotation is handled accordingly.
Asset Pre-Upload
----------------
Images and fonts are uploaded to the EVE chip's RAM_G as-needed during rendering.
An image or glyph will not be uploaded until it needs to be rendered. Once it is
uploaded, it will stay in RAM_G until reset. The first time a screen is shown,
there may be a noticeable delay while an image or set of glyphs is uploaded
for use for the first time. To mitigate this delay, there is a set of functions
provided to upload the assets early.
:cpp:func:`lv_draw_eve_pre_upload_image` is used to upload images.
:cpp:func:`lv_draw_eve_pre_upload_font_range` is used to upload a range of characters.
The range is provided as the first and last unicode code points in the range. Both
the start and the end values are included in the range. It can be called multiple
times with different ranges.
:cpp:func:`lv_draw_eve_pre_upload_font_text` is used to upload all the glyphs that
are needed to render a specific string (ASCII or UTF-8).
It can be called multiple times with different strings.
.. code-block:: c
LV_IMAGE_DECLARE(asset_digital_lock);
lv_draw_eve_pre_upload_image(disp, &asset_digital_lock);
LV_FONT_DECLARE(lv_font_montserrat_48);
lv_draw_eve_pre_upload_font_text(disp, &lv_font_montserrat_48, "The current time is");
lv_draw_eve_pre_upload_font_range(disp, &lv_font_montserrat_48, '0', '9');
lv_draw_eve_pre_upload_font_range(disp, &lv_font_montserrat_48, ':', ':');
.. _eve register access:
EVE Register Access
+118 -58
View File
@@ -54,14 +54,12 @@ static void convert_row_argb8888_to_argb4444(const uint8_t * src, uint8_t * dst,
void lv_draw_eve_image(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_dsc, const lv_area_t * coords)
{
if(lv_image_src_get_type(draw_dsc->src) != LV_IMAGE_SRC_VARIABLE) {
LV_LOG_WARN("v_draw_eve can only render images from variables (not files or symbols) for now.");
if(!lv_draw_eve_image_src_check(draw_dsc->src)) {
return;
}
const lv_image_dsc_t * img_dsc = draw_dsc->src;
const uint8_t * src_buf = img_dsc->data;
int32_t src_w = img_dsc->header.w;
int32_t src_h = img_dsc->header.h;
int32_t src_stride = img_dsc->header.stride;
@@ -73,89 +71,43 @@ void lv_draw_eve_image(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_dsc,
uint8_t eve_format;
int32_t eve_stride;
uint8_t eve_alignment;
switch(src_cf) {
case LV_COLOR_FORMAT_L8:
eve_format = EVE_L8;
eve_stride = src_stride;
eve_alignment = 1;
break;
case LV_COLOR_FORMAT_RGB565:
eve_format = EVE_RGB565;
eve_stride = src_stride;
eve_alignment = 2;
break;
case LV_COLOR_FORMAT_RGB565A8:
case LV_COLOR_FORMAT_ARGB8888:
eve_format = EVE_ARGB4;
eve_stride = src_w * 2;
eve_alignment = 2;
break;
default :
LV_LOG_WARN("v_draw_eve can only render L8, RGB565, RGB565A8, and ARGB8888 images for now.");
return;
LV_ASSERT(0);
}
int32_t eve_size = eve_stride * src_h;
uint32_t img_addr;
bool img_is_loaded = lv_draw_eve_ramg_get_addr(&img_addr, (uintptr_t) src_buf, eve_size, eve_alignment);
if(!img_is_loaded) { /* New image to load */
if(img_addr == LV_DRAW_EVE_RAMG_OUT_OF_RAMG) {
LV_LOG_WARN("Could not load image because space could not be allocated in RAM_G.");
return;
}
/* Load image to RAM_G */
EVE_end_cmd_burst();
switch(src_cf) {
case LV_COLOR_FORMAT_L8 :
case LV_COLOR_FORMAT_RGB565 :
EVE_memWrite_flash_buffer(img_addr, src_buf, eve_size);
break;
case LV_COLOR_FORMAT_RGB565A8 : {
uint8_t * tmp_buf = lv_malloc(eve_stride);
LV_ASSERT_MALLOC(tmp_buf);
const uint8_t * src_alpha_buf = src_buf + src_h * src_stride;
int32_t src_alpha_stride = src_stride / 2;
for(uint32_t y = 0; y < src_h; y++) {
convert_row_rgb565a8_to_argb4444(src_buf + y * src_stride, src_alpha_buf + y * src_alpha_stride, tmp_buf, src_w);
EVE_memWrite_flash_buffer(img_addr + y * eve_stride, tmp_buf, eve_stride);
}
lv_free(tmp_buf);
break;
}
case LV_COLOR_FORMAT_ARGB8888 : {
uint8_t * tmp_buf = lv_malloc(eve_stride);
LV_ASSERT_MALLOC(tmp_buf);
for(uint32_t y = 0; y < src_h; y++) {
convert_row_argb8888_to_argb4444(src_buf + y * src_stride, tmp_buf, src_w);
EVE_memWrite_flash_buffer(img_addr + y * eve_stride, tmp_buf, eve_stride);
}
lv_free(tmp_buf);
break;
}
default :
return;
}
EVE_start_cmd_burst();
uint32_t ramg_addr = lv_draw_eve_image_upload_image(true, img_dsc);
if(ramg_addr == LV_DRAW_EVE_RAMG_OUT_OF_RAMG) {
LV_LOG_WARN("Could not load image because space could not be allocated in RAM_G.");
return;
}
lv_eve_scissor(t->clip_area.x1, t->clip_area.y1, t->clip_area.x2, t->clip_area.y2);
lv_eve_save_context();
lv_eve_color_opa(draw_dsc->opa);
if(draw_dsc->recolor_opa > LV_OPA_MIN) {
lv_eve_color_opa(draw_dsc->recolor_opa);
lv_eve_color(draw_dsc->recolor);
lv_eve_color(lv_color_mix(draw_dsc->recolor, lv_color_white(), draw_dsc->recolor_opa));
}
lv_eve_primitive(LV_EVE_PRIMITIVE_BITMAPS);
EVE_cmd_dl_burst(BITMAP_SOURCE(img_addr));
EVE_cmd_dl_burst(BITMAP_SOURCE(ramg_addr));
/*real height and width is mandatory for rotation and scale (Clip Area)*/
EVE_cmd_dl_burst(BITMAP_SIZE(EVE_NEAREST, EVE_BORDER, EVE_BORDER, src_w, src_h));
@@ -185,6 +137,114 @@ void lv_draw_eve_image(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_dsc,
lv_eve_restore_context();
}
bool lv_draw_eve_image_src_check(const void * src)
{
if(lv_image_src_get_type(src) != LV_IMAGE_SRC_VARIABLE) {
LV_LOG_WARN("lv_draw_eve can only render images from variables (not files or symbols) for now.");
return false;
}
const lv_image_dsc_t * img_dsc = src;
switch(img_dsc->header.cf) {
case LV_COLOR_FORMAT_L8:
case LV_COLOR_FORMAT_RGB565:
case LV_COLOR_FORMAT_RGB565A8:
case LV_COLOR_FORMAT_ARGB8888:
break;
default :
LV_LOG_WARN("lv_draw_eve can only render L8, RGB565, RGB565A8, and ARGB8888 images for now.");
return false;
}
return true;
}
uint32_t lv_draw_eve_image_upload_image(bool burst_is_active, const lv_image_dsc_t * img_dsc)
{
const uint8_t * src_buf = img_dsc->data;
int32_t src_w = img_dsc->header.w;
int32_t src_h = img_dsc->header.h;
int32_t src_stride = img_dsc->header.stride;
lv_color_format_t src_cf = img_dsc->header.cf;
if(src_stride == 0) {
src_stride = src_w * lv_color_format_get_size(src_cf);
}
int32_t eve_stride;
uint8_t eve_alignment;
switch(src_cf) {
case LV_COLOR_FORMAT_L8:
eve_stride = src_stride;
eve_alignment = 1;
break;
case LV_COLOR_FORMAT_RGB565:
eve_stride = src_stride;
eve_alignment = 2;
break;
case LV_COLOR_FORMAT_RGB565A8:
case LV_COLOR_FORMAT_ARGB8888:
eve_stride = src_w * 2;
eve_alignment = 2;
break;
default :
LV_ASSERT(0);
}
int32_t eve_size = eve_stride * src_h;
uint32_t ramg_addr;
bool img_is_loaded = lv_draw_eve_ramg_get_addr(&ramg_addr, (uintptr_t) src_buf, eve_size, eve_alignment);
/* New image to load */
if(!img_is_loaded && ramg_addr != LV_DRAW_EVE_RAMG_OUT_OF_RAMG) {
/* Load image to RAM_G */
if(burst_is_active) {
EVE_end_cmd_burst();
}
switch(src_cf) {
case LV_COLOR_FORMAT_L8:
case LV_COLOR_FORMAT_RGB565:
EVE_memWrite_flash_buffer(ramg_addr, src_buf, eve_size);
break;
case LV_COLOR_FORMAT_RGB565A8: {
uint8_t * tmp_buf = lv_malloc(eve_stride);
LV_ASSERT_MALLOC(tmp_buf);
const uint8_t * src_alpha_buf = src_buf + src_h * src_stride;
int32_t src_alpha_stride = src_stride / 2;
for(uint32_t y = 0; y < src_h; y++) {
convert_row_rgb565a8_to_argb4444(src_buf + y * src_stride, src_alpha_buf + y * src_alpha_stride, tmp_buf, src_w);
EVE_memWrite_flash_buffer(ramg_addr + y * eve_stride, tmp_buf, eve_stride);
}
lv_free(tmp_buf);
break;
}
case LV_COLOR_FORMAT_ARGB8888: {
uint8_t * tmp_buf = lv_malloc(eve_stride);
LV_ASSERT_MALLOC(tmp_buf);
for(uint32_t y = 0; y < src_h; y++) {
convert_row_argb8888_to_argb4444(src_buf + y * src_stride, tmp_buf, src_w);
EVE_memWrite_flash_buffer(ramg_addr + y * eve_stride, tmp_buf, eve_stride);
}
lv_free(tmp_buf);
break;
}
default:
LV_ASSERT(0);
}
if(burst_is_active) {
EVE_start_cmd_burst();
}
}
return ramg_addr;
}
+57 -31
View File
@@ -18,8 +18,6 @@
#include "../lv_draw_label_private.h"
#include "../lv_draw_rect.h"
#include "lv_eve.h"
#include "lv_draw_eve_ram_g.h"
#include "../../font/lv_font_fmt_txt.h"
/*********************
* DEFINES
@@ -64,6 +62,57 @@ void lv_draw_eve_label(lv_draw_task_t * t, const lv_draw_label_dsc_t * dsc, cons
lv_eve_restore_context();
}
bool lv_draw_eve_label_font_check(const lv_font_t * font)
{
if(font->get_glyph_bitmap != lv_font_get_bitmap_fmt_txt) {
LV_LOG_WARN("lv_draw_eve can only render static fonts for now.");
return false;
}
const lv_font_fmt_txt_dsc_t * font_dsc = font->dsc;
/* Only 4 bpp is supported for now. Support for 1 and 8 bpp can be added. (EVE_L1, EVE_L8) */
if(font_dsc->bpp != 4) {
LV_LOG_WARN("lv_draw_eve can only render static fonts for now.");
return false;
}
return true;
}
uint32_t lv_draw_eve_label_upload_glyph(bool burst_is_active, const lv_font_fmt_txt_dsc_t * font_dsc,
uint32_t gid_index)
{
const lv_font_fmt_txt_glyph_dsc_t * glyph_dsc = &font_dsc->glyph_dsc[gid_index];
const uint8_t * glyph_bitmap = &font_dsc->glyph_bitmap[glyph_dsc->bitmap_index];
uint16_t g_box_w = glyph_dsc->box_w;
uint16_t g_box_h = glyph_dsc->box_h;
uint16_t g_aligned_stride = (g_box_w + 1) / 2;
uint32_t glyph_ramg_size = g_aligned_stride * g_box_h;
uint32_t ramg_addr;
uintptr_t glyph_ramg_key = (uintptr_t) glyph_bitmap;
bool font_is_loaded = lv_draw_eve_ramg_get_addr(&ramg_addr, glyph_ramg_key, glyph_ramg_size, 1);
/* If the font is not yet loaded in ramG, load it */
if(!font_is_loaded && ramg_addr != LV_DRAW_EVE_RAMG_OUT_OF_RAMG) {
if(burst_is_active) {
EVE_end_cmd_burst();
}
font_bitmap_to_ramg(ramg_addr, glyph_bitmap, g_box_w, g_box_h);
if(burst_is_active) {
EVE_start_cmd_burst();
}
}
return ramg_addr;
}
/**********************
* STATIC FUNCTIONS
**********************/
@@ -82,42 +131,25 @@ static void lv_draw_eve_letter_cb(lv_draw_task_t * t, lv_draw_glyph_dsc_t * glyp
const lv_font_t * font = glyph_draw_dsc->g->resolved_font;
if(font->get_glyph_bitmap != lv_font_get_bitmap_fmt_txt) {
LV_LOG_WARN("lv_draw_eve can only render static fonts for now.");
if(!lv_draw_eve_label_font_check(font)) {
return;
}
if(glyph_draw_dsc->format != LV_FONT_GLYPH_FORMAT_A4) {
LV_LOG_WARN("lv_draw_eve can only render 4 BPP fonts for now.");
return;
}
const lv_font_fmt_txt_dsc_t * font_dsc = (lv_font_fmt_txt_dsc_t *) font->dsc;
const lv_font_fmt_txt_dsc_t * font_dsc = font->dsc;
uint32_t gid_index = glyph_draw_dsc->g->gid.index;
const lv_font_fmt_txt_glyph_dsc_t * glyph_dsc = &font_dsc->glyph_dsc[gid_index];
const uint8_t * glyph_bitmap = &font_dsc->glyph_bitmap[glyph_dsc->bitmap_index];
uint16_t g_box_w = glyph_dsc->box_w;
uint16_t g_box_h = glyph_dsc->box_h;
uint16_t g_aligned_stride = (g_box_w + 1) / 2;
/* Only 4 bpp is supported for now. Support for 1 and 8 bpp can be added. (EVE_L1, EVE_L8) */
uint8_t bpp_eve = EVE_L4;
uint32_t glyph_ramg_size = g_aligned_stride * g_box_h;
uint32_t ramg_addr;
uintptr_t glyph_ramg_key = (uintptr_t) glyph_bitmap;
bool font_is_loaded = lv_draw_eve_ramg_get_addr(&ramg_addr, glyph_ramg_key, glyph_ramg_size, 1);
if(!font_is_loaded) { /* If the font is not yet loaded in ramG, load it */
if(ramg_addr == LV_DRAW_EVE_RAMG_OUT_OF_RAMG) {
LV_LOG_WARN("Could not load glyph because space could not be allocated in RAM_G.");
return;
}
font_bitmap_to_ramg(ramg_addr, glyph_bitmap, g_box_w, g_box_h);
uint32_t ramg_addr = lv_draw_eve_label_upload_glyph(true, font_dsc, gid_index);
if(ramg_addr == LV_DRAW_EVE_RAMG_OUT_OF_RAMG) {
LV_LOG_WARN("Could not load glyph because space could not be allocated in RAM_G.");
return;
}
lv_eve_color_opa(glyph_draw_dsc->opa);
@@ -134,15 +166,11 @@ static void lv_draw_eve_letter_cb(lv_draw_task_t * t, lv_draw_glyph_dsc_t * glyp
static void font_bitmap_to_ramg(uint32_t addr, const uint8_t * src, uint32_t width,
uint32_t height)
{
EVE_end_cmd_burst();
uint32_t stride = (width + 1) / 2;
if(width % 2 == 0) {
uint32_t size = stride * height;
EVE_memWrite_flash_buffer(addr, src, size);
EVE_start_cmd_burst();
return;
}
@@ -187,8 +215,6 @@ static void font_bitmap_to_ramg(uint32_t addr, const uint8_t * src, uint32_t wid
}
lv_free(row_buf);
EVE_start_cmd_burst();
}
+7
View File
@@ -23,12 +23,14 @@ extern "C" {
#if LV_USE_DRAW_EVE
#include "lv_draw_eve_target.h"
#include "lv_draw_eve_ram_g.h"
#include "../lv_draw_private.h"
#include "../../misc/lv_types.h"
#include "../../core/lv_global.h"
#include "../lv_draw_triangle.h"
#include "../lv_draw_line.h"
#include "../lv_draw_label.h"
#include "../../font/lv_font_fmt_txt.h"
#include "../lv_draw_arc.h"
/*********************
@@ -66,6 +68,8 @@ struct _lv_draw_eve_unit_t {
void lv_draw_eve_image(lv_draw_task_t * t, const lv_draw_image_dsc_t * draw_dsc,
const lv_area_t * coords);
bool lv_draw_eve_image_src_check(const void * src);
uint32_t lv_draw_eve_image_upload_image(bool burst_is_active, const lv_image_dsc_t * img_dsc);
void lv_draw_eve_fill(lv_draw_task_t * t, const lv_draw_fill_dsc_t * dsc, const lv_area_t * coords);
@@ -76,6 +80,9 @@ void lv_draw_eve_line(lv_draw_task_t * t, const lv_draw_line_dsc_t * dsc);
void lv_draw_eve_label(lv_draw_task_t * t, const lv_draw_label_dsc_t * dsc,
const lv_area_t * coords);
bool lv_draw_eve_label_font_check(const lv_font_t * font);
uint32_t lv_draw_eve_label_upload_glyph(bool burst_is_active, const lv_font_fmt_txt_dsc_t * font_dsc,
uint32_t gid_index);
void lv_draw_eve_arc(lv_draw_task_t * t, const lv_draw_arc_dsc_t * dsc, const lv_area_t * coords);
@@ -13,6 +13,7 @@
#include "../../../draw/eve/lv_eve.h"
#include "../../../draw/eve/lv_draw_eve.h"
#include "../../../display/lv_display_private.h"
#include "../../../misc/lv_text_private.h"
#include "../../../libs/FT800-FT813/EVE_commands.h"
@@ -89,6 +90,72 @@ lv_indev_t * lv_draw_eve_touch_create(lv_display_t * disp)
return indev;
}
void lv_draw_eve_pre_upload_image(lv_display_t * disp, const void * src)
{
LV_ASSERT_MSG(disp->flush_cb == flush_cb, "tried to do an LVGL EVE pre-upload without a draw_eve display");
if(!lv_draw_eve_image_src_check(src)) {
return;
}
uint32_t ramg_addr = lv_draw_eve_image_upload_image(false, src);
if(ramg_addr == LV_DRAW_EVE_RAMG_OUT_OF_RAMG) {
LV_LOG_WARN("Could not pre-upload image because space could not be allocated in RAM_G.");
}
}
void lv_draw_eve_pre_upload_font_range(lv_display_t * disp, const lv_font_t * font, uint32_t unicode_range_start,
uint32_t unicode_range_end)
{
LV_ASSERT_MSG(disp->flush_cb == flush_cb, "tried to do an LVGL EVE pre-upload without a draw_eve display");
if(!lv_draw_eve_label_font_check(font)) {
return;
}
for(uint32_t i = unicode_range_start; i <= unicode_range_end; i++) {
lv_font_glyph_dsc_t glyph_dsc;
bool found = lv_font_get_glyph_dsc_fmt_txt(font, &glyph_dsc, i, '\0');
if(!found) {
LV_LOG_INFO("Could not pre-upload glyph with unicode code point '0x%"LV_PRIX32"' "
"because it is not part of the font", i);
continue;
}
uint32_t ramg_addr = lv_draw_eve_label_upload_glyph(false, font->dsc, glyph_dsc.gid.index);
if(ramg_addr == LV_DRAW_EVE_RAMG_OUT_OF_RAMG) {
LV_LOG_WARN("Could not pre-upload glyph because space could not be allocated in RAM_G.");
/* don't return in case there are smaller glyphs that there is space for */
}
}
}
void lv_draw_eve_pre_upload_font_text(lv_display_t * disp, const lv_font_t * font, const char * text)
{
LV_ASSERT_MSG(disp->flush_cb == flush_cb, "tried to do an LVGL EVE pre-upload without a draw_eve display");
if(!lv_draw_eve_label_font_check(font)) {
return;
}
for(uint32_t i = 0; text[i];) {
uint32_t unicode_letter;
uint32_t unicode_letter_next;
lv_text_encoded_letter_next_2(text, &unicode_letter, &unicode_letter_next, &i);
lv_font_glyph_dsc_t glyph_dsc;
bool found = lv_font_get_glyph_dsc_fmt_txt(font, &glyph_dsc, unicode_letter, unicode_letter_next);
if(!found) {
LV_LOG_INFO("Could not pre-upload glyph with unicode code point '0x%"LV_PRIX32"' "
"because it is not part of the font", unicode_letter);
continue;
}
uint32_t ramg_addr = lv_draw_eve_label_upload_glyph(false, font->dsc, glyph_dsc.gid.index);
if(ramg_addr == LV_DRAW_EVE_RAMG_OUT_OF_RAMG) {
LV_LOG_WARN("Could not pre-upload glyph because space could not be allocated in RAM_G.");
/* don't return in case there are smaller glyphs that there is space for */
}
}
}
uint8_t lv_draw_eve_memread8(lv_display_t * disp, uint32_t address)
{
LV_ASSERT_MSG(disp->flush_cb == flush_cb, "tried to use an LVGL EVE command without a draw_eve display");
@@ -56,6 +56,38 @@ void * lv_draw_eve_display_get_user_data(lv_display_t * disp);
lv_indev_t * lv_draw_eve_touch_create(lv_display_t * disp);
/* RAM_G asset pre-upload functions */
/**
* Upload an image src to RAM_G now instead of as-needed during rendering.
* @param disp pointer to the lv_draw_eve display
* @param src image src. The value passed to `lv_image_set_src`
*/
void lv_draw_eve_pre_upload_image(lv_display_t * disp, const void * src);
/**
* Upload font glyphs to RAM_G now instead of as-needed during rendering.
* Upload all the glyphs in the range of unicode code points (inclusive of the start and end values).
* It can be called multiple times with different ranges.
* @param disp pointer to the lv_draw_eve display
* @param font the font to upload glyphs from
* @param unicode_range_start the first unicode code point in the range of glyphs to upload
* @param unicode_range_end the last unicode code point (inclusive) in the range of glyphs to upload
*/
void lv_draw_eve_pre_upload_font_range(lv_display_t * disp, const lv_font_t * font, uint32_t unicode_range_start,
uint32_t unicode_range_end);
/**
* Upload font glyphs to RAM_G now instead of as-needed during rendering.
* It will upload all the glyphs needed to render the string `text`.
* It can be called multiple times with different strings.
* @param disp pointer to the lv_draw_eve display
* @param font the font to upload glyphs from
* @param text the ASCII or UTF-8 string that will be iterated for glyphs to upload
*/
void lv_draw_eve_pre_upload_font_text(lv_display_t * disp, const lv_font_t * font, const char * text);
/* Low-level EVE control functions */
/**
+1 -1
View File
@@ -71,7 +71,7 @@ typedef struct {
int32_t outline_stroke_width; /**< used with freetype vector fonts - width of the letter border */
union {
uint32_t index; /**< Unicode code point*/
uint32_t index; /**< Glyph descriptor index*/
const void * src; /**< Pointer to the source data used by image fonts*/
} gid; /**< The index of the glyph in the font file. Used by the font cache*/
lv_cache_entry_t * entry; /**< The cache entry of the glyph draw data. Used by the font cache*/