docs: compare cold grid and translated pan rendering alternatives
This commit is contained in:
@@ -0,0 +1,153 @@
|
|||||||
|
# Cold construction and pan alternatives
|
||||||
|
|
||||||
|
Follow-up to [the stationary-camera cache](README.md), for issue 44. Application
|
||||||
|
source remains `336720559bcec511949caa8a42bee8a55c3822da`, with evidence checkpoint
|
||||||
|
`2ca84676ee4dc30846208881a27d90a901482085`. These standalone experiments change no
|
||||||
|
application code, dependencies, event handling or release. Native interaction
|
||||||
|
remains paused; no result below establishes native FPS.
|
||||||
|
|
||||||
|
## Question and method
|
||||||
|
|
||||||
|
The existing cache removes repeated construction at identical camera inputs but
|
||||||
|
misses during pan/zoom. Can simpler geometry or renderer-level translation remove
|
||||||
|
that cost without changing the grid's appearance? Use the same unoptimized Iced
|
||||||
|
0.14 WGPU dependencies and Windows environment recorded in `context.json`.
|
||||||
|
Compile the new drivers with the same `rustc`/extern/linker arguments described
|
||||||
|
in README, replacing the driver filename and output executable. No desktop window
|
||||||
|
is created and no input is sent. Run `cold_grid_probe` with argument `20`; phase
|
||||||
|
drivers take no arguments.
|
||||||
|
|
||||||
|
The cold driver compares original circles, one reusable origin circle transformed
|
||||||
|
for each fill, one path per column, and direct 1.15-unit squares. Every candidate
|
||||||
|
also constructs one origin-circle template; this small common overhead is retained.
|
||||||
|
Three warmups precede 20 changing-pan samples. Construction ends before geometry
|
||||||
|
destruction, rendering and readback. Percentiles use sorted index `ceil((n-1)*p)`.
|
||||||
|
Fixed candidate ordering and uncontrolled OS load limit small timing comparisons.
|
||||||
|
|
||||||
|
## Cold construction results
|
||||||
|
|
||||||
|
`cold_grid_probe.rs` produces `grid-cold-01.log`. Median milliseconds:
|
||||||
|
|
||||||
|
| Canvas, zoom | Original | Reused circle | Column batch | Square |
|
||||||
|
| --- | ---: | ---: | ---: | ---: |
|
||||||
|
| 1900x660, 1.0 | 61.0564 | 55.3975 | 54.3594 | 3.5527 |
|
||||||
|
| 1900x660, 0.5 | 215.8919 | 162.3073 | 158.5968 | 7.5699 |
|
||||||
|
| 1440x900, 1.0 | 60.1683 | 43.3860 | 60.8198 | 2.0340 |
|
||||||
|
| 1440x900, 0.5 | 165.2049 | 133.3420 | 143.1489 | 6.8178 |
|
||||||
|
|
||||||
|
Both circle alternatives exactly match original pixels in all 12 sampled cases
|
||||||
|
(four integer canvas/zoom pairs, three pan offsets, scale 1). This does not prove
|
||||||
|
equivalence at fractional zoom, other DPI or other camera inputs. Squares match
|
||||||
|
eight of those cases but differ at the third pan offset in each canvas/zoom pair:
|
||||||
|
4,266–13,184 changed pixels, maximum channel difference 7. Their different shape
|
||||||
|
and area are an explicit appearance change, not a pixel-preserving optimization.
|
||||||
|
|
||||||
|
Reusing circles and column batches leave substantial cold cost; the experiment
|
||||||
|
does not justify adding them to production as the solution to low FPS. The square
|
||||||
|
alternative is much faster in this scope, but is not adopted without evaluating
|
||||||
|
its appearance and the actual interaction result. The previous all-grid single
|
||||||
|
path experiment remains rejected for its much higher construction cost.
|
||||||
|
|
||||||
|
## Source explanation and independent review
|
||||||
|
|
||||||
|
A fresh read-only critic checked the probes and actual local Iced source. Each
|
||||||
|
`Path::circle` allocates/builds a path and converts its arc into quadratic segments.
|
||||||
|
Each WGPU `Frame::fill` allocates a boxed geometry builder and invokes Lyon fill
|
||||||
|
tessellation. Same-color fills already share a solid mesh buffer: this is not
|
||||||
|
one GPU draw call per dot. Frame translation transforms paths before tessellation,
|
||||||
|
so path reuse alone does not reuse triangles.
|
||||||
|
|
||||||
|
Renderer-level `with_translation` can reuse cached triangles. Stock Canvas cannot
|
||||||
|
attach a separate transform to each returned geometry; application adoption would
|
||||||
|
need a small background widget or wrapper, with layout, clipping, lifecycle and
|
||||||
|
interaction checks. Scaling the grid to handle zoom is unsuitable because the
|
||||||
|
dot radius must remain fixed in screen units.
|
||||||
|
|
||||||
|
The critic also identified two important controls. Original opaque background
|
||||||
|
geometry must not silently become screenshot-clear color: MSAA/alpha composition
|
||||||
|
can change quantized pixels. Also, `iced_wgpu::triangle::Storage::prepare` rewrites
|
||||||
|
cached mesh data when its transform changes. Construction/command-recording time
|
||||||
|
therefore excludes real preparation/upload costs. The later probe measures a
|
||||||
|
rendering/readback path separately; neither timer represents native presentation.
|
||||||
|
|
||||||
|
Primary sources: Iced 0.14 `iced_graphics/src/geometry/path{,/builder}.rs`,
|
||||||
|
`iced_wgpu/src/{geometry,triangle}.rs`, `iced_core/src/renderer.rs`, and
|
||||||
|
`iced_widget/src/canvas.rs`. The reviewer changed no files and did not execute the
|
||||||
|
probes; execution and interpretation remain the parent's responsibility.
|
||||||
|
|
||||||
|
## Renderer-translated phase cache
|
||||||
|
|
||||||
|
`phase_grid_probe_v1.rs` / `grid-phase-01.log` cache zero-phase circles once for
|
||||||
|
each size/spacing pair, translate by `pan.rem_euclid(step)`, and externally clip
|
||||||
|
to the original viewport. The original nonnegative row/column indices and fixed
|
||||||
|
screen-space radius are retained. Cache clip bounds include the radius margins.
|
||||||
|
This first prototype uses screenshot clear color instead of opaque background
|
||||||
|
geometry; its widespread one-level pixel differences are not accepted as parity.
|
||||||
|
Its compiler emitted one duplicate Renderer-import warning, retained in the
|
||||||
|
original driver. Later drivers remove that import and compile with `-D warnings`.
|
||||||
|
|
||||||
|
`phase_grid_opaque_probe.rs` / `grid-phase-opaque-01.log` add an oversized opaque
|
||||||
|
background to the same cached geometry as the circles. Its bounds extend from
|
||||||
|
`(-step,-step)` to `(width+2*step,height+2*step)`, covering the viewport at every
|
||||||
|
positive remainder without adding extra dot rows or columns. This directly
|
||||||
|
compares against the unchanged legacy painter. A proposed separate-background
|
||||||
|
control was not executed; no result is claimed for it.
|
||||||
|
|
||||||
|
Of 75 comparisons (five size/zoom pairs, five offsets, three DPI scales), 73 are
|
||||||
|
byte-exact. All 60 cases at integer canvas sizes and spacing 14 or 24 are exact.
|
||||||
|
At 301.5x211.25, zoom 0.73, pan (-13.25,9.75), scale 1 changes 12 pixels by at
|
||||||
|
most one channel level; scale 2 changes one pixel by at most six levels. These
|
||||||
|
are failures of exact parity and are preserved, not hidden behind a tolerance.
|
||||||
|
|
||||||
|
The targeted `phase_grid_diagnostic.rs` / `grid-phase-diagnostic-01.log` locates
|
||||||
|
all 12 scale-1 differences at the rightmost physical column x=301. The scale-2
|
||||||
|
single-pixel difference does not recur. That diagnostic skips earlier large
|
||||||
|
cases and their rendering/timing sequence: it does not exonerate the earlier
|
||||||
|
failure or establish that every residual difference is at an edge.
|
||||||
|
|
||||||
|
The replay driver's first compilation failed with E0689 because the new control's
|
||||||
|
`Vector::new(-13.25,9.75)` left its numeric type ambiguous before `rem_euclid`.
|
||||||
|
An explicit `Vector<f32>` annotation corrects the experiment harness. No probe
|
||||||
|
executed during that failed attempt; no application source changed.
|
||||||
|
|
||||||
|
`phase_grid_replay.rs` preserves the full opaque probe's rendering/timing sequence
|
||||||
|
and adds coordinate diagnostics without extra renders until that sequence ends.
|
||||||
|
`grid-phase-replay-01.log` reproduces both failures: the 12 right-edge pixels and
|
||||||
|
one **interior** pixel at physical (149,263), where legacy RGBA is
|
||||||
|
`[240,243,246,255]` and cached RGBA is `[246,248,251,255]`. The latter cannot be
|
||||||
|
dismissed as viewport-edge rounding. Afterwards, all 12 same-renderer repeat
|
||||||
|
controls (three repetitions of old/old and cached/cached at two scales) are
|
||||||
|
byte-exact; the control cache builds once. This finite control does not establish
|
||||||
|
universal determinism, but supports investigating differing geometry coverage
|
||||||
|
instead of treating the reproduced pixel as random readback noise.
|
||||||
|
|
||||||
|
Cold construction plus command recording takes 68.42–173.72ms median for the four
|
||||||
|
large viewports; cached translation takes 0.0008–0.0011ms. Each per-size/spacing
|
||||||
|
cache builds exactly once through all pan comparisons and measurements. Zoom
|
||||||
|
and resize through a single retained cache are not tested by these drivers.
|
||||||
|
The labels containing `submit` mean renderer command recording, not GPU submission.
|
||||||
|
|
||||||
|
Two selected cases include construction, recording, backend preparation and GPU
|
||||||
|
readback in a separate timer (two warmups, eight samples, sorted-index median):
|
||||||
|
|
||||||
|
| Canvas, zoom | Original p50 ms | Phase cache p50 ms |
|
||||||
|
| --- | ---: | ---: |
|
||||||
|
| 1900x660, 1.0 | 259.9265 | 212.6536 |
|
||||||
|
| 1440x900, 0.5 | 337.2560 | 170.3780 |
|
||||||
|
|
||||||
|
These support a benefit within the headless path, but retain significant renderer
|
||||||
|
and readback cost and variable outliers. They are not native frame times. Sample
|
||||||
|
size, sequential ordering and uncontrolled machine load prohibit a precise
|
||||||
|
general speedup claim. All driver/log hashes and execution mapping are in
|
||||||
|
`cold-pan-context.json`.
|
||||||
|
|
||||||
|
The phase candidate removes the measured pan tessellation cost, but does not
|
||||||
|
meet exact visual preservation. Do not adopt it as an invisible optimization.
|
||||||
|
The small circle rewrites leave the main cost and squares change appearance.
|
||||||
|
Further work should investigate the reproduced interior coverage difference or
|
||||||
|
compare optimized dependency/build profiles before adding a custom widget.
|
||||||
|
Any adopted rendering candidate must then verify a real mounted scene at a
|
||||||
|
nonzero widget origin, foreground ordering, viewport clipping, pan/zoom/resize
|
||||||
|
cache lifecycle and unchanged event behavior. Native interaction/FPS verification
|
||||||
|
remains a separate required gate. No application implementation is changed by
|
||||||
|
these experiments.
|
||||||
@@ -139,6 +139,11 @@ remains deferred by the user. No published release has been replaced.
|
|||||||
|
|
||||||
## Environment and reproduction
|
## Environment and reproduction
|
||||||
|
|
||||||
|
The subsequent [cold-construction and pan experiments](COLD-PAN.md) compare
|
||||||
|
additional approaches, including a renderer-translated cache. They preserve
|
||||||
|
their own pixel differences, timing limits and adoption gates; they do not
|
||||||
|
change the production implementation verified above.
|
||||||
|
|
||||||
Windows 10.0.26200, Rust 1.98.1, x86_64-pc-windows-gnullvm, development profile
|
Windows 10.0.26200, Rust 1.98.1, x86_64-pc-windows-gnullvm, development profile
|
||||||
with debug information disabled. The exposed CPU is Intel Core i7-10870H with
|
with debug information disabled. The exposed CPU is Intel Core i7-10870H with
|
||||||
4 cores/threads; Windows reports VMware SVGA 3D, driver 9.17.11.4. The headless
|
4 cores/threads; Windows reports VMware SVGA 3D, driver 9.17.11.4. The headless
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"application_source": "336720559bcec511949caa8a42bee8a55c3822da",
|
||||||
|
"base_evidence": "2ca84676ee4dc30846208881a27d90a901482085",
|
||||||
|
"production_changes": false,
|
||||||
|
"environment": "Same unoptimized Windows Iced/Tokio artifacts as context.json",
|
||||||
|
"logs": [
|
||||||
|
{
|
||||||
|
"driver": "cold_grid_probe.rs",
|
||||||
|
"exit_code": 0,
|
||||||
|
"log": "grid-cold-01.log"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"driver": "phase_grid_probe_v1.rs",
|
||||||
|
"exit_code": 0,
|
||||||
|
"compile_warning": "Unused duplicate Renderer trait import; retained in original driver",
|
||||||
|
"log": "grid-phase-01.log"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"driver": "phase_grid_opaque_probe.rs",
|
||||||
|
"exit_code": 0,
|
||||||
|
"compile_warnings_denied": true,
|
||||||
|
"log": "grid-phase-opaque-01.log"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"driver": "phase_grid_diagnostic.rs",
|
||||||
|
"exit_code": 0,
|
||||||
|
"compile_warnings_denied": true,
|
||||||
|
"log": "grid-phase-diagnostic-01.log"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"driver": "phase_grid_replay.rs",
|
||||||
|
"log": "grid-phase-replay-01.log",
|
||||||
|
"exit_code": 0,
|
||||||
|
"compile_warnings_denied": true,
|
||||||
|
"initial_compile": "E0689 ambiguous Vector scalar before rem_euclid, fixed with Vector<f32>; no execution on failed attempt"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sha256": {
|
||||||
|
"cold_grid_probe.rs": "a4cc6543229ae4901d54061823a3b05ec6fe3b988f245df12898e013dbb93323",
|
||||||
|
"phase_grid_probe_v1.rs": "c4293e8bb022fae5bffe67002a6f7c867549f2fa8a865b107f39070655bc57fc",
|
||||||
|
"phase_grid_opaque_probe.rs": "43ac5be462ca31f9d1c49554291e08b60bac9de38face7138eaa850e4dcc0ab9",
|
||||||
|
"phase_grid_diagnostic.rs": "8de3c980ac65eef4fcb32b1b121d14aca35b93c704c5b19a440ad9dc7042248c",
|
||||||
|
"grid-cold-01.log": "ca5cac0be409bafcea2c154d42998cbd622c9e898892574bcd5a2df0c1a70886",
|
||||||
|
"grid-phase-01.log": "e0b2e2a3e24d642e1b6c2b1b418f24c952399758159de051f7c1ba7efbb39c4a",
|
||||||
|
"grid-phase-opaque-01.log": "2716cbeb589f4b23a48575680022231c0b94b56ba9c06ec1adbf9e3e6d07f7cd",
|
||||||
|
"grid-phase-diagnostic-01.log": "1dbb0f745169b88c56a21683dba6797a3dbbe753e8dd742bc9ecc8ca24788886",
|
||||||
|
"phase_grid_replay.rs": "96e62ba5d08f7e26d9705d3f90e3785151597b526293439345b59ed842de4971",
|
||||||
|
"grid-phase-replay-01.log": "040034be1b8eb3d4fc010bbe34c5ded47a953b8295bcf2f9440507d1a149da1f"
|
||||||
|
},
|
||||||
|
"native_fps": "unverified"
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
//! Experimental cold-grid candidates; no window or input automation.
|
||||||
|
use iced::advanced::{
|
||||||
|
graphics::geometry::Renderer as _,
|
||||||
|
renderer::{Headless, Renderer as _},
|
||||||
|
};
|
||||||
|
use iced::{
|
||||||
|
Color, Point, Rectangle, Renderer, Size, Vector,
|
||||||
|
widget::canvas::{Frame, Geometry, Path},
|
||||||
|
};
|
||||||
|
use std::{hint::black_box, time::Instant};
|
||||||
|
const BG: Color = Color::from_rgb8(246, 248, 251);
|
||||||
|
const DOT: Color = Color::from_rgb(0.86, 0.89, 0.91);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum Candidate {
|
||||||
|
Original,
|
||||||
|
Template,
|
||||||
|
Column,
|
||||||
|
Square,
|
||||||
|
}
|
||||||
|
fn draw(r: &Renderer, size: Size, zoom: f32, pan: Vector, candidate: Candidate) -> Geometry {
|
||||||
|
let mut f = Frame::new(r, size);
|
||||||
|
f.fill_rectangle(Point::ORIGIN, size, BG);
|
||||||
|
let step = (24. * zoom).max(14.);
|
||||||
|
let ox = pan.x.rem_euclid(step);
|
||||||
|
let oy = pan.y.rem_euclid(step);
|
||||||
|
let circle = Path::circle(Point::ORIGIN, 0.65);
|
||||||
|
for x in 0..(size.width / step) as i32 + 1 {
|
||||||
|
if matches!(candidate, Candidate::Column) {
|
||||||
|
let p = Path::new(|p| {
|
||||||
|
for y in 0..(size.height / step) as i32 + 1 {
|
||||||
|
p.circle(Point::new(ox + x as f32 * step, oy + y as f32 * step), 0.65);
|
||||||
|
p.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
f.fill(&p, DOT);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for y in 0..(size.height / step) as i32 + 1 {
|
||||||
|
let center = Point::new(ox + x as f32 * step, oy + y as f32 * step);
|
||||||
|
match candidate {
|
||||||
|
Candidate::Original => f.fill(&Path::circle(center, 0.65), DOT),
|
||||||
|
Candidate::Template => f.with_save(|f| {
|
||||||
|
f.translate(Vector::new(center.x, center.y));
|
||||||
|
f.fill(&circle, DOT);
|
||||||
|
}),
|
||||||
|
Candidate::Square => f.fill_rectangle(
|
||||||
|
center - Vector::new(0.575, 0.575),
|
||||||
|
Size::new(1.15, 1.15),
|
||||||
|
DOT,
|
||||||
|
),
|
||||||
|
Candidate::Column => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.into_geometry()
|
||||||
|
}
|
||||||
|
fn pixels(r: &mut Renderer, size: Size, g: Geometry) -> Vec<u8> {
|
||||||
|
r.reset(Rectangle::with_size(size));
|
||||||
|
r.draw_geometry(g);
|
||||||
|
Headless::screenshot(r, Size::new(size.width as u32, size.height as u32), 1., BG)
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
let n = std::env::args()
|
||||||
|
.nth(1)
|
||||||
|
.map(|s| s.parse::<usize>().unwrap())
|
||||||
|
.unwrap_or(20)
|
||||||
|
.max(1);
|
||||||
|
let rt = tokio::runtime::Builder::new_current_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
let mut r = rt
|
||||||
|
.block_on(<Renderer as Headless>::new(
|
||||||
|
iced::Font::DEFAULT,
|
||||||
|
16.into(),
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
println!(
|
||||||
|
"renderer={} n={n}; construction only, unoptimized linked dependencies; NOT native FPS",
|
||||||
|
r.name()
|
||||||
|
);
|
||||||
|
for (size, zoom) in [
|
||||||
|
(Size::new(1900., 660.), 1.),
|
||||||
|
(Size::new(1900., 660.), 0.5),
|
||||||
|
(Size::new(1440., 900.), 1.),
|
||||||
|
(Size::new(1440., 900.), 0.5),
|
||||||
|
] {
|
||||||
|
println!("size={}x{} zoom={zoom}", size.width, size.height);
|
||||||
|
for candidate in [
|
||||||
|
Candidate::Original,
|
||||||
|
Candidate::Template,
|
||||||
|
Candidate::Column,
|
||||||
|
Candidate::Square,
|
||||||
|
] {
|
||||||
|
for pan in [
|
||||||
|
Vector::new(-13.25, 9.75),
|
||||||
|
Vector::new(0., 0.),
|
||||||
|
Vector::new(6.125, -8.5),
|
||||||
|
] {
|
||||||
|
let base = draw(&r, size, zoom, pan, Candidate::Original);
|
||||||
|
let base = pixels(&mut r, size, base);
|
||||||
|
let test = draw(&r, size, zoom, pan, candidate);
|
||||||
|
let test = pixels(&mut r, size, test);
|
||||||
|
let changed = base
|
||||||
|
.chunks_exact(4)
|
||||||
|
.zip(test.chunks_exact(4))
|
||||||
|
.filter(|(a, b)| a != b)
|
||||||
|
.count();
|
||||||
|
let max = base
|
||||||
|
.iter()
|
||||||
|
.zip(&test)
|
||||||
|
.map(|(a, b)| a.abs_diff(*b))
|
||||||
|
.max()
|
||||||
|
.unwrap_or(0);
|
||||||
|
println!(
|
||||||
|
"{candidate:?} pan={},{} changed_pixels={changed} max_channel_delta={max}",
|
||||||
|
pan.x, pan.y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let mut ms = Vec::new();
|
||||||
|
for i in 0..n + 3 {
|
||||||
|
let pan = Vector::new(-13.25 + i as f32 * 0.25, 9.75);
|
||||||
|
let now = Instant::now();
|
||||||
|
let g = black_box(draw(&r, size, zoom, pan, candidate));
|
||||||
|
let elapsed = now.elapsed().as_secs_f64() * 1000.;
|
||||||
|
drop(g);
|
||||||
|
if i >= 3 {
|
||||||
|
ms.push(elapsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ms.sort_by(f64::total_cmp);
|
||||||
|
println!(
|
||||||
|
"{candidate:?} changing_pan n={n} p50_ms={:.4} p95_ms={:.4} max_ms={:.4}",
|
||||||
|
ms[((n - 1) as f64 * 0.5).ceil() as usize],
|
||||||
|
ms[((n - 1) as f64 * 0.95).ceil() as usize],
|
||||||
|
ms[n - 1]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
renderer=wgpu n=20; construction only, unoptimized linked dependencies; NOT native FPS
|
||||||
|
size=1900x660 zoom=1
|
||||||
|
Original pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
Original pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
Original pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
Original changing_pan n=20 p50_ms=61.0564 p95_ms=111.2137 max_ms=111.2137
|
||||||
|
Template pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
Template pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
Template pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
Template changing_pan n=20 p50_ms=55.3975 p95_ms=73.8790 max_ms=73.8790
|
||||||
|
Column pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
Column pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
Column pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
Column changing_pan n=20 p50_ms=54.3594 p95_ms=69.6607 max_ms=69.6607
|
||||||
|
Square pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
Square pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
Square pan=6.125,-8.5 changed_pixels=4266 max_channel_delta=7
|
||||||
|
Square changing_pan n=20 p50_ms=3.5527 p95_ms=5.6911 max_ms=5.6911
|
||||||
|
size=1900x660 zoom=0.5
|
||||||
|
Original pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
Original pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
Original pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
Original changing_pan n=20 p50_ms=215.8919 p95_ms=253.9666 max_ms=253.9666
|
||||||
|
Template pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
Template pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
Template pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
Template changing_pan n=20 p50_ms=162.3073 p95_ms=212.2833 max_ms=212.2833
|
||||||
|
Column pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
Column pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
Column pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
Column changing_pan n=20 p50_ms=158.5968 p95_ms=449.6066 max_ms=449.6066
|
||||||
|
Square pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
Square pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
Square pan=6.125,-8.5 changed_pixels=12784 max_channel_delta=7
|
||||||
|
Square changing_pan n=20 p50_ms=7.5699 p95_ms=13.3416 max_ms=13.3416
|
||||||
|
size=1440x900 zoom=1
|
||||||
|
Original pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
Original pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
Original pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
Original changing_pan n=20 p50_ms=60.1683 p95_ms=88.4967 max_ms=88.4967
|
||||||
|
Template pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
Template pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
Template pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
Template changing_pan n=20 p50_ms=43.3860 p95_ms=53.1866 max_ms=53.1866
|
||||||
|
Column pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
Column pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
Column pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
Column changing_pan n=20 p50_ms=60.8198 p95_ms=80.8932 max_ms=80.8932
|
||||||
|
Square pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
Square pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
Square pan=6.125,-8.5 changed_pixels=4440 max_channel_delta=7
|
||||||
|
Square changing_pan n=20 p50_ms=2.0340 p95_ms=4.0620 max_ms=4.0620
|
||||||
|
size=1440x900 zoom=0.5
|
||||||
|
Original pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
Original pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
Original pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
Original changing_pan n=20 p50_ms=165.2049 p95_ms=203.5331 max_ms=203.5331
|
||||||
|
Template pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
Template pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
Template pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
Template changing_pan n=20 p50_ms=133.3420 p95_ms=143.9790 max_ms=143.9790
|
||||||
|
Column pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
Column pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
Column pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
Column changing_pan n=20 p50_ms=143.1489 p95_ms=155.3680 max_ms=155.3680
|
||||||
|
Square pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
Square pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
Square pan=6.125,-8.5 changed_pixels=13184 max_channel_delta=7
|
||||||
|
Square changing_pan n=20 p50_ms=6.8178 p95_ms=10.8775 max_ms=10.8775
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
renderer=wgpu; phase-cache prototype; NOT native FPS
|
||||||
|
size=1900x660 zoom=1 step=24
|
||||||
|
scale=1 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-13.25,9.75 changed_pixels=2212 max_channel_delta=1
|
||||||
|
scale=1 pan=6.125,-8.5 changed_pixels=2133 max_channel_delta=1
|
||||||
|
scale=1 pan=23.875,23.75 changed_pixels=2133 max_channel_delta=1
|
||||||
|
scale=1 pan=-0.125,0.125 changed_pixels=4424 max_channel_delta=1
|
||||||
|
scale=1.25 pan=0,0 changed_pixels=8745 max_channel_delta=1
|
||||||
|
scale=1.25 pan=-13.25,9.75 changed_pixels=2212 max_channel_delta=1
|
||||||
|
scale=1.25 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=23.875,23.75 changed_pixels=4266 max_channel_delta=1
|
||||||
|
scale=1.25 pan=-0.125,0.125 changed_pixels=6557 max_channel_delta=1
|
||||||
|
scale=2 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-13.25,9.75 changed_pixels=8848 max_channel_delta=1
|
||||||
|
scale=2 pan=6.125,-8.5 changed_pixels=4266 max_channel_delta=1
|
||||||
|
scale=2 pan=23.875,23.75 changed_pixels=10665 max_channel_delta=1
|
||||||
|
scale=2 pan=-0.125,0.125 changed_pixels=6478 max_channel_delta=1
|
||||||
|
cached=false construct_and_submit changing_pan n=20 p50_ms=66.6997 p95_ms=77.3888 max_ms=77.3888
|
||||||
|
cached=true construct_and_submit changing_pan n=20 p50_ms=0.0010 p95_ms=0.0017 max_ms=0.0017
|
||||||
|
cache_builds=1
|
||||||
|
size=1900x660 zoom=0.5 step=14
|
||||||
|
scale=1 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-13.25,9.75 changed_pixels=6392 max_channel_delta=1
|
||||||
|
scale=1 pan=6.125,-8.5 changed_pixels=6392 max_channel_delta=1
|
||||||
|
scale=1 pan=13.875,13.75 changed_pixels=6345 max_channel_delta=1
|
||||||
|
scale=1 pan=-0.125,0.125 changed_pixels=12960 max_channel_delta=1
|
||||||
|
scale=1.25 pan=0,0 changed_pixels=12781 max_channel_delta=1
|
||||||
|
scale=1.25 pan=-13.25,9.75 changed_pixels=9588 max_channel_delta=1
|
||||||
|
scale=1.25 pan=6.125,-8.5 changed_pixels=11288 max_channel_delta=1
|
||||||
|
scale=1.25 pan=13.875,13.75 changed_pixels=9494 max_channel_delta=1
|
||||||
|
scale=1.25 pan=-0.125,0.125 changed_pixels=12801 max_channel_delta=1
|
||||||
|
scale=2 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-13.25,9.75 changed_pixels=25568 max_channel_delta=1
|
||||||
|
scale=2 pan=6.125,-8.5 changed_pixels=12784 max_channel_delta=1
|
||||||
|
scale=2 pan=13.875,13.75 changed_pixels=31725 max_channel_delta=1
|
||||||
|
scale=2 pan=-0.125,0.125 changed_pixels=19170 max_channel_delta=1
|
||||||
|
cached=false construct_and_submit changing_pan n=20 p50_ms=189.4570 p95_ms=221.8240 max_ms=221.8240
|
||||||
|
cached=true construct_and_submit changing_pan n=20 p50_ms=0.0007 p95_ms=0.0008 max_ms=0.0008
|
||||||
|
cache_builds=1
|
||||||
|
size=1440x900 zoom=1 step=24
|
||||||
|
scale=1 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-13.25,9.75 changed_pixels=2280 max_channel_delta=1
|
||||||
|
scale=1 pan=6.125,-8.5 changed_pixels=2220 max_channel_delta=1
|
||||||
|
scale=1 pan=23.875,23.75 changed_pixels=2220 max_channel_delta=1
|
||||||
|
scale=1 pan=-0.125,0.125 changed_pixels=4522 max_channel_delta=1
|
||||||
|
scale=1.25 pan=0,0 changed_pixels=9000 max_channel_delta=1
|
||||||
|
scale=1.25 pan=-13.25,9.75 changed_pixels=2280 max_channel_delta=1
|
||||||
|
scale=1.25 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=23.875,23.75 changed_pixels=4403 max_channel_delta=1
|
||||||
|
scale=1.25 pan=-0.125,0.125 changed_pixels=6742 max_channel_delta=1
|
||||||
|
scale=2 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-13.25,9.75 changed_pixels=9120 max_channel_delta=1
|
||||||
|
scale=2 pan=6.125,-8.5 changed_pixels=4440 max_channel_delta=1
|
||||||
|
scale=2 pan=23.875,23.75 changed_pixels=11026 max_channel_delta=1
|
||||||
|
scale=2 pan=-0.125,0.125 changed_pixels=6683 max_channel_delta=1
|
||||||
|
cached=false construct_and_submit changing_pan n=20 p50_ms=66.8644 p95_ms=93.9216 max_ms=93.9216
|
||||||
|
cached=true construct_and_submit changing_pan n=20 p50_ms=0.0008 p95_ms=0.0008 max_ms=0.0008
|
||||||
|
cache_builds=1
|
||||||
|
size=1440x900 zoom=0.5 step=14
|
||||||
|
scale=1 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-13.25,9.75 changed_pixels=6592 max_channel_delta=1
|
||||||
|
scale=1 pan=6.125,-8.5 changed_pixels=6592 max_channel_delta=1
|
||||||
|
scale=1 pan=13.875,13.75 changed_pixels=6528 max_channel_delta=1
|
||||||
|
scale=1 pan=-0.125,0.125 changed_pixels=13260 max_channel_delta=1
|
||||||
|
scale=1.25 pan=0,0 changed_pixels=13306 max_channel_delta=1
|
||||||
|
scale=1.25 pan=-13.25,9.75 changed_pixels=9952 max_channel_delta=1
|
||||||
|
scale=1.25 pan=6.125,-8.5 changed_pixels=11488 max_channel_delta=1
|
||||||
|
scale=1.25 pan=13.875,13.75 changed_pixels=9792 max_channel_delta=1
|
||||||
|
scale=1.25 pan=-0.125,0.125 changed_pixels=13209 max_channel_delta=1
|
||||||
|
scale=2 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-13.25,9.75 changed_pixels=26368 max_channel_delta=1
|
||||||
|
scale=2 pan=6.125,-8.5 changed_pixels=13184 max_channel_delta=1
|
||||||
|
scale=2 pan=13.875,13.75 changed_pixels=32640 max_channel_delta=1
|
||||||
|
scale=2 pan=-0.125,0.125 changed_pixels=19686 max_channel_delta=1
|
||||||
|
cached=false construct_and_submit changing_pan n=20 p50_ms=202.5700 p95_ms=482.7433 max_ms=482.7433
|
||||||
|
cached=true construct_and_submit changing_pan n=20 p50_ms=0.0011 p95_ms=0.0041 max_ms=0.0041
|
||||||
|
cache_builds=1
|
||||||
|
size=301.5x211.25 zoom=0.73 step=17.52
|
||||||
|
scale=1 pan=0,0 changed_pixels=263 max_channel_delta=1
|
||||||
|
scale=1 pan=-13.25,9.75 changed_pixels=251 max_channel_delta=1
|
||||||
|
scale=1 pan=6.125,-8.5 changed_pixels=250 max_channel_delta=1
|
||||||
|
scale=1 pan=17.395,17.27 changed_pixels=238 max_channel_delta=1
|
||||||
|
scale=1 pan=-0.125,0.125 changed_pixels=241 max_channel_delta=1
|
||||||
|
scale=1.25 pan=0,0 changed_pixels=379 max_channel_delta=1
|
||||||
|
scale=1.25 pan=-13.25,9.75 changed_pixels=395 max_channel_delta=1
|
||||||
|
scale=1.25 pan=6.125,-8.5 changed_pixels=332 max_channel_delta=1
|
||||||
|
scale=1.25 pan=17.395,17.27 changed_pixels=289 max_channel_delta=1
|
||||||
|
scale=1.25 pan=-0.125,0.125 changed_pixels=372 max_channel_delta=1
|
||||||
|
scale=2 pan=0,0 changed_pixels=759 max_channel_delta=1
|
||||||
|
scale=2 pan=-13.25,9.75 changed_pixels=626 max_channel_delta=6
|
||||||
|
scale=2 pan=6.125,-8.5 changed_pixels=731 max_channel_delta=1
|
||||||
|
scale=2 pan=17.395,17.27 changed_pixels=576 max_channel_delta=1
|
||||||
|
scale=2 pan=-0.125,0.125 changed_pixels=784 max_channel_delta=1
|
||||||
|
cached=false construct_and_submit changing_pan n=20 p50_ms=6.6260 p95_ms=21.1743 max_ms=21.1743
|
||||||
|
cached=true construct_and_submit changing_pan n=20 p50_ms=0.0010 p95_ms=0.0012 max_ms=0.0012
|
||||||
|
cache_builds=1
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
renderer=wgpu; phase-cache prototype; NOT native FPS
|
||||||
|
size=301.5x211.25 zoom=0.73 step=17.52
|
||||||
|
scale=1 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
difference_xy=301,26 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
difference_xy=301,27 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
difference_xy=301,62 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
difference_xy=301,80 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
difference_xy=301,97 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
difference_xy=301,115 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
difference_xy=301,132 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
difference_xy=301,150 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
difference_xy=301,167 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
difference_xy=301,184 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
difference_xy=301,185 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
difference_xy=301,202 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
scale=1 pan=-13.25,9.75 changed_pixels=12 max_channel_delta=1
|
||||||
|
scale=1 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=17.395,17.27 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=17.395,17.27 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=17.395,17.27 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
cached=false construct_and_submit changing_pan n=20 p50_ms=6.1755 p95_ms=8.4025 max_ms=8.4025
|
||||||
|
cached=true construct_and_submit changing_pan n=20 p50_ms=0.0011 p95_ms=0.0019 max_ms=0.0019
|
||||||
|
cache_builds=1
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
renderer=wgpu; phase-cache prototype; NOT native FPS
|
||||||
|
size=1900x660 zoom=1 step=24
|
||||||
|
scale=1 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=23.875,23.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=23.875,23.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=23.875,23.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
cached=false construct_and_submit changing_pan n=20 p50_ms=72.0271 p95_ms=99.9725 max_ms=99.9725
|
||||||
|
cached=true construct_and_submit changing_pan n=20 p50_ms=0.0011 p95_ms=0.0015 max_ms=0.0015
|
||||||
|
cache_builds=1
|
||||||
|
cached=false construct_submit_screenshot changing_pan n=8 p50_ms=259.9265 min_ms=253.3506 max_ms=281.4865
|
||||||
|
cached=true construct_submit_screenshot changing_pan n=8 p50_ms=212.6536 min_ms=184.5191 max_ms=299.2711
|
||||||
|
size=1900x660 zoom=0.5 step=14
|
||||||
|
scale=1 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=13.875,13.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=13.875,13.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=13.875,13.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
cached=false construct_and_submit changing_pan n=20 p50_ms=167.4776 p95_ms=186.8968 max_ms=186.8968
|
||||||
|
cached=true construct_and_submit changing_pan n=20 p50_ms=0.0008 p95_ms=0.0008 max_ms=0.0008
|
||||||
|
cache_builds=1
|
||||||
|
size=1440x900 zoom=1 step=24
|
||||||
|
scale=1 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=23.875,23.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=23.875,23.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=23.875,23.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
cached=false construct_and_submit changing_pan n=20 p50_ms=68.4232 p95_ms=97.6147 max_ms=97.6147
|
||||||
|
cached=true construct_and_submit changing_pan n=20 p50_ms=0.0008 p95_ms=0.0458 max_ms=0.0458
|
||||||
|
cache_builds=1
|
||||||
|
size=1440x900 zoom=0.5 step=14
|
||||||
|
scale=1 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=13.875,13.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=13.875,13.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=13.875,13.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
cached=false construct_and_submit changing_pan n=20 p50_ms=173.7177 p95_ms=215.3188 max_ms=215.3188
|
||||||
|
cached=true construct_and_submit changing_pan n=20 p50_ms=0.0008 p95_ms=0.0009 max_ms=0.0009
|
||||||
|
cache_builds=1
|
||||||
|
cached=false construct_submit_screenshot changing_pan n=8 p50_ms=337.2560 min_ms=319.0543 max_ms=366.4956
|
||||||
|
cached=true construct_submit_screenshot changing_pan n=8 p50_ms=170.3780 min_ms=144.1992 max_ms=188.4337
|
||||||
|
size=301.5x211.25 zoom=0.73 step=17.52
|
||||||
|
scale=1 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-13.25,9.75 changed_pixels=12 max_channel_delta=1
|
||||||
|
scale=1 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=17.395,17.27 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=17.395,17.27 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-13.25,9.75 changed_pixels=1 max_channel_delta=6
|
||||||
|
scale=2 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=17.395,17.27 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
cached=false construct_and_submit changing_pan n=20 p50_ms=5.4797 p95_ms=6.8957 max_ms=6.8957
|
||||||
|
cached=true construct_and_submit changing_pan n=20 p50_ms=0.0007 p95_ms=0.0008 max_ms=0.0008
|
||||||
|
cache_builds=1
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
renderer=wgpu; phase-cache prototype; NOT native FPS
|
||||||
|
size=1900x660 zoom=1 step=24
|
||||||
|
scale=1 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=23.875,23.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=23.875,23.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=23.875,23.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
cached=false construct_and_submit changing_pan n=20 p50_ms=68.3424 p95_ms=88.0883 max_ms=88.0883
|
||||||
|
cached=true construct_and_submit changing_pan n=20 p50_ms=0.0010 p95_ms=0.0012 max_ms=0.0012
|
||||||
|
cache_builds=1
|
||||||
|
cached=false construct_submit_screenshot changing_pan n=8 p50_ms=249.7269 min_ms=216.9378 max_ms=267.1425
|
||||||
|
cached=true construct_submit_screenshot changing_pan n=8 p50_ms=215.6865 min_ms=177.7329 max_ms=262.5719
|
||||||
|
size=1900x660 zoom=0.5 step=14
|
||||||
|
scale=1 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=13.875,13.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=13.875,13.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=13.875,13.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
cached=false construct_and_submit changing_pan n=20 p50_ms=190.0141 p95_ms=231.4193 max_ms=231.4193
|
||||||
|
cached=true construct_and_submit changing_pan n=20 p50_ms=0.0008 p95_ms=0.0008 max_ms=0.0008
|
||||||
|
cache_builds=1
|
||||||
|
size=1440x900 zoom=1 step=24
|
||||||
|
scale=1 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=23.875,23.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=23.875,23.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=23.875,23.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
cached=false construct_and_submit changing_pan n=20 p50_ms=72.2449 p95_ms=86.5021 max_ms=86.5021
|
||||||
|
cached=true construct_and_submit changing_pan n=20 p50_ms=0.0008 p95_ms=0.0008 max_ms=0.0008
|
||||||
|
cache_builds=1
|
||||||
|
size=1440x900 zoom=0.5 step=14
|
||||||
|
scale=1 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=13.875,13.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=13.875,13.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=13.875,13.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
cached=false construct_and_submit changing_pan n=20 p50_ms=209.4728 p95_ms=329.0977 max_ms=329.0977
|
||||||
|
cached=true construct_and_submit changing_pan n=20 p50_ms=0.0008 p95_ms=0.0009 max_ms=0.0009
|
||||||
|
cache_builds=1
|
||||||
|
cached=false construct_submit_screenshot changing_pan n=8 p50_ms=384.7680 min_ms=347.4879 max_ms=420.2894
|
||||||
|
cached=true construct_submit_screenshot changing_pan n=8 p50_ms=164.1611 min_ms=150.1276 max_ms=186.4567
|
||||||
|
size=301.5x211.25 zoom=0.73 step=17.52
|
||||||
|
scale=1 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-13.25,9.75 changed_pixels=12 max_channel_delta=1
|
||||||
|
difference_xy=301,26 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
difference_xy=301,27 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
difference_xy=301,62 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
difference_xy=301,80 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
difference_xy=301,97 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
difference_xy=301,115 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
difference_xy=301,132 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
difference_xy=301,150 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
difference_xy=301,167 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
difference_xy=301,184 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
difference_xy=301,185 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
difference_xy=301,202 expected=[240, 243, 247, 255] actual=[240, 243, 246, 255]
|
||||||
|
scale=1 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=17.395,17.27 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=17.395,17.27 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=1.25 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=0,0 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-13.25,9.75 changed_pixels=1 max_channel_delta=6
|
||||||
|
difference_xy=149,263 expected=[240, 243, 246, 255] actual=[246, 248, 251, 255]
|
||||||
|
scale=2 pan=6.125,-8.5 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=17.395,17.27 changed_pixels=0 max_channel_delta=0
|
||||||
|
scale=2 pan=-0.125,0.125 changed_pixels=0 max_channel_delta=0
|
||||||
|
cached=false construct_and_submit changing_pan n=20 p50_ms=5.5680 p95_ms=7.0634 max_ms=7.0634
|
||||||
|
cached=true construct_and_submit changing_pan n=20 p50_ms=0.0007 p95_ms=0.0008 max_ms=0.0008
|
||||||
|
cache_builds=1
|
||||||
|
original_sequence_complete; beginning same-renderer repeat controls
|
||||||
|
comparison=old/old repetition=1 size=301.5x211.25 scale=1 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
comparison=cached/cached repetition=1 size=301.5x211.25 scale=1 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
comparison=old/old repetition=1 size=301.5x211.25 scale=2 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
comparison=cached/cached repetition=1 size=301.5x211.25 scale=2 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
comparison=old/old repetition=2 size=301.5x211.25 scale=1 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
comparison=cached/cached repetition=2 size=301.5x211.25 scale=1 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
comparison=old/old repetition=2 size=301.5x211.25 scale=2 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
comparison=cached/cached repetition=2 size=301.5x211.25 scale=2 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
comparison=old/old repetition=3 size=301.5x211.25 scale=1 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
comparison=cached/cached repetition=3 size=301.5x211.25 scale=1 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
comparison=old/old repetition=3 size=301.5x211.25 scale=2 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
comparison=cached/cached repetition=3 size=301.5x211.25 scale=2 pan=-13.25,9.75 changed_pixels=0 max_channel_delta=0
|
||||||
|
control_cache_builds=1
|
||||||
@@ -0,0 +1,209 @@
|
|||||||
|
//! Renderer-level phase translation experiment, not application code.
|
||||||
|
use iced::advanced::{Renderer as _, graphics::geometry::Renderer as _, renderer::Headless};
|
||||||
|
use iced::{
|
||||||
|
Color, Point, Rectangle, Renderer, Size, Vector,
|
||||||
|
widget::canvas::{Cache, Frame, Geometry, Path},
|
||||||
|
};
|
||||||
|
use std::{cell::Cell, hint::black_box, time::Instant};
|
||||||
|
const BG: Color = Color::from_rgb8(246, 248, 251);
|
||||||
|
const DOT: Color = Color::from_rgb(0.86, 0.89, 0.91);
|
||||||
|
fn dots(f: &mut Frame, size: Size, step: f32, phase: Vector) {
|
||||||
|
for x in 0..(size.width / step) as i32 + 1 {
|
||||||
|
for y in 0..(size.height / step) as i32 + 1 {
|
||||||
|
f.fill(
|
||||||
|
&Path::circle(
|
||||||
|
Point::new(phase.x + x as f32 * step, phase.y + y as f32 * step),
|
||||||
|
0.65,
|
||||||
|
),
|
||||||
|
DOT,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn old(r: &Renderer, size: Size, step: f32, phase: Vector) -> Geometry {
|
||||||
|
let mut f = Frame::new(r, size);
|
||||||
|
f.fill_rectangle(Point::ORIGIN, size, BG);
|
||||||
|
dots(&mut f, size, step, phase);
|
||||||
|
f.into_geometry()
|
||||||
|
}
|
||||||
|
fn phase(r: &Renderer, cache: &Cache, size: Size, step: f32, builds: &Cell<usize>) -> Geometry {
|
||||||
|
cache.draw_with_bounds(
|
||||||
|
r,
|
||||||
|
Rectangle {
|
||||||
|
x: -step,
|
||||||
|
y: -step,
|
||||||
|
width: size.width + 3. * step,
|
||||||
|
height: size.height + 3. * step,
|
||||||
|
},
|
||||||
|
|f| {
|
||||||
|
builds.set(builds.get() + 1);
|
||||||
|
f.fill_rectangle(
|
||||||
|
Point::new(-step, -step),
|
||||||
|
Size::new(size.width + 3. * step, size.height + 3. * step),
|
||||||
|
BG,
|
||||||
|
);
|
||||||
|
dots(f, size, step, Vector::ZERO);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn submit(r: &mut Renderer, size: Size, g: Geometry, pan: Vector) {
|
||||||
|
r.with_layer(Rectangle::with_size(size), |r| {
|
||||||
|
r.with_translation(pan, |r| r.draw_geometry(g))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fn shot(r: &mut Renderer, size: Size, scale: f32) -> Vec<u8> {
|
||||||
|
Headless::screenshot(
|
||||||
|
r,
|
||||||
|
Size::new(
|
||||||
|
(size.width * scale).ceil() as u32,
|
||||||
|
(size.height * scale).ceil() as u32,
|
||||||
|
),
|
||||||
|
scale,
|
||||||
|
BG,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
let rt = tokio::runtime::Builder::new_current_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
let mut r = rt
|
||||||
|
.block_on(<Renderer as Headless>::new(
|
||||||
|
iced::Font::DEFAULT,
|
||||||
|
16.into(),
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
println!(
|
||||||
|
"renderer={}; phase-cache prototype; NOT native FPS",
|
||||||
|
r.name()
|
||||||
|
);
|
||||||
|
for (size, zoom) in [
|
||||||
|
(Size::new(1900., 660.), 1.),
|
||||||
|
(Size::new(1900., 660.), 0.5),
|
||||||
|
(Size::new(1440., 900.), 1.),
|
||||||
|
(Size::new(1440., 900.), 0.5),
|
||||||
|
(Size::new(301.5, 211.25), 0.73),
|
||||||
|
] {
|
||||||
|
if size.width != 301.5 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let step = (24f32 * zoom).max(14.);
|
||||||
|
let cache = Cache::new();
|
||||||
|
let builds = Cell::new(0);
|
||||||
|
println!(
|
||||||
|
"size={}x{} zoom={zoom} step={step}",
|
||||||
|
size.width, size.height
|
||||||
|
);
|
||||||
|
for scale in [1., 1.25, 2.] {
|
||||||
|
for pan in [
|
||||||
|
Vector::ZERO,
|
||||||
|
Vector::new(-13.25, 9.75),
|
||||||
|
Vector::new(6.125, -8.5),
|
||||||
|
Vector::new(step - 0.125, step - 0.25),
|
||||||
|
Vector::new(-0.125, 0.125),
|
||||||
|
] {
|
||||||
|
let offset = Vector::new(pan.x.rem_euclid(step), pan.y.rem_euclid(step));
|
||||||
|
r.reset(Rectangle::with_size(size));
|
||||||
|
let g = old(&r, size, step, offset);
|
||||||
|
r.draw_geometry(g);
|
||||||
|
let expected = shot(&mut r, size, scale);
|
||||||
|
r.reset(Rectangle::with_size(size));
|
||||||
|
let g = phase(&r, &cache, size, step, &builds);
|
||||||
|
submit(&mut r, size, g, offset);
|
||||||
|
let actual = shot(&mut r, size, scale);
|
||||||
|
assert_eq!(expected.len(), actual.len());
|
||||||
|
for (index, (a, b)) in expected
|
||||||
|
.chunks_exact(4)
|
||||||
|
.zip(actual.chunks_exact(4))
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_, (a, b))| a != b)
|
||||||
|
.take(20)
|
||||||
|
{
|
||||||
|
println!(
|
||||||
|
"difference_xy={},{} expected={a:?} actual={b:?}",
|
||||||
|
index % (size.width * scale).ceil() as usize,
|
||||||
|
index / (size.width * scale).ceil() as usize
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let changed = expected
|
||||||
|
.chunks_exact(4)
|
||||||
|
.zip(actual.chunks_exact(4))
|
||||||
|
.filter(|(a, b)| a != b)
|
||||||
|
.count();
|
||||||
|
let max = expected
|
||||||
|
.iter()
|
||||||
|
.zip(&actual)
|
||||||
|
.map(|(a, b)| a.abs_diff(*b))
|
||||||
|
.max()
|
||||||
|
.unwrap_or(0);
|
||||||
|
println!(
|
||||||
|
"scale={scale} pan={},{} changed_pixels={changed} max_channel_delta={max}",
|
||||||
|
pan.x, pan.y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(builds.get(), 1);
|
||||||
|
for cached in [false, true] {
|
||||||
|
let mut ms = Vec::new();
|
||||||
|
for i in 0..23 {
|
||||||
|
r.reset(Rectangle::with_size(size));
|
||||||
|
let offset = Vector::new((i as f32 * 0.25).rem_euclid(step), 9.75);
|
||||||
|
let now = Instant::now();
|
||||||
|
let g = if cached {
|
||||||
|
phase(&r, &cache, size, step, &builds)
|
||||||
|
} else {
|
||||||
|
old(&r, size, step, offset)
|
||||||
|
};
|
||||||
|
if cached {
|
||||||
|
submit(&mut r, size, g, offset)
|
||||||
|
} else {
|
||||||
|
r.draw_geometry(g)
|
||||||
|
};
|
||||||
|
let elapsed = black_box(now.elapsed().as_secs_f64() * 1000.);
|
||||||
|
if i >= 3 {
|
||||||
|
ms.push(elapsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ms.sort_by(f64::total_cmp);
|
||||||
|
println!(
|
||||||
|
"cached={cached} construct_and_submit changing_pan n=20 p50_ms={:.4} p95_ms={:.4} max_ms={:.4}",
|
||||||
|
ms[10], ms[19], ms[19]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
println!("cache_builds={}", builds.get());
|
||||||
|
assert_eq!(builds.get(), 1);
|
||||||
|
// Includes backend prepare/upload and readback; still not native presentation.
|
||||||
|
if size.width == 1900. && zoom == 1. || size.width == 1440. && zoom == 0.5 {
|
||||||
|
for cached in [false, true] {
|
||||||
|
let mut ms = Vec::new();
|
||||||
|
for i in 0..10 {
|
||||||
|
r.reset(Rectangle::with_size(size));
|
||||||
|
let offset = Vector::new((i as f32 * 0.25).rem_euclid(step), 9.75);
|
||||||
|
let now = Instant::now();
|
||||||
|
let g = if cached {
|
||||||
|
phase(&r, &cache, size, step, &builds)
|
||||||
|
} else {
|
||||||
|
old(&r, size, step, offset)
|
||||||
|
};
|
||||||
|
if cached {
|
||||||
|
submit(&mut r, size, g, offset);
|
||||||
|
} else {
|
||||||
|
r.draw_geometry(g);
|
||||||
|
}
|
||||||
|
let pixels = black_box(shot(&mut r, size, 1.));
|
||||||
|
let elapsed = now.elapsed().as_secs_f64() * 1000.;
|
||||||
|
drop(pixels);
|
||||||
|
if i >= 2 {
|
||||||
|
ms.push(elapsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ms.sort_by(f64::total_cmp);
|
||||||
|
println!(
|
||||||
|
"cached={cached} construct_submit_screenshot changing_pan n=8 p50_ms={:.4} min_ms={:.4} max_ms={:.4}",
|
||||||
|
ms[4], ms[0], ms[7]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,193 @@
|
|||||||
|
//! Renderer-level phase translation experiment, not application code.
|
||||||
|
use iced::advanced::{Renderer as _, graphics::geometry::Renderer as _, renderer::Headless};
|
||||||
|
use iced::{
|
||||||
|
Color, Point, Rectangle, Renderer, Size, Vector,
|
||||||
|
widget::canvas::{Cache, Frame, Geometry, Path},
|
||||||
|
};
|
||||||
|
use std::{cell::Cell, hint::black_box, time::Instant};
|
||||||
|
const BG: Color = Color::from_rgb8(246, 248, 251);
|
||||||
|
const DOT: Color = Color::from_rgb(0.86, 0.89, 0.91);
|
||||||
|
fn dots(f: &mut Frame, size: Size, step: f32, phase: Vector) {
|
||||||
|
for x in 0..(size.width / step) as i32 + 1 {
|
||||||
|
for y in 0..(size.height / step) as i32 + 1 {
|
||||||
|
f.fill(
|
||||||
|
&Path::circle(
|
||||||
|
Point::new(phase.x + x as f32 * step, phase.y + y as f32 * step),
|
||||||
|
0.65,
|
||||||
|
),
|
||||||
|
DOT,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn old(r: &Renderer, size: Size, step: f32, phase: Vector) -> Geometry {
|
||||||
|
let mut f = Frame::new(r, size);
|
||||||
|
f.fill_rectangle(Point::ORIGIN, size, BG);
|
||||||
|
dots(&mut f, size, step, phase);
|
||||||
|
f.into_geometry()
|
||||||
|
}
|
||||||
|
fn phase(r: &Renderer, cache: &Cache, size: Size, step: f32, builds: &Cell<usize>) -> Geometry {
|
||||||
|
cache.draw_with_bounds(
|
||||||
|
r,
|
||||||
|
Rectangle {
|
||||||
|
x: -step,
|
||||||
|
y: -step,
|
||||||
|
width: size.width + 3. * step,
|
||||||
|
height: size.height + 3. * step,
|
||||||
|
},
|
||||||
|
|f| {
|
||||||
|
builds.set(builds.get() + 1);
|
||||||
|
f.fill_rectangle(
|
||||||
|
Point::new(-step, -step),
|
||||||
|
Size::new(size.width + 3. * step, size.height + 3. * step),
|
||||||
|
BG,
|
||||||
|
);
|
||||||
|
dots(f, size, step, Vector::ZERO);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn submit(r: &mut Renderer, size: Size, g: Geometry, pan: Vector) {
|
||||||
|
r.with_layer(Rectangle::with_size(size), |r| {
|
||||||
|
r.with_translation(pan, |r| r.draw_geometry(g))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fn shot(r: &mut Renderer, size: Size, scale: f32) -> Vec<u8> {
|
||||||
|
Headless::screenshot(
|
||||||
|
r,
|
||||||
|
Size::new(
|
||||||
|
(size.width * scale).ceil() as u32,
|
||||||
|
(size.height * scale).ceil() as u32,
|
||||||
|
),
|
||||||
|
scale,
|
||||||
|
BG,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
let rt = tokio::runtime::Builder::new_current_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
let mut r = rt
|
||||||
|
.block_on(<Renderer as Headless>::new(
|
||||||
|
iced::Font::DEFAULT,
|
||||||
|
16.into(),
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
println!(
|
||||||
|
"renderer={}; phase-cache prototype; NOT native FPS",
|
||||||
|
r.name()
|
||||||
|
);
|
||||||
|
for (size, zoom) in [
|
||||||
|
(Size::new(1900., 660.), 1.),
|
||||||
|
(Size::new(1900., 660.), 0.5),
|
||||||
|
(Size::new(1440., 900.), 1.),
|
||||||
|
(Size::new(1440., 900.), 0.5),
|
||||||
|
(Size::new(301.5, 211.25), 0.73),
|
||||||
|
] {
|
||||||
|
let step = (24f32 * zoom).max(14.);
|
||||||
|
let cache = Cache::new();
|
||||||
|
let builds = Cell::new(0);
|
||||||
|
println!(
|
||||||
|
"size={}x{} zoom={zoom} step={step}",
|
||||||
|
size.width, size.height
|
||||||
|
);
|
||||||
|
for scale in [1., 1.25, 2.] {
|
||||||
|
for pan in [
|
||||||
|
Vector::ZERO,
|
||||||
|
Vector::new(-13.25, 9.75),
|
||||||
|
Vector::new(6.125, -8.5),
|
||||||
|
Vector::new(step - 0.125, step - 0.25),
|
||||||
|
Vector::new(-0.125, 0.125),
|
||||||
|
] {
|
||||||
|
let offset = Vector::new(pan.x.rem_euclid(step), pan.y.rem_euclid(step));
|
||||||
|
r.reset(Rectangle::with_size(size));
|
||||||
|
let g = old(&r, size, step, offset);
|
||||||
|
r.draw_geometry(g);
|
||||||
|
let expected = shot(&mut r, size, scale);
|
||||||
|
r.reset(Rectangle::with_size(size));
|
||||||
|
let g = phase(&r, &cache, size, step, &builds);
|
||||||
|
submit(&mut r, size, g, offset);
|
||||||
|
let actual = shot(&mut r, size, scale);
|
||||||
|
assert_eq!(expected.len(), actual.len());
|
||||||
|
let changed = expected
|
||||||
|
.chunks_exact(4)
|
||||||
|
.zip(actual.chunks_exact(4))
|
||||||
|
.filter(|(a, b)| a != b)
|
||||||
|
.count();
|
||||||
|
let max = expected
|
||||||
|
.iter()
|
||||||
|
.zip(&actual)
|
||||||
|
.map(|(a, b)| a.abs_diff(*b))
|
||||||
|
.max()
|
||||||
|
.unwrap_or(0);
|
||||||
|
println!(
|
||||||
|
"scale={scale} pan={},{} changed_pixels={changed} max_channel_delta={max}",
|
||||||
|
pan.x, pan.y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(builds.get(), 1);
|
||||||
|
for cached in [false, true] {
|
||||||
|
let mut ms = Vec::new();
|
||||||
|
for i in 0..23 {
|
||||||
|
r.reset(Rectangle::with_size(size));
|
||||||
|
let offset = Vector::new((i as f32 * 0.25).rem_euclid(step), 9.75);
|
||||||
|
let now = Instant::now();
|
||||||
|
let g = if cached {
|
||||||
|
phase(&r, &cache, size, step, &builds)
|
||||||
|
} else {
|
||||||
|
old(&r, size, step, offset)
|
||||||
|
};
|
||||||
|
if cached {
|
||||||
|
submit(&mut r, size, g, offset)
|
||||||
|
} else {
|
||||||
|
r.draw_geometry(g)
|
||||||
|
};
|
||||||
|
let elapsed = black_box(now.elapsed().as_secs_f64() * 1000.);
|
||||||
|
if i >= 3 {
|
||||||
|
ms.push(elapsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ms.sort_by(f64::total_cmp);
|
||||||
|
println!(
|
||||||
|
"cached={cached} construct_and_submit changing_pan n=20 p50_ms={:.4} p95_ms={:.4} max_ms={:.4}",
|
||||||
|
ms[10], ms[19], ms[19]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
println!("cache_builds={}", builds.get());
|
||||||
|
assert_eq!(builds.get(), 1);
|
||||||
|
// Includes backend prepare/upload and readback; still not native presentation.
|
||||||
|
if size.width == 1900. && zoom == 1. || size.width == 1440. && zoom == 0.5 {
|
||||||
|
for cached in [false, true] {
|
||||||
|
let mut ms = Vec::new();
|
||||||
|
for i in 0..10 {
|
||||||
|
r.reset(Rectangle::with_size(size));
|
||||||
|
let offset = Vector::new((i as f32 * 0.25).rem_euclid(step), 9.75);
|
||||||
|
let now = Instant::now();
|
||||||
|
let g = if cached {
|
||||||
|
phase(&r, &cache, size, step, &builds)
|
||||||
|
} else {
|
||||||
|
old(&r, size, step, offset)
|
||||||
|
};
|
||||||
|
if cached {
|
||||||
|
submit(&mut r, size, g, offset);
|
||||||
|
} else {
|
||||||
|
r.draw_geometry(g);
|
||||||
|
}
|
||||||
|
let pixels = black_box(shot(&mut r, size, 1.));
|
||||||
|
let elapsed = now.elapsed().as_secs_f64() * 1000.;
|
||||||
|
drop(pixels);
|
||||||
|
if i >= 2 {
|
||||||
|
ms.push(elapsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ms.sort_by(f64::total_cmp);
|
||||||
|
println!(
|
||||||
|
"cached={cached} construct_submit_screenshot changing_pan n=8 p50_ms={:.4} min_ms={:.4} max_ms={:.4}",
|
||||||
|
ms[4], ms[0], ms[7]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
//! Renderer-level phase translation experiment, not application code.
|
||||||
|
use iced::advanced::{
|
||||||
|
Renderer as _,
|
||||||
|
graphics::geometry::Renderer as _,
|
||||||
|
renderer::{Headless, Renderer as _},
|
||||||
|
};
|
||||||
|
use iced::{
|
||||||
|
Color, Point, Rectangle, Renderer, Size, Vector,
|
||||||
|
widget::canvas::{Cache, Frame, Geometry, Path},
|
||||||
|
};
|
||||||
|
use std::{cell::Cell, hint::black_box, time::Instant};
|
||||||
|
const BG: Color = Color::from_rgb8(246, 248, 251);
|
||||||
|
const DOT: Color = Color::from_rgb(0.86, 0.89, 0.91);
|
||||||
|
fn dots(f: &mut Frame, size: Size, step: f32, phase: Vector) {
|
||||||
|
for x in 0..(size.width / step) as i32 + 1 {
|
||||||
|
for y in 0..(size.height / step) as i32 + 1 {
|
||||||
|
f.fill(
|
||||||
|
&Path::circle(
|
||||||
|
Point::new(phase.x + x as f32 * step, phase.y + y as f32 * step),
|
||||||
|
0.65,
|
||||||
|
),
|
||||||
|
DOT,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn old(r: &Renderer, size: Size, step: f32, phase: Vector) -> Geometry {
|
||||||
|
let mut f = Frame::new(r, size);
|
||||||
|
f.fill_rectangle(Point::ORIGIN, size, BG);
|
||||||
|
dots(&mut f, size, step, phase);
|
||||||
|
f.into_geometry()
|
||||||
|
}
|
||||||
|
fn phase(r: &Renderer, cache: &Cache, size: Size, step: f32, builds: &Cell<usize>) -> Geometry {
|
||||||
|
cache.draw_with_bounds(
|
||||||
|
r,
|
||||||
|
Rectangle {
|
||||||
|
x: -1.,
|
||||||
|
y: -1.,
|
||||||
|
width: size.width + step + 2.,
|
||||||
|
height: size.height + step + 2.,
|
||||||
|
},
|
||||||
|
|f| {
|
||||||
|
builds.set(builds.get() + 1);
|
||||||
|
dots(f, size, step, Vector::ZERO);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn submit(r: &mut Renderer, size: Size, g: Geometry, pan: Vector) {
|
||||||
|
r.with_layer(Rectangle::with_size(size), |r| {
|
||||||
|
r.with_translation(pan, |r| r.draw_geometry(g))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fn shot(r: &mut Renderer, size: Size, scale: f32) -> Vec<u8> {
|
||||||
|
Headless::screenshot(
|
||||||
|
r,
|
||||||
|
Size::new(
|
||||||
|
(size.width * scale).ceil() as u32,
|
||||||
|
(size.height * scale).ceil() as u32,
|
||||||
|
),
|
||||||
|
scale,
|
||||||
|
BG,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
let rt = tokio::runtime::Builder::new_current_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
let mut r = rt
|
||||||
|
.block_on(<Renderer as Headless>::new(
|
||||||
|
iced::Font::DEFAULT,
|
||||||
|
16.into(),
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
println!(
|
||||||
|
"renderer={}; phase-cache prototype; NOT native FPS",
|
||||||
|
r.name()
|
||||||
|
);
|
||||||
|
for (size, zoom) in [
|
||||||
|
(Size::new(1900., 660.), 1.),
|
||||||
|
(Size::new(1900., 660.), 0.5),
|
||||||
|
(Size::new(1440., 900.), 1.),
|
||||||
|
(Size::new(1440., 900.), 0.5),
|
||||||
|
(Size::new(301.5, 211.25), 0.73),
|
||||||
|
] {
|
||||||
|
let step = (24f32 * zoom).max(14.);
|
||||||
|
let cache = Cache::new();
|
||||||
|
let builds = Cell::new(0);
|
||||||
|
println!(
|
||||||
|
"size={}x{} zoom={zoom} step={step}",
|
||||||
|
size.width, size.height
|
||||||
|
);
|
||||||
|
for scale in [1., 1.25, 2.] {
|
||||||
|
for pan in [
|
||||||
|
Vector::ZERO,
|
||||||
|
Vector::new(-13.25, 9.75),
|
||||||
|
Vector::new(6.125, -8.5),
|
||||||
|
Vector::new(step - 0.125, step - 0.25),
|
||||||
|
Vector::new(-0.125, 0.125),
|
||||||
|
] {
|
||||||
|
let offset = Vector::new(pan.x.rem_euclid(step), pan.y.rem_euclid(step));
|
||||||
|
r.reset(Rectangle::with_size(size));
|
||||||
|
let g = old(&r, size, step, offset);
|
||||||
|
r.draw_geometry(g);
|
||||||
|
let expected = shot(&mut r, size, scale);
|
||||||
|
r.reset(Rectangle::with_size(size));
|
||||||
|
let g = phase(&r, &cache, size, step, &builds);
|
||||||
|
submit(&mut r, size, g, offset);
|
||||||
|
let actual = shot(&mut r, size, scale);
|
||||||
|
assert_eq!(expected.len(), actual.len());
|
||||||
|
let changed = expected
|
||||||
|
.chunks_exact(4)
|
||||||
|
.zip(actual.chunks_exact(4))
|
||||||
|
.filter(|(a, b)| a != b)
|
||||||
|
.count();
|
||||||
|
let max = expected
|
||||||
|
.iter()
|
||||||
|
.zip(&actual)
|
||||||
|
.map(|(a, b)| a.abs_diff(*b))
|
||||||
|
.max()
|
||||||
|
.unwrap_or(0);
|
||||||
|
println!(
|
||||||
|
"scale={scale} pan={},{} changed_pixels={changed} max_channel_delta={max}",
|
||||||
|
pan.x, pan.y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(builds.get(), 1);
|
||||||
|
for cached in [false, true] {
|
||||||
|
let mut ms = Vec::new();
|
||||||
|
for i in 0..23 {
|
||||||
|
r.reset(Rectangle::with_size(size));
|
||||||
|
let offset = Vector::new((i as f32 * 0.25).rem_euclid(step), 9.75);
|
||||||
|
let now = Instant::now();
|
||||||
|
let g = if cached {
|
||||||
|
phase(&r, &cache, size, step, &builds)
|
||||||
|
} else {
|
||||||
|
old(&r, size, step, offset)
|
||||||
|
};
|
||||||
|
if cached {
|
||||||
|
submit(&mut r, size, g, offset)
|
||||||
|
} else {
|
||||||
|
r.draw_geometry(g)
|
||||||
|
};
|
||||||
|
let elapsed = black_box(now.elapsed().as_secs_f64() * 1000.);
|
||||||
|
if i >= 3 {
|
||||||
|
ms.push(elapsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ms.sort_by(f64::total_cmp);
|
||||||
|
println!(
|
||||||
|
"cached={cached} construct_and_submit changing_pan n=20 p50_ms={:.4} p95_ms={:.4} max_ms={:.4}",
|
||||||
|
ms[10], ms[19], ms[19]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
println!("cache_builds={}", builds.get());
|
||||||
|
assert_eq!(builds.get(), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,285 @@
|
|||||||
|
//! Full-sequence opaque phase replay with diagnostics and repeat controls; not application code.
|
||||||
|
use iced::advanced::{Renderer as _, graphics::geometry::Renderer as _, renderer::Headless};
|
||||||
|
use iced::{
|
||||||
|
Color, Point, Rectangle, Renderer, Size, Vector,
|
||||||
|
widget::canvas::{Cache, Frame, Geometry, Path},
|
||||||
|
};
|
||||||
|
use std::{cell::Cell, hint::black_box, time::Instant};
|
||||||
|
const BG: Color = Color::from_rgb8(246, 248, 251);
|
||||||
|
const DOT: Color = Color::from_rgb(0.86, 0.89, 0.91);
|
||||||
|
fn dots(f: &mut Frame, size: Size, step: f32, phase: Vector) {
|
||||||
|
for x in 0..(size.width / step) as i32 + 1 {
|
||||||
|
for y in 0..(size.height / step) as i32 + 1 {
|
||||||
|
f.fill(
|
||||||
|
&Path::circle(
|
||||||
|
Point::new(phase.x + x as f32 * step, phase.y + y as f32 * step),
|
||||||
|
0.65,
|
||||||
|
),
|
||||||
|
DOT,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn old(r: &Renderer, size: Size, step: f32, phase: Vector) -> Geometry {
|
||||||
|
let mut f = Frame::new(r, size);
|
||||||
|
f.fill_rectangle(Point::ORIGIN, size, BG);
|
||||||
|
dots(&mut f, size, step, phase);
|
||||||
|
f.into_geometry()
|
||||||
|
}
|
||||||
|
fn phase(r: &Renderer, cache: &Cache, size: Size, step: f32, builds: &Cell<usize>) -> Geometry {
|
||||||
|
cache.draw_with_bounds(
|
||||||
|
r,
|
||||||
|
Rectangle {
|
||||||
|
x: -step,
|
||||||
|
y: -step,
|
||||||
|
width: size.width + 3. * step,
|
||||||
|
height: size.height + 3. * step,
|
||||||
|
},
|
||||||
|
|f| {
|
||||||
|
builds.set(builds.get() + 1);
|
||||||
|
f.fill_rectangle(
|
||||||
|
Point::new(-step, -step),
|
||||||
|
Size::new(size.width + 3. * step, size.height + 3. * step),
|
||||||
|
BG,
|
||||||
|
);
|
||||||
|
dots(f, size, step, Vector::ZERO);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn submit(r: &mut Renderer, size: Size, g: Geometry, pan: Vector) {
|
||||||
|
r.with_layer(Rectangle::with_size(size), |r| {
|
||||||
|
r.with_translation(pan, |r| r.draw_geometry(g))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fn shot(r: &mut Renderer, size: Size, scale: f32) -> Vec<u8> {
|
||||||
|
Headless::screenshot(
|
||||||
|
r,
|
||||||
|
Size::new(
|
||||||
|
(size.width * scale).ceil() as u32,
|
||||||
|
(size.height * scale).ceil() as u32,
|
||||||
|
),
|
||||||
|
scale,
|
||||||
|
BG,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// Diagnostics only: this performs no rendering and does not mutate the renderer.
|
||||||
|
fn log_coordinates(expected: &[u8], actual: &[u8], size: Size, scale: f32) {
|
||||||
|
assert_eq!(expected.len(), actual.len());
|
||||||
|
let physical_width = (size.width * scale).ceil() as usize;
|
||||||
|
for (index, (a, b)) in expected
|
||||||
|
.as_chunks::<4>()
|
||||||
|
.0
|
||||||
|
.iter()
|
||||||
|
.zip(actual.as_chunks::<4>().0)
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_, (a, b))| a != b)
|
||||||
|
.take(20)
|
||||||
|
{
|
||||||
|
println!(
|
||||||
|
"difference_xy={},{} expected={a:?} actual={b:?}",
|
||||||
|
index % physical_width,
|
||||||
|
index / physical_width
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn report_control(label: &str, expected: &[u8], actual: &[u8], size: Size, scale: f32) {
|
||||||
|
assert_eq!(expected.len(), actual.len());
|
||||||
|
let changed = expected
|
||||||
|
.as_chunks::<4>()
|
||||||
|
.0
|
||||||
|
.iter()
|
||||||
|
.zip(actual.as_chunks::<4>().0)
|
||||||
|
.filter(|(a, b)| a != b)
|
||||||
|
.count();
|
||||||
|
let max = expected
|
||||||
|
.iter()
|
||||||
|
.zip(actual)
|
||||||
|
.map(|(a, b)| a.abs_diff(*b))
|
||||||
|
.max()
|
||||||
|
.unwrap_or(0);
|
||||||
|
println!(
|
||||||
|
"comparison={label} size={}x{} scale={scale} pan=-13.25,9.75 changed_pixels={changed} max_channel_delta={max}",
|
||||||
|
size.width, size.height
|
||||||
|
);
|
||||||
|
log_coordinates(expected, actual, size, scale);
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
let rt = tokio::runtime::Builder::new_current_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
let mut r = rt
|
||||||
|
.block_on(<Renderer as Headless>::new(
|
||||||
|
iced::Font::DEFAULT,
|
||||||
|
16.into(),
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
println!(
|
||||||
|
"renderer={}; phase-cache prototype; NOT native FPS",
|
||||||
|
r.name()
|
||||||
|
);
|
||||||
|
for (size, zoom) in [
|
||||||
|
(Size::new(1900., 660.), 1.),
|
||||||
|
(Size::new(1900., 660.), 0.5),
|
||||||
|
(Size::new(1440., 900.), 1.),
|
||||||
|
(Size::new(1440., 900.), 0.5),
|
||||||
|
(Size::new(301.5, 211.25), 0.73),
|
||||||
|
] {
|
||||||
|
let step = (24f32 * zoom).max(14.);
|
||||||
|
let cache = Cache::new();
|
||||||
|
let builds = Cell::new(0);
|
||||||
|
println!(
|
||||||
|
"size={}x{} zoom={zoom} step={step}",
|
||||||
|
size.width, size.height
|
||||||
|
);
|
||||||
|
for scale in [1., 1.25, 2.] {
|
||||||
|
for pan in [
|
||||||
|
Vector::ZERO,
|
||||||
|
Vector::new(-13.25, 9.75),
|
||||||
|
Vector::new(6.125, -8.5),
|
||||||
|
Vector::new(step - 0.125, step - 0.25),
|
||||||
|
Vector::new(-0.125, 0.125),
|
||||||
|
] {
|
||||||
|
let offset = Vector::new(pan.x.rem_euclid(step), pan.y.rem_euclid(step));
|
||||||
|
r.reset(Rectangle::with_size(size));
|
||||||
|
let g = old(&r, size, step, offset);
|
||||||
|
r.draw_geometry(g);
|
||||||
|
let expected = shot(&mut r, size, scale);
|
||||||
|
r.reset(Rectangle::with_size(size));
|
||||||
|
let g = phase(&r, &cache, size, step, &builds);
|
||||||
|
submit(&mut r, size, g, offset);
|
||||||
|
let actual = shot(&mut r, size, scale);
|
||||||
|
assert_eq!(expected.len(), actual.len());
|
||||||
|
let changed = expected
|
||||||
|
.chunks_exact(4)
|
||||||
|
.zip(actual.chunks_exact(4))
|
||||||
|
.filter(|(a, b)| a != b)
|
||||||
|
.count();
|
||||||
|
let max = expected
|
||||||
|
.iter()
|
||||||
|
.zip(&actual)
|
||||||
|
.map(|(a, b)| a.abs_diff(*b))
|
||||||
|
.max()
|
||||||
|
.unwrap_or(0);
|
||||||
|
println!(
|
||||||
|
"scale={scale} pan={},{} changed_pixels={changed} max_channel_delta={max}",
|
||||||
|
pan.x, pan.y
|
||||||
|
);
|
||||||
|
// Keep the original render/timing sequence; print diagnostics only.
|
||||||
|
log_coordinates(&expected, &actual, size, scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(builds.get(), 1);
|
||||||
|
for cached in [false, true] {
|
||||||
|
let mut ms = Vec::new();
|
||||||
|
for i in 0..23 {
|
||||||
|
r.reset(Rectangle::with_size(size));
|
||||||
|
let offset = Vector::new((i as f32 * 0.25).rem_euclid(step), 9.75);
|
||||||
|
let now = Instant::now();
|
||||||
|
let g = if cached {
|
||||||
|
phase(&r, &cache, size, step, &builds)
|
||||||
|
} else {
|
||||||
|
old(&r, size, step, offset)
|
||||||
|
};
|
||||||
|
if cached {
|
||||||
|
submit(&mut r, size, g, offset)
|
||||||
|
} else {
|
||||||
|
r.draw_geometry(g)
|
||||||
|
};
|
||||||
|
let elapsed = black_box(now.elapsed().as_secs_f64() * 1000.);
|
||||||
|
if i >= 3 {
|
||||||
|
ms.push(elapsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ms.sort_by(f64::total_cmp);
|
||||||
|
println!(
|
||||||
|
"cached={cached} construct_and_submit changing_pan n=20 p50_ms={:.4} p95_ms={:.4} max_ms={:.4}",
|
||||||
|
ms[10], ms[19], ms[19]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
println!("cache_builds={}", builds.get());
|
||||||
|
assert_eq!(builds.get(), 1);
|
||||||
|
// Includes backend prepare/upload and readback; still not native presentation.
|
||||||
|
if size.width == 1900. && zoom == 1. || size.width == 1440. && zoom == 0.5 {
|
||||||
|
for cached in [false, true] {
|
||||||
|
let mut ms = Vec::new();
|
||||||
|
for i in 0..10 {
|
||||||
|
r.reset(Rectangle::with_size(size));
|
||||||
|
let offset = Vector::new((i as f32 * 0.25).rem_euclid(step), 9.75);
|
||||||
|
let now = Instant::now();
|
||||||
|
let g = if cached {
|
||||||
|
phase(&r, &cache, size, step, &builds)
|
||||||
|
} else {
|
||||||
|
old(&r, size, step, offset)
|
||||||
|
};
|
||||||
|
if cached {
|
||||||
|
submit(&mut r, size, g, offset);
|
||||||
|
} else {
|
||||||
|
r.draw_geometry(g);
|
||||||
|
}
|
||||||
|
let pixels = black_box(shot(&mut r, size, 1.));
|
||||||
|
let elapsed = now.elapsed().as_secs_f64() * 1000.;
|
||||||
|
drop(pixels);
|
||||||
|
if i >= 2 {
|
||||||
|
ms.push(elapsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ms.sort_by(f64::total_cmp);
|
||||||
|
println!(
|
||||||
|
"cached={cached} construct_submit_screenshot changing_pan n=8 p50_ms={:.4} min_ms={:.4} max_ms={:.4}",
|
||||||
|
ms[4], ms[0], ms[7]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// All original cases, timings and screenshots have completed above.
|
||||||
|
// Reuse the same renderer for controls. This cache is newly constructed,
|
||||||
|
// then retained across all control repetitions; original per-case caches
|
||||||
|
// have already gone out of scope, exactly as in the opaque probe.
|
||||||
|
println!("original_sequence_complete; beginning same-renderer repeat controls");
|
||||||
|
let size = Size::new(301.5, 211.25);
|
||||||
|
let step = (24f32 * 0.73).max(14.);
|
||||||
|
let pan: Vector<f32> = Vector::new(-13.25, 9.75);
|
||||||
|
let offset = Vector::new(pan.x.rem_euclid(step), pan.y.rem_euclid(step));
|
||||||
|
let cache = Cache::new();
|
||||||
|
let builds = Cell::new(0);
|
||||||
|
for repetition in 1..=3 {
|
||||||
|
for scale in [1., 2.] {
|
||||||
|
r.reset(Rectangle::with_size(size));
|
||||||
|
let g = old(&r, size, step, offset);
|
||||||
|
r.draw_geometry(g);
|
||||||
|
let first = shot(&mut r, size, scale);
|
||||||
|
r.reset(Rectangle::with_size(size));
|
||||||
|
let g = old(&r, size, step, offset);
|
||||||
|
r.draw_geometry(g);
|
||||||
|
let second = shot(&mut r, size, scale);
|
||||||
|
report_control(
|
||||||
|
&format!("old/old repetition={repetition}"),
|
||||||
|
&first,
|
||||||
|
&second,
|
||||||
|
size,
|
||||||
|
scale,
|
||||||
|
);
|
||||||
|
|
||||||
|
r.reset(Rectangle::with_size(size));
|
||||||
|
let g = phase(&r, &cache, size, step, &builds);
|
||||||
|
submit(&mut r, size, g, offset);
|
||||||
|
let first = shot(&mut r, size, scale);
|
||||||
|
r.reset(Rectangle::with_size(size));
|
||||||
|
let g = phase(&r, &cache, size, step, &builds);
|
||||||
|
submit(&mut r, size, g, offset);
|
||||||
|
let second = shot(&mut r, size, scale);
|
||||||
|
report_control(
|
||||||
|
&format!("cached/cached repetition={repetition}"),
|
||||||
|
&first,
|
||||||
|
&second,
|
||||||
|
size,
|
||||||
|
scale,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("control_cache_builds={}", builds.get());
|
||||||
|
assert_eq!(builds.get(), 1);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user