图库: 修 M27 评审 P1 门控旁路 + 三个 P2(r1)
P1-1:判定为 backend 的页不再无条件放行 + 后端中途失败不再静默回退 stb。 - meow_img_load_file_step_ex 增加 allow_stb_fallback 参数:0 = 只试后端, 失败返回 NULL(坏图占位),绝不回落 stb。阅读器按 dec.path 传入。 - 旧行为实测:截断 12MP JPEG 18,403kB、3000×3000 24bpp 头-only BMP 36,056kB、 非法位深 PNG 16,409kB(stb 都"成功"出图)。修复后: 截断 JPEG 275kB→NULL、头-only BMP 908kB→NULL、非法位深 PNG 门控占位(0 分配)。 P2-1:PNG 支持矩阵补 png_depth_ok 同式(color 2/4/6 仅 8/16;color 3 无 16; color 0 允许 1/2/4/8/16),不再出现「矩阵说支持、后端拒绝」。 P2-2:后端命中页也保留两道安全阀:MemAvailable<6MB 占位、估算 >12MB 硬上限占位。 P2-3:B8 指标改为「窗口稳定后只 reset 一次」,量整个 30 翻窗口内相对稳态基线的 最大存活增量(淘汰不再掩盖峰值),并打印稳态/驻留/增量。 P2-4:page_source.h 的估算精度口径限定为「后端命中/典型页」。 回归: - B7c 新增截断 12MP JPEG / 24bpp 头-only BMP / 非法位深 PNG,断言 backend-only NULL 且峰值 ≤3MB、或 stb 门控占位;B7 典型页与 B7b 回退矩阵保持全绿。 - test_reader_many_pages 恢复 24bpp 头-only 夹具(1bpp 保留):24bpp 判 failed、 1bpp 判 skipped;断言 failed=2 / skipped=1。 - run_tests.sh / run_webtoon_tests.sh EXIT=0;sdk/test_meow_img_stream ALL PASS; 交叉构建(SDK + tuku)零警告。
This commit is contained in:
1 parent
1725af631b
commit
11e09af7a4
8 files changed
+171
-49
No files matched your search
@@ -15,7 +15,9 @@
|
||||
* B7 M27:6 类典型页(2000×3000 baseline/渐进/restart、1600×2400 PNG/BMP、4MP、12MP)
|
||||
* 全部走后端、不占位;估算 ≥ 实测且 ≤1.5×;输出尺寸与显示框一致
|
||||
* B7b 回退路径:CMYK / Adam7 PNG / 1bpp BMP 走 stb,按旧门控占位
|
||||
* B8 M27:连翻 30 页(6 类循环)不掉页、不占位、分配峰值 ≤3MB
|
||||
* B7c P1-1 旁路回归:截断 12MP JPEG / 3000×3000 24bpp 头-only BMP(判定 backend,
|
||||
* 后端失败必须 NULL、峰值 ≤3MB)/ 非法位深 PNG(矩阵拒绝→stb 占位)
|
||||
* B8 M27:连翻 30 页(6 类循环)不掉页、不占位、任何时刻存活增量 ≤3MB
|
||||
* B9 M27:CMYK 回退页集成 —— 占位可重试且不崩
|
||||
*
|
||||
* 夹具:BMP/PNG 小夹具由本文件用 C 写;JPEG/PNG/BMP 大夹具由 python3+Pillow 生成
|
||||
@@ -374,6 +376,7 @@ static int gen_jpeg_fixtures(const char *dir)
|
||||
"base2000.jpg", "prog2000.jpg", "restart2000.jpg",
|
||||
"page1600.png", "page1600.bmp", "mp4.jpg", "mp12.jpg",
|
||||
"cmyk.jpg", "adam7.png", "mono1.bmp",
|
||||
"trunc2000.jpg", "hdr3000.bmp", "baddepth.png",
|
||||
};
|
||||
for (size_t i = 0; i < sizeof need / sizeof need[0]; i++) {
|
||||
char p[MR_PATH_MAX];
|
||||
@@ -384,15 +387,17 @@ static int gen_jpeg_fixtures(const char *dir)
|
||||
}
|
||||
|
||||
/* 与 reader_load_page 完全同路径:_step_ex → 兜底降采样 → 落框重采样。
|
||||
* allow_stb 与阅读器一致:判定 backend 时传 0(后端失败即 NULL,绝不回退 stb)。
|
||||
* 返回真实分配峰值(字节),并回报实际路径与最终尺寸。 */
|
||||
static size_t measure_page_decode(const char *path, const mr_img_info *in, int step,
|
||||
int box_w, int box_h, int *used_backend, int *ow, int *oh)
|
||||
int allow_stb, int box_w, int box_h,
|
||||
int *used_backend, int *ow, int *oh)
|
||||
{
|
||||
int dim = box_w > box_h ? box_w : box_h;
|
||||
size_t base = g_live;
|
||||
peak_reset();
|
||||
int used = 0;
|
||||
meow_img *im = meow_img_load_file_step_ex(path, dim, step, &used);
|
||||
meow_img *im = meow_img_load_file_step_ex(path, dim, step, allow_stb, &used);
|
||||
if (im && (meow_img_w(im) > dim || meow_img_h(im) > dim)) {
|
||||
meow_img *small = meow_img_downscale(im, dim);
|
||||
if (small) { meow_img_free(im); im = small; }
|
||||
@@ -633,7 +638,7 @@ int main(void)
|
||||
mr_decode_decision dec;
|
||||
reader_estimate_peak(&in, step, box_w, box_h, -1, -1, &dec);
|
||||
int used = 0, ow = 0, oh = 0;
|
||||
size_t measured = measure_page_decode(p, &in, dec.step, box_w, box_h,
|
||||
size_t measured = measure_page_decode(p, &in, dec.step, 1, box_w, box_h,
|
||||
&used, &ow, &oh) + 1;
|
||||
printf(" %-16s %-8s %10lld %10zu %6.2f\n", typical[i],
|
||||
dec.path == MR_DECODE_PATH_BACKEND ? "backend" : "stb",
|
||||
@@ -664,7 +669,7 @@ int main(void)
|
||||
int step = in.codec == MR_IMG_CODEC_JPEG
|
||||
? meow_img_pick_scale(in.w > in.h ? in.w : in.h, dim) : 1;
|
||||
int used = 0, ow = 0, oh = 0;
|
||||
measure_page_decode(p, &in, step, box_w, box_h, &used, &ow, &oh);
|
||||
measure_page_decode(p, &in, step, 1, box_w, box_h, &used, &ow, &oh);
|
||||
/* 旧路径(与 meow_img_load_file_step 的 stb 分支同式):先 stbi 缩解,再精修。 */
|
||||
int sw = 0, sh = 0, sc = 0, ew = 0, eh = 0;
|
||||
unsigned char *raw = stbi_load_scaled(p, &sw, &sh, &sc, 4, step);
|
||||
@@ -701,7 +706,7 @@ int main(void)
|
||||
mr_decode_decision dec;
|
||||
reader_estimate_peak(&in, step, box_w, box_h, -1, -1, &dec);
|
||||
int used = 1, ow = 0, oh = 0;
|
||||
size_t measured = measure_page_decode(p, &in, dec.step, box_w, box_h,
|
||||
size_t measured = measure_page_decode(p, &in, dec.step, 1, box_w, box_h,
|
||||
&used, &ow, &oh) + 1;
|
||||
printf(" %-16s %-8s %10lld %10zu %6.2f\n", fallback[i],
|
||||
dec.path == MR_DECODE_PATH_BACKEND ? "backend" : "stb",
|
||||
@@ -715,6 +720,44 @@ int main(void)
|
||||
fallback[i]);
|
||||
if (ow > 0 && oh > 0) {} /* 尺寸仅记录 */
|
||||
}
|
||||
/* ---- B7c(P1-1 回归):头部判支持、解码中途失败的坏文件 ----
|
||||
* 旧实现「后端失败 → 静默回退 stb」实测放出 16–36MB;现在必须:
|
||||
* - 判定 backend 的(截断 JPEG / 头-only 24bpp BMP)→ backend-only 解码返回 NULL,
|
||||
* 峰值只含失败前的小分配(≤3MB),绝不 stb 整幅;
|
||||
* - 判定 stb 的(非法位深 PNG,矩阵已镜像 png_depth_ok)→ skip=peak,不分配。 */
|
||||
static const char *const badmeta[] = { "trunc2000.jpg", "hdr3000.bmp", "baddepth.png" };
|
||||
printf(" [B7c] 坏文件(P1-1 旁路回归):\n");
|
||||
for (size_t i = 0; i < sizeof badmeta / sizeof badmeta[0]; i++) {
|
||||
char p[MR_PATH_MAX];
|
||||
snprintf(p, sizeof p, "%s/%s", jpgbook, badmeta[i]);
|
||||
mr_img_info in;
|
||||
if (!mr_probe_info(p, &in)) { CHECK(0, "probe %s", badmeta[i]); continue; }
|
||||
int box_w = 480;
|
||||
int box_h = (int)((long)in.h * box_w / in.w);
|
||||
int dim = box_w > box_h ? box_w : box_h;
|
||||
int step = in.codec == MR_IMG_CODEC_JPEG
|
||||
? meow_img_pick_scale(in.w > in.h ? in.w : in.h, dim) : 1;
|
||||
mr_decode_decision dec;
|
||||
reader_estimate_peak(&in, step, box_w, box_h, -1, -1, &dec);
|
||||
if (dec.path == MR_DECODE_PATH_BACKEND) {
|
||||
int used = 1, ow = 0, oh = 0;
|
||||
size_t measured = measure_page_decode(p, &in, dec.step, 0, box_w, box_h,
|
||||
&used, &ow, &oh) + 1;
|
||||
printf(" %-16s backend-only measured=%zuKB (backend 失败→NULL)\n",
|
||||
badmeta[i], measured / 1024);
|
||||
CHECK(used == 0, "%s 不走 stb(used=0)", badmeta[i]);
|
||||
CHECK(ow == 0 && oh == 0, "%s 返回 NULL(坏图占位)", badmeta[i]);
|
||||
CHECK(measured <= 3 * 1024 * 1024,
|
||||
"%s backend-only 峰值 ≤3MB (%zuKB)", badmeta[i], measured / 1024);
|
||||
} else {
|
||||
printf(" %-16s stb skip=%d est=%lldkB(门控占位,不分配)\n",
|
||||
badmeta[i], dec.skip, dec.peak_bytes / 1024);
|
||||
CHECK(dec.skip != MR_DECODE_OK, "%s 门控必须占位 (skip=%d)",
|
||||
badmeta[i], dec.skip);
|
||||
CHECK(dec.peak_bytes > 3LL * 1024 * 1024,
|
||||
"%s stb 模型判超预算 (%lldkB)", badmeta[i], dec.peak_bytes / 1024);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf(" SKIP jpeg assertions: Pillow unavailable (python3 -c 'import PIL')\n");
|
||||
}
|
||||
@@ -728,32 +771,30 @@ int main(void)
|
||||
int w = meow_ui_width();
|
||||
int advanced = 0, skipped_max = 0;
|
||||
size_t live_steady = g_live;
|
||||
size_t peak_steady = g_peak;
|
||||
int d0 = mr_reader_ui_decode_count();
|
||||
size_t peak_max = 0;
|
||||
/* P2-3:只在窗口稳定后 reset 一次,之后不再 reset——这样淘汰旧图不会掩盖
|
||||
* 「分配新图 + 解码」的真实峰值;指标 = 整个 30 翻窗口内相对稳态基线的最大存活增量。
|
||||
* (旧实现每翻页 reset 一次,淘汰把基线拉低,报告里的 536KB 是伪值。) */
|
||||
size_t base = peak_reset();
|
||||
for (int i = 0; i < 30; i++) {
|
||||
int before = mr_reader_ui_page();
|
||||
size_t base = g_live;
|
||||
peak_reset(); /* 每页单独量「相对当前存活」的瞬时增量 */
|
||||
tap(i % 2 == 0 ? 40 : w - 40, 300);
|
||||
pump_ms(220);
|
||||
size_t step_peak = g_peak > base ? g_peak - base : 0;
|
||||
if (step_peak > peak_max) peak_max = step_peak;
|
||||
if (mr_reader_ui_page() != before) advanced++;
|
||||
if (mr_reader_ui_skipped_pages() > skipped_max)
|
||||
skipped_max = mr_reader_ui_skipped_pages();
|
||||
}
|
||||
size_t transient = g_peak > peak_steady ? g_peak - peak_steady : 0;
|
||||
size_t transient = g_peak > base ? g_peak - base : 0;
|
||||
INFO("30 mixed flips: advanced=%d skipped=%d decodes=%d steady=%zuKB "
|
||||
"max_step_peak=%zuKB cumulative=%zuKB",
|
||||
"resident=%ldKB max_live_delta=%zuKB",
|
||||
advanced, skipped_max, mr_reader_ui_decode_count() - d0,
|
||||
live_steady / 1024, peak_max / 1024, transient / 1024);
|
||||
live_steady / 1024, mr_reader_ui_resident_kb(), transient / 1024);
|
||||
CHECK(advanced == 30, "30 页全部翻到 (%d/30)", advanced);
|
||||
CHECK(skipped_max == 0, "典型页连翻无占位 (max=%d)", skipped_max);
|
||||
CHECK(mr_reader_ui_failed_pages() == 0, "无永久失败页 (%d)",
|
||||
mr_reader_ui_failed_pages());
|
||||
CHECK(peak_max <= 3 * 1024 * 1024,
|
||||
"30 页连翻单页分配峰值 ≤3MB (%zuKB)", peak_max / 1024);
|
||||
CHECK(transient <= 3 * 1024 * 1024,
|
||||
"30 页连翻任何时刻存活增量 ≤3MB (%zuKB)", transient / 1024);
|
||||
meow_view_page_pop();
|
||||
pump_ms(200);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user