原汁原味补全官方管线细节:0x8c CDF 中心、temporal 移植、uniform 分支、状态标志

- 抓取官方会话控制字段确认实际启用路径:0x109c0→0x11ee0→0x19740;
  temporal(0x41fe0=1)/帧差(0x230=0)/隔行平滑(0x41fe8=0)/0x30=0 全关
- 实现 0x8c=1 分支:CDF 中心=max(均值bin, 累计75%bin),lres 545→631
  (官方 633,跨帧差 2 bin);用官方 cdf 离线验证 LUT 差异降至 123/1024
  (集中在灰度过渡区,跨帧异步所致)
- 移植 temporal filter(0x18001e920,0x41fe0>1 启用,默认关=官方)
- 补 uniform 帧分支(0x109c0:fmin==fmax 时 LUT/gray 置中灰)
- 补官方标志维护(0x4203c/0x42038/0x42004)
- 实机确认:ref=15502(type1)、d=-2390、win/stats 正常
This commit is contained in:
ZXCLI
2026-08-14 16:33:13 +08:00
parent 004f28910f
commit fe91a82762
92 changed files with 292 additions and 8 deletions
+70
View File
@@ -105,6 +105,7 @@ static int g_dev24 = 5; /* window base */
static int g_dev4c_shift = 3; /* 0x4794c */
static int g_dev48; /* contrast -100..100 */
static int g_dev4c; /* window scale -100..100 */
static int g_dev8c = 1; /* 0x8c: CDF pivot at 75% cumulative (live=1) */
static int g_shift; /* 0x11c = 12 */
static int g_ep_temps[64]; /* T[] */
static int g_blind_cnt[64];
@@ -133,6 +134,9 @@ static int g_f20[NPIX];
static int g_fcount;
static int g_manual_ffc;
static int g_startup_ffc_done;
static int g_flag4203c; /* official 0x4203c: auto-gray-path marker */
static int g_flag42038; /* official 0x42038: temporal ran this frame */
static int g_flag42004; /* official 0x42004: NUC output valid this frame */
/* ---- render state ---- */
static unsigned short g_nuc[NPIX];
@@ -358,6 +362,16 @@ static void official_stats_window(const unsigned short *nuc) {
double var = (double)s2sum / NPIX - dmean * dmean;
g_stat_std = (int)sqrt(var > 0 ? var : 0);
(void)mi; (void)xi;
/* official 0x109c0 uniform-frame branch: fmin==fmax -> window pinned,
* LUT/gray reset to mid level, flag 0x4203c set (auto path marker). */
if (mn == mx) {
g_win_lo = g_win_hi = (int)mn;
memset(g_lut, 0x80, sizeof(g_lut));
memset(g_gray160, 0x80, sizeof(g_gray160));
g_flag4203c = 1;
return;
}
g_flag4203c = 0;
/* window half (FUN_1800108a0): base = max(0x80, dev24*1000>>shift) */
int base = (g_dev24 * 1000) >> g_dev4c_shift;
if (base < 0x80) base = 0x80;
@@ -408,6 +422,19 @@ static void lut_rebuild(const unsigned short *nuc) {
int lres = ((g_stat_mean - g_win_lo) * 0x3ff) / span;
if (lres < 0) lres = 0;
if (lres > 1023) lres = 1023;
/* official 0x8c=1 (live): CDF center = max(mean-bin, first bin whose
* cumulative count reaches total*3/4). This moves the equalization
* pivot to the 75% accumulation point (FUN_180011ee0). */
if (g_dev8c) {
unsigned acc = 0;
int k = 0;
while (k < 1024) {
acc += g_hist1024[k];
if (acc >= (total * 3 >> 2)) break;
k++;
}
if (k < 1024 && k > lres) lres = k;
}
/* 3. CDF: down from lres, up from lres+1 */
unsigned u11 = 0, u13 = 0;
@@ -511,6 +538,40 @@ static void lut_rebuild(const unsigned short *nuc) {
}
}
/* ---------------- temporal filter (FUN_18001e920) ---------------- */
/* Official object at dev+0x41f40: +0x10 history (u16), +0x28 ring write
* pointer, +0x30 counter, +0x34 pixel count, +0x38 period(mode), +0x3c
* enabled. Active when dev+0x41fe0 > 1; live session = 1 (off).
* period==1: out[i] = in[i] - ((in[i]-prev[i])>>1) when |d|<=thr (EMA). */
static unsigned short g_tmp_hist[NPIX];
static unsigned short *g_tmp_ring = g_tmp_hist;
static int g_tmp_cnt;
static int g_tmp_period = 1; /* dev+0x41f40+0x38 */
static int g_tmp_enabled; /* dev+0x41f40+0x3c */
static int g_tmp_mode = 1; /* dev+0x41fe0 */
static void temporal_apply(unsigned short *buf, int thr) {
if (!g_tmp_enabled) return;
g_tmp_cnt++;
if (g_tmp_period < g_tmp_cnt) {
if (g_tmp_period != 1) return;
for (int i = 0; i < NPIX; ++i) {
unsigned prev = g_tmp_hist[i];
g_tmp_hist[i] = buf[i];
int d = (int)buf[i] - (int)prev;
if (d <= thr && -d <= thr && d != 0)
buf[i] = (unsigned short)(buf[i] - (d >> 1));
}
} else {
memcpy(g_tmp_ring, buf, NPIX * 2);
}
if (g_tmp_cnt % g_tmp_period != 0) {
g_tmp_ring += NPIX;
return;
}
g_tmp_ring = g_tmp_hist;
}
/* ---------------- gray + 2x upscale (FUN_180019740) ---------------- */
static void gray_map(const unsigned short *nuc) {
@@ -964,10 +1025,19 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmd, int show) {
if (dbg) { fprintf(dbg, "RENDER f=%u has_ref=%d tables=%d\n", g_fcount, g_has_ref, g_tables_ready); fflush(dbg); }
if (g_has_ref && g_tables_ready) {
official_nuc_and_blind(g_live, g_nuc);
/* official 0xca30: temporal filter when 0x41fe0 > 1 (live=1, off) */
g_flag42038 = 0;
if (g_tmp_mode > 1) {
int thr = (g_dev24 * 1000 >> 1) >> g_dev4c_shift; /* 0x15680 static */
if (thr > 0xffff) thr = 0xffff;
temporal_apply(g_nuc, thr);
g_flag42038 = 1;
}
official_stats_window(g_nuc);
lut_rebuild(g_nuc);
gray_map(g_nuc);
upscale2x();
g_flag42004 = 1;
} else {
memset(g_nuc, 0, sizeof(g_nuc));
memset(g_gray160, 0, sizeof(g_gray160));
+24
View File
@@ -167,6 +167,30 @@ int main(int argc, char **argv) {
*(int *)(dev + 0x47940), *(int *)(dev + 0x44c50), *(int *)(dev + 0x44c60),
*(int *)(dev + 0x44c64), *(int *)(dev + 0x44c68),
*(int *)(dev + 0x42010), *(int *)(dev + 0x42014));
fprintf(cfg, "ctrl: 28=%d 30=%d 44=%d 88=%d 8c=%d 90=%d 230=%d 234=%d\n",
*(int *)(dev + 0x28), *(int *)(dev + 0x30), *(int *)(dev + 0x44),
*(int *)(dev + 0x88), *(int *)(dev + 0x8c), *(int *)(dev + 0x90),
*(int *)(dev + 0x230), *(int *)(dev + 0x234));
fprintf(cfg, "temporal: 41f40+30=%d +34=%d +38=%d +3c=%d 41f68=%p 41f70=%d 41f74=%d 41f7c=%d\n",
*(int *)(dev + 0x41f40 + 0x30), *(int *)(dev + 0x41f40 + 0x34),
*(int *)(dev + 0x41f40 + 0x38), *(int *)(dev + 0x41f40 + 0x3c),
*(void **)(dev + 0x41f68), *(int *)(dev + 0x41f70), *(int *)(dev + 0x41f74),
*(int *)(dev + 0x41f7c));
fprintf(cfg, "smo2: 41f90+30=%d +38=%d +3c=%d 41fa8=%p 41fb0=%d 41fb4=%d 41fbc=%d\n",
*(int *)(dev + 0x41f90 + 0x30), *(int *)(dev + 0x41f90 + 0x38),
*(int *)(dev + 0x41f90 + 0x3c), *(void **)(dev + 0x41fa8),
*(int *)(dev + 0x41fb0), *(int *)(dev + 0x41fb4), *(int *)(dev + 0x41fbc));
fprintf(cfg, "flags: 4203c=%d 42038=%d 42040=%d 42044=%d 42004=%d 41ffc=%d 41fdc=%d\n",
*(int *)(dev + 0x4203c), *(int *)(dev + 0x42038), *(int *)(dev + 0x42040),
*(int *)(dev + 0x42044), *(int *)(dev + 0x42004), *(int *)(dev + 0x41ffc),
*(int *)(dev + 0x41fdc));
fprintf(cfg, "bufs: 270=%p 278=%p 280=%p 288=%p 290=%p 2a0=%p 2b0=%p 2c8=%p\n",
*(void **)(dev + 0x270), *(void **)(dev + 0x278), *(void **)(dev + 0x280),
*(void **)(dev + 0x288), *(void **)(dev + 0x290), *(void **)(dev + 0x2a0),
*(void **)(dev + 0x2b0), *(void **)(dev + 0x2c8));
fprintf(cfg, "win: 42018=%d 4201c=%d 44c48=%d 44c64=%d 44c68=%d\n",
*(int *)(dev + 0x42018), *(int *)(dev + 0x4201c), *(int *)(dev + 0x44c48),
*(int *)(dev + 0x44c64), *(int *)(dev + 0x44c68));
fclose(cfg);
}
/* copy the DDT file */