1use core::time::Duration;
2use core::{fmt, ops};
3
4#[cfg(feature = "rerun")]
5use all_is_cubes::rerun_glue as rg;
6use all_is_cubes::util::{Fmt, Refmt, ShowStatus, StatusText};
7use all_is_cubes_mesh::dynamic::CsmUpdateInfo;
8use all_is_cubes_render::{Flaws, camera::Layers};
9
10#[derive(Clone, Debug, Default)]
14#[non_exhaustive]
15pub struct RenderInfo {
16 pub(crate) waiting_for_gpu: Duration,
17 pub(crate) update: UpdateInfo,
18 pub(crate) draw: DrawInfo,
19 pub flaws: Flaws,
21}
22
23#[derive(Clone, Debug, Default)]
29#[non_exhaustive]
30pub struct UpdateInfo {
31 pub(crate) flaws: Flaws,
35 pub(crate) total_time: Duration,
37 pub(crate) prep_time: Duration,
40 pub(crate) lines_time: Duration,
42 pub(crate) submit_time: Option<Duration>,
45 pub(crate) spaces: Layers<SpaceUpdateInfo>,
47}
48
49impl UpdateInfo {
50 #[doc(hidden)] pub fn flaws(&self) -> Flaws {
52 self.flaws
53 }
54}
55
56#[derive(Clone, Debug, Default)]
57#[non_exhaustive]
58pub(crate) struct DrawInfo {
59 pub(crate) times: Layers<Duration>,
61 pub(crate) space_info: Layers<SpaceDrawInfo>,
62 pub(crate) submit_time: Option<Duration>,
65}
66impl DrawInfo {
67 pub(crate) fn flaws(&self) -> Flaws {
68 self.space_info.world.flaws | self.space_info.ui.flaws
69 }
70}
71
72impl Fmt<StatusText> for RenderInfo {
73 fn fmt(&self, fmt: &mut fmt::Formatter<'_>, fopt: &StatusText) -> fmt::Result {
74 let &Self {
75 waiting_for_gpu,
76 update:
77 UpdateInfo {
78 flaws: _, total_time: update_time,
80 prep_time: update_prep_time,
81 lines_time,
82 submit_time: update_submit_time,
83 spaces: ref update_spaces,
84 },
85 draw:
86 DrawInfo {
87 times: draw_time,
88 space_info: ref draw_spaces,
89 submit_time,
90 },
91 flaws,
92 } = self;
93
94 let total_time = waiting_for_gpu
95 .saturating_add(update_time)
96 .saturating_add(draw_time.world)
97 .saturating_add(draw_time.ui);
98
99 write!(
101 fmt,
102 "Frame time: {} (GPU wait {}, update {}, draw world {}, ui {}",
104 total_time.refmt(fopt),
105 waiting_for_gpu.refmt(fopt),
106 update_time.refmt(fopt),
107 draw_time.world.refmt(fopt),
108 draw_time.ui.refmt(fopt),
109 )?;
110 if let Some(t) = submit_time {
111 write!(fmt, ", submit {}", t.refmt(fopt))?;
112 }
113 writeln!(fmt, ")")?;
114
115 write!(
117 fmt,
118 "Update breakdown: prep {}, world mesh {}, ui mesh {}, lines {}",
119 update_prep_time.refmt(fopt),
120 update_spaces.world.total_time.refmt(fopt),
121 update_spaces.ui.total_time.refmt(fopt),
122 lines_time.refmt(fopt),
123 )?;
124 if let Some(t) = update_submit_time {
125 write!(fmt, ", submit {}", t.refmt(fopt))?;
126 }
127
128 if fopt.show.contains(ShowStatus::WORLD) {
130 write!(
131 fmt,
132 "\n\nWORLD:\n{}\n{}",
133 update_spaces.world.refmt(fopt),
134 draw_spaces.world.refmt(fopt)
135 )?;
136 }
137 if fopt.show.contains(ShowStatus::UI) {
138 write!(
139 fmt,
140 "\n\nUI:\n{}\n{}",
141 update_spaces.ui.refmt(fopt),
142 draw_spaces.ui.refmt(fopt)
143 )?;
144 }
145
146 write!(fmt, "\nRender flaws: {flaws}")?;
147 Ok(())
148 }
149}
150
151#[derive(Clone, Debug, Default, Eq, PartialEq)]
158#[non_exhaustive]
159pub struct SpaceUpdateInfo {
160 pub(crate) total_time: Duration,
161
162 pub(crate) chunk_info: CsmUpdateInfo,
164 pub(crate) texture_info: BlockTextureInfo,
166
167 pub(crate) light_update_time: Duration,
169 pub(crate) light_update_count: usize,
171}
172
173impl SpaceUpdateInfo {
174 pub(crate) fn flaws(&self) -> Flaws {
175 self.chunk_info.flaws
176 }
177
178 #[cfg(feature = "rerun")]
179 pub(crate) fn write_to_rerun(&self, destination: &rg::Destination) {
180 use alloc::string::ToString as _;
181
182 destination.log(
183 &"info".into(),
184 &rg::archetypes::TextDocument::new(self.refmt(&StatusText::ALL).to_string())
185 .with_media_type(rg::components::MediaType::TEXT),
186 );
187
188 let &Self {
190 total_time,
191 chunk_info:
192 CsmUpdateInfo {
193 total_time: chunk_total_time,
194 ..
195 },
196 texture_info: _,
197 light_update_time,
198 light_update_count: _,
199 } = self;
200
201 destination.log(&"update_total_time".into(), &rg::milliseconds(total_time));
202 destination.log(
203 &"chunk_total_time".into(),
204 &rg::milliseconds(chunk_total_time),
205 );
206 destination.log(
207 &"light_update_time".into(),
208 &rg::milliseconds(light_update_time),
209 );
210 }
211}
212
213impl Fmt<StatusText> for SpaceUpdateInfo {
214 fn fmt(&self, fmt: &mut fmt::Formatter<'_>, fopt: &StatusText) -> fmt::Result {
215 let &SpaceUpdateInfo {
216 total_time: _, ref chunk_info,
218 ref texture_info,
219 light_update_time,
220 light_update_count,
221 } = self;
222
223 let light_update_time = light_update_time.refmt(fopt);
224
225 writeln!(fmt, "{}", chunk_info.refmt(fopt))?;
226 writeln!(
227 fmt,
228 "Light: {light_update_count:3} cubes in {light_update_time}"
229 )?;
230 write!(fmt, "{:#?}", texture_info.refmt(fopt))?;
231 Ok(())
232 }
233}
234
235#[derive(Clone, Debug, Default, Eq, PartialEq)]
246#[non_exhaustive]
247pub struct SpaceDrawInfo {
248 pub(crate) draw_init_time: Duration,
250 pub(crate) draw_opaque_chunks_time: Duration,
253 pub(crate) draw_opaque_blocks_time: Duration,
255 pub(crate) draw_transparent_time: Duration,
258 pub(crate) finalize_time: Duration,
261
262 pub(crate) chunk_meshes_drawn: usize,
264 pub(crate) chunks_with_instances_drawn: usize,
266 pub(crate) blocks_drawn: usize,
268 pub(crate) triangles_drawn: usize,
270
271 pub(crate) flaws: Flaws,
272}
273
274impl Fmt<StatusText> for SpaceDrawInfo {
275 fn fmt(&self, fmt: &mut fmt::Formatter<'_>, fopt: &StatusText) -> fmt::Result {
276 let &SpaceDrawInfo {
277 draw_init_time,
278 draw_opaque_chunks_time,
279 draw_opaque_blocks_time,
280 draw_transparent_time,
281 finalize_time,
282 chunk_meshes_drawn,
283 chunks_with_instances_drawn,
284 blocks_drawn,
285 triangles_drawn,
286 flaws: _, } = self;
288
289 let draw_init_time = draw_init_time.refmt(fopt);
290 let draw_opaque_chunks_time = draw_opaque_chunks_time.refmt(fopt);
291 let draw_opaque_blocks_time = draw_opaque_blocks_time.refmt(fopt);
292 let draw_transparent_time = draw_transparent_time.refmt(fopt);
293 let finalize_time = finalize_time.refmt(fopt);
294
295 writeln!(
296 fmt,
297 "Draw init: {draw_init_time} \
298 opaque chunks: {draw_opaque_chunks_time} \
299 opaque blocks: {draw_opaque_blocks_time} \
300 transparent chunks: {draw_transparent_time} \
301 finalize: {finalize_time}",
302 )?;
303 writeln!(
304 fmt,
305 "Chunk meshes drawn: {chunk_meshes_drawn:3} \
306 Block insts drawn: {blocks_drawn:3} in {chunks_with_instances_drawn:3} chunks \
307 Triangles drawn: {triangles_drawn:7}",
308 )?;
309 Ok(())
310 }
311}
312
313#[derive(Clone, Debug, Default, Eq, PartialEq)]
317pub struct BlockTextureInfo {
318 pub(crate) flushed: usize,
319 pub(crate) flush_time: Duration,
320 pub(crate) in_use_tiles: usize,
321 pub(crate) texels: crate::octree_alloc::Info,
322}
323
324impl ops::Add for BlockTextureInfo {
325 type Output = Self;
326 fn add(self, rhs: Self) -> Self::Output {
327 BlockTextureInfo {
328 flushed: self.flushed + rhs.flushed,
329 flush_time: self.flush_time + rhs.flush_time,
330 in_use_tiles: self.in_use_tiles + rhs.in_use_tiles,
331 texels: self.texels + rhs.texels,
332 }
333 }
334}
335
336impl Fmt<StatusText> for BlockTextureInfo {
337 fn fmt(&self, fmt: &mut fmt::Formatter<'_>, fopt: &StatusText) -> fmt::Result {
338 write!(
339 fmt,
340 "Textures: {} Atlas: {} Flushed: {:2} in {}",
341 self.in_use_tiles,
342 self.texels.refmt(fopt),
343 self.flushed,
344 self.flush_time.refmt(fopt)
345 )
346 }
347}