This saves a second or two from bootup; AFAICT this *mostly* reclaims the dynamic fonts boot time regression.custom
parent
cbcf1bea61
commit
88ac96242f
@ -1,49 +1,23 @@ |
||||
#include "luavgl.h" |
||||
#include "private.h" |
||||
|
||||
static char *to_lower(char *str) |
||||
{ |
||||
for (char *s = str; *s; ++s) |
||||
*s = *s >= 'A' && *s <= 'Z' ? *s | 0x60 : *s; |
||||
return str; |
||||
} |
||||
|
||||
static char *luavgl_strchr(const char *s, char c) |
||||
{ |
||||
while (*s) { |
||||
if (c == *s) { |
||||
return (char *)s; |
||||
} |
||||
s++; |
||||
} |
||||
return NULL; |
||||
} |
||||
|
||||
/**
|
||||
* Dynamic font family fallback is not supported. |
||||
* The fallback only happen when font creation fails and continue to try next |
||||
* one. Fallback logic in lvgl is supposed to be system wide. |
||||
* |
||||
* lvgl.Font("MiSansW medium, montserrat", 24, "normal") |
||||
*/ |
||||
static int luavgl_font_create(lua_State *L) |
||||
{ |
||||
|
||||
if (!lua_isstring(L, 1)) { |
||||
return luaL_argerror(L, 1, "expect string"); |
||||
} |
||||
const char *name = lua_tostring(L, 1); |
||||
const lv_font_t *font = NULL; |
||||
if (!lua_isfunction(L, 2)) { |
||||
return luaL_argerror(L, 1, "expect function"); |
||||
} |
||||
|
||||
luavgl_ctx_t *ctx = luavgl_context(L); |
||||
if (ctx->make_font) { |
||||
font = ctx->make_font(name); |
||||
if (!ctx->make_font) { |
||||
return luaL_error(L, "cannot create font"); |
||||
} |
||||
|
||||
if (font) { |
||||
lua_pushlightuserdata(L, (void *)font); |
||||
return 1; |
||||
} |
||||
const char *name = lua_tostring(L, 1); |
||||
int cb_ref = luaL_ref(L, LUA_REGISTRYINDEX); |
||||
ctx->make_font(L, name, cb_ref); |
||||
|
||||
return luaL_error(L, "cannot create font"); |
||||
return 0; |
||||
} |
||||
|
@ -1,6 +1,36 @@ |
||||
local lvgl = require("lvgl") |
||||
|
||||
return { |
||||
fusion_12 = lvgl.Font("//lua/fonts/fusion12"), |
||||
fusion_10 = lvgl.Font("//lua/fonts/fusion10"), |
||||
local fonts = {} |
||||
local fonts_priv = { |
||||
has_invoked_cb = false, |
||||
cb = nil, |
||||
} |
||||
|
||||
function fonts_priv.has_loaded_all() |
||||
return fonts.fusion_12 and fonts.fusion_10 |
||||
end |
||||
|
||||
function fonts_priv.invoke_cb() |
||||
if fonts_priv.has_invoked_cb or not fonts_priv.cb then return end |
||||
if not fonts_priv.has_loaded_all() then return end |
||||
fonts_priv.has_invoked_cb = true |
||||
fonts_priv.cb() |
||||
end |
||||
|
||||
lvgl.Font("//lua/fonts/fusion12", function(font) |
||||
fonts.fusion_12 = font |
||||
fonts_priv.invoke_cb() |
||||
end) |
||||
|
||||
lvgl.Font("//lua/fonts/fusion10", function(font) |
||||
fonts.fusion_10 = font |
||||
fonts_priv.invoke_cb() |
||||
end) |
||||
|
||||
function fonts.on_loaded(cb) |
||||
fonts_priv.cb = cb |
||||
fonts_priv.has_invoked_cb = false |
||||
fonts_priv.invoke_cb() |
||||
end |
||||
|
||||
return fonts |
||||
|
@ -0,0 +1,115 @@ |
||||
/*
|
||||
* Copyright 2024 jacqueline <me@jacqueline.id.au> |
||||
* |
||||
* SPDX-License-Identifier: GPL-3.0-only |
||||
*/ |
||||
|
||||
#include "lua_font.hpp" |
||||
|
||||
#include <cstdint> |
||||
#include <string> |
||||
|
||||
#include "lauxlib.h" |
||||
#include "lua.h" |
||||
#include "lvgl.h" |
||||
|
||||
#include "events/event_queue.hpp" |
||||
#include "lua/bridge.hpp" |
||||
#include "lua/lua_registry.hpp" |
||||
#include "lua/lua_thread.hpp" |
||||
|
||||
namespace lua { |
||||
|
||||
[[maybe_unused]] static constexpr char kTag[] = "lua_font"; |
||||
|
||||
/* Reads the given file completely into PSRAM. */ |
||||
static auto readFont(std::string path) -> std::span<uint8_t> { |
||||
// This following is a bit C-brained. Sorry.
|
||||
FILE* f = fopen(path.c_str(), "r"); |
||||
if (!f) { |
||||
return {}; |
||||
} |
||||
|
||||
uint8_t* data = NULL; |
||||
long len = 0; |
||||
|
||||
if (fseek(f, 0, SEEK_END)) { |
||||
goto fail; |
||||
} |
||||
|
||||
len = ftell(f); |
||||
if (len <= 0) { |
||||
goto fail; |
||||
} |
||||
|
||||
if (fseek(f, 0, SEEK_SET)) { |
||||
len = 0; |
||||
goto fail; |
||||
} |
||||
|
||||
data = reinterpret_cast<uint8_t*>(heap_caps_malloc(len, MALLOC_CAP_SPIRAM)); |
||||
if (!data) { |
||||
len = 0; |
||||
goto fail; |
||||
} |
||||
|
||||
if (fread(data, 1, len, f) < len) { |
||||
heap_caps_free(data); |
||||
len = 0; |
||||
} |
||||
|
||||
fail: |
||||
fclose(f); |
||||
|
||||
return {data, static_cast<size_t>(len)}; |
||||
} |
||||
|
||||
static auto parseFont(std::span<uint8_t> data) -> lv_font_t* { |
||||
if (data.empty()) { |
||||
return nullptr; |
||||
} |
||||
|
||||
lv_font_t* font = lv_binfont_create_from_buffer(data.data(), data.size()); |
||||
heap_caps_free(data.data()); |
||||
|
||||
return font; |
||||
} |
||||
|
||||
auto loadFont(lua_State* L, const char* path, int cb_ref) -> void { |
||||
// Most Lua file paths start with "//" in order to deal with LVGL's Windows-y
|
||||
// approach to paths. Try to handle such paths correctly so that paths in Lua
|
||||
// code look a bit more consistent.
|
||||
std::string path_str = path; |
||||
if (path_str.starts_with("//")) { |
||||
path++; |
||||
path_str = path; |
||||
} |
||||
|
||||
// Do the file read from the current thread, since the path might be for a
|
||||
// file in flash, and we can't read from flash in a background task.
|
||||
auto font_data = readFont(path_str); |
||||
|
||||
Bridge* bridge = Bridge::Get(L); |
||||
bridge->services().bg_worker().Dispatch<void>([=]() { |
||||
// Do the parsing now that we're in the background.
|
||||
lv_font_t* font = parseFont(font_data); |
||||
|
||||
// Hop back to the UI task to invoke the Lua callback.
|
||||
events::Ui().RunOnTask([=] { |
||||
// Retrieve the callback by ref, and release the ref.
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, cb_ref); |
||||
luaL_unref(L, LUA_REGISTRYINDEX, cb_ref); |
||||
|
||||
// We always invoke the callback, but we don't always have a result.
|
||||
if (font) { |
||||
lua_pushlightuserdata(L, (void*)font); |
||||
} else { |
||||
lua_pushnil(L); |
||||
} |
||||
|
||||
CallProtected(L, 1, 0); |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
} // namespace lua
|
@ -0,0 +1,15 @@ |
||||
/*
|
||||
* Copyright 2024 jacqueline <me@jacqueline.id.au> |
||||
* |
||||
* SPDX-License-Identifier: GPL-3.0-only |
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include "lua.hpp" |
||||
|
||||
namespace lua { |
||||
|
||||
auto loadFont(lua_State* L, const char* name, int cb_ref) -> void; |
||||
|
||||
} |
Loading…
Reference in new issue