diff options
| author | jacqueline <me@jacqueline.id.au> | 2024-07-03 10:43:54 +1000 |
|---|---|---|
| committer | jacqueline <me@jacqueline.id.au> | 2024-07-03 10:43:54 +1000 |
| commit | 88ac96242f0d36e53876ece9f90baf776616f0bc (patch) | |
| tree | 4a937dd3f5f0178e91d5b797a276187a0fa7b64b /src | |
| parent | cbcf1bea617a8f57fe80264e4b96da9274d133f0 (diff) | |
| download | tangara-fw-88ac96242f0d36e53876ece9f90baf776616f0bc.tar.gz | |
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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/tangara/lua/bridge.cpp | 62 | ||||
| -rw-r--r-- | src/tangara/lua/lua_font.cpp | 115 | ||||
| -rw-r--r-- | src/tangara/lua/lua_font.hpp | 15 |
3 files changed, 132 insertions, 60 deletions
diff --git a/src/tangara/lua/bridge.cpp b/src/tangara/lua/bridge.cpp index 0f1e65ac..1c757a22 100644 --- a/src/tangara/lua/bridge.cpp +++ b/src/tangara/lua/bridge.cpp @@ -24,6 +24,7 @@ #include "lua/lua_controls.hpp" #include "lua/lua_database.hpp" #include "lua/lua_filesystem.hpp" +#include "lua/lua_font.hpp" #include "lua/lua_queue.hpp" #include "lua/lua_screen.hpp" #include "lua/lua_testing.hpp" @@ -50,65 +51,6 @@ namespace lua { static constexpr char kBridgeKey[] = "bridge"; -static auto make_font_cb(const char* name) -> const lv_font_t* { - // 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 name_str = name; - if (name_str.starts_with("//")) { - name++; - } - } - - // This following is a bit C-brained. Sorry. - - ESP_LOGI(kTag, "load font '%s'", name); - FILE* f = fopen(name, "r"); - if (!f) { - return NULL; - } - - uint8_t* data = NULL; - long len = 0; - lv_font_t* font = NULL; - - if (fseek(f, 0, SEEK_END)) { - goto fail_with_file; - } - - len = ftell(f); - if (len <= 0) { - goto fail_with_file; - } - - if (fseek(f, 0, SEEK_SET)) { - goto fail_with_file; - } - - data = reinterpret_cast<uint8_t*>(heap_caps_malloc(len, MALLOC_CAP_SPIRAM)); - if (!data) { - goto fail_with_buffer; - } - - if (fread(data, 1, len, f) < len) { - goto fail_with_buffer; - } - - // We can finally start parsing the font! - font = lv_binfont_create_from_buffer(data, len); - -fail_with_buffer: - // LVGL copies the font data out of the buffer, so we don't need to big raw - // data alloc after this function returns. - heap_caps_free(data); - -fail_with_file: - fclose(f); - - return font; -} - static auto delete_font_cb(const lv_font_t* font) -> void { // FIXME: luavgl never actually calls this? } @@ -146,7 +88,7 @@ auto Bridge::installBaseModules(lua_State* L) -> void { auto Bridge::installLvgl(lua_State* L) -> void { luavgl_set_pcall(L, CallProtected); - luavgl_set_font_extension(L, make_font_cb, delete_font_cb); + luavgl_set_font_extension(L, loadFont, delete_font_cb); luaL_requiref(L, "lvgl", luaopen_lvgl, true); lua_pop(L, 1); } 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 <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 diff --git a/src/tangara/lua/lua_font.hpp b/src/tangara/lua/lua_font.hpp new file mode 100644 index 00000000..dfec4eb0 --- /dev/null +++ b/src/tangara/lua/lua_font.hpp @@ -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; + +} |
