From 88ac96242f0d36e53876ece9f90baf776616f0bc Mon Sep 17 00:00:00 2001 From: jacqueline Date: Wed, 3 Jul 2024 10:43:54 +1000 Subject: Load fonts asynchronously on a bg task This saves a second or two from bootup; AFAICT this *mostly* reclaims the dynamic fonts boot time regression. --- src/tangara/lua/lua_font.cpp | 115 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 src/tangara/lua/lua_font.cpp (limited to 'src/tangara/lua/lua_font.cpp') diff --git a/src/tangara/lua/lua_font.cpp b/src/tangara/lua/lua_font.cpp new file mode 100644 index 00000000..e5913492 --- /dev/null +++ b/src/tangara/lua/lua_font.cpp @@ -0,0 +1,115 @@ +/* + * Copyright 2024 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include "lua_font.hpp" + +#include +#include + +#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 { + // 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(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(len)}; +} + +static auto parseFont(std::span 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([=]() { + // 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 -- cgit v1.2.3