iris/android-app: Diagnostics control, top-bar status-bar padding, cargo fmt
Adds a third "Diagnostics" button to the bench screen's top row, filling the existing benchmark-report TextEdit (so the existing "Copy report" button and clipboard path work on it unchanged) with adapter identity, font resolution, atlas view count, wgpu errors seen so far and the frame report -- RUST.md's P0 box, "a named Diagnostics control ... copy this and send it to Iris." Logs the same font-resolution summary once at startup too. Wires BenchClient::on_insets_changed (the new AndroidAppState hook) to rebuild the top button row with Padding::top(insets.top), through a WidgetPtr slot (top_bar) so it can be swapped once the status-bar inset is known -- fixes RUST.md's P0 box, "the status-bar inset is not applied," where the two top buttons sat directly under the status bar because nothing in this file read insets().top at all. cargo fmt --all across the touched files. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
184a6c5b33
commit
27511302f2
6 files changed
+119
-25
No files matched your search
@@ -58,6 +58,12 @@ pub struct BenchClient {
|
|||||||
ui_state: AndroidUiState,
|
ui_state: AndroidUiState,
|
||||||
content: WeakWidget<WidgetPtr>,
|
content: WeakWidget<WidgetPtr>,
|
||||||
report_display: WeakWidget<TextEdit>,
|
report_display: WeakWidget<TextEdit>,
|
||||||
|
/// The top button row, in a `WidgetPtr` slot rather than added
|
||||||
|
/// directly (like `content`) so `on_insets_changed` can swap in a
|
||||||
|
/// version padded for the status bar once insets are known -- RUST.md's
|
||||||
|
/// P0 box, "the status-bar inset is not applied," found the row sitting
|
||||||
|
/// directly under it because nothing here read `insets().top` at all.
|
||||||
|
top_bar: WeakWidget<WidgetPtr>,
|
||||||
screen: Option<transcript_ui::TranscriptScreen>,
|
screen: Option<transcript_ui::TranscriptScreen>,
|
||||||
items: Vec<TranscriptItem>,
|
items: Vec<TranscriptItem>,
|
||||||
/// The events not yet streamed -- consumed by `start_benchmark`'s own
|
/// The events not yet streamed -- consumed by `start_benchmark`'s own
|
||||||
@@ -172,9 +178,11 @@ impl AndroidAppState for BenchClient {
|
|||||||
.label("Benchmark report")
|
.label("Benchmark report")
|
||||||
.add(rsc);
|
.add(rsc);
|
||||||
|
|
||||||
let controls = bench_controls(rsc);
|
let top_bar = WidgetPtr::new().add(rsc);
|
||||||
|
let controls = bench_controls(rsc, 0.0);
|
||||||
|
top_bar(rsc).set(controls);
|
||||||
let tree = (
|
let tree = (
|
||||||
controls,
|
top_bar,
|
||||||
content.height(rest(2)),
|
content.height(rest(2)),
|
||||||
report_display.height(rest(1)).pad(8),
|
report_display.height(rest(1)).pad(8),
|
||||||
)
|
)
|
||||||
@@ -183,10 +191,28 @@ impl AndroidAppState for BenchClient {
|
|||||||
.any();
|
.any();
|
||||||
ui_state.set_root(tree);
|
ui_state.set_root(tree);
|
||||||
|
|
||||||
|
// Startup log line (RUST.md's P0 box, "log once at startup ... the
|
||||||
|
// number of font families found, the default family resolved"):
|
||||||
|
// what font discovery actually found on this device, before
|
||||||
|
// anything is drawn.
|
||||||
|
let font = rsc.ui.text.font_diagnostics();
|
||||||
|
log::info!(
|
||||||
|
"iris fonts: {} families found, default={:?} mono={:?}, resolved regular={:?} \
|
||||||
|
bold={:?} italic={:?} mono={:?}",
|
||||||
|
font.families_found,
|
||||||
|
font.default_family,
|
||||||
|
font.default_mono_family,
|
||||||
|
font.regular_resolved,
|
||||||
|
font.bold_resolved,
|
||||||
|
font.italic_resolved,
|
||||||
|
font.mono_resolved,
|
||||||
|
);
|
||||||
|
|
||||||
let mut client = Self {
|
let mut client = Self {
|
||||||
ui_state,
|
ui_state,
|
||||||
content,
|
content,
|
||||||
report_display,
|
report_display,
|
||||||
|
top_bar,
|
||||||
screen: None,
|
screen: None,
|
||||||
items: Vec::new(),
|
items: Vec::new(),
|
||||||
stream_tail: Vec::new(),
|
stream_tail: Vec::new(),
|
||||||
@@ -216,11 +242,24 @@ impl AndroidAppState for BenchClient {
|
|||||||
fn back_pressed(&mut self, _rsc: &mut AndroidRsc<Self>, _render: &mut UiRenderState) -> bool {
|
fn back_pressed(&mut self, _rsc: &mut AndroidRsc<Self>, _render: &mut UiRenderState) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pads the top button row by the status-bar inset -- see `top_bar`'s
|
||||||
|
/// field comment. Rebuilds the row rather than mutating a stored
|
||||||
|
/// `Padding` in place, since nothing here holds a handle to one.
|
||||||
|
fn on_insets_changed(&mut self, rsc: &mut AndroidRsc<Self>, insets: iris::android::LogicalInsets) {
|
||||||
|
let controls = bench_controls(rsc, insets.top);
|
||||||
|
(self.top_bar)(rsc).set(controls);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Rsc = AndroidRsc<BenchClient>;
|
type Rsc = AndroidRsc<BenchClient>;
|
||||||
|
|
||||||
fn bench_controls(rsc: &mut Rsc) -> WeakWidget {
|
/// `top_pad` is the status-bar inset in logical units (0.0 until
|
||||||
|
/// `on_insets_changed` has run once) -- folded in here, rather than
|
||||||
|
/// exposing the unadded builder for a caller to `.pad()` itself, because
|
||||||
|
/// naming that builder's type at each call site is more machinery than a
|
||||||
|
/// top-of-screen padding number is worth.
|
||||||
|
fn bench_controls(rsc: &mut Rsc, top_pad: f32) -> StrongWidget {
|
||||||
let run_rect = rect(Color::rgb(40, 70, 40))
|
let run_rect = rect(Color::rgb(40, 70, 40))
|
||||||
.on(
|
.on(
|
||||||
CursorSense::click(),
|
CursorSense::click(),
|
||||||
@@ -253,7 +292,28 @@ fn bench_controls(rsc: &mut Rsc) -> WeakWidget {
|
|||||||
.pad(8)
|
.pad(8)
|
||||||
.add(rsc);
|
.add(rsc);
|
||||||
|
|
||||||
(run, copy).span(Dir::RIGHT).height(56).add(rsc)
|
let diag_rect = rect(Color::rgb(60, 45, 70))
|
||||||
|
.on(
|
||||||
|
CursorSense::click(),
|
||||||
|
|ctx: EventIdCtx<'_, Rsc, _, _>, rsc: &mut Rsc| {
|
||||||
|
ctx.state.show_diagnostics(rsc);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.label("Diagnostics");
|
||||||
|
let diagnostics = (
|
||||||
|
diag_rect,
|
||||||
|
wtext("Diagnostics").size(18).text_align(Align::CENTER),
|
||||||
|
)
|
||||||
|
.stack()
|
||||||
|
.pad(8)
|
||||||
|
.add(rsc);
|
||||||
|
|
||||||
|
(run, copy, diagnostics)
|
||||||
|
.span(Dir::RIGHT)
|
||||||
|
.height(56)
|
||||||
|
.pad(Padding::top(top_pad))
|
||||||
|
.add_strong(rsc)
|
||||||
|
.any()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BenchClient {
|
impl BenchClient {
|
||||||
@@ -270,6 +330,26 @@ impl BenchClient {
|
|||||||
self.screen = Some(screen);
|
self.screen = Some(screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// RUST.md's P0 box: "a named `Diagnostics` control ... with 'copy this
|
||||||
|
/// and send it to Iris'." Fills `report_display` (the same TextEdit the
|
||||||
|
/// benchmark report uses) rather than a separate widget, so the
|
||||||
|
/// existing "Copy report" button and clipboard path work on whichever
|
||||||
|
/// text is currently shown -- `last_report` is what `copy_report` reads,
|
||||||
|
/// so it's set here too rather than adding a second copy path.
|
||||||
|
fn show_diagnostics(&mut self, rsc: &mut Rsc) {
|
||||||
|
let font = rsc.ui.text.font_diagnostics();
|
||||||
|
let frame_report = match self.android_state().frame_report.report() {
|
||||||
|
Some(stats) => format!("{stats}"),
|
||||||
|
None => "no frames recorded yet".to_string(),
|
||||||
|
};
|
||||||
|
let report = match &self.android_state().renderer {
|
||||||
|
Some(renderer) => renderer.diagnostics_report(&font, &frame_report),
|
||||||
|
None => "iris diagnostics: no renderer yet (no surface)".to_string(),
|
||||||
|
};
|
||||||
|
self.report_display.edit(rsc).set(&report);
|
||||||
|
self.last_report = Some(report);
|
||||||
|
}
|
||||||
|
|
||||||
fn copy_report(&mut self) {
|
fn copy_report(&mut self) {
|
||||||
let Some(report) = &self.last_report else {
|
let Some(report) = &self.last_report else {
|
||||||
log::info!("iris bench report: nothing to copy -- run the benchmark first");
|
log::info!("iris bench report: nothing to copy -- run the benchmark first");
|
||||||
|
|||||||
@@ -26,10 +26,8 @@ use swash::{
|
|||||||
const NOTO_SANS_REGULAR: &[u8] = include_bytes!("../../assets/fonts/NotoSans-Regular.ttf");
|
const NOTO_SANS_REGULAR: &[u8] = include_bytes!("../../assets/fonts/NotoSans-Regular.ttf");
|
||||||
const NOTO_SANS_BOLD: &[u8] = include_bytes!("../../assets/fonts/NotoSans-Bold.ttf");
|
const NOTO_SANS_BOLD: &[u8] = include_bytes!("../../assets/fonts/NotoSans-Bold.ttf");
|
||||||
const NOTO_SANS_ITALIC: &[u8] = include_bytes!("../../assets/fonts/NotoSans-Italic.ttf");
|
const NOTO_SANS_ITALIC: &[u8] = include_bytes!("../../assets/fonts/NotoSans-Italic.ttf");
|
||||||
const NOTO_SANS_BOLD_ITALIC: &[u8] =
|
const NOTO_SANS_BOLD_ITALIC: &[u8] = include_bytes!("../../assets/fonts/NotoSans-BoldItalic.ttf");
|
||||||
include_bytes!("../../assets/fonts/NotoSans-BoldItalic.ttf");
|
const NOTO_SANS_MONO_REGULAR: &[u8] = include_bytes!("../../assets/fonts/NotoSansMono-Regular.ttf");
|
||||||
const NOTO_SANS_MONO_REGULAR: &[u8] =
|
|
||||||
include_bytes!("../../assets/fonts/NotoSansMono-Regular.ttf");
|
|
||||||
const NOTO_SANS_MONO_BOLD: &[u8] = include_bytes!("../../assets/fonts/NotoSansMono-Bold.ttf");
|
const NOTO_SANS_MONO_BOLD: &[u8] = include_bytes!("../../assets/fonts/NotoSansMono-Bold.ttf");
|
||||||
|
|
||||||
/// What starting up found about text rendering, for the on-screen
|
/// What starting up found about text rendering, for the on-screen
|
||||||
@@ -203,14 +201,26 @@ impl TextData {
|
|||||||
family_id.and_then(|id| self.font_cx.collection.family_name(id).map(str::to_string))
|
family_id.and_then(|id| self.font_cx.collection.family_name(id).map(str::to_string))
|
||||||
};
|
};
|
||||||
|
|
||||||
let regular_resolved =
|
let regular_resolved = resolve_family(
|
||||||
resolve_family(GenericFamily::SansSerif, FontWeight::NORMAL, FontStyle::Normal);
|
GenericFamily::SansSerif,
|
||||||
let bold_resolved =
|
FontWeight::NORMAL,
|
||||||
resolve_family(GenericFamily::SansSerif, FontWeight::BOLD, FontStyle::Normal);
|
FontStyle::Normal,
|
||||||
let italic_resolved =
|
);
|
||||||
resolve_family(GenericFamily::SansSerif, FontWeight::NORMAL, FontStyle::Italic);
|
let bold_resolved = resolve_family(
|
||||||
let mono_resolved =
|
GenericFamily::SansSerif,
|
||||||
resolve_family(GenericFamily::Monospace, FontWeight::NORMAL, FontStyle::Normal);
|
FontWeight::BOLD,
|
||||||
|
FontStyle::Normal,
|
||||||
|
);
|
||||||
|
let italic_resolved = resolve_family(
|
||||||
|
GenericFamily::SansSerif,
|
||||||
|
FontWeight::NORMAL,
|
||||||
|
FontStyle::Italic,
|
||||||
|
);
|
||||||
|
let mono_resolved = resolve_family(
|
||||||
|
GenericFamily::Monospace,
|
||||||
|
FontWeight::NORMAL,
|
||||||
|
FontStyle::Normal,
|
||||||
|
);
|
||||||
|
|
||||||
FontDiagnostics {
|
FontDiagnostics {
|
||||||
families_found,
|
families_found,
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ mod view;
|
|||||||
pub use insets::Insets;
|
pub use insets::Insets;
|
||||||
pub use render::AndroidRenderer;
|
pub use render::AndroidRenderer;
|
||||||
pub use view::{
|
pub use view::{
|
||||||
AndroidAppState, AndroidRsc, AndroidUiState, HasAndroidUiState, IrisViewPeer, new_peer,
|
AndroidAppState, AndroidRsc, AndroidUiState, HasAndroidUiState, IrisViewPeer, LogicalInsets,
|
||||||
|
new_peer,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Registers the extra native methods this backend needs beyond what
|
/// Registers the extra native methods this backend needs beyond what
|
||||||
|
|||||||
@@ -213,10 +213,8 @@ impl AndroidRenderer {
|
|||||||
// for why this crate now divides at all (RUST.md's P0 box, "text
|
// for why this crate now divides at all (RUST.md's P0 box, "text
|
||||||
// is far too small"). The swapchain above stays at the real
|
// is far too small"). The swapchain above stays at the real
|
||||||
// physical `width`/`height` for a sharp framebuffer.
|
// physical `width`/`height` for a sharp framebuffer.
|
||||||
let logical_size = iris_core::util::Vec2::new(
|
let logical_size =
|
||||||
width as f32 / content_scale,
|
iris_core::util::Vec2::new(width as f32 / content_scale, height as f32 / content_scale);
|
||||||
height as f32 / content_scale,
|
|
||||||
);
|
|
||||||
let ui = match UiRenderNode::new(&device, &queue, &config, logical_size) {
|
let ui = match UiRenderNode::new(&device, &queue, &config, logical_size) {
|
||||||
Ok(ui) => ui,
|
Ok(ui) => ui,
|
||||||
Err(wgpu_error) => return Err(Self::diagnostic(&adapter, &wgpu_error)),
|
Err(wgpu_error) => return Err(Self::diagnostic(&adapter, &wgpu_error)),
|
||||||
|
|||||||
@@ -19,8 +19,7 @@ impl Input {
|
|||||||
pub fn event(&mut self, event: &WindowEvent, scale_factor: f32) -> bool {
|
pub fn event(&mut self, event: &WindowEvent, scale_factor: f32) -> bool {
|
||||||
match event {
|
match event {
|
||||||
WindowEvent::CursorMoved { position, .. } => {
|
WindowEvent::CursorMoved { position, .. } => {
|
||||||
self.cursor.pos =
|
self.cursor.pos = Vec2::new(position.x as f32, position.y as f32) / scale_factor;
|
||||||
Vec2::new(position.x as f32, position.y as f32) / scale_factor;
|
|
||||||
self.cursor.exists = true;
|
self.cursor.exists = true;
|
||||||
}
|
}
|
||||||
WindowEvent::MouseInput { state, button, .. } => {
|
WindowEvent::MouseInput { state, button, .. } => {
|
||||||
@@ -79,7 +78,10 @@ impl DefaultUiState {
|
|||||||
let window = self.renderer.window();
|
let window = self.renderer.window();
|
||||||
let size = window.inner_size();
|
let size = window.inner_size();
|
||||||
let scale_factor = window.scale_factor() as f32;
|
let scale_factor = window.scale_factor() as f32;
|
||||||
Vec2::new(size.width as f32 / scale_factor, size.height as f32 / scale_factor)
|
Vec2::new(
|
||||||
|
size.width as f32 / scale_factor,
|
||||||
|
size.height as f32 / scale_factor,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cursor_state(&self) -> &CursorState {
|
pub fn cursor_state(&self) -> &CursorState {
|
||||||
|
|||||||
@@ -163,7 +163,10 @@ impl UiRenderer {
|
|||||||
// found on Iris's phone, just never noticed here because this
|
// found on Iris's phone, just never noticed here because this
|
||||||
// crate's own dev monitors happen to run at 1.0.
|
// crate's own dev monitors happen to run at 1.0.
|
||||||
let scale_factor = window.scale_factor() as f32;
|
let scale_factor = window.scale_factor() as f32;
|
||||||
let logical_size = Vec2::new(size.width as f32 / scale_factor, size.height as f32 / scale_factor);
|
let logical_size = Vec2::new(
|
||||||
|
size.width as f32 / scale_factor,
|
||||||
|
size.height as f32 / scale_factor,
|
||||||
|
);
|
||||||
let ui = UiRenderNode::new(&device, &queue, &config, logical_size)
|
let ui = UiRenderNode::new(&device, &queue, &config, logical_size)
|
||||||
.expect("Could not create iris render node!");
|
.expect("Could not create iris render node!");
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user