fix(desktop): 建窗与置脏标记加关键区,消除并发导致的共槽/同 z_order
create() 由各 App 线程经 syscall 并发调用(开机多 App 同时建窗最易命中),但 _win_count/_next_z 的读-改-写无互斥:抢占后读到同一 _win_count ⇒ 两个 App 共用同一 AppWindow 槽,标题/坐标/z_order/fb 互相覆盖;读到同一 _next_z ⇒ z_order 相同,渲染排序退化成槽位下标顺序 —— 均表现为更下方窗口的 title 突然显示到最上方。 改为:关键区①只原子分配槽位,结构体填充留在区外(避免长时间关中断);关键区②把 active/z_order/焦点一次性发布(渲染线程只在 active==1 后读该槽)。_bring_to_front 的 _next_z 自增同加关键区;_mark_rows_dirty/_mark_all_dirty/_clear_dirty_flags 同加关键区,避免与 App 线程并发时丢置脏标记(丢标记会让该行永不重绘,旧合成滞留在屏幕上)。
This commit is contained in:
1 parent
1b2f6853fc
commit
82e951ee84
1 file changed
+33
-5
@@ -396,6 +396,11 @@ def _get_title_height(style: int) -> int:
|
||||
|
||||
def _mark_rows_dirty(start_y: int, count: int):
|
||||
global _dirty_count, _dirty_y_min, _dirty_y_max
|
||||
# 关键区:本函数会被 App 线程(draw_text/flush/set_title → syscall)与桌面线程并发调用,
|
||||
# 对 _dirty_rows/_dirty_count/_dirty_y_min/_dirty_y_max 的读-改-写不加锁会丢置脏标记
|
||||
# ⇒ 该行永远不重绘,旧合成(例如下方窗口的 title 压在其它窗口上)会留在屏幕上,
|
||||
# 直到别的操作再次置脏才"弹回去"——正是"更下方的 title 突然跑到最上方、不易复现"。
|
||||
asm.cli()
|
||||
for i in range(start_y, start_y + count):
|
||||
if i >= 0 and i < _screen_h:
|
||||
if not _dirty_rows[i]:
|
||||
@@ -405,23 +410,29 @@ def _mark_rows_dirty(start_y: int, count: int):
|
||||
_dirty_y_min = i
|
||||
if i > _dirty_y_max or _dirty_count == 1:
|
||||
_dirty_y_max = i
|
||||
asm.sti()
|
||||
|
||||
def _mark_all_dirty():
|
||||
global _dirty_count, _dirty_y_min, _dirty_y_max
|
||||
asm.cli()
|
||||
string.memset(_dirty_rows, 1, _screen_h)
|
||||
_dirty_count = _screen_h
|
||||
_dirty_y_min = 0
|
||||
_dirty_y_max = _screen_h - 1
|
||||
asm.sti()
|
||||
|
||||
def _has_dirty_rows() -> int:
|
||||
return _dirty_count
|
||||
|
||||
def _clear_dirty_flags():
|
||||
global _dirty_count, _dirty_y_min, _dirty_y_max
|
||||
# 关键区:清除与(App 线程的)置脏并发时,会把刚置上的行清掉 ⇒ 同样丢一帧更新
|
||||
asm.cli()
|
||||
string.memset(_dirty_rows, 0, _screen_h)
|
||||
_dirty_count = 0
|
||||
_dirty_y_min = _screen_h
|
||||
_dirty_y_max = -1
|
||||
asm.sti()
|
||||
|
||||
def _wait_vblank():
|
||||
global _vblank_ok
|
||||
@@ -573,8 +584,11 @@ def _bring_to_front(idx: int):
|
||||
if idx < 0 or idx >= _win_count: return
|
||||
aw: AppWindow* = &_wins[idx]
|
||||
if not aw.active or aw.minimized: return
|
||||
# 与 create() 共用 _next_z,同样必须原子自增,否则可能出现两个窗口 z_order 相同
|
||||
asm.cli()
|
||||
_next_z += 1
|
||||
aw.z_order = _next_z
|
||||
asm.sti()
|
||||
|
||||
def _hit_test_window(mx: int, my: int) -> int:
|
||||
best: int = -1
|
||||
@@ -2558,18 +2572,24 @@ def _draw_app_window(back: uint32*, win: AppWindow*):
|
||||
|
||||
def create(x: int, y: int, w: int, h: int, title: const str, style: int) -> int:
|
||||
global _win_count, _next_z, _focused_win
|
||||
if _win_count >= MAX_APP_WINDOWS: return -1
|
||||
# 关键区①:槽位分配必须原子。create() 由各 App 线程经 syscall 并发调用(开机时多个
|
||||
# App 同时建窗,最易命中)。若被定时器抢占后读到同一个 _win_count,两个 App 会共用
|
||||
# 同一个 AppWindow 槽 ⇒ 标题/坐标/z_order/fb 被互相覆盖 ⇒ "更下方的 title 突然跑到
|
||||
# 最上方"(现场)。这里只做"占位",结构体填充放在关键区外,避免长时间关中断。
|
||||
asm.cli()
|
||||
if _win_count >= MAX_APP_WINDOWS:
|
||||
asm.sti()
|
||||
return -1
|
||||
idx: int = _win_count
|
||||
_win_count += 1
|
||||
asm.sti()
|
||||
aw: AppWindow* = &_wins[idx]
|
||||
aw.active = 1
|
||||
aw.active = 0
|
||||
aw.x = x
|
||||
aw.y = y
|
||||
aw.w = w
|
||||
aw.h = h
|
||||
aw.content_h = h - _get_title_height(style) - 2
|
||||
_next_z += 1
|
||||
aw.z_order = _next_z
|
||||
aw.style = style
|
||||
aw.close_hover = 0
|
||||
aw.min_hover = 0
|
||||
@@ -2608,8 +2628,16 @@ def create(x: int, y: int, w: int, h: int, title: const str, style: int) -> int:
|
||||
fb_size: int = w * aw.content_h
|
||||
for fi in range(fb_size):
|
||||
aw.fb[fi] = bg_col
|
||||
_mark_rows_dirty(y, h)
|
||||
# 关键区②:发布窗口 —— active/z_order/焦点一次性生效。渲染线程只在 active==1 之后
|
||||
# 才会读这个槽,所以上面的字段填充必须先完成;且 _next_z 与 _bring_to_front 共用,
|
||||
# 必须原子自增,否则两个窗口会拿到相同 z_order ⇒ 排序退化成槽位下标顺序。
|
||||
asm.cli()
|
||||
_next_z += 1
|
||||
aw.z_order = _next_z
|
||||
aw.active = 1
|
||||
_focused_win = idx
|
||||
asm.sti()
|
||||
_mark_rows_dirty(y, h)
|
||||
return idx
|
||||
|
||||
def draw_text(win_id: int, x: int, y: int, text: const str, color: uint32) -> int:
|
||||
|
||||
Reference in new issue
Block a user