summaryrefslogtreecommitdiff
path: root/src/tangara/lua
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2024-07-03 10:43:54 +1000
committerjacqueline <me@jacqueline.id.au>2024-07-03 10:43:54 +1000
commit88ac96242f0d36e53876ece9f90baf776616f0bc (patch)
tree4a937dd3f5f0178e91d5b797a276187a0fa7b64b /src/tangara/lua
parentcbcf1bea617a8f57fe80264e4b96da9274d133f0 (diff)
downloadtangara-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/tangara/lua')
-rw-r--r--src/tangara/lua/bridge.cpp62
-rw-r--r--src/tangara/lua/lua_font.cpp115
-rw-r--r--src/tangara/lua/lua_font.hpp15
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;
+
+}