package miaou-driver-matrix
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
Miaou high-performance terminal driver with diff rendering
Install
dune-project
Dependency
Authors
Maintainers
Sources
v0.5.2.tar.gz
md5=60a3b9f181f24572a06a9492532bfdda
sha512=fcc35a275066be2900e6201782faf47503076fa4640f08cf78067835a6f447b74613009e55b2ac799adb7ca46f1bffa261fc5971753f2cc3c6bef327511c7ef6
doc/src/miaou-driver-matrix.driver/matrix_render_loop.ml.html
Source file matrix_render_loop.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131(*****************************************************************************) (* *) (* SPDX-License-Identifier: MIT *) (* Copyright (c) 2025 Nomadic Labs <contact@nomadic-labs.com> *) (* *) (*****************************************************************************) [@@@warning "-69"] type t = { config : Matrix_config.t; buffer : Matrix_buffer.t; writer : Matrix_ansi_writer.t; write : string -> unit; shutdown_flag : bool Atomic.t; mutable render_domain : unit Domain.t option; mutable last_frame_time : float; mutable frame_count : int; mutable loop_count : int; mutable fps_start_time : float; current_fps : float Atomic.t; (* Actual renders per second *) loop_fps : float Atomic.t; (* Loop iterations per second (cap) *) } let do_render t = (* Reset style to ensure consistency. Close any active OSC 8 hyperlink before SGR reset. *) t.write "\027]8;;\027\\\027[0m" ; Matrix_ansi_writer.reset t.writer ; (* Compute diff atomically - holds lock during read to prevent torn reads. This also swaps the buffers and clears the dirty flag while holding the lock to prevent race conditions with new writes. *) let changes = Matrix_diff.compute_atomic t.buffer in (* Generate ANSI output *) let ansi = Matrix_ansi_writer.render t.writer changes in (* Write to output sink *) if String.length ansi > 0 then t.write ansi ; (* Update frame timing *) t.last_frame_time <- Unix.gettimeofday () ; t.frame_count <- t.frame_count + 1 (* Render domain main loop *) let render_loop_fn t = let frame_time_s = t.config.frame_time_ms /. 1000.0 in while not (Atomic.get t.shutdown_flag) do let frame_start = Unix.gettimeofday () in (* Count loop iteration *) t.loop_count <- t.loop_count + 1 ; (* Only render if buffer is dirty *) if Matrix_buffer.is_dirty t.buffer then do_render t ; (* Update loop FPS calculation every second *) let now = Unix.gettimeofday () in let elapsed_since_start = now -. t.fps_start_time in if elapsed_since_start >= 1.0 then begin Atomic.set t.loop_fps (float_of_int t.loop_count /. elapsed_since_start) ; Atomic.set t.current_fps (float_of_int t.frame_count /. elapsed_since_start) ; t.loop_count <- 0 ; t.frame_count <- 0 ; t.fps_start_time <- now end ; (* Sleep to maintain frame rate *) let elapsed = Unix.gettimeofday () -. frame_start in let sleep_time = frame_time_s -. elapsed in if sleep_time > 0.0 then (Thread.delay [@allow_forbidden "render loop runs in dedicated thread"]) sleep_time done let create ~config ~buffer ~writer ~write = let now = Unix.gettimeofday () in { config; buffer; writer; write; shutdown_flag = Atomic.make false; render_domain = None; last_frame_time = now; frame_count = 0; loop_count = 0; fps_start_time = now; current_fps = Atomic.make 0.0; loop_fps = Atomic.make 0.0; } (* Start the render domain *) let start t = if Option.is_none t.render_domain then begin let domain = Domain.spawn (fun () -> render_loop_fn t) in t.render_domain <- Some domain end (* Legacy API for compatibility - now just marks dirty *) let request_frame _t = () let frame_pending t = Matrix_buffer.is_dirty t.buffer (* Synchronous render - for use before domain starts or after shutdown *) let render_if_needed t = if Atomic.get t.shutdown_flag then false else if not (Matrix_buffer.is_dirty t.buffer) then false else begin do_render t ; true end let force_render t = if not (Atomic.get t.shutdown_flag) then do_render t let shutdown t = Atomic.set t.shutdown_flag true ; match t.render_domain with | Some domain -> Domain.join domain ; t.render_domain <- None | None -> () let current_fps t = Atomic.get t.current_fps let loop_fps t = Atomic.get t.loop_fps let is_running t = Option.is_some t.render_domain
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>