From e1d31c3dc9c3b1fb3cd1117cc45e7453fdf376a7 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Fri, 16 Oct 2026 21:55:36 +0800 Subject: [PATCH] =?UTF-8?q?diag(explorer,fb0):=20vblank=20=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E7=AD=89=E5=BE=85=E8=BF=AD=E4=BB=A3=E6=95=B0=E5=B9=B6?= =?UTF-8?q?=E6=89=93=E7=82=B9=EF=BC=9B=E8=84=8F=E8=A1=8C=E5=90=88=E5=B9=B6?= =?UTF-8?q?=E4=B8=BA=E4=B8=80=E6=AE=B5=E6=B8=B2=E6=9F=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 排查'仍闪烁':① FB_WAIT_VBLANK 改为返回等待消耗的迭代数(到上限 = 超时 = 当前没有 VGA 回扫信号),explorer 首次调用打印一次 —— 用来判定垂直回扫同步是否真的生效;② render() 原来按连续脏行分段、每段各渲染一次,同一帧的多次写屏会跨越多个扫描周期,现在把脏行合并成一段连续范围一次性渲染,缩小撕裂窗口。 --- Apps/Explorer/desk_server.vp | 29 ++++++++++++++++++--------- VKernel/Kernel/drivers/devfs/devfs.vp | 9 +++++---- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/Apps/Explorer/desk_server.vp b/Apps/Explorer/desk_server.vp index 5cfcfe1..eb0135a 100644 --- a/Apps/Explorer/desk_server.vp +++ b/Apps/Explorer/desk_server.vp @@ -11,6 +11,8 @@ import viperlib # 【诊断·临时】首个鼠标包已收到的标记(0 = 未收到) _mouse_logged: int = 0 +# 首次 vblank 等待的迭代数只打一次(诊断同步是否真的生效;到上限 = 超时) +_vblank_logged: int = 0 # ============================================================================ @@ -661,17 +663,26 @@ class DeskServer: def render(self): if self.dirty_any == 0: return - # 写屏前等垂直回扫(用户态不能 inb 0x3DA,由内核代等),避免撕裂 - devfs.fb_wait_vblank(self.fb_fd) + y0: int = -1 + y1: int = -1 y: int = 0 while y < self.fb_h: - if self.dirty[y] == 0: - y += 1 - continue - y0: int = y - while y < self.fb_h and self.dirty[y] != 0: - y += 1 - self.render_range(y0, y) + if self.dirty[y] != 0: + if y0 < 0: y0 = y + y1 = y + 1 + y += 1 + if y0 < 0: + self.clear_dirty() + return + # 写屏前等垂直回扫(用户态无 IO 权限,由内核代等);脏行合并成**一段**连续范围 + # 一次性渲染 —— 分段渲染会让同一帧的多次写屏跨越多个扫描周期,撕裂更明显。 + vw: int = devfs.fb_wait_vblank(self.fb_fd) + if _vblank_logged == 0: + _vblank_logged = 1 + _vb: [96]char + viperlib.snprintf(&_vb, 96, "[explorer] vblank iters=%d\n", vw) + devfs.serial_puts(&_vb) + self.render_range(y0, y1) self.clear_dirty() # ---------------- 事件投递 ---------------- diff --git a/VKernel/Kernel/drivers/devfs/devfs.vp b/VKernel/Kernel/drivers/devfs/devfs.vp index 1daa36f..0a41bc8 100644 --- a/VKernel/Kernel/drivers/devfs/devfs.vp +++ b/VKernel/Kernel/drivers/devfs/devfs.vp @@ -522,12 +522,13 @@ virtual class framebuffer_device(devfs_file): def ioctl(self, fd: int, request: int, arg: rawptr) -> int: if request == FB_WAIT_VBLANK: - # 等进入垂直回扫期(0x3DA bit3)。带超时:当前若无 VGA 时序不至于死等。 + # 等进入垂直回扫期(0x3DA bit3)。返回等待消耗的迭代数:到上限即超时 + #(当前没有 VGA 回扫信号),调用方可据此判断同步是否真的生效。 t: int = 100000 while (asm.inb(0x3DA) & 0x08) != 0 and t > 0: t -= 1 - t = 100000 - while (asm.inb(0x3DA) & 0x08) == 0 and t > 0: t -= 1 - return 0 + t2: int = 100000 + while (asm.inb(0x3DA) & 0x08) == 0 and t2 > 0: t2 -= 1 + return 100000 - t2 if request != FB_GET_INFO or not arg: return -1 info: FbInfo* = FbInfo*(uint64(arg))