Source code

Revision control

Other Tools

1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
* License, v. 2.0. If a copy of the MPL was not distributed with this
3
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
use api::{ColorF, ColorU};
6
use crate::debug_render::DebugRenderer;
7
use crate::device::query::{GpuSampler, GpuTimer, NamedTag};
8
use euclid::{Point2D, Rect, Size2D, vec2, default};
9
use crate::internal_types::FastHashMap;
10
use crate::renderer::{MAX_VERTEX_TEXTURE_WIDTH, wr_has_been_initialized};
11
use std::collections::vec_deque::VecDeque;
12
use std::{f32, mem};
13
use std::ffi::CStr;
14
use std::ops::Range;
15
use std::time::Duration;
16
use time::precise_time_ns;
17
18
pub mod expected {
19
use std::ops::Range;
20
pub const AVG_BACKEND_CPU_TIME: Range<f64> = 0.0..3.0;
21
pub const MAX_BACKEND_CPU_TIME: Range<f64> = 0.0..6.0;
22
pub const AVG_RENDERER_CPU_TIME: Range<f64> = 0.0..5.0;
23
pub const MAX_RENDERER_CPU_TIME: Range<f64> = 0.0..10.0;
24
pub const AVG_IPC_TIME: Range<f64> = 0.0..2.0;
25
pub const MAX_IPC_TIME: Range<f64> = 0.0..4.0;
26
pub const AVG_GPU_TIME: Range<f64> = 0.0..8.0;
27
pub const MAX_GPU_TIME: Range<f64> = 0.0..15.0;
28
pub const DRAW_CALLS: Range<u64> = 1..100;
29
pub const VERTICES: Range<u64> = 10..25_000;
30
pub const TOTAL_PRIMITIVES: Range<u64> = 1..5000;
31
pub const VISIBLE_PRIMITIVES: Range<u64> = 1..5000;
32
pub const USED_TARGETS: Range<u64> = 1..4;
33
pub const COLOR_PASSES: Range<u64> = 1..4;
34
pub const ALPHA_PASSES: Range<u64> = 0..3;
35
pub const RENDERED_PICTURE_CACHE_TILES: Range<u64> = 0..5;
36
pub const TOTAL_PICTURE_CACHE_TILES: Range<u64> = 0..15;
37
pub const CREATED_TARGETS: Range<u64> = 0..3;
38
pub const CHANGED_TARGETS: Range<u64> = 0..3;
39
pub const TEXTURE_DATA_UPLOADED: Range<u64> = 0..10;
40
pub const GPU_CACHE_ROWS_TOTAL: Range<u64> = 1..50;
41
pub const GPU_CACHE_ROWS_UPDATED: Range<u64> = 0..25;
42
pub const GPU_CACHE_BLOCKS_TOTAL: Range<u64> = 1..65_000;
43
pub const GPU_CACHE_BLOCKS_UPDATED: Range<u64> = 0..1000;
44
pub const GPU_CACHE_BLOCKS_SAVED: Range<u64> = 0..50_000;
45
pub const DISPLAY_LIST_BUILD_TIME: Range<f64> = 0.0..3.0;
46
pub const MAX_SCENE_BUILD_TIME: Range<f64> = 0.0..3.0;
47
pub const DISPLAY_LIST_SEND_TIME: Range<f64> = 0.0..1.0;
48
pub const DISPLAY_LIST_TOTAL_TIME: Range<f64> = 0.0..4.0;
49
pub const NUM_FONT_TEMPLATES: Range<usize> = 0..50;
50
pub const FONT_TEMPLATES_MB: Range<f32> = 0.0..40.0;
51
pub const NUM_IMAGE_TEMPLATES: Range<usize> = 0..20;
52
pub const IMAGE_TEMPLATES_MB: Range<f32> = 0.0..10.0;
53
pub const DISPLAY_LIST_MB: Range<f32> = 0.0..0.2;
54
pub const NUM_RASTERIZED_BLOBS: Range<usize> = 0..25; // in tiles
55
pub const RASTERIZED_BLOBS_MB: Range<f32> = 0.0..4.0;
56
}
57
58
const GRAPH_WIDTH: f32 = 1024.0;
59
const GRAPH_HEIGHT: f32 = 320.0;
60
const GRAPH_PADDING: f32 = 8.0;
61
const GRAPH_FRAME_HEIGHT: f32 = 16.0;
62
const PROFILE_PADDING: f32 = 8.0;
63
64
const ONE_SECOND_NS: u64 = 1000000000;
65
const AVERAGE_OVER_NS: u64 = ONE_SECOND_NS / 2;
66
67
#[derive(Copy, Clone, Debug, PartialEq)]
68
pub enum ProfileStyle {
69
Full,
70
Compact,
71
Smart,
72
}
73
74
/// Defines the interface for hooking up an external profiler to WR.
75
pub trait ProfilerHooks : Send + Sync {
76
/// Called at the beginning of a profile scope. The label must
77
/// be a C string (null terminated).
78
fn begin_marker(&self, label: &CStr);
79
80
/// Called at the end of a profile scope. The label must
81
/// be a C string (null terminated).
82
fn end_marker(&self, label: &CStr);
83
84
/// Called to mark an event happening. The label must
85
/// be a C string (null terminated).
86
fn event_marker(&self, label: &CStr);
87
88
/// Called with a duration to indicate a text marker that just ended. Text
89
/// markers allow different types of entries to be recorded on the same row
90
/// in the timeline, by adding labels to the entry.
91
///
92
/// This variant is also useful when the caller only wants to record events
93
/// longer than a certain threshold, and thus they don't know in advance
94
/// whether the event will qualify.
95
fn add_text_marker(&self, label: &CStr, text: &str, duration: Duration);
96
97
/// Returns true if the current thread is being profiled.
98
fn thread_is_being_profiled(&self) -> bool;
99
}
100
101
/// The current global profiler callbacks, if set by embedder.
102
pub static mut PROFILER_HOOKS: Option<&'static dyn ProfilerHooks> = None;
103
104
/// Set the profiler callbacks, or None to disable the profiler.
105
/// This function must only ever be called before any WR instances
106
/// have been created, or the hooks will not be set.
107
pub fn set_profiler_hooks(hooks: Option<&'static dyn ProfilerHooks>) {
108
if !wr_has_been_initialized() {
109
unsafe {
110
PROFILER_HOOKS = hooks;
111
}
112
}
113
}
114
115
/// A simple RAII style struct to manage a profile scope.
116
pub struct ProfileScope {
117
name: &'static CStr,
118
}
119
120
/// Records a marker of the given duration that just ended.
121
pub fn add_text_marker(label: &CStr, text: &str, duration: Duration) {
122
unsafe {
123
if let Some(ref hooks) = PROFILER_HOOKS {
124
hooks.add_text_marker(label, text, duration);
125
}
126
}
127
}
128
129
/// Records a marker of the given duration that just ended.
130
pub fn add_event_marker(label: &CStr) {
131
unsafe {
132
if let Some(ref hooks) = PROFILER_HOOKS {
133
hooks.event_marker(label);
134
}
135
}
136
}
137
138
/// Returns true if the current thread is being profiled.
139
pub fn thread_is_being_profiled() -> bool {
140
unsafe {
141
PROFILER_HOOKS.map_or(false, |h| h.thread_is_being_profiled())
142
}
143
}
144
145
impl ProfileScope {
146
/// Begin a new profile scope
147
pub fn new(name: &'static CStr) -> Self {
148
unsafe {
149
if let Some(ref hooks) = PROFILER_HOOKS {
150
hooks.begin_marker(name);
151
}
152
}
153
154
ProfileScope {
155
name,
156
}
157
}
158
}
159
160
impl Drop for ProfileScope {
161
fn drop(&mut self) {
162
unsafe {
163
if let Some(ref hooks) = PROFILER_HOOKS {
164
hooks.end_marker(self.name);
165
}
166
}
167
}
168
}
169
170
/// A helper macro to define profile scopes.
171
macro_rules! profile_marker {
172
($string:expr) => {
173
let _scope = $crate::profiler::ProfileScope::new(cstr!($string));
174
};
175
}
176
177
#[derive(Debug, Clone)]
178
pub struct GpuProfileTag {
179
pub label: &'static str,
180
pub color: ColorF,
181
}
182
183
impl NamedTag for GpuProfileTag {
184
fn get_label(&self) -> &str {
185
self.label
186
}
187
}
188
189
trait ProfileCounter {
190
fn description(&self) -> &'static str;
191
fn value(&self) -> String;
192
fn is_expected(&self) -> bool;
193
}
194
195
#[derive(Clone)]
196
pub struct IntProfileCounter {
197
description: &'static str,
198
value: usize,
199
expect: Option<Range<u64>>,
200
}
201
202
impl IntProfileCounter {
203
fn new(description: &'static str, expect: Option<Range<u64>>) -> Self {
204
IntProfileCounter {
205
description,
206
value: 0,
207
expect,
208
}
209
}
210
211
#[inline(always)]
212
pub fn inc(&mut self) {
213
self.value += 1;
214
}
215
216
pub fn set(&mut self, value: usize) {
217
self.value = value;
218
}
219
}
220
221
impl ProfileCounter for IntProfileCounter {
222
fn description(&self) -> &'static str {
223
self.description
224
}
225
226
fn value(&self) -> String {
227
format!("{}", self.value)
228
}
229
230
fn is_expected(&self) -> bool {
231
self.expect.as_ref().map(|range| range.contains(&(self.value as u64))).unwrap_or(true)
232
}
233
}
234
235
/// A profile counter recording average and maximum integer values over time slices
236
/// of half a second.
237
#[derive(Clone)]
238
pub struct AverageIntProfileCounter {
239
description: &'static str,
240
/// Start of the current time slice.
241
start_ns: u64,
242
/// Sum of the values recorded during the current time slice.
243
sum: u64,
244
/// Number of samples in the current time slice.
245
num_samples: u64,
246
/// The max value in in-progress time slice.
247
next_max: u64,
248
/// The max value of the previous time slice (displayed).
249
max: u64,
250
/// The average value of the previous time slice (displayed).
251
avg: u64,
252
/// Intermediate accumulator for `add` and `inc`.
253
accum: u64,
254
/// Expected average range of values, if any.
255
expect_avg: Option<Range<u64>>,
256
/// Expected maximum range of values, if any.
257
expect_max: Option<Range<u64>>,
258
}
259
260
impl AverageIntProfileCounter {
261
pub fn new(
262
description: &'static str,
263
expect_avg: Option<Range<u64>>,
264
expect_max: Option<Range<u64>>,
265
) -> Self {
266
AverageIntProfileCounter {
267
description,
268
start_ns: precise_time_ns(),
269
sum: 0,
270
num_samples: 0,
271
next_max: 0,
272
max: 0,
273
avg: 0,
274
accum: 0,
275
expect_avg,
276
expect_max,
277
}
278
}
279
280
pub fn reset(&mut self) {
281
if self.accum > 0 {
282
self.set_u64(self.accum);
283
self.accum = 0;
284
}
285
}
286
287
pub fn set(&mut self, val: usize) {
288
self.set_u64(val as u64);
289
}
290
291
pub fn set_u64(&mut self, val: u64) {
292
let now = precise_time_ns();
293
if (now - self.start_ns) > AVERAGE_OVER_NS && self.num_samples > 0 {
294
self.avg = self.sum / self.num_samples;
295
self.max = self.next_max;
296
self.start_ns = now;
297
self.sum = 0;
298
self.num_samples = 0;
299
self.next_max = 0;
300
}
301
self.next_max = self.next_max.max(val);
302
self.sum += val;
303
self.num_samples += 1;
304
self.accum = 0;
305
}
306
307
pub fn add(&mut self, val: usize) {
308
self.accum += val as u64;
309
}
310
311
pub fn inc(&mut self) {
312
self.accum += 1;
313
}
314
315
/// Returns either the most up to date value if the counter is updated
316
/// with add add inc, or the average over the previous time slice.
317
pub fn get(&self) -> usize {
318
let result = if self.accum != 0 {
319
self.accum
320
} else {
321
self.avg
322
};
323
324
result as usize
325
}
326
}
327
328
impl ProfileCounter for AverageIntProfileCounter {
329
fn description(&self) -> &'static str {
330
self.description
331
}
332
333
fn value(&self) -> String {
334
format!("{:.2} (max {:.2})", self.avg, self.max)
335
}
336
337
fn is_expected(&self) -> bool {
338
self.expect_avg.as_ref().map(|range| range.contains(&self.avg)).unwrap_or(true)
339
&& self.expect_max.as_ref().map(|range| range.contains(&self.max)).unwrap_or(true)
340
}
341
}
342
343
pub struct PercentageProfileCounter {
344
description: &'static str,
345
value: f32,
346
}
347
348
impl ProfileCounter for PercentageProfileCounter {
349
fn description(&self) -> &'static str {
350
self.description
351
}
352
353
fn value(&self) -> String {
354
format!("{:.2}%", self.value * 100.0)
355
}
356
357
fn is_expected(&self) -> bool { true }
358
}
359
360
#[derive(Clone)]
361
pub struct ResourceProfileCounter {
362
description: &'static str,
363
value: usize,
364
// in bytes.
365
size: usize,
366
expected_count: Option<Range<usize>>,
367
// in MB
368
expected_size: Option<Range<f32>>,
369
}
370
371
impl ResourceProfileCounter {
372
fn new(
373
description: &'static str,
374
expected_count: Option<Range<usize>>,
375
expected_size: Option<Range<f32>>
376
) -> Self {
377
ResourceProfileCounter {
378
description,
379
value: 0,
380
size: 0,
381
expected_count,
382
expected_size,
383
}
384
}
385
386
#[allow(dead_code)]
387
fn reset(&mut self) {
388
self.value = 0;
389
self.size = 0;
390
}
391
392
#[inline(always)]
393
pub fn inc(&mut self, size: usize) {
394
self.value += 1;
395
self.size += size;
396
}
397
398
pub fn set(&mut self, count: usize, size: usize) {
399
self.value = count;
400
self.size = size;
401
}
402
403
pub fn size_mb(&self) -> f32 {
404
self.size as f32 / (1024.0 * 1024.0)
405
}
406
}
407
408
impl ProfileCounter for ResourceProfileCounter {
409
fn description(&self) -> &'static str {
410
self.description
411
}
412
413
fn value(&self) -> String {
414
format!("{} ({:.2} MB)", self.value, self.size_mb())
415
}
416
417
fn is_expected(&self) -> bool {
418
self.expected_count.as_ref().map(|range| range.contains(&self.value)).unwrap_or(true)
419
&& self.expected_size.as_ref().map(|range| range.contains(&self.size_mb())).unwrap_or(true)
420
}
421
}
422
423
#[derive(Clone)]
424
pub struct TimeProfileCounter {
425
description: &'static str,
426
nanoseconds: u64,
427
invert: bool,
428
expect_ms: Option<Range<f64>>,
429
}
430
431
pub struct Timer<'a> {
432
start: u64,
433
result: &'a mut u64,
434
}
435
436
impl<'a> Drop for Timer<'a> {
437
fn drop(&mut self) {
438
let end = precise_time_ns();
439
*self.result += end - self.start;
440
}
441
}
442
443
impl TimeProfileCounter {
444
pub fn new(description: &'static str, invert: bool, expect_ms: Option<Range<f64>>) -> Self {
445
TimeProfileCounter {
446
description,
447
nanoseconds: 0,
448
invert,
449
expect_ms,
450
}
451
}
452
453
fn reset(&mut self) {
454
self.nanoseconds = 0;
455
}
456
457
#[allow(dead_code)]
458
pub fn set(&mut self, ns: u64) {
459
self.nanoseconds = ns;
460
}
461
462
pub fn profile<T, F>(&mut self, callback: F) -> T
463
where
464
F: FnOnce() -> T,
465
{
466
let t0 = precise_time_ns();
467
let val = callback();
468
let t1 = precise_time_ns();
469
let ns = t1 - t0;
470
self.nanoseconds += ns;
471
val
472
}
473
474
pub fn timer(&mut self) -> Timer {
475
Timer {
476
start: precise_time_ns(),
477
result: &mut self.nanoseconds,
478
}
479
}
480
481
pub fn inc(&mut self, ns: u64) {
482
self.nanoseconds += ns;
483
}
484
485
pub fn get(&self) -> u64 {
486
self.nanoseconds
487
}
488
489
pub fn get_ms(&self) -> f64 {
490
self.nanoseconds as f64 / 1000000.0
491
}
492
}
493
494
impl ProfileCounter for TimeProfileCounter {
495
fn description(&self) -> &'static str {
496
self.description
497
}
498
499
fn value(&self) -> String {
500
if self.invert {
501
format!("{:.2} fps", 1000000000.0 / self.nanoseconds as f64)
502
} else {
503
format!("{:.2} ms", self.get_ms())
504
}
505
}
506
507
fn is_expected(&self) -> bool {
508
self.expect_ms.as_ref()
509
.map(|range| range.contains(&(self.nanoseconds as f64 / 1000000.0)))
510
.unwrap_or(true)
511
}
512
}
513
514
#[derive(Clone)]
515
pub struct AverageTimeProfileCounter {
516
counter: AverageIntProfileCounter,
517
invert: bool,
518
}
519
520
impl AverageTimeProfileCounter {
521
pub fn new(
522
description: &'static str,
523
invert: bool,
524
expect_avg: Option<Range<f64>>,
525
expect_max: Option<Range<f64>>,
526
) -> Self {
527
let expect_avg_ns = expect_avg.map(
528
|range| (range.start * 1000000.0) as u64 .. (range.end * 1000000.0) as u64
529
);
530
let expect_max_ns = expect_max.map(
531
|range| (range.start * 1000000.0) as u64 .. (range.end * 1000000.0) as u64
532
);
533
534
AverageTimeProfileCounter {
535
counter: AverageIntProfileCounter::new(
536
description,
537
expect_avg_ns,
538
expect_max_ns,
539
),
540
invert,
541
}
542
}
543
544
pub fn set(&mut self, ns: u64) {
545
self.counter.set_u64(ns);
546
}
547
548
#[allow(dead_code)]
549
pub fn profile<T, F>(&mut self, callback: F) -> T
550
where
551
F: FnOnce() -> T,
552
{
553
let t0 = precise_time_ns();
554
let val = callback();
555
let t1 = precise_time_ns();
556
self.counter.set_u64(t1 - t0);
557
val
558
}
559
560
pub fn avg_ms(&self) -> f64 { self.counter.avg as f64 / 1000000.0 }
561
562
pub fn max_ms(&self) -> f64 { self.counter.max as f64 / 1000000.0 }
563
}
564
565
impl ProfileCounter for AverageTimeProfileCounter {
566
fn description(&self) -> &'static str {
567
self.counter.description
568
}
569
570
fn value(&self) -> String {
571
if self.invert {
572
format!("{:.2} fps", 1000000000.0 / self.counter.avg as f64)
573
} else {
574
format!("{:.2} ms (max {:.2} ms)", self.avg_ms(), self.max_ms())
575
}
576
}
577
578
fn is_expected(&self) -> bool {
579
self.counter.is_expected()
580
}
581
}
582
583
584
#[derive(Clone)]
585
pub struct FrameProfileCounters {
586
pub total_primitives: AverageIntProfileCounter,
587
pub visible_primitives: AverageIntProfileCounter,
588
pub targets_used: AverageIntProfileCounter,
589
pub targets_changed: AverageIntProfileCounter,
590
pub targets_created: AverageIntProfileCounter,
591
}
592
593
impl FrameProfileCounters {
594
pub fn new() -> Self {
595
FrameProfileCounters {
596
total_primitives: AverageIntProfileCounter::new(
597
"Total Primitives",
598
None, Some(expected::TOTAL_PRIMITIVES),
599
),
600
visible_primitives: AverageIntProfileCounter::new(
601
"Visible Primitives",
602
None, Some(expected::VISIBLE_PRIMITIVES),
603
),
604
targets_used: AverageIntProfileCounter::new(
605
"Used targets",
606
None, Some(expected::USED_TARGETS),
607
),
608
targets_changed: AverageIntProfileCounter::new(
609
"Changed targets",
610
None, Some(expected::CHANGED_TARGETS),
611
),
612
targets_created: AverageIntProfileCounter::new(
613
"Created targets",
614
None, Some(expected::CREATED_TARGETS),
615
),
616
}
617
}
618
619
pub fn reset_targets(&mut self) {
620
self.targets_used.reset();
621
self.targets_changed.reset();
622
self.targets_created.reset();
623
}
624
}
625
626
#[derive(Clone)]
627
pub struct TextureCacheProfileCounters {
628
pub pages_alpha8_linear: ResourceProfileCounter,
629
pub pages_alpha16_linear: ResourceProfileCounter,
630
pub pages_color8_linear: ResourceProfileCounter,
631
pub pages_color8_nearest: ResourceProfileCounter,
632
pub pages_picture: ResourceProfileCounter,
633
pub rasterized_blob_pixels: ResourceProfileCounter,
634
}
635
636
impl TextureCacheProfileCounters {
637
pub fn new() -> Self {
638
TextureCacheProfileCounters {
639
pages_alpha8_linear: ResourceProfileCounter::new("Texture A8 cached pages", None, None),
640
pages_alpha16_linear: ResourceProfileCounter::new("Texture A16 cached pages", None, None),
641
pages_color8_linear: ResourceProfileCounter::new("Texture RGBA8 cached pages (L)", None, None),
642
pages_color8_nearest: ResourceProfileCounter::new("Texture RGBA8 cached pages (N)", None, None),
643
pages_picture: ResourceProfileCounter::new("Picture cached pages", None, None),
644
rasterized_blob_pixels: ResourceProfileCounter::new(
645
"Rasterized Blob Pixels",
646
Some(expected::NUM_RASTERIZED_BLOBS),
647
Some(expected::RASTERIZED_BLOBS_MB),
648
),
649
}
650
}
651
}
652
653
#[derive(Clone)]
654
pub struct GpuCacheProfileCounters {
655
pub allocated_rows: AverageIntProfileCounter,
656
pub allocated_blocks: AverageIntProfileCounter,
657
pub updated_rows: AverageIntProfileCounter,
658
pub updated_blocks: AverageIntProfileCounter,
659
pub saved_blocks: AverageIntProfileCounter,
660
}
661
662
impl GpuCacheProfileCounters {
663
pub fn new() -> Self {
664
GpuCacheProfileCounters {
665
allocated_rows: AverageIntProfileCounter::new(
666
"GPU cache rows: total",
667
None, Some(expected::GPU_CACHE_ROWS_TOTAL),
668
),
669
updated_rows: AverageIntProfileCounter::new(
670
"GPU cache rows: updated",
671
None, Some(expected::GPU_CACHE_ROWS_UPDATED),
672
),
673
allocated_blocks: AverageIntProfileCounter::new(
674
"GPU cache blocks: total",
675
None, Some(expected::GPU_CACHE_BLOCKS_TOTAL),
676
),
677
updated_blocks: AverageIntProfileCounter::new(
678
"GPU cache blocks: updated",
679
None, Some(expected::GPU_CACHE_BLOCKS_UPDATED),
680
),
681
saved_blocks: AverageIntProfileCounter::new(
682
"GPU cache blocks: saved",
683
None, Some(expected::GPU_CACHE_BLOCKS_SAVED),
684
),
685
}
686
}
687
}
688
689
#[derive(Clone)]
690
pub struct BackendProfileCounters {
691
pub total_time: TimeProfileCounter,
692
pub resources: ResourceProfileCounters,
693
pub txn: TransactionProfileCounters,
694
pub intern: InternProfileCounters,
695
pub scene_changed: bool,
696
}
697
698
#[derive(Clone)]
699
pub struct ResourceProfileCounters {
700
pub font_templates: ResourceProfileCounter,
701
pub image_templates: ResourceProfileCounter,
702
pub texture_cache: TextureCacheProfileCounters,
703
pub gpu_cache: GpuCacheProfileCounters,
704
pub content_slices: IntProfileCounter,
705
}
706
707
#[derive(Clone)]
708
pub struct TransactionProfileCounters {
709
pub display_list_build_time: TimeProfileCounter,
710
pub scene_build_time: TimeProfileCounter,
711
/// Time between when the display list is built and when it is sent by the API.
712
pub content_send_time: TimeProfileCounter,
713
/// Time between sending the SetDisplayList from the API and picking it up on
714
/// the render scene builder thread.
715
pub api_send_time: TimeProfileCounter,
716
/// Sum of content_send_time and api_send_time.
717
pub total_send_time: TimeProfileCounter,
718
pub display_lists: ResourceProfileCounter,
719
}
720
721
macro_rules! declare_intern_profile_counters {
722
( $( $name:ident : $ty:ty, )+ ) => {
723
#[derive(Clone)]
724
pub struct InternProfileCounters {
725
$(
726
pub $name: ResourceProfileCounter,
727
)+
728
}
729
730
impl InternProfileCounters {
731
fn draw(
732
&self,
733
debug_renderer: &mut DebugRenderer,
734
draw_state: &mut DrawState,
735
) {
736
Profiler::draw_counters(
737
&[
738
$(
739
&self.$name,
740
)+
741
],
742
None,
743
debug_renderer,
744
false,
745
draw_state,
746
);
747
}
748
}
749
}
750
}
751
752
enumerate_interners!(declare_intern_profile_counters);
753
754
impl TransactionProfileCounters {
755
pub fn set(
756
&mut self,
757
dl_build_start: u64,
758
dl_build_end: u64,
759
send_start: u64,
760
scene_build_start: u64,
761
scene_build_end: u64,
762
display_len: usize,
763
) {
764
self.display_list_build_time.reset();
765
self.content_send_time.reset();
766
self.api_send_time.reset();
767
self.total_send_time.reset();
768
self.scene_build_time.reset();
769
self.display_lists.reset();
770
771
let dl_build_time = dl_build_end - dl_build_start;
772
let scene_build_time = scene_build_end - scene_build_start;
773
let content_send_time = send_start - dl_build_end;
774
let api_send_time = scene_build_start - send_start;
775
self.display_list_build_time.inc(dl_build_time);
776
self.scene_build_time.inc(scene_build_time);
777
self.content_send_time.inc(content_send_time);
778
self.api_send_time.inc(api_send_time);
779
self.total_send_time.inc(content_send_time + api_send_time);
780
self.display_lists.inc(display_len);
781
}
782
}
783
784
impl BackendProfileCounters {
785
pub fn new() -> Self {
786
BackendProfileCounters {
787
total_time: TimeProfileCounter::new(
788
"Backend CPU Time", false,
789
Some(expected::MAX_BACKEND_CPU_TIME),
790
),
791
resources: ResourceProfileCounters {
792
font_templates: ResourceProfileCounter::new(
793
"Font Templates",
794
Some(expected::NUM_FONT_TEMPLATES),
795
Some(expected::FONT_TEMPLATES_MB),
796
),
797
image_templates: ResourceProfileCounter::new(
798
"Image Templates",
799
Some(expected::NUM_IMAGE_TEMPLATES),
800
Some(expected::IMAGE_TEMPLATES_MB),
801
),
802
content_slices: IntProfileCounter::new(
803
"Content Slices",
804
None,
805
),
806
texture_cache: TextureCacheProfileCounters::new(),
807
gpu_cache: GpuCacheProfileCounters::new(),
808
},
809
txn: TransactionProfileCounters {
810
display_list_build_time: TimeProfileCounter::new(
811
"DisplayList Build Time", false,
812
Some(expected::DISPLAY_LIST_BUILD_TIME)
813
),
814
scene_build_time: TimeProfileCounter::new(
815
"Scene build time", false,
816
Some(expected::MAX_SCENE_BUILD_TIME),
817
),
818
content_send_time: TimeProfileCounter::new(
819
"Content Send Time", false,
820
Some(expected::DISPLAY_LIST_SEND_TIME),
821
),
822
api_send_time: TimeProfileCounter::new(
823
"API Send Time", false,
824
Some(expected::DISPLAY_LIST_SEND_TIME),
825
),
826
total_send_time: TimeProfileCounter::new(
827
"Total IPC Time", false,
828
Some(expected::DISPLAY_LIST_TOTAL_TIME),
829
),
830
display_lists: ResourceProfileCounter::new(
831
"DisplayLists Sent",
832
None, Some(expected::DISPLAY_LIST_MB),
833
),
834
},
835
//TODO: generate this by a macro
836
intern: InternProfileCounters {
837
prim: ResourceProfileCounter::new("Interned primitives", None, None),
838
conic_grad: ResourceProfileCounter::new("Interned conic gradients", None, None),
839
image: ResourceProfileCounter::new("Interned images", None, None),
840
image_border: ResourceProfileCounter::new("Interned image borders", None, None),
841
line_decoration: ResourceProfileCounter::new("Interned line decorations", None, None),
842
linear_grad: ResourceProfileCounter::new("Interned linear gradients", None, None),
843
normal_border: ResourceProfileCounter::new("Interned normal borders", None, None),
844
picture: ResourceProfileCounter::new("Interned pictures", None, None),
845
radial_grad: ResourceProfileCounter::new("Interned radial gradients", None, None),
846
text_run: ResourceProfileCounter::new("Interned text runs", None, None),
847
yuv_image: ResourceProfileCounter::new("Interned YUV images", None, None),
848
clip: ResourceProfileCounter::new("Interned clips", None, None),
849
filter_data: ResourceProfileCounter::new("Interned filter data", None, None),
850
backdrop: ResourceProfileCounter::new("Interned backdrops", None, None),
851
},
852
scene_changed: false,
853
}
854
}
855
856
pub fn reset(&mut self) {
857
self.total_time.reset();
858
self.resources.texture_cache.rasterized_blob_pixels.reset();
859
self.scene_changed = false;
860
}
861
}
862
863
pub struct RendererProfileCounters {
864
pub frame_counter: IntProfileCounter,
865
pub frame_time: AverageTimeProfileCounter,
866
pub draw_calls: AverageIntProfileCounter,
867
pub vertices: AverageIntProfileCounter,
868
pub vao_count_and_size: ResourceProfileCounter,
869
pub color_passes: AverageIntProfileCounter,
870
pub alpha_passes: AverageIntProfileCounter,
871
pub texture_data_uploaded: AverageIntProfileCounter,
872
pub rendered_picture_cache_tiles: AverageIntProfileCounter,
873
pub total_picture_cache_tiles: AverageIntProfileCounter,
874
}
875
876
pub struct RendererProfileTimers {
877
pub cpu_time: TimeProfileCounter,
878
pub gpu_graph: TimeProfileCounter,
879
pub gpu_samples: Vec<GpuTimer<GpuProfileTag>>,
880
}
881
882
impl RendererProfileCounters {
883
pub fn new() -> Self {
884
RendererProfileCounters {
885
frame_counter: IntProfileCounter::new("Frame", None),
886
frame_time: AverageTimeProfileCounter::new(
887
"FPS", true, None, None,
888
),
889
draw_calls: AverageIntProfileCounter::new(
890
"Draw Calls",
891
None, Some(expected::DRAW_CALLS),
892
),
893
vertices: AverageIntProfileCounter::new(
894
"Vertices",
895
None, Some(expected::VERTICES),
896
),
897
vao_count_and_size: ResourceProfileCounter::new("VAO", None, None),
898
color_passes: AverageIntProfileCounter::new(
899
"Color passes",
900
None, Some(expected::COLOR_PASSES),
901
),
902
alpha_passes: AverageIntProfileCounter::new(
903
"Alpha passes",
904
None, Some(expected::ALPHA_PASSES),
905
),
906
texture_data_uploaded: AverageIntProfileCounter::new(
907
"Texture data, kb",
908
None, Some(expected::TEXTURE_DATA_UPLOADED),
909
),
910
rendered_picture_cache_tiles: AverageIntProfileCounter::new(
911
"Rendered tiles",
912
None, Some(expected::RENDERED_PICTURE_CACHE_TILES),
913
),
914
total_picture_cache_tiles: AverageIntProfileCounter::new(
915
"Total tiles",
916
None, Some(expected::TOTAL_PICTURE_CACHE_TILES),
917
),
918
}
919
}
920
921
pub fn reset(&mut self) {
922
self.draw_calls.reset();
923
self.vertices.reset();
924
self.color_passes.reset();
925
self.alpha_passes.reset();
926
self.texture_data_uploaded.reset();
927
self.rendered_picture_cache_tiles.reset();
928
self.total_picture_cache_tiles.reset();
929
}
930
}
931
932
impl RendererProfileTimers {
933
pub fn new() -> Self {
934
RendererProfileTimers {
935
cpu_time: TimeProfileCounter::new("Renderer CPU Time", false, None),
936
gpu_samples: Vec::new(),
937
gpu_graph: TimeProfileCounter::new("GPU Time", false, None),
938
}
939
}
940
}
941
942
struct GraphStats {
943
min_value: f32,
944
mean_value: f32,
945
max_value: f32,
946
}
947
948
struct ProfileGraph {
949
max_samples: usize,
950
scale: f32,
951
values: VecDeque<f32>,
952
short_description: &'static str,
953
unit_description: &'static str,
954
}
955
956
impl ProfileGraph {
957
fn new(
958
max_samples: usize,
959
scale: f32,
960
short_description: &'static str,
961
unit_description: &'static str,
962
) -> Self {
963
ProfileGraph {
964
max_samples,
965
scale,
966
values: VecDeque::new(),
967
short_description,
968
unit_description,
969
}
970
}
971
972
fn push(&mut self, ns: u64) {
973
let val = ns as f64 * self.scale as f64;
974
if self.values.len() == self.max_samples {
975
self.values.pop_back();
976
}
977
self.values.push_front(val as f32);
978
}
979
980
fn stats(&self) -> GraphStats {
981
let mut stats = GraphStats {
982
min_value: f32::MAX,
983
mean_value: 0.0,
984
max_value: -f32::MAX,
985
};
986
987
for value in &self.values {
988
stats.min_value = stats.min_value.min(*value);
989
stats.mean_value += *value;
990
stats.max_value = stats.max_value.max(*value);
991
}
992
993
if !self.values.is_empty() {
994
stats.mean_value /= self.values.len() as f32;
995
}
996
997
stats
998
}
999
1000
fn draw_graph(
1001
&self,
1002
x: f32,
1003
y: f32,
1004
description: &'static str,
1005
debug_renderer: &mut DebugRenderer,
1006
) -> default::Rect<f32> {
1007
let size = Size2D::new(600.0, 100.0);
1008
let line_height = debug_renderer.line_height();
1009
let graph_rect = Rect::new(Point2D::new(x, y), size);
1010
let mut rect = graph_rect.inflate(10.0, 10.0);
1011
1012
let stats = self.stats();
1013
1014
let text_color = ColorU::new(255, 255, 0, 255);
1015
let text_origin = rect.origin + vec2(rect.size.width, 20.0);
1016
debug_renderer.add_text(
1017
text_origin.x,
1018
text_origin.y,
1019
description,
1020
ColorU::new(0, 255, 0, 255),
1021
None,
1022
);
1023
debug_renderer.add_text(
1024
text_origin.x,
1025
text_origin.y + line_height,
1026
&format!("Min: {:.2} {}", stats.min_value, self.unit_description),
1027
text_color,
1028
None,
1029
);
1030
debug_renderer.add_text(
1031
text_origin.x,
1032
text_origin.y + line_height * 2.0,
1033
&format!("Mean: {:.2} {}", stats.mean_value, self.unit_description),
1034
text_color,
1035
None,
1036
);
1037
debug_renderer.add_text(
1038
text_origin.x,
1039
text_origin.y + line_height * 3.0,
1040
&format!("Max: {:.2} {}", stats.max_value, self.unit_description),
1041
text_color,
1042
None,
1043
);
1044
1045
rect.size.width += 140.0;
1046
debug_renderer.add_quad(
1047
rect.origin.x,
1048
rect.origin.y,
1049
rect.origin.x + rect.size.width + 10.0,
1050
rect.origin.y + rect.size.height,
1051
ColorU::new(25, 25, 25, 200),
1052
ColorU::new(51, 51, 51, 200),
1053
);
1054
1055
let bx1 = graph_rect.max_x();
1056
let by1 = graph_rect.max_y();
1057
1058
let w = graph_rect.size.width / self.max_samples as f32;
1059
let h = graph_rect.size.height;
1060
1061
let color_t0 = ColorU::new(0, 255, 0, 255);
1062
let color_b0 = ColorU::new(0, 180, 0, 255);
1063
1064
let color_t1 = ColorU::new(0, 255, 0, 255);
1065
let color_b1 = ColorU::new(0, 180, 0, 255);
1066
1067
let color_t2 = ColorU::new(255, 0, 0, 255);
1068
let color_b2 = ColorU::new(180, 0, 0, 255);
1069
1070
for (index, sample) in self.values.iter().enumerate() {
1071
let sample = *sample;
1072
let x1 = bx1 - index as f32 * w;
1073
let x0 = x1 - w;
1074
1075
let y0 = by1 - (sample / stats.max_value) as f32 * h;
1076
let y1 = by1;
1077
1078
let (color_top, color_bottom) = if sample < 1000.0 / 60.0 {
1079
(color_t0, color_b0)
1080
} else if sample < 1000.0 / 30.0 {
1081
(color_t1, color_b1)
1082
} else {
1083
(color_t2, color_b2)
1084
};
1085
1086
debug_renderer.add_quad(x0, y0, x1, y1, color_top, color_bottom);
1087
}
1088
1089
rect
1090
}
1091
}
1092
1093
impl ProfileCounter for ProfileGraph {
1094
fn description(&self) -> &'static str {
1095
self.short_description
1096
}
1097
1098
fn value(&self) -> String {
1099
format!("{:.2}ms", self.stats().mean_value)
1100
}
1101
1102
fn is_expected(&self) -> bool { true }
1103
}
1104
1105
struct GpuFrame {
1106
total_time: u64,
1107
samples: Vec<GpuTimer<GpuProfileTag>>,
1108
}
1109
1110
struct GpuFrameCollection {
1111
frames: VecDeque<GpuFrame>,
1112
}
1113
1114
impl GpuFrameCollection {
1115
fn new() -> Self {
1116
GpuFrameCollection {
1117
frames: VecDeque::new(),
1118
}
1119
}
1120
1121
fn push(&mut self, total_time: u64, samples: Vec<GpuTimer<GpuProfileTag>>) {
1122
if self.frames.len() == 20 {
1123
self.frames.pop_back();
1124
}
1125
self.frames.push_front(GpuFrame {
1126
total_time,
1127
samples,
1128
});
1129
}
1130
}
1131
1132
impl GpuFrameCollection {
1133
fn draw(&self, x: f32, y: f32, debug_renderer: &mut DebugRenderer) -> default::Rect<f32> {
1134
let graph_rect = Rect::new(
1135
Point2D::new(x, y),
1136
Size2D::new(GRAPH_WIDTH, GRAPH_HEIGHT),
1137
);
1138
let bounding_rect = graph_rect.inflate(GRAPH_PADDING, GRAPH_PADDING);
1139
1140
debug_renderer.add_quad(
1141
bounding_rect.origin.x,
1142
bounding_rect.origin.y,
1143
bounding_rect.origin.x + bounding_rect.size.width,
1144
bounding_rect.origin.y + bounding_rect.size.height,
1145
ColorU::new(25, 25, 25, 200),
1146
ColorU::new(51, 51, 51, 200),
1147
);
1148
1149
let w = graph_rect.size.width;
1150
let mut y0 = graph_rect.origin.y;
1151
1152
let max_time = self.frames
1153
.iter()
1154
.max_by_key(|f| f.total_time)
1155
.unwrap()
1156
.total_time as f32;
1157
1158
let mut tags_present = FastHashMap::default();
1159
1160
for frame in &self.frames {
1161
let y1 = y0 + GRAPH_FRAME_HEIGHT;
1162
1163
let mut current_ns = 0;
1164
for sample in &frame.samples {
1165
let x0 = graph_rect.origin.x + w * current_ns as f32 / max_time;
1166
current_ns += sample.time_ns;
1167
let x1 = graph_rect.origin.x + w * current_ns as f32 / max_time;
1168
let mut bottom_color = sample.tag.color;
1169
bottom_color.a *= 0.5;
1170
1171
debug_renderer.add_quad(
1172
x0,
1173
y0,
1174
x1,
1175
y1,
1176
sample.tag.color.into(),
1177
bottom_color.into(),
1178
);
1179
1180
tags_present.insert(sample.tag.label, sample.tag.color);
1181
}
1182
1183
y0 = y1;
1184
}
1185
1186
// Add a legend to see which color correspond to what primitive.
1187
const LEGEND_SIZE: f32 = 20.0;
1188
const PADDED_LEGEND_SIZE: f32 = 25.0;
1189
if !tags_present.is_empty() {
1190
debug_renderer.add_quad(
1191
bounding_rect.max_x() + GRAPH_PADDING,
1192
bounding_rect.origin.y,
1193
bounding_rect.max_x() + GRAPH_PADDING + 200.0,
1194
bounding_rect.origin.y + tags_present.len() as f32 * PADDED_LEGEND_SIZE + GRAPH_PADDING,
1195
ColorU::new(25, 25, 25, 200),
1196
ColorU::new(51, 51, 51, 200),
1197
);
1198
}
1199
1200
for (i, (label, &color)) in tags_present.iter().enumerate() {
1201
let x0 = bounding_rect.origin.x + bounding_rect.size.width + GRAPH_PADDING * 2.0;
1202
let y0 = bounding_rect.origin.y + GRAPH_PADDING + i as f32 * PADDED_LEGEND_SIZE;
1203
1204
debug_renderer.add_quad(
1205
x0, y0, x0 + LEGEND_SIZE, y0 + LEGEND_SIZE,
1206
color.into(),
1207
color.into(),
1208
);
1209
1210
debug_renderer.add_text(
1211
x0 + PADDED_LEGEND_SIZE,
1212
y0 + LEGEND_SIZE * 0.75,
1213
label,
1214
ColorU::new(255, 255, 0, 255),
1215
None,
1216
);
1217
}
1218
1219
bounding_rect
1220
}
1221
}
1222
1223
struct DrawState {
1224
x_left: f32,
1225
y_left: f32,
1226
x_right: f32,
1227
y_right: f32,
1228
}
1229
1230
pub struct Profiler {
1231
draw_state: DrawState,
1232
backend_graph: ProfileGraph,
1233
renderer_graph: ProfileGraph,
1234
gpu_graph: ProfileGraph,
1235
ipc_graph: ProfileGraph,
1236
display_list_build_graph: ProfileGraph,
1237
scene_build_graph: ProfileGraph,
1238
blob_raster_graph: ProfileGraph,
1239
backend_time: AverageTimeProfileCounter,
1240
renderer_time: AverageTimeProfileCounter,
1241
gpu_time: AverageTimeProfileCounter,
1242
ipc_time: AverageTimeProfileCounter,
1243
gpu_frames: GpuFrameCollection,
1244
cooldowns: Vec<i32>,
1245
}
1246
1247
impl Profiler {
1248
pub fn new() -> Self {
1249
let to_ms_scale = 1.0 / 1000000.0;
1250
Profiler {
1251
draw_state: DrawState {
1252
x_left: 0.0,
1253
y_left: 0.0,
1254
x_right: 0.0,
1255
y_right: 0.0,
1256
},
1257
backend_graph: ProfileGraph::new(600, to_ms_scale, "Backend:", "ms"),
1258
renderer_graph: ProfileGraph::new(600, to_ms_scale, "Renderer:", "ms"),
1259
gpu_graph: ProfileGraph::new(600, to_ms_scale, "GPU:", "ms"),
1260
ipc_graph: ProfileGraph::new(600, to_ms_scale, "IPC:", "ms"),
1261
display_list_build_graph: ProfileGraph::new(600, to_ms_scale, "DisplayList build", "ms"),
1262
scene_build_graph: ProfileGraph::new(600, to_ms_scale, "Scene build:", "ms"),
1263
blob_raster_graph: ProfileGraph::new(600, 1.0, "Rasterized blob pixels:", "px"),
1264
gpu_frames: GpuFrameCollection::new(),
1265
backend_time: AverageTimeProfileCounter::new(
1266
"Backend:", false,
1267
Some(expected::AVG_BACKEND_CPU_TIME),
1268
Some(expected::MAX_BACKEND_CPU_TIME),
1269
),
1270
renderer_time: AverageTimeProfileCounter::new(
1271
"Renderer:", false,
1272
Some(expected::AVG_RENDERER_CPU_TIME),
1273
Some(expected::MAX_RENDERER_CPU_TIME),
1274
),
1275
ipc_time: AverageTimeProfileCounter::new(
1276
"IPC:", false,
1277
Some(expected::AVG_IPC_TIME),
1278
Some(expected::MAX_IPC_TIME),
1279
),
1280
gpu_time: AverageTimeProfileCounter::new(
1281
"GPU:", false,
1282
Some(expected::AVG_GPU_TIME),
1283
Some(expected::MAX_GPU_TIME),
1284
),
1285
cooldowns: Vec::new(),
1286
}
1287
}
1288
1289
// If we have an array of "cooldown" counters, then only display profiles that
1290
// are out of the ordinary and keep displaying them until the cooldown is over.
1291
fn draw_counters<T: ProfileCounter + ?Sized>(
1292
counters: &[&T],
1293
mut cooldowns: Option<&mut [i32]>,
1294
debug_renderer: &mut DebugRenderer,
1295
left: bool,
1296
draw_state: &mut DrawState,
1297
) {
1298
let mut label_rect = Rect::zero();
1299
let mut value_rect = Rect::zero();
1300
let (mut current_x, mut current_y) = if left {
1301
(draw_state.x_left, draw_state.y_left)
1302
} else {
1303
(draw_state.x_right, draw_state.y_right)
1304
};
1305
let mut color_index = 0;
1306
let line_height = debug_renderer.line_height();
1307
1308
let colors = [
1309
// Regular values,
1310
ColorU::new(255, 255, 255, 255),
1311
ColorU::new(255, 255, 0, 255),
1312
// Unexpected values,
1313
ColorU::new(255, 80, 0, 255),
1314
ColorU::new(255, 0, 0, 255),
1315
];
1316
1317
for (idx, counter) in counters.iter().enumerate() {
1318
if let Some(cooldowns) = cooldowns.as_mut() {
1319
if !counter.is_expected() {
1320
cooldowns[idx] = 40;
1321
}
1322
if cooldowns[idx] == 0 {
1323
continue;
1324
}
1325
}
1326
let rect = debug_renderer.add_text(
1327
current_x,
1328
current_y,
1329
counter.description(),
1330
colors[color_index],
1331
None,
1332
);
1333
color_index = (color_index + 1) % 2;
1334
1335
label_rect = label_rect.union(&rect);
1336
current_y += line_height;
1337
}
1338
1339
color_index = 0;
1340
current_x = label_rect.origin.x + label_rect.size.width + 60.0;
1341
current_y = if left { draw_state.y_left } else { draw_state.y_right };
1342
1343
for (idx, counter) in counters.iter().enumerate() {
1344
let expected_offset = if counter.is_expected() || cooldowns.is_some() { 0 } else { 2 };
1345
if let Some(cooldowns) = cooldowns.as_mut() {
1346
if cooldowns[idx] > 0 {
1347
cooldowns[idx] -= 1;
1348
} else {
1349
continue;
1350
}
1351
}
1352
let rect = debug_renderer.add_text(
1353
current_x,
1354
current_y,
1355
&counter.value(),
1356
colors[color_index + expected_offset],
1357
None,
1358
);
1359
color_index = (color_index + 1) % 2;
1360
1361
value_rect = value_rect.union(&rect);
1362
current_y += line_height;
1363
}
1364
1365
let total_rect = label_rect.union(&value_rect).inflate(10.0, 10.0);
1366
debug_renderer.add_quad(
1367
total_rect.origin.x,
1368
total_rect.origin.y,
1369
total_rect.origin.x + total_rect.size.width,
1370
total_rect.origin.y + total_rect.size.height,
1371
ColorF::new(0.1, 0.1, 0.1, 0.8).into(),
1372
ColorF::new(0.2, 0.2, 0.2, 0.8).into(),
1373
);
1374
let new_y = total_rect.origin.y + total_rect.size.height + 30.0;
1375
if left {
1376
draw_state.y_left = new_y;
1377
} else {
1378
draw_state.y_right = new_y;
1379
}
1380
}
1381
1382
fn draw_bar(
1383
&mut self,
1384
label: &str,
1385
label_color: ColorU,
1386
counters: &[(ColorU, &AverageIntProfileCounter)],
1387
debug_renderer: &mut DebugRenderer,
1388
) -> default::Rect<f32> {
1389
let mut rect = debug_renderer.add_text(
1390
self.draw_state.x_left,
1391
self.draw_state.y_left,
1392
label,
1393
label_color,
1394
None,
1395
);
1396
1397
let x_base = rect.origin.x + rect.size.width + 10.0;
1398
let height = debug_renderer.line_height();
1399
let width = (self.draw_state.x_right - 30.0 - x_base).max(0.0);
1400
let total_value = counters.last().unwrap().1.get();
1401
let scale = width / total_value as f32;
1402
let mut x_current = x_base;
1403
1404
for &(color, counter) in counters {
1405
let x_stop = x_base + counter.get() as f32 * scale;
1406
debug_renderer.add_quad(
1407
x_current,
1408
rect.origin.y,
1409
x_stop,
1410
rect.origin.y + height,
1411
color,
1412
color,
1413
);
1414
x_current = x_stop;
1415
}
1416
1417
self.draw_state.y_left += height;
1418
1419
rect.size.width += width + 10.0;
1420
rect
1421
}
1422
1423
fn draw_gpu_cache_bars(
1424
&mut self,
1425
counters: &GpuCacheProfileCounters,
1426
debug_renderer: &mut DebugRenderer,
1427
) {
1428
let color_updated = ColorU::new(0xFF, 0, 0, 0xFF);
1429
let color_free = ColorU::new(0, 0, 0xFF, 0xFF);
1430
let color_saved = ColorU::new(0, 0xFF, 0, 0xFF);
1431
1432
let mut requested_blocks = AverageIntProfileCounter::new("", None, None);
1433
requested_blocks.set(counters.updated_blocks.get() + counters.saved_blocks.get());
1434
1435
let mut total_blocks = AverageIntProfileCounter::new("", None, None);
1436
total_blocks.set(counters.allocated_rows.get() * MAX_VERTEX_TEXTURE_WIDTH);
1437
1438
let rect0 = self.draw_bar(
1439
&format!("GPU cache rows ({}):", counters.allocated_rows.get()),
1440
ColorU::new(0xFF, 0xFF, 0xFF, 0xFF),
1441
&[
1442
(color_updated, &counters.updated_rows),
1443
(color_free, &counters.allocated_rows),
1444
],
1445
debug_renderer,
1446
);
1447
1448
let rect1 = self.draw_bar(
1449
"GPU cache blocks",
1450
ColorU::new(0xFF, 0xFF, 0, 0xFF),
1451
&[
1452
(color_updated, &counters.updated_blocks),
1453
(color_saved, &requested_blocks),
1454
(color_free, &counters.allocated_blocks),
1455
(ColorU::new(0, 0, 0, 0xFF), &total_blocks),
1456
],
1457
debug_renderer,
1458
);
1459
1460
let total_rect = rect0.union(&rect1).inflate(10.0, 10.0);
1461
debug_renderer.add_quad(
1462
total_rect.origin.x,
1463
total_rect.origin.y,
1464
total_rect.origin.x + total_rect.size.width,
1465
total_rect.origin.y + total_rect.size.height,
1466
ColorF::new(0.1, 0.1, 0.1, 0.8).into(),
1467
ColorF::new(0.2, 0.2, 0.2, 0.8).into(),
1468
);
1469
1470
self.draw_state.y_left = total_rect.origin.y + total_rect.size.height + 30.0;
1471
}
1472
1473
fn draw_frame_bars(
1474
&mut self,
1475
counters: &FrameProfileCounters,
1476
debug_renderer: &mut DebugRenderer,
1477
) {
1478
let rect0 = self.draw_bar(
1479
&format!("primitives ({}):", counters.total_primitives.get()),
1480
ColorU::new(0xFF, 0xFF, 0xFF, 0xFF),
1481
&[
1482
(ColorU::new(0, 0, 0xFF, 0xFF), &counters.visible_primitives),
1483
(ColorU::new(0, 0, 0, 0xFF), &counters.total_primitives),
1484
],
1485
debug_renderer,
1486
);
1487
1488
let rect1 = self.draw_bar(
1489
&format!("GPU targets ({}):", &counters.targets_used.get()),
1490
ColorU::new(0xFF, 0xFF, 0, 0xFF),
1491
&[
1492
(ColorU::new(0, 0, 0xFF, 0xFF), &counters.targets_created),
1493
(ColorU::new(0xFF, 0, 0, 0xFF), &counters.targets_changed),
1494
(ColorU::new(0, 0xFF, 0, 0xFF), &counters.targets_used),
1495
],
1496
debug_renderer,
1497
);
1498
1499
let total_rect = rect0.union(&rect1).inflate(10.0, 10.0);
1500
debug_renderer.add_quad(
1501
total_rect.origin.x,
1502
total_rect.origin.y,
1503
total_rect.origin.x + total_rect.size.width,
1504
total_rect.origin.y + total_rect.size.height,
1505
ColorF::new(0.1, 0.1, 0.1, 0.8).into(),
1506
ColorF::new(0.2, 0.2, 0.2, 0.8).into(),
1507
);
1508
1509
self.draw_state.y_left = total_rect.origin.y + total_rect.size.height + 30.0;
1510
}
1511
1512
fn draw_compact_profile(
1513
&mut self,
1514
backend_profile: &BackendProfileCounters,
1515
renderer_profile: &RendererProfileCounters,
1516
debug_renderer: &mut DebugRenderer,
1517
) {
1518
Profiler::draw_counters(
1519
&[
1520
&renderer_profile.frame_time as &dyn ProfileCounter,
1521
&renderer_profile.color_passes,
1522
&renderer_profile.alpha_passes,
1523
&renderer_profile.draw_calls,
1524
&renderer_profile.vertices,
1525
&renderer_profile.rendered_picture_cache_tiles,
1526
&renderer_profile.texture_data_uploaded,
1527
&backend_profile.resources.content_slices,
1528
&self.ipc_time,
1529
&self.backend_time,
1530
&self.renderer_time,
1531
&self.gpu_time,
1532
],
1533
None,
1534
debug_renderer,
1535
true,
1536
&mut self.draw_state,
1537
);
1538
}
1539
1540
fn draw_full_profile(
1541
&mut self,
1542
frame_profiles: &[FrameProfileCounters],
1543
backend_profile: &BackendProfileCounters,
1544
renderer_profile: &RendererProfileCounters,
1545
renderer_timers: &mut RendererProfileTimers,
1546
gpu_samplers: &[GpuSampler<GpuProfileTag>],
1547
screen_fraction: f32,
1548
debug_renderer: &mut DebugRenderer,
1549
) {
1550
Profiler::draw_counters(
1551
&[
1552
&renderer_profile.frame_time as &dyn ProfileCounter,
1553
&renderer_profile.frame_counter,
1554
&renderer_profile.color_passes,
1555
&renderer_profile.alpha_passes,
1556
&renderer_profile.rendered_picture_cache_tiles,
1557
&renderer_profile.total_picture_cache_tiles,
1558
&renderer_profile.texture_data_uploaded,
1559
&backend_profile.resources.content_slices,
1560
],
1561
None,
1562
debug_renderer,
1563
true,
1564
&mut self.draw_state
1565
);
1566
1567
self.draw_gpu_cache_bars(
1568
&backend_profile.resources.gpu_cache,
1569
debug_renderer,
1570
);
1571
1572
Profiler::draw_counters(
1573
&[
1574
&backend_profile.resources.font_templates,
1575
&backend_profile.resources.image_templates,
1576
],
1577
None,
1578
debug_renderer,
1579
true,
1580
&mut self.draw_state
1581
);
1582
1583
backend_profile.intern.draw(debug_renderer, &mut self.draw_state);
1584
1585
Profiler::draw_counters(
1586
&[
1587
&backend_profile.resources.texture_cache.pages_alpha8_linear,
1588
&backend_profile.resources.texture_cache.pages_color8_linear,
1589
&backend_profile.resources.texture_cache.pages_color8_nearest,
1590
&backend_profile.txn.display_lists,
1591
],
1592
None,
1593
debug_renderer,
1594
true,
1595
&mut self.draw_state
1596
);
1597
1598
Profiler::draw_counters(
1599
&[
1600
&backend_profile.txn.display_list_build_time,
1601
&backend_profile.txn.scene_build_time,
1602
&backend_profile.txn.content_send_time,
1603
&backend_profile.txn.api_send_time,
1604
&backend_profile.txn.total_send_time,
1605
],
1606
None,
1607
debug_renderer,
1608
true,
1609
&mut self.draw_state
1610
);
1611
1612
for frame_profile in frame_profiles {
1613
self.draw_frame_bars(frame_profile, debug_renderer);
1614
}
1615
1616
Profiler::draw_counters(
1617
&[&renderer_profile.draw_calls, &renderer_profile.vertices],
1618
None,
1619
debug_renderer,
1620
true,
1621
&mut self.draw_state
1622
);
1623
1624
Profiler::draw_counters(
1625
&[
1626
&backend_profile.total_time,
1627
&renderer_timers.cpu_time,
1628
&renderer_timers.gpu_graph,
1629
],
1630
None,
1631
debug_renderer,
1632
false,
1633
&mut self.draw_state
1634
);
1635
1636
if !gpu_samplers.is_empty() {
1637
let mut samplers = Vec::<PercentageProfileCounter>::new();
1638
// Gathering unique GPU samplers. This has O(N^2) complexity,
1639
// but we only have a few samplers per target.
1640
let mut total = 0.0;
1641
for sampler in gpu_samplers {
1642
let value = sampler.count as f32 * screen_fraction;
1643
total += value;
1644
match samplers.iter().position(|s| {
1645
s.description as *const _ == sampler.tag.label as *const _
1646
}) {
1647
Some(pos) => samplers[pos].value += value,
1648
None => samplers.push(PercentageProfileCounter {
1649
description: sampler.tag.label,
1650
value,
1651
}),
1652
}
1653
}
1654
samplers.push(PercentageProfileCounter {
1655
description: "Total",
1656
value: total,
1657
});
1658
let samplers: Vec<&dyn ProfileCounter> = samplers.iter().map(|sampler| {
1659
sampler as &dyn ProfileCounter
1660
}).collect();
1661
Profiler::draw_counters(
1662
&samplers,
1663
None,
1664
debug_renderer,
1665
false,
1666
&mut self.draw_state,
1667
);
1668
}
1669
1670
let rect =
1671
self.backend_graph
1672
.draw_graph(self.draw_state.x_right, self.draw_state.y_right, "CPU (backend)", debug_renderer);
1673
self.draw_state.y_right += rect.size.height + PROFILE_PADDING;
1674
let rect = self.renderer_graph.draw_graph(
1675
self.draw_state.x_right,
1676
self.draw_state.y_right,
1677
"CPU (renderer)",
1678
debug_renderer,
1679
);
1680
self.draw_state.y_right += rect.size.height + PROFILE_PADDING;
1681
let rect =
1682
self.ipc_graph
1683
.draw_graph(self.draw_state.x_right, self.draw_state.y_right, "DisplayList IPC", debug_renderer);
1684
self.draw_state.y_right += rect.size.height + PROFILE_PADDING;
1685
1686
let rect = self.display_list_build_graph
1687
.draw_graph(self.draw_state.x_right, self.draw_state.y_right, "DisplayList build", debug_renderer);
1688
self.draw_state.y_right += rect.size.height + PROFILE_PADDING;
1689
1690
let rect = self.scene_build_graph
1691
.draw_graph(self.draw_state.x_right, self.draw_state.y_right, "Scene build", debug_renderer);
1692
self.draw_state.y_right += rect.size.height + PROFILE_PADDING;
1693
1694
let rect = self.gpu_graph
1695
.draw_graph(self.draw_state.x_right, self.draw_state.y_right, "GPU", debug_renderer);
1696
self.draw_state.y_right += rect.size.height + PROFILE_PADDING;
1697
1698
let rect = self.blob_raster_graph
1699
.draw_graph(self.draw_state.x_right, self.draw_state.y_right, "Blob pixels", debug_renderer);
1700
self.draw_state.y_right += rect.size.height + PROFILE_PADDING;
1701
1702
let rect = self.gpu_frames
1703
.draw(self.draw_state.x_left, f32::max(self.draw_state.y_left, self.draw_state.y_right), debug_renderer);
1704
self.draw_state.y_right += rect.size.height + PROFILE_PADDING;
1705
}
1706
1707
fn draw_smart_profile(
1708
&mut self,
1709
backend_profile: &BackendProfileCounters,
1710
renderer_profile: &RendererProfileCounters,
1711
debug_renderer: &mut DebugRenderer,
1712
) {
1713
while self.cooldowns.len() < 18 {
1714
self.cooldowns.push(0);
1715
}
1716
1717
// Always show the fps counter.
1718
Profiler::draw_counters(
1719
&[
1720
&renderer_profile.frame_time,
1721
],
1722
None,
1723
debug_renderer,
1724
true,
1725
&mut self.draw_state,
1726
);
1727
1728
let mut start = 0;
1729
let counters: &[&[&dyn ProfileCounter]] = &[
1730
&[
1731
&self.backend_time,
1732
&self.renderer_time,
1733
&self.gpu_time,
1734
],
1735
&[
1736
&renderer_profile.color_passes,
1737
&renderer_profile.alpha_passes,
1738
&renderer_profile.draw_calls,
1739
&renderer_profile.vertices,
1740
&renderer_profile.rendered_picture_cache_tiles,
1741
&renderer_profile.total_picture_cache_tiles,
1742
],
1743
&[
1744
&backend_profile.resources.gpu_cache.allocated_rows,
1745
&backend_profile.resources.gpu_cache.updated_rows,
1746
&backend_profile.resources.gpu_cache.allocated_blocks,
1747
&backend_profile.resources.gpu_cache.updated_blocks,
1748
&backend_profile.resources.gpu_cache.saved_blocks,
1749
],
1750
&[
1751
&backend_profile.resources.image_templates,
1752
&backend_profile.resources.font_templates,
1753
&backend_profile.resources.texture_cache.rasterized_blob_pixels,
1754
&backend_profile.txn.display_lists,
1755
],
1756
];
1757
1758
for group in counters {
1759
let end = start + group.len();
1760
Profiler::draw_counters(
1761
&group[..],
1762
Some(&mut self.cooldowns[start..end]),
1763
debug_renderer,
1764
true,
1765
&mut self.draw_state,
1766
);
1767
start = end;
1768
}
1769
}
1770
1771
pub fn draw_profile(
1772
&mut self,
1773
frame_profiles: &[FrameProfileCounters],
1774
backend_profile: &BackendProfileCounters,
1775
renderer_profile: &RendererProfileCounters,
1776
renderer_timers: &mut RendererProfileTimers,
1777
gpu_samplers: &[GpuSampler<GpuProfileTag>],
1778
screen_fraction: f32,
1779
debug_renderer: &mut DebugRenderer,
1780
style: ProfileStyle,
1781
) {
1782
self.draw_state.x_left = 20.0;
1783
self.draw_state.y_left = 50.0;
1784
self.draw_state.x_right = 450.0;
1785
self.draw_state.y_right = 40.0;
1786
1787
let mut gpu_graph = 0;
1788
let gpu_graphrs = mem::replace(&mut renderer_timers.gpu_samples, Vec::new());
1789
for sample in &gpu_graphrs {
1790
gpu_graph += sample.time_ns;
1791
}
1792
renderer_timers.gpu_graph.set(gpu_graph);
1793
1794
self.backend_graph
1795
.push(backend_profile.total_time.nanoseconds);
1796
self.backend_time.set(backend_profile.total_time.nanoseconds);
1797
self.renderer_graph
1798
.push(renderer_timers.cpu_time.nanoseconds);
1799
self.renderer_time.set(renderer_timers.cpu_time.nanoseconds);
1800
self.ipc_graph
1801
.push(backend_profile.txn.total_send_time.nanoseconds);
1802
self.display_list_build_graph
1803
.push(backend_profile.txn.display_list_build_time.nanoseconds);
1804
self.scene_build_graph
1805
.push(backend_profile.txn.scene_build_time.nanoseconds);
1806
self.blob_raster_graph
1807
.push(backend_profile.resources.texture_cache.rasterized_blob_pixels.size as u64);
1808
self.ipc_time.set(backend_profile.txn.total_send_time.nanoseconds);
1809
self.gpu_graph.push(gpu_graph);
1810
self.gpu_time.set(gpu_graph);
1811
self.gpu_frames.push(gpu_graph, gpu_graphrs);
1812
1813
match style {
1814
ProfileStyle::Full => {
1815
self.draw_full_profile(
1816
frame_profiles,
1817
backend_profile,
1818
renderer_profile,
1819
renderer_timers,
1820
gpu_samplers,
1821
screen_fraction,
1822
debug_renderer,
1823
);
1824
}
1825
ProfileStyle::Compact => {
1826
self.draw_compact_profile(
1827
backend_profile,
1828
renderer_profile,
1829
debug_renderer,
1830
);
1831
}
1832
ProfileStyle::Smart => {
1833
self.draw_smart_profile(
1834
backend_profile,
1835
renderer_profile,
1836
debug_renderer,
1837
);
1838
}
1839
}
1840
}
1841
}
1842
1843
pub struct ChangeIndicator {
1844
counter: u32,
1845
}
1846
1847
impl ChangeIndicator {