From 5f863bed7125177242cc322134590670bdabba1c Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Fri, 16 Oct 2026 22:31:35 +0800 Subject: [PATCH] =?UTF-8?q?perf(explorer):=20=E5=90=88=E6=88=90=E6=94=B9?= =?UTF-8?q?=E7=94=BB=E5=90=8E=E5=A4=87=E7=BC=93=E5=86=B2=EF=BC=8C=E6=B8=B2?= =?UTF-8?q?=E6=9F=93=E6=9C=AB=E5=B0=BE=E5=8F=AA=E6=8F=90=E4=BA=A4=E8=84=8F?= =?UTF-8?q?=E8=A1=8C=E5=88=B0=20framebuffer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 消除撕裂:原来所有绘制直接写真实 framebuffer,与显示器扫描并发 ⇒ 撕裂/闪烁;而用户态无法做垂直同步(QEMU/OVMF 的 GOP 线性帧缓冲没有 VGA 回扫信号,FB_WAIT_VBLANK 实测返回 0 空转)。改法对齐历史内核桌面的做法:DeskServer 增加进程本地后备缓冲 back(与 bg_row 同机制 mmap 匿名页),row_fill/row_blit/draw_char/阴影混合/任务栏 logo 等所有写入点从 self.fb 改到 self.back(back 行距 = fb_w,framebuffer 行距 = pitch_px),render() 先把脏行范围渲染到 back,末尾再把仍脏的行逐行 memcpy 提交到 framebuffer。分配失败时打印并退回直写。同时删掉已完成使命的 vblank iters 诊断打印。 --- Apps/Explorer/desk_server.vp | 47 ++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/Apps/Explorer/desk_server.vp b/Apps/Explorer/desk_server.vp index 5fb0bb8..0761e80 100644 --- a/Apps/Explorer/desk_server.vp +++ b/Apps/Explorer/desk_server.vp @@ -11,8 +11,6 @@ import viperlib # 【诊断·临时】首个鼠标包已收到的标记(0 = 未收到) _mouse_logged: int = 0 -# 首次 vblank 等待的迭代数只打一次(诊断同步是否真的生效;到上限 = 超时) -_vblank_logged: int = 0 # ============================================================================ @@ -78,6 +76,7 @@ class DeskServer: pitch_px: int fmt: uint32 # 0 = RGBA, 1 = BGRA bg_row: uint32* # 一行背景的预构造副本 + back: uint32* # 后备缓冲:绘制先落这里,整帧后逐行拷到 fb # 共享区 shm: uint64 # 输入 @@ -167,6 +166,16 @@ class DeskServer: col: uint32 = self.rgb(uint32(25), uint32(25), uint32(35)) for i in range(w): self.bg_row[i] = col + # 后备缓冲:整屏像素,行距 = fb_w(与 framebuffer 的 pitch 无关) + back_va: uint64 = syscall.mmap(0, uint64(w) * uint64(h) * uint64(4), + uint64(syscall.PROT_READ | syscall.PROT_WRITE), + uint64(syscall.MAP_PRIVATE | syscall.MAP_ANONYMOUS), + syscall.MMAP_FD_ANON, 0) + if back_va == 0: + devfs.serial_puts("[explorer] back buffer alloc FAILED\n") + self.back = self.fb # 退化:直写 framebuffer,保留原行为 + else: + self.back = uint32*(back_va) self.mark_all() # ---------------- 脏行 ---------------- @@ -215,8 +224,8 @@ class DeskServer: if x + dw > self.fb_w: dw = self.fb_w - x if dw <= 0: return - base: int = y * self.pitch_px - string.memset32(rawptr(uint64(self.fb) + uint64((base + x) * 4)), col, uint64(dw)) + base: int = y * self.fb_w + string.memset32(rawptr(uint64(self.back) + uint64((base + x) * 4)), col, uint64(dw)) def row_blit(self, x0: int, y: int, src: uint32*, src_off: int, w: int): """把 src[src_off .. src_off+w) 拷到屏幕 (x0, y),裁剪到屏幕内。""" @@ -231,7 +240,7 @@ class DeskServer: if dx + dw > self.fb_w: dw = self.fb_w - dx if dw <= 0: return - dst: uint64 = uint64(self.fb) + uint64(y * self.pitch_px + dx) * uint64(4) + dst: uint64 = uint64(self.back) + uint64(y * self.fb_w + dx) * uint64(4) srcp: uint64 = uint64(src) + uint64(src_off + sx) * uint64(4) string.memcpy(rawptr(dst), rawptr(srcp), uint64(dw) * uint64(4)) @@ -295,13 +304,13 @@ class DeskServer: if ty >= 0 and ty < self.fb_h: row: uint8 = vpui.font[ci][fy] if row != uint8(0): - base: int = ty * self.pitch_px + base: int = ty * self.fb_w fx: int = 0 while fx < vpui.CHAR_W: if row & (0x80 >> fx): px: int = x + fx if px >= 0 and px < self.fb_w: - self.fb[base + px] = col + self.back[base + px] = col fx += 1 fy += 1 @@ -364,8 +373,8 @@ class DeskServer: t_inv: int = 256 - t_val a: int = (sa * t_inv * t_inv) / 65536 if a > 0: - idx: int = yy * self.pitch_px + px - self.fb[idx] = self._blend(self.fb[idx], shadow_col, a) + idx: int = yy * self.fb_w + px + self.back[idx] = self._blend(self.back[idx], shadow_col, a) px += 1 yy += 1 @@ -450,9 +459,9 @@ class DeskServer: px: int = logo_x + lx if px >= 0 and px < self.fb_w: if d2 <= (lr * lr) / 2: - self.fb[yy * self.pitch_px + px] = lc_core + self.back[yy * self.fb_w + px] = lc_core else: - self.fb[yy * self.pitch_px + px] = lc_ring + self.back[yy * self.fb_w + px] = lc_ring lx += 1 yy += 1 # 品牌文字 @@ -666,7 +675,6 @@ class DeskServer: y += 1 def render(self): - global _vblank_logged if self.dirty_any == 0: return y0: int = -1 y1: int = -1 @@ -681,13 +689,16 @@ class DeskServer: 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) + devfs.fb_wait_vblank(self.fb_fd) self.render_range(y0, y1) + # 提交:整帧已画进 back,只把仍脏的行拷到 framebuffer(fb 行距 = pitch_px) + y = y0 + while y < y1: + if self.dirty[y] != 0: + string.memcpy(rawptr(uint64(self.fb) + uint64(y * self.pitch_px) * uint64(4)), + rawptr(uint64(self.back) + uint64(y * self.fb_w) * uint64(4)), + uint64(self.fb_w) * uint64(4)) + y += 1 self.clear_dirty() # ---------------- 事件投递 ----------------