gpu_allocator/metal/
visualizer.rs

1#![allow(clippy::new_without_default)]
2
3use super::Allocator;
4use crate::visualizer::{
5    render_allocation_reports_ui, AllocationReportVisualizeSettings, ColorScheme,
6    MemoryChunksVisualizationSettings,
7};
8
9struct AllocatorVisualizerBlockWindow {
10    memory_type_index: usize,
11    block_index: usize,
12    settings: MemoryChunksVisualizationSettings,
13}
14impl AllocatorVisualizerBlockWindow {
15    fn new(memory_type_index: usize, block_index: usize) -> Self {
16        Self {
17            memory_type_index,
18            block_index,
19            settings: Default::default(),
20        }
21    }
22}
23
24pub struct AllocatorVisualizer {
25    selected_blocks: Vec<AllocatorVisualizerBlockWindow>,
26    color_scheme: ColorScheme,
27    breakdown_settings: AllocationReportVisualizeSettings,
28}
29
30impl AllocatorVisualizer {
31    pub fn new() -> Self {
32        Self {
33            selected_blocks: Vec::default(),
34            color_scheme: ColorScheme::default(),
35            breakdown_settings: Default::default(),
36        }
37    }
38
39    pub fn set_color_scheme(&mut self, color_scheme: ColorScheme) {
40        self.color_scheme = color_scheme;
41    }
42
43    pub fn render_memory_block_ui(&mut self, ui: &mut egui::Ui, alloc: &Allocator) {
44        ui.collapsing(
45            format!("Memory Types: ({} types)", alloc.memory_types.len()),
46            |ui| {
47                for (mem_type_idx, mem_type) in alloc.memory_types.iter().enumerate() {
48                    ui.collapsing(
49                        format!(
50                            "Type: {} ({} blocks)",
51                            mem_type_idx,
52                            mem_type.memory_blocks.len(),
53                        ),
54                        |ui| {
55                            let mut total_block_size = 0;
56                            let mut total_allocated = 0;
57
58                            for block in mem_type.memory_blocks.iter().flatten() {
59                                total_block_size += block.size;
60                                total_allocated += block.sub_allocator.allocated();
61                            }
62
63                            let active_block_count = mem_type
64                                .memory_blocks
65                                .iter()
66                                .filter(|block| block.is_some())
67                                .count();
68
69                            ui.label(format!("properties: {:?}", mem_type.heap_properties));
70                            ui.label(format!("memory type index: {}", mem_type.memory_type_index));
71                            ui.label(format!("total block size: {} KiB", total_block_size / 1024));
72                            ui.label(format!("total allocated:  {} KiB", total_allocated / 1024));
73                            ui.label(format!("block count: {active_block_count}"));
74
75                            for (block_idx, block) in mem_type.memory_blocks.iter().enumerate() {
76                                let Some(block) = block else { continue };
77
78                                ui.collapsing(format!("Block: {block_idx}"), |ui| {
79                                    ui.label(format!("size: {} KiB", block.size / 1024));
80                                    ui.label(format!(
81                                        "allocated: {} KiB",
82                                        block.sub_allocator.allocated() / 1024
83                                    ));
84                                    ui.label(format!("Heap: {:?}", &block.heap));
85
86                                    block.sub_allocator.draw_base_info(ui);
87
88                                    if block.sub_allocator.supports_visualization()
89                                        && ui.button("visualize").clicked()
90                                        && !self.selected_blocks.iter().any(|x| {
91                                            x.memory_type_index == mem_type_idx
92                                                && x.block_index == block_idx
93                                        })
94                                    {
95                                        self.selected_blocks.push(
96                                            AllocatorVisualizerBlockWindow::new(
97                                                mem_type_idx,
98                                                block_idx,
99                                            ),
100                                        );
101                                    }
102                                });
103                            }
104                        },
105                    );
106                }
107            },
108        );
109    }
110
111    pub fn render_memory_block_window(
112        &mut self,
113        ctx: &egui::Context,
114        allocator: &Allocator,
115        open: &mut bool,
116    ) {
117        egui::Window::new("Allocator Memory Blocks")
118            .open(open)
119            .show(ctx, |ui| self.render_breakdown_ui(ui, allocator));
120    }
121
122    pub fn render_memory_block_visualization_windows(
123        &mut self,
124        ctx: &egui::Context,
125        allocator: &Allocator,
126    ) {
127        // Draw each window.
128        let color_scheme = &self.color_scheme;
129
130        self.selected_blocks.retain_mut(|window| {
131            let mut open = true;
132
133            egui::Window::new(format!(
134                "Block Visualizer {}:{}",
135                window.memory_type_index, window.block_index
136            ))
137            .default_size([1920.0 * 0.5, 1080.0 * 0.5])
138            .open(&mut open)
139            .show(ctx, |ui| {
140                let memblock = &allocator.memory_types[window.memory_type_index].memory_blocks
141                    [window.block_index]
142                    .as_ref();
143                if let Some(memblock) = memblock {
144                    ui.label(format!(
145                        "Memory type {}, Memory block {}, Block size: {} KiB",
146                        window.memory_type_index,
147                        window.block_index,
148                        memblock.size / 1024
149                    ));
150
151                    window
152                        .settings
153                        .ui(ui, allocator.debug_settings.store_stack_traces);
154
155                    ui.separator();
156
157                    memblock
158                        .sub_allocator
159                        .draw_visualization(color_scheme, ui, &window.settings);
160                } else {
161                    ui.label("Deallocated memory block");
162                }
163            });
164
165            open
166        });
167    }
168
169    pub fn render_breakdown_ui(&mut self, ui: &mut egui::Ui, allocator: &Allocator) {
170        render_allocation_reports_ui(
171            ui,
172            &mut self.breakdown_settings,
173            allocator
174                .memory_types
175                .iter()
176                .flat_map(|memory_type| memory_type.memory_blocks.iter())
177                .flatten()
178                .flat_map(|memory_block| memory_block.sub_allocator.report_allocations()),
179        );
180    }
181
182    pub fn render_breakdown_window(
183        &mut self,
184        ctx: &egui::Context,
185        allocator: &Allocator,
186        open: &mut bool,
187    ) {
188        egui::Window::new("Allocator Breakdown")
189            .open(open)
190            .show(ctx, |ui| self.render_breakdown_ui(ui, allocator));
191    }
192}