Merge branch 'feat/m29-reader-shelf-scan-cache-and-row-draw'
This commit is contained in:
commit
dc559aa1ac
5 files changed
+151
-6
No files matched your search
@@ -15,3 +15,4 @@
|
|||||||
/test/mem_account_host
|
/test/mem_account_host
|
||||||
*.o
|
*.o
|
||||||
*.a
|
*.a
|
||||||
|
/test/shelf_bench_ondev_mipsel
|
||||||
@@ -1 +1 @@
|
|||||||
{"name":"Reader","exec":"/usr/data/mnt/sd_0/MeowAPPs/os.meow.reader/reader","package":"os.meow.reader","version":"0.1.1","version_code":2,"framework":1,"fonts":"common","author":"MeowOS","icon":"icon.png","volume_page":true}
|
{"name":"Reader","exec":"/usr/data/mnt/sd_0/MeowAPPs/os.meow.reader/reader","package":"os.meow.reader","version":"0.1.2","version_code":3,"framework":1,"fonts":"common","author":"MeowOS","icon":"icon.png","volume_page":true}
|
||||||
@@ -2,8 +2,9 @@
|
|||||||
* 其它显示「R2 支持」占位);MD3 布局(meow_topappbar + list/grid)+ 最近阅读置顶 + 段头分组。
|
* 其它显示「R2 支持」占位);MD3 布局(meow_topappbar + list/grid)+ 最近阅读置顶 + 段头分组。
|
||||||
*
|
*
|
||||||
* 布局(README §3.2,用户 2026-09-04 拍板):
|
* 布局(README §3.2,用户 2026-09-04 拍板):
|
||||||
* - 默认 list(meow_listview_set_container(on) MD3 圆角卡),可切 grid(meow_lazygrid 4 列封面卡);
|
* - 默认 list(meow_listview_set_container(on) MD3 圆角卡;**行数 > SHELF_ROUND_MAX_ROWS
|
||||||
* 布局存 reader.conf `ui.shelf_layout`(rdconf_get()->shelf);
|
* 时自动降级为扁平行**——圆角卡逐像素填充太慢,见 shelf_build_content 注释),
|
||||||
|
* 可切 grid(meow_lazygrid 4 列封面卡);布局存 reader.conf `ui.shelf_layout`;
|
||||||
* - 顶栏 meow_topappbar:标题「书架」+ 动作(布局切换 / 分组切换 / 刷新 / App 设置入口);
|
* - 顶栏 meow_topappbar:标题「书架」+ 动作(布局切换 / 分组切换 / 刷新 / App 设置入口);
|
||||||
* - 无书也渲染完整骨架(顶栏 + 内容区 + 居中空态卡 + 指引 + 支持格式);
|
* - 无书也渲染完整骨架(顶栏 + 内容区 + 居中空态卡 + 指引 + 支持格式);
|
||||||
* - 封面:MVP 无封面提取(engine F1);无则圆角占位(surfaceContainerHigh + 格式徽标)。
|
* - 封面:MVP 无封面提取(engine F1);无则圆角占位(surfaceContainerHigh + 格式徽标)。
|
||||||
@@ -12,6 +13,12 @@
|
|||||||
* format = 按格式分段(TXT/FB2/EPUB/MOBI/CBZ);
|
* format = 按格式分段(TXT/FB2/EPUB/MOBI/CBZ);
|
||||||
* folder = 按 Books/ 下的「第一级目录」分段(根下=未分类),更深子路径(分类/作品)进副题。
|
* folder = 按 Books/ 下的「第一级目录」分段(根下=未分类),更深子路径(分类/作品)进副题。
|
||||||
* 扫描/行序列在 app/shelf_model.c(纯 C,宿主可测);本文件只做控件装配与绘制。
|
* 扫描/行序列在 app/shelf_model.c(纯 C,宿主可测);本文件只做控件装配与绘制。
|
||||||
|
*
|
||||||
|
* M29 性能(用户反馈「几百本书首页卡得飞起」):
|
||||||
|
* - **扫描结果进程内缓存**:只在本进程首次进入书架时扫 Books/;从阅读页返回不再重扫
|
||||||
|
* (真机 exFAT 全量扫描 3.1s,是「回书架冻结」的唯一大头)。顶栏「刷新」强制重扫。
|
||||||
|
* 行为变化:新放进 Books/ 的书、以及刚读完那本书的「最近阅读置顶」需点一次「刷新」才更新。
|
||||||
|
* - **行数多时关圆角容器**(见 SHELF_ROUND_MAX_ROWS):圆角卡逐像素填充,595 本时滑一步 46ms。
|
||||||
*/
|
*/
|
||||||
#include "../reader_internal.h"
|
#include "../reader_internal.h"
|
||||||
#include "progress.h"
|
#include "progress.h"
|
||||||
@@ -25,9 +32,12 @@
|
|||||||
#define SHELF_APPBAR_H 56
|
#define SHELF_APPBAR_H 56
|
||||||
#define SHELF_LIST_X 0
|
#define SHELF_LIST_X 0
|
||||||
#define SHELF_LIST_W 480
|
#define SHELF_LIST_W 480
|
||||||
|
/* 圆角卡容器阈值:行数 ≤ 该值用 MD3 圆角卡(观感优先),超过则扁平行(滚动流畅优先)。 */
|
||||||
|
#define SHELF_ROUND_MAX_ROWS 200
|
||||||
|
|
||||||
static shelf_book g_books[SHELF_MAX_BOOKS];
|
static shelf_book g_books[SHELF_MAX_BOOKS];
|
||||||
static int g_nbooks;
|
static int g_nbooks;
|
||||||
|
static int g_scanned; /* 1=本进程已扫过 Books/(进书架缓存;「刷新」动作强制重扫) */
|
||||||
static int g_active;
|
static int g_active;
|
||||||
static meow_widget *g_list; /* listview(布局=list) */
|
static meow_widget *g_list; /* listview(布局=list) */
|
||||||
static meow_lazygrid *g_grid; /* lazygrid(布局=grid) */
|
static meow_lazygrid *g_grid; /* lazygrid(布局=grid) */
|
||||||
@@ -61,6 +71,7 @@ static void notice_set(const char *line1, const char *line2)
|
|||||||
g_notice_until = meow_ui_time_ms() + 6000; /* 6s 后由 shelf_on_tick 清掉,不常驻压列表 */
|
g_notice_until = meow_ui_time_ms() + 6000; /* 6s 后由 shelf_on_tick 清掉,不常驻压列表 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 扫描 Books/ 并写入 g_books/g_nbooks(同时更新提示条)。首次进入书架与顶栏「刷新」才调。 */
|
||||||
static void scan_books(void)
|
static void scan_books(void)
|
||||||
{
|
{
|
||||||
const char *dir = READER_SD_ROOT "/Books";
|
const char *dir = READER_SD_ROOT "/Books";
|
||||||
@@ -69,6 +80,7 @@ static void scan_books(void)
|
|||||||
g_notice_ms = 0;
|
g_notice_ms = 0;
|
||||||
shelf_scan_report rep;
|
shelf_scan_report rep;
|
||||||
g_nbooks = shelf_scan_books(dir, g_books, SHELF_MAX_BOOKS, shelf_ts_of, &rep);
|
g_nbooks = shelf_scan_books(dir, g_books, SHELF_MAX_BOOKS, shelf_ts_of, &rep);
|
||||||
|
g_scanned = 1;
|
||||||
if (rep.root_missing) {
|
if (rep.root_missing) {
|
||||||
char line[160];
|
char line[160];
|
||||||
snprintf(line, sizeof line, "未找到 %s 目录,请放入书籍(TXT)", dir);
|
snprintf(line, sizeof line, "未找到 %s 目录,请放入书籍(TXT)", dir);
|
||||||
@@ -223,7 +235,11 @@ static void shelf_build_content(void)
|
|||||||
g_nrows, NULL, NULL, MEOW_LIST_SEL_SINGLE);
|
g_nrows, NULL, NULL, MEOW_LIST_SEL_SINGLE);
|
||||||
if (g_list) {
|
if (g_list) {
|
||||||
meow_listview_set_vsource(g_list, shelf_list_count, shelf_list_bind, NULL);
|
meow_listview_set_vsource(g_list, shelf_list_count, shelf_list_bind, NULL);
|
||||||
meow_listview_set_container(g_list, 1);
|
/* MD3 圆角容器(surfaceContainer 卡)走 meow_gfx_fill_round 逐像素 rr_inside:
|
||||||
|
* 真机一张 464×54 卡 3.8–6.4ms、可见 11 行≈42ms/帧(滑一步 46ms)。行数多时
|
||||||
|
* 自动降级为扁平行(survey 实测同滚动 14ms),行数少(≤SHELF_ROUND_MAX_ROWS)
|
||||||
|
* 仍保留圆角卡观感。 */
|
||||||
|
meow_listview_set_container(g_list, g_nrows > SHELF_ROUND_MAX_ROWS ? 0 : 1);
|
||||||
meow_listview_set_item_tier(g_list, 2);
|
meow_listview_set_item_tier(g_list, 2);
|
||||||
meow_listview_set_on_tap(g_list, shelf_list_tapcb, NULL);
|
meow_listview_set_on_tap(g_list, shelf_list_tapcb, NULL);
|
||||||
}
|
}
|
||||||
@@ -256,7 +272,11 @@ static void shelf_on_enter(meow_view *v, void *ctx)
|
|||||||
const rdconf *c = rdconf_get();
|
const rdconf *c = rdconf_get();
|
||||||
g_layout = (c && c->shelf[0] && strcmp(c->shelf, "grid") == 0) ? 1 : 0;
|
g_layout = (c && c->shelf[0] && strcmp(c->shelf, "grid") == 0) ? 1 : 0;
|
||||||
g_group_folder = (c && strcmp(c->shelf_group, "folder") == 0) ? 1 : 0;
|
g_group_folder = (c && strcmp(c->shelf_group, "folder") == 0) ? 1 : 0;
|
||||||
scan_books(); /* 回到书架即重扫(新增/最近读置顶刷新) */
|
/* 书架缓存:本进程只在首次进入时扫一次 Books/(从阅读页返回不再重扫)。
|
||||||
|
* 扫描在真机是 3.1s(exFAT 434 目录 opendir/readdir),是「回书架冻结」的唯一大头。
|
||||||
|
* 代价:新放入的书 / 刚读完的书不会自动置顶,需点顶栏「刷新」(强制重扫)。
|
||||||
|
* 提示条(超上限截断 / 超深目录)语义不变:首次扫描时算好并保留在 g_notice*。 */
|
||||||
|
if (!g_scanned) scan_books();
|
||||||
build_rows();
|
build_rows();
|
||||||
const meow_theme *th = meow_theme_get();
|
const meow_theme *th = meow_theme_get();
|
||||||
g_bg = th->bg; g_fg = th->fg; g_dim = th->dim;
|
g_bg = th->bg; g_fg = th->fg; g_dim = th->dim;
|
||||||
@@ -383,7 +403,8 @@ int shelf_on_tap(int x, int y)
|
|||||||
} else if (bi == 1) { /* 分组切换:format ↔ folder */
|
} else if (bi == 1) { /* 分组切换:format ↔ folder */
|
||||||
shelf_set_group(g_group_folder ? 0 : 1);
|
shelf_set_group(g_group_folder ? 0 : 1);
|
||||||
return 1;
|
return 1;
|
||||||
} else if (bi == 2) { /* 刷新:重扫 */
|
} else if (bi == 2) { /* 刷新:强制重扫(缓存失效 + 重扫;新书/刚读完的书在此出现) */
|
||||||
|
g_scanned = 0;
|
||||||
scan_books(); build_rows();
|
scan_books(); build_rows();
|
||||||
shelf_build_content();
|
shelf_build_content();
|
||||||
shelf_redraw();
|
shelf_redraw();
|
||||||
|
|||||||
@@ -169,4 +169,13 @@ ls -la reader
|
|||||||
file reader
|
file reader
|
||||||
md5sum reader
|
md5sum reader
|
||||||
echo " 运行(qemu): qemu-mipsel ./reader"
|
echo " 运行(qemu): qemu-mipsel ./reader"
|
||||||
|
|
||||||
|
# ---------- 8) 真机耗时基准(不进发行包:与 reader 同源,只把 app.c 的 main 换成 bench main) ----------
|
||||||
|
# 用法(设备):MEOW_FONT_* 等 env 与 App 一致时执行 ./shelf_bench_ondev_mipsel [书...]
|
||||||
|
echo "==> ondev shelf bench (not shipped)"
|
||||||
|
APP_BENCH_L="app/shelf.c app/shelf_model.c app/reader.c app/book.c app/progress.c app/settings.c app/reader_conf.c app/reader_ipc.c"
|
||||||
|
$CC -Os -static -Wall -Wextra -I../sdk -I../meow_launcherd -I. -Icore -Iapp -Iengine $FT_INCS $COREINC \
|
||||||
|
test/shelf_bench_ondev.c $CORE_L $APP_BENCH_L $ENGINE_L "$OBJ"/mz_*.o "$OBJ"/lm_*.o "$OBJ"/rdimg.o \
|
||||||
|
../sdk/meow_ui.a "$SYSROOT/lib/libz.a" "$FT_BUILD/libfreetype.a" -lpthread -o test/shelf_bench_ondev_mipsel
|
||||||
|
ls -la test/shelf_bench_ondev_mipsel
|
||||||
echo "build_reader OK"
|
echo "build_reader OK"
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
/* test/shelf_bench_ondev.c — 真机耗时基准(不进发行包,不参与 mpk)。
|
||||||
|
*
|
||||||
|
* 目的:在**同一台设备、同一字库/主题环境**下量 App 的同步耗时,用来给书架缓存 /
|
||||||
|
* 行自绘 / 开书路径做前后对比(宿主数字不算数)。
|
||||||
|
*
|
||||||
|
* 只调 App/SDK 公共入口(与 app.c 的调用顺序一致),不复制任何内部实现:
|
||||||
|
* meow_ui_init → 建三页 → push 书架(= 首次进书架,含扫描)
|
||||||
|
* → push/pop 阅读页 ×N(= 从阅读页返回书架)
|
||||||
|
* → shelf_on_swipe ×N(= 书架滑动,含 widget_draw + flush 上屏)
|
||||||
|
* → reader_open + push 阅读页(= 点书开读首屏)、翻页
|
||||||
|
*
|
||||||
|
* 用法(设备):shelf_bench_ondev [book1 [book2 ...]]
|
||||||
|
* 输出:`BENCH <key> <min>-<max> (avg ...)` 行,ms 为毫秒(设备时钟 10ms 分辨率,
|
||||||
|
* 单次量用多轮取样给区间;批量操作用「总时长/次数」给出平均值)。
|
||||||
|
*/
|
||||||
|
#include "reader_internal.h"
|
||||||
|
#include "app/shelf_model.h"
|
||||||
|
#include "meow_ui_internal.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static uint64_t now_ms(void) { return meow_ui_time_ms(); }
|
||||||
|
|
||||||
|
static void bench_scan(void)
|
||||||
|
{
|
||||||
|
static shelf_book books[SHELF_MAX_BOOKS];
|
||||||
|
shelf_scan_report rep;
|
||||||
|
uint64_t t0 = now_ms();
|
||||||
|
int n = shelf_scan_books(READER_SD_ROOT "/Books", books, SHELF_MAX_BOOKS, NULL, &rep);
|
||||||
|
uint64_t t1 = now_ms();
|
||||||
|
printf("BENCH scan_ms %llu (n=%d truncated=%d depth_skipped=%d root_missing=%d)\n",
|
||||||
|
(unsigned long long)(t1 - t0), n, rep.truncated, rep.depth_skipped, rep.root_missing);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
meow_ui_opts o = { 480, 720 };
|
||||||
|
if (meow_ui_init(&o) != 0) { printf("BENCH init_fail\n"); return 1; }
|
||||||
|
meow_theme_add_listener(NULL);
|
||||||
|
|
||||||
|
bench_scan(); /* 纯扫描基线(不建 UI) */
|
||||||
|
|
||||||
|
shelf_view_create();
|
||||||
|
reader_view_create();
|
||||||
|
settings_view_create();
|
||||||
|
|
||||||
|
/* ① 首次进书架(新进程:含全量扫描 + 建控件 + 首帧上屏) */
|
||||||
|
uint64_t t0 = now_ms();
|
||||||
|
meow_view_page_push(ACT_SHELF);
|
||||||
|
uint64_t t1 = now_ms();
|
||||||
|
printf("BENCH shelf_first_enter_ms %llu\n", (unsigned long long)(t1 - t0));
|
||||||
|
|
||||||
|
/* ② 从阅读页返回书架:push 阅读页(不等书)→ pop 回书架;连做 5 次给区间 */
|
||||||
|
unsigned long long rmin = 0, rmax = 0, rsum = 0;
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
meow_view_page_push(ACT_READER);
|
||||||
|
uint64_t a = now_ms();
|
||||||
|
meow_view_page_pop();
|
||||||
|
uint64_t b = now_ms();
|
||||||
|
uint64_t d = b - a;
|
||||||
|
if (i == 0 || d < rmin) rmin = d;
|
||||||
|
if (i == 0 || d > rmax) rmax = d;
|
||||||
|
rsum += d;
|
||||||
|
}
|
||||||
|
printf("BENCH shelf_return_ms %llu-%llu (avg %llu)\n",
|
||||||
|
rmin, rmax, rsum / 5);
|
||||||
|
|
||||||
|
/* ③ 书架滑动:每步 62px(与 survey 同口径:scroll 62 + widget_draw + flush) */
|
||||||
|
for (int batch = 0; batch < 3; batch++) {
|
||||||
|
uint64_t a = now_ms();
|
||||||
|
for (int i = 0; i < 30; i++) shelf_on_swipe(MEOW_SWIPE_UP, 0, 62);
|
||||||
|
uint64_t b = now_ms();
|
||||||
|
printf("BENCH shelf_scroll_step_ms %.1f (batch %d: 30 steps %llu ms)\n",
|
||||||
|
(double)(b - a) / 30.0, batch, (unsigned long long)(b - a));
|
||||||
|
for (int i = 0; i < 30; i++) shelf_on_swipe(MEOW_SWIPE_DOWN, 0, 62); /* 回到顶部 */
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
/* ④ 开书首屏 / 翻页(argv 给书路径;不给则跳过) */
|
||||||
|
for (int i = 1; i < argc; i++) {
|
||||||
|
uint64_t a = now_ms();
|
||||||
|
int rc = reader_open(argv[i]);
|
||||||
|
uint64_t b = now_ms();
|
||||||
|
if (rc != 0) { printf("BENCH open_fail %s\n", argv[i]); continue; }
|
||||||
|
meow_view_page_push(ACT_READER);
|
||||||
|
uint64_t c = now_ms();
|
||||||
|
printf("BENCH open_ms %llu (reader_open %llu + page_push %llu) %s\n",
|
||||||
|
(unsigned long long)(c - a), (unsigned long long)(b - a),
|
||||||
|
(unsigned long long)(c - b), argv[i]);
|
||||||
|
/* 翻页:reader_page_key 置 pending → reader_on_tick 消费(同步段=turn+refill+redraw)
|
||||||
|
* 轮数由 MEOW_BENCH_TURNS 控制(0=不翻页 → 用于「开书不翻页进度文件不变」回归)。 */
|
||||||
|
const char *et = getenv("MEOW_BENCH_TURNS");
|
||||||
|
int nturns = et && et[0] ? atoi(et) : 4;
|
||||||
|
unsigned long long tmin = 0, tmax = 0, tsum = 0;
|
||||||
|
for (int p = 0; p < nturns; p++) {
|
||||||
|
reader_page_key(1);
|
||||||
|
uint64_t x = now_ms();
|
||||||
|
reader_on_tick(now_ms());
|
||||||
|
uint64_t y = now_ms();
|
||||||
|
uint64_t d = y - x;
|
||||||
|
if (p == 0 || d < tmin) tmin = d;
|
||||||
|
if (p == 0 || d > tmax) tmax = d;
|
||||||
|
tsum += d;
|
||||||
|
}
|
||||||
|
printf("BENCH turn_ms %llu-%llu (avg %llu) %s\n", tmin, tmax, nturns ? tsum / nturns : 0, argv[i]);
|
||||||
|
meow_view_page_pop();
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
meow_ui_shutdown();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user