Files
ViperOS/Apps/Explorer/main.vp
T
TermiNexus e41701e201 feat(fb0): 新增 FB_WAIT_VBLANK ioctl,合成前等垂直回扫
explorer 直接写 framebuffer 会与显示器扫描并发,造成撕裂/闪烁;而它在 Ring3 没有 IO 端口权限,不能像历史内核桌面那样自己 inb 0x3DA。所以在 /dev/fb0 上加 FB_WAIT_VBLANK(0x4601)由内核代等垂直回扫(带超时,无 VGA 时序时不死等),vpsdk 暴露 fb_wait_vblank(),desk_server.render() 写屏前调用一次。
2026-10-16 21:37:58 +08:00

94 lines
3.5 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import vpsdk.devfs as devfs
import vpsdk.desk as desk
import vpsdk.process as process
from stdint import *
import viperlib
import desk_server
def _dbg(msg: const str):
# S4:改走 /dev/serial0(SERIAL_PUTS 私有 syscall 已删除)
devfs.serial_puts(msg)
@__attribute__(section(".text.startup"), aligned(16))
export def _start() -> int:
_dbg("[explorer] start\n")
# 1) 打开 framebuffer 设备,问几何,再映射成线性地址
fb_fd: int = devfs.fb_open()
if fb_fd < 0:
_dbg("[explorer] open /dev/fb0 FAILED\n")
process.exit(1)
return 0
# fb_get_info 改为出参 + 返回码:必须判返回码,否则拿到的是"未写入的残留"
# (旧写法按值返回 FbInfo,只见前 16 字节有效 ⇒ size/phys 打出垃圾)。
info: devfs.FbInfo
_fb_ret: int = devfs.fb_get_info(fb_fd, &info)
if _fb_ret != 0:
_dbg("[explorer] FB_GET_INFO FAILED\n")
process.exit(1)
return 0
buf: [160]char
viperlib.snprintf(&buf, 160,
"[explorer] fb %ux%u pitch=%u fmt=%u size=%lu phys=0x%lx\n",
info.width, info.height, info.pitch, info.format, info.size, info.phys)
_dbg(&buf)
if info.pitch == 0 or info.size == 0:
# 几何为 0 ⇒ 内核侧登记/回填没成功(例如注册时传进去的 width/height 是 0)。
# 继续走只会以 pitch=0 画崩,这里 fail-fast 并把原因说清楚。
_dbg("[explorer] fb geometry invalid (pitch/size=0)\n")
process.exit(1)
return 0
fb_va: uint64 = devfs.fb_map(fb_fd, info.size)
if fb_va == 0:
_dbg("[explorer] mmap /dev/fb0 FAILED\n")
process.exit(1)
return 0
buf2: [96]char
viperlib.snprintf(&buf2, 96, "[explorer] fb mapped at 0x%lx\n", fb_va)
_dbg(&buf2)
# 2) 屏幕几何/映射地址已打印(上面两行),像素通路由此验证;真正的绘制在服务端。
fb: uint32* = uint32*(fb_va)
# 4) 输入设备可达性:能 open 到就说明 /dev/* 通路已打通
# (真正读事件、接管窗口合成放到 S3 —— 内核桌面此刻还在抢同一个 PS/2 口)。
kfd: int = devfs.kbd_open()
mfd: int = devfs.mouse_open()
buf3: [96]char
viperlib.snprintf(&buf3, 96, "[explorer] input: kbd=%d mouse=%d\n", kfd, mfd)
_dbg(&buf3)
# 5) 挂上 /dev/desk 共享区并格式化 —— explorer 是图形壳,共享区由它初始化,
# app 侧只 desk_ready() 校验。这里先把头打出来证明 IPC 底座可用。
desk_fd: int = desk.desk_open()
if desk_fd < 0:
_dbg("[explorer] open /dev/desk FAILED\n")
process.exit(1)
return 0
shm: uint64 = desk.desk_map(desk_fd)
if shm == 0:
_dbg("[explorer] mmap /dev/desk FAILED\n")
process.exit(1)
return 0
desk.desk_format(shm, info.width, info.height, info.pitch)
hdr: desk.DeskHeader* = desk.DeskHeader*(shm + desk.desk_header_off())
buf4: [144]char
viperlib.snprintf(&buf4, 144,
"[explorer] desk shm=0x%lx ready=%d slot=%lu arena=%u\n",
shm, hdr.ready, uint64(desk.desk_slot_size()), hdr.arena_off)
_dbg(&buf4)
# 6) 进入窗口服务端主循环(永不返回):请求环 + 输入 + 合成。
srv: desk_server.DeskServer = desk_server.DeskServer()
srv.init(fb, int(info.width), int(info.height), int(info.pitch), info.format, shm, kfd, mfd, fb_fd)
_dbg("[explorer] desk server running\n")
srv.serve()
return 0