mcap/src/app/app_ui.jai
Musa Mahmood 0bf505f0dd [0.1.25] GPU benchmark (gpu-bench branch, not for master)
bin/gpu-bench times every GPU model (OCR mobile and server, the label
image encoder, segmentation; optionally the CPU and the label text
encoder) over a fixed 30-image corpus in tools/gpu_bench/corpus. Every
corpus file is checked against corpus.txt's SHA-256 before anything
runs; each model's files and models.config entry are fingerprinted;
the GPU, driver, power limit, CUDA runtime, cuDNN and onnxruntime are
recorded, and NVML samples memory, load, power and clocks during the
timed passes. Results go to bin/gpu-bench-results as text files.

The GPU Bench button opens a window that runs gpu-bench in its own
process (no console) and lays results files from several machines side
by side against a baseline, marking a different corpus or model.
2026-10-17 21:13:01 -04:00

130 lines
5.8 KiB
Plaintext

// The app's own UI: the capture viewer (app/viewer.jai). Everything else in src/ is the shell
// around it: the window, the frame loop, the tray, hotkeys, settings, themes, logging and the
// debug panels.
APP_MAIN_WINDOW_LABEL :: "Main";
// Once, after ImGui, the fonts, the theme and the settings are up and before the first frame.
app_ui_startup :: () {
// View mode (app/open_file.jai): the file alone. The library is not listed, and no model, scan,
// watcher or recording starts.
if app.view_mode {
import_startup();
open_file_startup();
return;
}
viewer_startup();
import_startup();
ocr_ui_startup();
labels_ui_startup();
segment_ui_startup(); // the library folders' options: after the viewer, which knows the library
screen_record_startup(); // recordings a crash left behind, to offer
open_file_startup(); // mcap.exe FILE: after the viewer, which knows whether it is in the library
}
// Every frame, before input is handed to ImGui. Poll background work here.
app_ui_frame_start :: () {
if app.view_mode return;
screen_capture_frame(); // also while hidden in the tray, where the frame ends before the UI
ocr_ui_unload_idle_models(); // models unused for a while, also while in the tray
}
// Once, on the shutdown thread after the window is asked to close (exit_shutdown.jai): save and
// stop background work here. Must not touch ImGui, since the main thread is still drawing frames
// (the overlay; app_main_window_ui stops running the app's frames once shutdown starts).
app_ui_shutdown :: () {
if app.view_mode {
app_shutdown_step(.IMPORT);
import_shutdown();
open_file_shutdown();
return;
}
gpu_bench_ui_shutdown(); // ends a benchmark run still going
app_shutdown_step(.CAPTURE);
screen_capture_shutdown();
app_shutdown_step(.IMPORT);
import_shutdown(); // before the viewer: it hands the viewer what it writes
app_shutdown_step(.VIEWER);
viewer_shutdown();
app_shutdown_step(.OCR);
ocr_ui_shutdown();
app_shutdown_step(.SEGMENT);
segment_ui_shutdown(); // after the OCR thread, which runs its scans
app_shutdown_step(.LABELS);
labels_ui_shutdown(); // after the OCR thread and the background workers have stopped
app_shutdown_step(.STATS);
stats_ui_shutdown();
open_file_shutdown();
}
// Which step of app_ui_shutdown is running, and since when, for the overlay a slow shutdown shows.
App_Shutdown_Step :: enum s32 { NONE; CAPTURE; IMPORT; VIEWER; OCR; SEGMENT; LABELS; STATS; }
app_shutdown: struct {
step: App_Shutdown_Step;
step_started_ns: s64; // monotonic
}
app_shutdown_step :: (step: App_Shutdown_Step) {
atomic_write(*app_shutdown.step_started_ns, to_nanoseconds(current_time_monotonic()));
atomic_write(*app_shutdown.step, step);
}
// Main thread, while app_ui_shutdown runs: what it is waiting on, as a line or two for the overlay
// (temp); "" before it has started a step.
app_ui_shutdown_status :: () -> string {
step := atomic_read(*app_shutdown.step);
text: string;
if step == {
case .NONE; return "";
case .CAPTURE; text = "Saving a screen capture.";
case .IMPORT;
if importer.phase == .INDEXING text = "Stopping the import: it is indexing the library, and stops after the files it is on.";
else if importer.running text = "Stopping the import: finishing the files it is on (a large video takes a while to copy).";
else text = "Stopping the import.";
case .VIEWER;
text = "Stopping the thumbnail, catalog and search workers";
if viewer.open_started text = tprint("%, and writing out % to play", text, viewer.open_name);
text = tprint("%.", text);
case .OCR;
text = "Closing the OCR model.";
if ocr_ui.thread_busy if ocr_ui.task.kind == {
case .SCAN; text = "Stopping the OCR scan: finishing the text lines it is reading.";
case .ERASE; text = "Stopping the erase: finishing the capture it is on.";
case .READ; text = "Waiting for OCR to finish reading a capture.";
case .CREATE; text = "Waiting for the OCR model to finish loading.";
case .LABELS_CREATE; text = "Waiting for the label model to finish loading.";
case .LABEL_SET; text = "Waiting for the label list to finish.";
case .SEGMENT; text = "Stopping the segmentation scan: finishing the images it is segmenting.";
case .UNLOAD; text = "Waiting for the models unused for a while to unload.";
case; text = "Stopping OCR.";
}
case .SEGMENT; text = "Closing the segmentation model.";
case .LABELS; text = "Closing the label model.";
case .STATS; text = "Closing Stats.";
}
waited := cast(float64) (to_nanoseconds(current_time_monotonic()) - atomic_read(*app_shutdown.step_started_ns)) / 1_000_000_000.0;
if waited >= 2 text = tprint("%\n(this step: % s)", text, FormatFloat.{value = waited, trailing_width = 0, zero_removal = .NO});
return text;
}
app_main_window_ui :: () {
if app.view_mode {
if !app_exit_shutdown_started() open_file_view_mode_ui(); // the whole window (app/open_file.jai)
return;
}
push_imgui_window(APP_MAIN_WINDOW_LABEL);
// Once shutdown has started, its thread is stopping the threads these frames hand work to and take
// it from (the viewer's workers, the search group, the import, OCR), and freeing what they share:
// running them now would race it. The exit overlay says what it is waiting on.
if app_exit_shutdown_started() return;
viewer_ui();
ocr_ui_frame();
labels_ui_frame();
segment_ui_frame();
stats_ui_frame();
gpu_bench_ui_frame(); // app/gpu_bench_ui.jai
import_frame();
open_file_frame(); // after import_frame, which hands the grid what an import of it wrote
screen_record_leftovers_popup();
}