fix: wait a fresh idle interval before predictive reflow
This commit is contained in:
parent
39d079b2cc
commit
73357dee94
6
ebox.el
6
ebox.el
@ -2463,7 +2463,8 @@ publishes the prepared rendered-body entry plus its derived root templates."
|
|||||||
(puthash
|
(puthash
|
||||||
buffer
|
buffer
|
||||||
(run-with-idle-timer
|
(run-with-idle-timer
|
||||||
(max 0 ebox-runtime-idle-reflow-cache-prewarm-delay)
|
(ebox--idle-continuation-delay
|
||||||
|
ebox-runtime-idle-reflow-cache-prewarm-delay)
|
||||||
nil #'ebox--run-root-width-cache-prewarm
|
nil #'ebox--run-root-width-cache-prewarm
|
||||||
buffer state revision region-id source-width target-width)
|
buffer state revision region-id source-width target-width)
|
||||||
ebox--reflow-cache-prewarm-timers)))))
|
ebox--reflow-cache-prewarm-timers)))))
|
||||||
@ -2505,7 +2506,8 @@ predictions are skipped."
|
|||||||
(puthash
|
(puthash
|
||||||
buffer
|
buffer
|
||||||
(run-with-idle-timer
|
(run-with-idle-timer
|
||||||
(max 0 ebox-runtime-idle-reflow-cache-prewarm-delay)
|
(ebox--idle-continuation-delay
|
||||||
|
ebox-runtime-idle-reflow-cache-prewarm-delay)
|
||||||
nil #'ebox--run-reflow-cache-prewarm
|
nil #'ebox--run-reflow-cache-prewarm
|
||||||
buffer state revision viewport-width target-width viewport-height)
|
buffer state revision viewport-width target-width viewport-height)
|
||||||
ebox--reflow-cache-prewarm-timers))))))
|
ebox--reflow-cache-prewarm-timers))))))
|
||||||
|
|||||||
@ -1652,7 +1652,7 @@
|
|||||||
(kill-buffer buffer)))))
|
(kill-buffer buffer)))))
|
||||||
|
|
||||||
(ert-deftest ebox-root-width-cache-prewarm-yields-to-user-input ()
|
(ert-deftest ebox-root-width-cache-prewarm-yields-to-user-input ()
|
||||||
"Ordinary root prediction should run only after an idle interval."
|
"Ordinary root prediction should wait a fresh interval even while idle."
|
||||||
(ebox-test--reset-runtime-state)
|
(ebox-test--reset-runtime-state)
|
||||||
(let* ((layout
|
(let* ((layout
|
||||||
(ebox-test-box :id "root" :width '(240)
|
(ebox-test-box :id "root" :width '(240)
|
||||||
@ -1674,7 +1674,9 @@
|
|||||||
(generate-new-buffer-name " *ebox-root-schedule*")
|
(generate-new-buffer-name " *ebox-root-schedule*")
|
||||||
layout))
|
layout))
|
||||||
(let ((root-id (ebox-test--selector-region-id buffer "#root")))
|
(let ((root-id (ebox-test--selector-region-id buffer "#root")))
|
||||||
(cl-letf (((symbol-function 'run-at-time)
|
(cl-letf (((symbol-function 'current-idle-time)
|
||||||
|
(lambda () (seconds-to-time 0.4)))
|
||||||
|
((symbol-function 'run-at-time)
|
||||||
(lambda (&rest _)
|
(lambda (&rest _)
|
||||||
(ert-fail "Resize prediction must yield to input")))
|
(ert-fail "Resize prediction must yield to input")))
|
||||||
((symbol-function 'run-with-idle-timer)
|
((symbol-function 'run-with-idle-timer)
|
||||||
@ -1687,7 +1689,7 @@
|
|||||||
(ebox--schedule-buffer-root-width-cache-prewarm
|
(ebox--schedule-buffer-root-width-cache-prewarm
|
||||||
buffer root-id 240 260)))
|
buffer root-id 240 260)))
|
||||||
(should (= scheduled-delay
|
(should (= scheduled-delay
|
||||||
ebox-runtime-idle-reflow-cache-prewarm-delay))
|
(+ 0.4 ebox-runtime-idle-reflow-cache-prewarm-delay)))
|
||||||
(should-not scheduled-repeat)
|
(should-not scheduled-repeat)
|
||||||
(should (eq scheduled-function
|
(should (eq scheduled-function
|
||||||
#'ebox--run-root-width-cache-prewarm))
|
#'ebox--run-root-width-cache-prewarm))
|
||||||
@ -1697,6 +1699,72 @@
|
|||||||
(when (buffer-live-p buffer)
|
(when (buffer-live-p buffer)
|
||||||
(kill-buffer buffer)))))
|
(kill-buffer buffer)))))
|
||||||
|
|
||||||
|
(ert-deftest ebox-reflow-prewarm-replacement-and-one-shot-completion ()
|
||||||
|
"Fresh and zero-delay predictions replace old jobs and complete once."
|
||||||
|
(ebox-test--reset-runtime-state)
|
||||||
|
(let ((ebox-viewport-width 900)
|
||||||
|
(ebox-viewport-height 4)
|
||||||
|
(ebox-runtime-idle-prewarm nil)
|
||||||
|
(ebox-runtime-idle-reflow-cache-prewarm t)
|
||||||
|
(ebox--runtime-prewarm-allow-noninteractive t)
|
||||||
|
buffer)
|
||||||
|
(unwind-protect
|
||||||
|
(progn
|
||||||
|
(setq buffer
|
||||||
|
(ebox-render-to-buffer
|
||||||
|
(generate-new-buffer-name " *ebox-prewarm-one-shot*")
|
||||||
|
(ebox-test-box :id "root" :width '(240) :height 1
|
||||||
|
(ebox-test-text "prediction"))))
|
||||||
|
(let ((state (ebox--buffer-render-state buffer))
|
||||||
|
(root-id (ebox-test--selector-region-id buffer "#root")))
|
||||||
|
(dolist (kind '(viewport root-width))
|
||||||
|
(dolist (case '((nil 0.15 0.15) (0.4 0 0.4)))
|
||||||
|
(pcase-let* ((`(,idle-age ,delay ,threshold) case)
|
||||||
|
(ebox-runtime-idle-reflow-cache-prewarm-delay delay)
|
||||||
|
(scratch (plist-get state :reflow-prewarm-scratch))
|
||||||
|
(cancel (symbol-function 'cancel-timer))
|
||||||
|
(registrations 0)
|
||||||
|
(scheduled nil)
|
||||||
|
(cancelled nil))
|
||||||
|
(cl-letf
|
||||||
|
(((symbol-function 'current-idle-time)
|
||||||
|
(lambda () (and idle-age (seconds-to-time idle-age))))
|
||||||
|
((symbol-function 'cancel-timer)
|
||||||
|
(lambda (timer)
|
||||||
|
(push timer cancelled)
|
||||||
|
(funcall cancel timer)))
|
||||||
|
((symbol-function 'run-with-idle-timer)
|
||||||
|
(lambda (seconds repeat function &rest arguments)
|
||||||
|
(cl-incf registrations)
|
||||||
|
(setq scheduled (list seconds repeat function arguments))
|
||||||
|
(timer-create))))
|
||||||
|
(dotimes (attempt 2)
|
||||||
|
(let ((old (gethash buffer ebox--reflow-cache-prewarm-timers)))
|
||||||
|
(pcase kind
|
||||||
|
('viewport
|
||||||
|
(ebox--schedule-buffer-reflow-cache-prewarm
|
||||||
|
buffer 880 900))
|
||||||
|
('root-width
|
||||||
|
(ebox--schedule-buffer-root-width-cache-prewarm
|
||||||
|
buffer root-id 240 260)))
|
||||||
|
(when (= attempt 1)
|
||||||
|
(should (memq old cancelled))
|
||||||
|
(should-not
|
||||||
|
(eq old (gethash buffer ebox--reflow-cache-prewarm-timers))))))
|
||||||
|
(should (= registrations 2))
|
||||||
|
(should (= (car scheduled) threshold))
|
||||||
|
(should-not (cadr scheduled))
|
||||||
|
(should (eq scratch (plist-get state :reflow-prewarm-scratch)))
|
||||||
|
;; Advance the same idle period beyond the fixed threshold.
|
||||||
|
;; Run the real callback, including its state/revision guards.
|
||||||
|
(setq idle-age (+ threshold 1))
|
||||||
|
(should (apply (nth 2 scheduled) (nth 3 scheduled)))
|
||||||
|
(should (plist-get state :reflow-prewarm-scratch))
|
||||||
|
(should-not (gethash buffer ebox--reflow-cache-prewarm-timers))
|
||||||
|
(should (= registrations 2))))))))
|
||||||
|
(when (buffer-live-p buffer)
|
||||||
|
(kill-buffer buffer)))))
|
||||||
|
|
||||||
(ert-deftest ebox-scheduled-reflow-prewarms-use-offscreen-gc-pressure ()
|
(ert-deftest ebox-scheduled-reflow-prewarms-use-offscreen-gc-pressure ()
|
||||||
"Both predicted reflow paths should move GC pressure off visible frames."
|
"Both predicted reflow paths should move GC pressure off visible frames."
|
||||||
(let ((prewarm-count 0)
|
(let ((prewarm-count 0)
|
||||||
@ -10656,7 +10724,7 @@
|
|||||||
:rendered-region-line-span-index-deferred))))))
|
:rendered-region-line-span-index-deferred))))))
|
||||||
|
|
||||||
(ert-deftest ebox-reflow-cache-prewarm-uses-first-valid-width-delta ()
|
(ert-deftest ebox-reflow-cache-prewarm-uses-first-valid-width-delta ()
|
||||||
"Predictive warming should start from the first valid resize velocity."
|
"First resize prediction should wait a fresh interval even while idle."
|
||||||
(ebox-test--reset-runtime-state)
|
(ebox-test--reset-runtime-state)
|
||||||
(let* ((layout
|
(let* ((layout
|
||||||
(ebox-test-box :id "root" :width '(viewport) :height 2
|
(ebox-test-box :id "root" :width '(viewport) :height 2
|
||||||
@ -10676,7 +10744,9 @@
|
|||||||
(setq buffer
|
(setq buffer
|
||||||
(ebox-render-to-buffer
|
(ebox-render-to-buffer
|
||||||
(generate-new-buffer-name " *ebox-test*") layout))
|
(generate-new-buffer-name " *ebox-test*") layout))
|
||||||
(cl-letf (((symbol-function 'run-at-time)
|
(cl-letf (((symbol-function 'current-idle-time)
|
||||||
|
(lambda () (seconds-to-time 0.4)))
|
||||||
|
((symbol-function 'run-at-time)
|
||||||
(lambda (&rest _)
|
(lambda (&rest _)
|
||||||
(ert-fail "Resize prediction must yield to input")))
|
(ert-fail "Resize prediction must yield to input")))
|
||||||
((symbol-function 'run-with-idle-timer)
|
((symbol-function 'run-with-idle-timer)
|
||||||
@ -10688,7 +10758,7 @@
|
|||||||
'scheduled-reflow-timer)))
|
'scheduled-reflow-timer)))
|
||||||
(ebox-rerender-buffer-with-context buffer 260 4))
|
(ebox-rerender-buffer-with-context buffer 260 4))
|
||||||
(should (= scheduled-delay
|
(should (= scheduled-delay
|
||||||
ebox-runtime-idle-reflow-cache-prewarm-delay))
|
(+ 0.4 ebox-runtime-idle-reflow-cache-prewarm-delay)))
|
||||||
(should-not scheduled-repeat)
|
(should-not scheduled-repeat)
|
||||||
(should (eq scheduled-function #'ebox--run-reflow-cache-prewarm))
|
(should (eq scheduled-function #'ebox--run-reflow-cache-prewarm))
|
||||||
(should (equal (car scheduled-arguments) buffer))
|
(should (equal (car scheduled-arguments) buffer))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user