///|
pub struct RuntimeFrameTiming {
priv build_ms : Double
priv layout_ms : Double
priv paint_ms : Double
priv draw_ms : Double
priv total_ms : Double
} derive(Eq, Debug, ToJson)
///|
pub extend RuntimeFrameTiming with Debug::{to_repr}
///|
pub extend RuntimeFrameTiming with Eq::{not_equal, equal}
///|
pub extend RuntimeFrameTiming with ToJson::{to_json}
///|
pub struct ProfiledDrawFrame {
priv frame : @core.DrawFrame
priv timing : RuntimeFrameTiming
}
///|
fn RuntimeFrameTiming::zero() -> RuntimeFrameTiming {
{ build_ms: 0.0, layout_ms: 0.0, paint_ms: 0.0, draw_ms: 0.0, total_ms: 0.0, }
}
///|
pub fn RuntimeFrameTiming::build_ms(self : RuntimeFrameTiming) -> Double {
self.build_ms
}
///|
pub fn RuntimeFrameTiming::layout_ms(self : RuntimeFrameTiming) -> Double {
self.layout_ms
}
///|
pub fn RuntimeFrameTiming::paint_ms(self : RuntimeFrameTiming) -> Double {
self.paint_ms
}
///|
pub fn RuntimeFrameTiming::draw_ms(self : RuntimeFrameTiming) -> Double {
self.draw_ms
}
///|
pub fn RuntimeFrameTiming::total_ms(self : RuntimeFrameTiming) -> Double {
self.total_ms
}
///|
pub fn ProfiledDrawFrame::frame(self : ProfiledDrawFrame) -> @core.DrawFrame {
self.frame
}
///|
pub fn ProfiledDrawFrame::timing(
self : ProfiledDrawFrame,
) -> RuntimeFrameTiming {
self.timing
}
///|
fn runtime_elapsed_ms(start : Double, finish : Double) -> Double {
(finish - start).max(0.0)
}
///|
/// Runs the same pipeline as draw_frame, while timing runtime-owned phases
/// with a caller-supplied monotonic millisecond clock. Renderer encoding and
/// presentation remain renderer/host measurements and are not included.
pub fn AppRuntime::profile_draw_frame(
self : AppRuntime,
clock : () -> Double,
) -> ProfiledDrawFrame {
let total_start = clock()
// Advance the animation clock on every presented frame so runtime-driven
// transitions (overlay enter/exit fades) progress without user input.
self.state.advance_time(total_start)
let build_ms = if self.state.dirty.needs_rebuild {
let start = clock()
self.state.rebuild_if_possible()
runtime_elapsed_ms(start, clock())
} else {
0.0
}
let layout_ms = if self.state.dirty.needs_layout {
let start = clock()
self.state.ensure_layout_tree()
runtime_elapsed_ms(start, clock())
} else {
0.0
}
let paint_ms = if self.state.dirty.needs_paint {
let start = clock()
self.state.render_current_tree()
runtime_elapsed_ms(start, clock())
} else {
0.0
}
let draw_start = clock()
let frame = self.state.build_draw_frame()
let draw_ms = runtime_elapsed_ms(draw_start, clock())
let timing = RuntimeFrameTiming::{
build_ms,
layout_ms,
paint_ms,
draw_ms,
total_ms: runtime_elapsed_ms(total_start, clock()),
}
self.state.last_frame_timing = timing
{ frame, timing, }
}