gpu_allocator/vulkan/
visualizer.rs1#![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 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}