// Pseudo-code / toolkit-agnostic example. // Goal: never render more than one frame concurrently, and always render the latest params. // // Это не “асинхронная работа в фоне”, а чистый паттерн управления вызовами Render. // Он работает в любом UI, где у тебя есть loop и возможность запускать отрисовку // (например, через requestAnimationFrame-аналог или таски). // // Как это сочетается с CoalesceUpdates // - Если params.Options.Incremental.CoalesceUpdates == true, UI использует этот scheduler. // - Если false, UI может пытаться рендерить каждое событие (но это обычно хуже). // // # Важный момент // // Это не делает рендер асинхронным в смысле “рендерить в фоне” — в реальном UI ты должен // выполнять w.Render строго в UI thread. Я показал go только как “планировщик” // (в твоём GUI заменишь на invokeOnMainThread/PostTask/RunOnUI). package world import "sync" type RenderScheduler struct { w *World drawer PrimitiveDrawer // Protects fields below. mu sync.Mutex inFlight bool pending bool latest RenderParams } // RequestRender stores the latest params and schedules rendering. // If a render is already in progress, it coalesces (drops intermediate requests). func (s *RenderScheduler) RequestRender(params RenderParams) { s.mu.Lock() s.latest = params if s.inFlight { s.pending = true s.mu.Unlock() return } s.inFlight = true s.mu.Unlock() // Schedule on the UI thread/event loop. Replace this with your toolkit method. go s.runOnUIThread() } // runOnUIThread should execute on the UI thread. // Replace the body with actual UI scheduling primitives. func (s *RenderScheduler) runOnUIThread() { for { s.mu.Lock() params := s.latest s.mu.Unlock() _ = s.w.Render(s.drawer, params) // handle error in real code s.mu.Lock() if !s.pending { s.inFlight = false s.mu.Unlock() return } // There was a newer request while we were rendering. Loop and render latest. s.pending = false s.mu.Unlock() } }