perf(explorer): 合成改画后备缓冲,渲染末尾只提交脏行到 framebuffer
消除撕裂:原来所有绘制直接写真实 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 诊断打印。
This commit is contained in:
1 parent
3945decc2d
commit
5f863bed71
1 file changed
+29
-18
@@ -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()
|
||||
|
||||
# ---------------- 事件投递 ----------------
|
||||
|
||||
Reference in new issue
Block a user