真机 meow_ui_time_ms() 返回「低 32=秒×1000、高 32 随机」的根因不是 SDK 写法,
而是 zig 0.17 自带 musl 在 mipsel 上的 time64 ABI 自相矛盾:
- zig 头(mips-linux-musl/bits/alltypes.h)无条件 64 位 time_t、struct timespec 16 字节;
- zig 的 clang 给 32 位 mips 预定义 __ILP32__,musl 的 time64 回退分支
`#if defined(SYS_x_time64) && !defined(__ILP32__)`(本意只排除 x32)被编译掉;
- 于是 libc 的 __clock_gettime64 实为 o32 time32 实现(SYS_clock_gettime 4263),
只写 8 字节 {int32 sec; int32 nsec},与头的 16 字节布局错配。
修复(patch_v2/sdk/meow_ui_time.c):
- meow_ui_time_ms() 直接按内核 o32 ABI 取 8 字节 time32,再升 64 位毫秒;
- 同 TU 强定义 __clock_gettime/__clock_gettime64(归档先于 -lc,链接期接管,
time()/gettimeofday()/pthread 定时等待的内部取时随之修正);
- 同源缺陷一并修:__nanosleep_time64/__clock_nanosleep(_time64) 转换 time32 后重发
(修复前 usleep(16000) 等亚秒睡眠立即返回、变忙等空转);
- gfx/sys/input/cachegov 四处重复 now_ms 收敛到 meow_ui_time_ms;
- build_sdk.sh OBJS 增加 meow_ui_time;新增 test_meow_time 宿主单测、
tools/clock_abi_probe.c 探针、CLOCK_ABI.md 根因/验证/影响面文档;
- 26 个宿主测试的编译注释补 meow_ui_time.c(cachegov 测试补时钟源)。
验证:宿主单测 PASS;anim(32)/view_event 宿主用例全过;build_sdk_host.sh --verify
76 成员全 MIPS32r2、0 warning;探针链接后无 libc cgt_init/__vdsosym,
__time64/__timedwait_cp 的取时指向本 TU,睡眠走 4166/4265 且用本地 8 字节结构。
100 lines
4.5 KiB
C
100 lines
4.5 KiB
C
/* test_meow_ui_ft.c — SDK 矢量字(meow_ft_*,§10.1)宿主单测。
|
||
* 覆盖任务要求的五项:加载 / 渲染像素非空 / 宽度测量 / LRU 淘汰 / 降级回退。
|
||
*
|
||
* 编译(宿主 gcc,链真实 gfx/sys/theme/vol/log/notify_ipc + 打桩 font/global + meow_ui_ft + 宿主 freetype):
|
||
* gcc -o test_meow_ui_ft test_meow_ui_ft.c test_host_stub.c \
|
||
* meow_ui_gfx.c meow_ui_time.c meow_ui_sys.c meow_ui_theme.c meow_ui_vol.c meow_ui_log.c meow_notify_ipc.c \
|
||
* meow_ui_ft.c \
|
||
* -I. -Iinclude -I../meow_launcherd -DMEOW_UI_HOST_TEST -pthread vendor/freetype-build-host/libfreetype.a
|
||
* 用法:./test_meow_ui_ft [font.otf] (缺省用仓库 font/src/MiSans-Regular.otf)
|
||
*/
|
||
#include "meow_ui.h"
|
||
#include "meow_ui_internal.h" /* meow_ft_glyph(LRU 淘汰测试直接用底层光栅化) */
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
static int fails = 0;
|
||
#define CHECK(c, m) do { if (c) printf(" ok %s\n", m); else { printf("FAIL %s\n", m); fails++; } } while (0)
|
||
|
||
/* 统计 back_buf 中 != bg 的像素数(RGB565 host 16bpp)。 */
|
||
static int count_changed(unsigned char *fb, int pitch, int bg565)
|
||
{
|
||
int n = 0;
|
||
for (int y = 0; y < 720; y++) {
|
||
uint16_t *row = (uint16_t *)(fb + (size_t)y * (size_t)pitch);
|
||
for (int x = 0; x < 480; x++) if (row[x] != (uint16_t)bg565) n++;
|
||
}
|
||
return n;
|
||
}
|
||
|
||
int main(int argc, char **argv)
|
||
{
|
||
const char *font = (argc > 1) ? argv[1] : "/home/Aska/Project/R3ProII/font/src/MiSans-Regular.otf";
|
||
meow_ui_opts o = { 480, 720 };
|
||
CHECK(meow_ui_init(&o) == 0, "meow_ui_init(480x720)");
|
||
int pitch = meow_ui_back_buf_pitch();
|
||
CHECK(pitch == 480 * 2, "back_buf pitch=960");
|
||
CHECK(meow_ui_back_buf_bpp() == 16, "bpp=16");
|
||
unsigned char *fb = meow_ui_back_buf();
|
||
CHECK(fb != NULL, "back_buf non-null");
|
||
|
||
/* ---- 1) 加载 ---- */
|
||
CHECK(!meow_ft_loaded(), "no font loaded initially");
|
||
CHECK(meow_ft_load("nonexistent-font.otf") != 0, "load(bad path) fails");
|
||
CHECK(!meow_ft_loaded(), "bad load leaves unloaded");
|
||
CHECK(meow_ft_load(font) == 0, "meow_ft_load(MiSans)");
|
||
CHECK(meow_ft_loaded(), "meow_ft_loaded after load");
|
||
CHECK(meow_ft_cache_slots() == 512, "default LRU slots=512");
|
||
|
||
/* ---- 2) 渲染像素非空(矢量) ---- */
|
||
meow_ui_clear(0xFFFFFF); /* 白底 */
|
||
int r = meow_ft_text(10, 50, "你好A", 20, 0x000000);
|
||
CHECK(r == 0, "meow_ft_text(vec) returns 0");
|
||
int vec_dark = count_changed(fb, pitch, 0xFFFF);
|
||
printf(" vec dark=%d\n", vec_dark);
|
||
CHECK(vec_dark > 50, "vector render produced non-empty pixels");
|
||
|
||
/* ---- 3) 宽度测量 ---- */
|
||
int w20 = meow_ft_width("你好A", 20);
|
||
int w10 = meow_ft_width("你好A", 10);
|
||
printf(" width(你好A,20)=%d width(...,10)=%d\n", w20, w10);
|
||
CHECK(w20 > 0, "vec width(20)>0");
|
||
CHECK(w20 > w10, "larger px -> larger width");
|
||
CHECK(meow_ft_width("", 20) == 0, "empty string width=0");
|
||
CHECK(meow_ft_width("你", 20) > 0, "CJK width>0");
|
||
/* 单 CJK 字 width ≈ 字号(MiSans CJK 满宽 advance) */
|
||
CHECK(meow_ft_width("你", 20) >= 17 && meow_ft_width("你", 20) <= 23, "CJK adv ~20");
|
||
|
||
/* ---- 4) LRU 淘汰 ---- */
|
||
int got = meow_ft_cache_set_slots(256);
|
||
CHECK(got == 256, "set LRU slots=256");
|
||
CHECK(meow_ft_cache_slots() == 256, "LRU slots now 256");
|
||
for (int i = 0; i < 300; i++) {
|
||
int adv = 0, bw = 0, bh = 0, left = 0, top = 0;
|
||
const uint8_t *bmp = NULL;
|
||
meow_ft_glyph(20, 0x4E00u + (uint32_t)i, &adv, &bmp, &bw, &bh, &left, &top);
|
||
}
|
||
int used = meow_ft_cache_used();
|
||
printf(" lru used=%d slots=256\n", used);
|
||
CHECK(used <= 256, "lru used <= 256 after 300 requests");
|
||
CHECK(used >= 1, "lru used >= 1");
|
||
meow_ft_cache_set_slots(512); /* 还原默认,供后续 */
|
||
|
||
/* ---- 5) 降级回退(无矢量字体 → 位图字库/5x7,不出豆腐) ---- */
|
||
meow_ft_unload();
|
||
CHECK(!meow_ft_loaded(), "after unload not loaded");
|
||
meow_ui_clear(0xFFFFFF);
|
||
r = meow_ft_text(10, 50, "X", 20, 0x000000);
|
||
CHECK(r == -1, "meow_ft_text degrades (returns -1)");
|
||
int deg_dark = count_changed(fb, pitch, 0xFFFF);
|
||
printf(" degrade dark=%d\n", deg_dark);
|
||
CHECK(deg_dark > 0, "degrade still draws (5x7/bitmap, no tofu crash)");
|
||
/* 降级宽度 = 位图字库宽度(宿主无位图库 → 5x7 兜底:len*6*scale(20=2)) */
|
||
CHECK(meow_ft_width("X", 20) == 12, "degrade width via bitmap (5x7) = 12");
|
||
|
||
meow_ui_shutdown();
|
||
printf("test_meow_ui_ft: %s\n", fails ? "FAIL" : "PASS");
|
||
return fails ? 1 : 0;
|
||
}
|