summaryrefslogtreecommitdiff
path: root/src/tangara/lua/lua_font.cpp
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/lua_font.cpp
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/lua_font.cpp')
-rw-r--r--src/tangara/lua/lua_font.cpp115
1 files changed, 115 insertions, 0 deletions
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