Skip to content

Commit 43e5530

Browse files
authored
Merge pull request #37 from talex5/optimise-redraw
Optimise redraw
2 parents 37e2f25 + 637269f commit 43e5530

File tree

1 file changed

+81
-43
lines changed

1 file changed

+81
-43
lines changed

lib/render.ml

Lines changed: 81 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
let rec find_first_aux arr test low high =
2+
if low = high then high
3+
else (
4+
let mid = (low + high) / 2 in
5+
let diff = test mid in
6+
if diff >= 0. then find_first_aux arr test low mid
7+
else find_first_aux arr test (mid + 1) high
8+
)
9+
10+
(* Binary search. Return the index of the first element where [test i] is true.
11+
If [test] isn't true for any element, returns the length of the array.
12+
Assumes that if [test i] then it's true for all later entries. *)
13+
let find_first ?(start = 0) arr test =
14+
find_first_aux arr test start (Array.length arr)
15+
116
module type CANVAS = sig
217
type context
318

@@ -215,63 +230,86 @@ module Make (C : CANVAS) = struct
215230
in
216231
C.paint_text cr ~x:(x +. 2.) ~y:(y +. 8.) ~clip_area:(clip_width -. 2., v.height) label
217232

233+
let min_render_width = 0.2
234+
235+
(* Call [fn] for each event in the visible region, plus one on each side (if any).
236+
Very close events (at the current zoom level) are skipped.
237+
The caller will typically render the region ending in this event. *)
218238
let iter_gc_spans v fn ring =
219239
let arr = ring.Layout.Ring.events in
220-
(* todo: binary search *)
221-
for i = 0 to Array.length arr - 1 do
222-
let time, e = arr.(i) in
223-
fn (time, e)
224-
done;
225-
fn (v.View.layout.duration, [])
240+
let time_of i = fst arr.(i) in
241+
let start = max 0 (find_first arr (fun i -> time_of i -. v.View.start_time) - 1) in
242+
let stop_time = View.time_of_x v v.width in
243+
let stop = min (Array.length arr) (1 + find_first arr (fun i -> time_of i -. stop_time) ~start) in
244+
let visible_time = View.timespan_of_width v min_render_width in
245+
let rec visit ~prev i =
246+
if i < stop then (
247+
let time, e = arr.(i) in
248+
let next_useful_time = prev +. visible_time in
249+
if time < next_useful_time then (
250+
let i = find_first arr (fun i -> time_of i -. next_useful_time) ~start:(i + 1) - 1 in
251+
let time, e = arr.(i) in
252+
fn (i, time, e);
253+
visit ~prev:time (i + 1)
254+
) else (
255+
fn (i, time, e);
256+
visit ~prev:time (i + 1)
257+
)
258+
)
259+
in
260+
visit ~prev:(-.visible_time) start;
261+
if stop = Array.length arr then
262+
fn (stop, v.View.layout.duration, [])
226263

227264
let render_gc_events v cr (ring : Layout.Ring.t) layer =
228265
let y = y_of_row v ring.y in
229266
let h = float ring.height *. Style.line_spacing in
230-
let prev_stack = ref [] in
231-
let event = ref (0.0, []) in
232-
C.set_font_size cr Style.big_text;
233-
ring |> iter_gc_spans v (fun event' ->
234-
let t0, stack = !event in
235-
event := event';
236-
let t1 = fst event' in
237-
let x0 = View.x_of_time v t0 in
238-
let x1 = View.x_of_time v t1 in
239-
let w = x1 -. x0 in
240-
begin match stack with
241-
| [] -> ()
242-
| Suspend op :: p ->
243-
begin match layer with
267+
if y <= v.height && y +. h >= 0. then(
268+
let event = ref (0, 0.0, []) in
269+
C.set_font_size cr Style.big_text;
270+
ring |> iter_gc_spans v (fun event' ->
271+
let i, t0, stack = !event in
272+
let prev_stack = if i = 0 then [] else snd (ring.events.(i - 1)) in
273+
event := event';
274+
let _, t1, _ = event' in
275+
let x0 = View.x_of_time v t0 in
276+
let x1 = View.x_of_time v t1 in
277+
let w = x1 -. x0 in
278+
begin match stack with
279+
| [] -> ()
280+
| Suspend op :: p ->
281+
begin match layer with
282+
| `Bg ->
283+
let g = 0.9 in
284+
C.set_source_rgb cr ~r:g ~g:g ~b:(g /. 2.);
285+
C.rectangle cr ~x:x0 ~y ~w ~h;
286+
C.fill cr
287+
| `Fg ->
288+
if p == prev_stack then (
289+
let clip_area = (w -. 0.2, v.height) in
290+
C.set_source_rgb cr ~r:0.0 ~g:0.0 ~b:0.0;
291+
C.paint_text cr ~x:(x0 +. 2.) ~y:(y +. 12.) op
292+
~clip_area
293+
)
294+
end
295+
| Gc op :: p ->
296+
let g = max 0.1 (0.1 *. float (List.length stack)) in
297+
match layer with
244298
| `Bg ->
245-
let g = 0.9 in
246-
C.set_source_rgb cr ~r:g ~g:g ~b:(g /. 2.);
299+
C.set_source_rgb cr ~r:1.0 ~g:g ~b:(g /. 2.);
247300
C.rectangle cr ~x:x0 ~y ~w ~h;
248301
C.fill cr
249302
| `Fg ->
250-
if p == !prev_stack then (
303+
if p == prev_stack then (
251304
let clip_area = (w -. 0.2, v.height) in
252-
C.set_source_rgb cr ~r:0.0 ~g:0.0 ~b:0.0;
305+
if g < 0.5 then C.set_source_rgb cr ~r:1.0 ~g:1.0 ~b:1.0
306+
else C.set_source_rgb cr ~r:0.0 ~g:0.0 ~b:0.0;
253307
C.paint_text cr ~x:(x0 +. 2.) ~y:(y +. 12.) op
254308
~clip_area
255309
)
256-
end
257-
| Gc op :: p ->
258-
let g = max 0.1 (0.1 *. float (List.length stack)) in
259-
match layer with
260-
| `Bg ->
261-
C.set_source_rgb cr ~r:1.0 ~g:g ~b:(g /. 2.);
262-
C.rectangle cr ~x:x0 ~y ~w ~h;
263-
C.fill cr
264-
| `Fg ->
265-
if p == !prev_stack then (
266-
let clip_area = (w -. 0.2, v.height) in
267-
if g < 0.5 then C.set_source_rgb cr ~r:1.0 ~g:1.0 ~b:1.0
268-
else C.set_source_rgb cr ~r:0.0 ~g:0.0 ~b:0.0;
269-
C.paint_text cr ~x:(x0 +. 2.) ~y:(y +. 12.) op
270-
~clip_area
271-
)
272-
end;
273-
prev_stack := stack
274-
)
310+
end
311+
)
312+
)
275313

276314
let link_domain v cr ~x (fiber : Layout.item) (ring : Layout.Ring.t) =
277315
let fiber_y = y_of_row v fiber.y +. Style.fiber_padding_top in

0 commit comments

Comments
 (0)