gpu_allocator/vulkan/
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.label(format!(
45            "buffer image granularity: {:?}",
46            alloc.buffer_image_granularity
47        ));
48
49        ui.collapsing(
50            format!("Memory Heaps ({} heaps)", alloc.memory_heaps.len()),
51            |ui| {
52                for (i, heap) in alloc.memory_heaps.iter().enumerate() {
53                    ui.collapsing(format!("Heap: {}", i), |ui| {
54                        ui.label(format!("flags: {:?}", heap.flags));
55                        ui.label(format!(
56                            "size:  {} MiB",
57                            heap.size as f64 / (1024 * 1024) as f64
58                        ));
59                    });
60                }
61            },
62        );
63
64        ui.collapsing(
65            format!("Memory Types: ({} types)", alloc.memory_types.len()),
66            |ui| {
67                for (mem_type_idx, mem_type) in alloc.memory_types.iter().enumerate() {
68                    ui.collapsing(
69                        format!(
70                            "Type: {} ({} blocks)",
71                            mem_type_idx,
72                            mem_type.memory_blocks.len(),
73                        ),
74                        |ui| {
75                            let mut total_block_size = 0;
76                            let mut total_allocated = 0;
77
78                            for block in mem_type.memory_blocks.iter().flatten() {
79                                total_block_size += block.size;
80                                total_allocated += block.sub_allocator.allocated();
81                            }
82
83                            let active_block_count = mem_type
84                                .memory_blocks
85                                .iter()
86                                .filter(|block| block.is_some())
87                                .count();
88
89                            ui.label(format!("properties: {:?}", mem_type.memory_properties));
90                            ui.label(format!("heap index: {}", mem_type.heap_index));
91                            ui.label(format!("total block size: {} KiB", total_block_size / 1024));
92                            ui.label(format!("total allocated:  {} KiB", total_allocated / 1024));
93                            ui.label(format!("block count: {}", active_block_count));
94
95                            for (block_idx, block) in mem_type.memory_blocks.iter().enumerate() {
96                                let Some(block) = block else { continue };
97
98                                ui.collapsing(format!("Block: {}", block_idx), |ui| {
99                                    use ash::vk::Handle;
100
101                                    ui.label(format!("size: {} KiB", block.size / 1024));
102                                    ui.label(format!(
103                                        "allocated: {} KiB",
104                                        block.sub_allocator.allocated() / 1024
105                                    ));
106                                    ui.label(format!(
107                                        "vk device memory: 0x{:x}",
108                                        block.device_memory.as_raw()
109                                    ));
110                                    if let Some(mapped_ptr) = block.mapped_ptr {
111                                        ui.label(format!(
112                                            "mapped pointer: {:#p}",
113                                            mapped_ptr.0.as_ptr()
114                                        ));
115                                    }
116                                    if block.dedicated_allocation {
117                                        ui.label("Dedicated Allocation");
118                                    }
119
120                                    block.sub_allocator.draw_base_info(ui);
121
122                                    if block.sub_allocator.supports_visualization()
123                                        && ui.button("visualize").clicked()
124                                        && !self.selected_blocks.iter().any(|x| {
125                                            x.memory_type_index == mem_type_idx
126                                                && x.block_index == block_idx
127                                        })
128                                    {
129                                        self.selected_blocks.push(
130                                            AllocatorVisualizerBlockWindow::new(
131                                                mem_type_idx,
132                                                block_idx,
133                                            ),
134                                        );
135                                    }
136                                });
137                            }
138                        },
139                    );
140                }
141            },
142        );
143    }
144
145    pub fn render_memory_block_window(
146        &mut self,
147        ctx: &egui::Context,
148        allocator: &Allocator,
149        open: &mut bool,
150    ) {
151        egui::Window::new("Allocator Memory Blocks")
152            .open(open)
153            .show(ctx, |ui| self.render_breakdown_ui(ui, allocator));
154    }
155
156    pub fn render_memory_block_visualization_windows(
157        &mut self,
158        ctx: &egui::Context,
159        allocator: &Allocator,
160    ) {
161        // Draw each window.
162        let color_scheme = &self.color_scheme;
163
164        self.selected_blocks.retain_mut(|window| {
165            let mut open = true;
166
167            egui::Window::new(format!(
168                "Block Visualizer {}:{}",
169                window.memory_type_index, window.block_index
170            ))
171            .default_size([1920.0 * 0.5, 1080.0 * 0.5])
172            .open(&mut open)
173            .show(ctx, |ui| {
174                let memblock = &allocator.memory_types[window.memory_type_index].memory_blocks
175                    [window.block_index]
176                    .as_ref();
177                if let Some(memblock) = memblock {
178                    ui.label(format!(
179                        "Memory type {}, Memory block {}, Block size: {} KiB",
180                        window.memory_type_index,
181                        window.block_index,
182                        memblock.size / 1024
183                    ));
184
185                    window
186                        .settings
187                        .ui(ui, allocator.debug_settings.store_stack_traces);
188
189                    ui.separator();
190
191                    memblock
192                        .sub_allocator
193                        .draw_visualization(color_scheme, ui, &window.settings);
194                } else {
195                    ui.label("Deallocated memory block");
196                }
197            });
198
199            open
200        });
201    }
202
203    pub fn render_breakdown_ui(&mut self, ui: &mut egui::Ui, allocator: &Allocator) {
204        render_allocation_reports_ui(
205            ui,
206            &mut self.breakdown_settings,
207            allocator
208                .memory_types
209                .iter()
210                .flat_map(|memory_type| memory_type.memory_blocks.iter())
211                .flatten()
212                .flat_map(|memory_block| memory_block.sub_allocator.report_allocations()),
213        );
214    }
215
216    pub fn render_breakdown_window(
217        &mut self,
218        ctx: &egui::Context,
219        allocator: &Allocator,
220        open: &mut bool,
221    ) {
222        egui::Window::new("Allocator Breakdown")
223            .open(open)
224            .show(ctx, |ui| self.render_breakdown_ui(ui, allocator));
225    }
226}