Commit 9154b90
3
files
+118
added
-9
deleted
@@ -44,6 +44,8 @@ fn main() -> Result<(), Box<dyn Error>> {
44
44
let mut timer = 0.0f64;
45
45
// Lista okien z kompozytora (foreign-toplevel) — własne połączenie + wątek.
46
46
let toplevels = luna::toplevels::Toplevels::spawn();
47
+ // Sygnatura stanu — przerysowujemy tylko, gdy coś się zmieniło.
48
+ let mut last_sig: (bool, String, u64) = (false, String::new(), u64::MAX);
47
49
48
50
run(cfg, move |frame: &mut Frame| {
49
51
let dt = frame.delta_time();
@@ -206,7 +208,20 @@ fn main() -> Result<(), Box<dyn Error>> {
206
208
Rect::from_xywh(0.0, THICKNESS + 8.0, size.width, size.height - THICKNESS),
207
209
);
208
210
209
- frame.request_frame();
211
+ // Przerysowujemy tylko, gdy coś się zmieniło — inaczej powłoka nie commituje
212
+ // bufora 1920x680 przy każdej klatce (mniej pracy dla kompozytora i CPU).
213
+ let mut th: u64 = state.tasks.len() as u64;
214
+ for t in &state.tasks {
215
+ th = th
216
+ .wrapping_mul(1_099_511_628_211)
217
+ .wrapping_add(u64::from(t.active) ^ t.title.len() as u64);
218
+ }
219
+ let sig = (open, state.clock.clone(), th);
220
+ let animating = osd.visible() || notes.visible();
221
+ if !frame.events.is_empty() || animating || open || sig != last_sig {
222
+ frame.request_frame();
223
+ }
224
+ last_sig = sig;
210
225
})
211
226
}
212
227
@@ -58,6 +58,11 @@ impl Notifications {
58
58
Self::default()
59
59
}
60
60
61
+ /// Czy stos powiadomień nie jest pusty (potrzebna animacja/przerysowanie).
62
+ pub fn visible(&self) -> bool {
63
+ !self.items.is_empty()
64
+ }
65
+
61
66
/// Dodaje powiadomienie na wierzch stosu.
62
67
pub fn push(&mut self, n: Notification) {
63
68
self.items.push((n, 0.0));
@@ -139,11 +139,21 @@ pub fn spawn_drm(model: WindowModel, cursor: CursorModel) {
139
139
let mut frames = 0u64;
140
140
let (mut ms_render, mut ms_present, mut ms_wait) = (0.0f64, 0.0f64, 0.0f64);
141
141
let mut report = std::time::Instant::now();
142
+ let mut last_sig: Option<u64> = None;
142
143
loop {
144
+ // Przerysowujemy tylko, gdy coś się zmieniło (okna albo kursor). Inaczej
145
+ // śpimy — mniej CPU i brak zbędnych page-flipów, przy płynnym kursorze.
146
+ let cur = *cursor.lock_or_recover();
147
+ let sig = scene_signature(&model, cur);
148
+ if last_sig == Some(sig) {
149
+ std::thread::sleep(Duration::from_millis(4));
150
+ continue;
151
+ }
152
+ last_sig = Some(sig);
153
+
143
154
for i in 0..sizes.len() {
144
155
let (w, h) = sizes[i];
145
156
let (ox, oy) = origins[i];
146
- let cur = *cursor.lock_or_recover();
147
157
148
158
let t = std::time::Instant::now();
149
159
let mut scene = Scene::new();
@@ -159,7 +169,8 @@ pub fn spawn_drm(model: WindowModel, cursor: CursorModel) {
159
169
ms_render += t.elapsed().as_secs_f64() * 1000.0;
160
170
161
171
let t = std::time::Instant::now();
162
- if !backend.present(i, renderers[i].data()) && !flip_error_logged {
172
+ let flipped = backend.present(i, renderers[i].data());
173
+ if !flipped && !flip_error_logged {
163
174
eprintln!(
164
175
"{}",
165
176
libluna_i18n::tr("DRM page-flip failed (screen may stay blank)")
@@ -168,14 +179,15 @@ pub fn spawn_drm(model: WindowModel, cursor: CursorModel) {
168
179
}
169
180
ms_present += t.elapsed().as_secs_f64() * 1000.0;
170
181
171
- let t = std::time::Instant::now();
172
- backend.wait_flip();
173
- ms_wait += t.elapsed().as_secs_f64() * 1000.0;
182
+ // Czekamy na flip tylko, gdy został zakolejkowany (inaczej `read`
183
+ // mógłby zablokować się na zawsze).
184
+ if flipped {
185
+ let t = std::time::Instant::now();
186
+ backend.wait_flip();
187
+ ms_wait += t.elapsed().as_secs_f64() * 1000.0;
188
+ }
174
189
}
175
- // `wait_flip` i tak synchronizuje z vblankiem, więc nie dosypujemy snu
176
- // (wcześniejsze 16 ms samo ograniczało do ~20 fps).
177
190
frames += 1;
178
-
179
191
if stats && report.elapsed().as_secs_f64() >= 2.0 {
180
192
let secs = report.elapsed().as_secs_f64();
181
193
let per_frame = (frames * sizes.len() as u64).max(1) as f64;
@@ -196,6 +208,33 @@ pub fn spawn_drm(model: WindowModel, cursor: CursorModel) {
196
208
});
197
209
}
198
210
211
+/// Sygnatura sceny (okna + kursor) — do wykrywania, że nic się nie zmieniło.
212
+fn scene_signature(model: &WindowModel, cursor: Option<Point>) -> u64 {
213
+ let mut h: u64 = 0xcbf2_9ce4_8422_2325;
214
+ let mut mix = |v: u64| {
215
+ h ^= v;
216
+ h = h.wrapping_mul(0x0000_0100_0000_01b3);
217
+ };
218
+ {
219
+ let windows = model.lock_or_recover();
220
+ mix(windows.len() as u64);
221
+ for w in windows.iter() {
222
+ mix(w.x.to_bits());
223
+ mix(w.y.to_bits());
224
+ mix(w.z as u64);
225
+ mix(w.width as u64);
226
+ mix(w.height as u64);
227
+ mix(u64::from(w.mapped) | (u64::from(w.minimized) << 1) | (u64::from(w.layer) << 2));
228
+ mix(std::sync::Arc::as_ptr(&w.data) as u64);
229
+ }
230
+ }
231
+ if let Some(c) = cursor {
232
+ mix(c.x.to_bits());
233
+ mix(c.y.to_bits());
234
+ }
235
+ h
236
+}
237
+
199
238
/// Buduje scenę okien w rozmiarze wyjścia, przesuniętą o `(ox, oy)` (origin monitora).
200
239
fn build_scene(
201
240
scene: &mut Scene,
@@ -357,4 +396,54 @@ mod tests {
357
396
t.elapsed().as_secs_f64() * 1000.0 / n as f64
358
397
);
359
398
}
399
+
400
+ #[test]
401
+ #[ignore = "benchmark reczny"]
402
+ fn bench_1080p_with_panel() {
403
+ use std::sync::{Arc, Mutex};
404
+ use std::time::Instant;
405
+ let data = Arc::new(libluna_render::ImageData::new(
406
+ 1920,
407
+ 680,
408
+ vec![128u8; 1920 * 680 * 4],
409
+ ));
410
+ let windows = vec![Window {
411
+ x: 0.0,
412
+ y: 0.0,
413
+ width: 1920,
414
+ height: 680,
415
+ z: 1_000_000,
416
+ title: String::new(),
417
+ popup: false,
418
+ layer: true,
419
+ mapped: true,
420
+ minimized: false,
421
+ maximized: false,
422
+ fullscreen: false,
423
+ saved: None,
424
+ data,
425
+ }];
426
+ let model: WindowModel = Arc::new(Mutex::new(windows));
427
+ let bg = Color::from_rgba8(0x1e, 0x20, 0x28, 0xff);
428
+ let mut renderer = SoftwareRenderer::new(1920, 1080);
429
+ let n = 20;
430
+ // Sam render sceny:
431
+ let t = Instant::now();
432
+ for _ in 0..n {
433
+ let mut scene = Scene::new();
434
+ build_scene(
435
+ &mut scene,
436
+ Size::new(1920.0, 1080.0),
437
+ 0.0,
438
+ 0.0,
439
+ &model,
440
+ Some(Point::new(100.0, 100.0)),
441
+ );
442
+ renderer.draw(&scene, 1.0, bg);
443
+ }
444
+ println!(
445
+ "render 1080p + panel 1920x680: {:.2} ms/klatke",
446
+ t.elapsed().as_secs_f64() * 1000.0 / n as f64
447
+ );
448
+ }
360
449
}