1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
content / browser / resources / webxr_internals / session_statistics_table.ts [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {CustomElement} from 'chrome://resources/js/custom_element.js';
import {getTemplate} from './session_statistics_table.html.js';
import type {XrFrameStatistics, XrLogMessage} from './xr_session.mojom-webui.js';
const COLUMN_NAMES = ['Logs'];
export class SessionStatisticsTable extends CustomElement {
textLines: string[];
totalDuration: bigint;
static override get template() {
return getTemplate();
}
constructor() {
super();
this.totalDuration = 0n;
this.textLines = [COLUMN_NAMES.join(', ')];
const table =
this.getRequiredElement<HTMLTableElement>('#session-statistics-table');
const headerRow = table.insertRow();
COLUMN_NAMES.forEach((columnName) => {
const headerCell = document.createElement('th');
headerCell.textContent = columnName;
headerRow.appendChild(headerCell);
});
// Add event listener to the button
const button = this.getRequiredElement<HTMLTableElement>('#copy-button');
button.addEventListener('click', () => {
this.copyToClipboard();
});
}
addXrSessionStatisticsRow(xrSessionStatistics: XrFrameStatistics) {
const durationInMilliseconds =
xrSessionStatistics.duration.microseconds / 1000n;
this.totalDuration += durationInMilliseconds;
const durationInSeconds = durationInMilliseconds / 1000n;
const fps = xrSessionStatistics.numFrames / durationInSeconds;
const droppedFrames = xrSessionStatistics.droppedFrames / durationInSeconds;
const frameDataTime = this.getDisplayMillisecondsFromMicroSeconds(
xrSessionStatistics.frameDataTime.microseconds);
const animationFrameTime = this.getDisplayMillisecondsFromMicroSeconds(
xrSessionStatistics.pageAnimationFrameTime.microseconds);
const submitFrameTime = this.getDisplayMillisecondsFromMicroSeconds(
xrSessionStatistics.submitFrameTime.microseconds);
const cellValues = [
`${this.totalDuration}`,
`${fps}`,
`${droppedFrames}`,
`${frameDataTime}`,
`${animationFrameTime}`,
`${submitFrameTime}`,
];
this.textLines.push(cellValues.join(', '));
const cellValuesString = `Duration:${this.totalDuration}ms, Frame Rate:${
fps}, Dropped Frames:${droppedFrames}, Frame Data Time:${
frameDataTime}ms/frame, Animation Frame Time:${
animationFrameTime}ms/frame, Submit Frame Time:${
submitFrameTime}ms/frame`;
this.addRow([cellValuesString]);
}
addRow(cellValues: string[]) {
const table =
this.getRequiredElement<HTMLTableElement>('#session-statistics-table');
const newRow = table.insertRow();
cellValues.forEach((value) => {
const cell = newRow.insertCell();
cell.textContent = value;
});
}
// Method to copy textLines to clipboard
async copyToClipboard(): Promise<void> {
const textToCopy = this.textLines.join('\n');
await navigator.clipboard.writeText(textToCopy);
}
addConsoleMessageRow(xrLogMessage: XrLogMessage) {
const message = xrLogMessage.message;
this.addRow([message]);
}
// Method to convert microseconds to milliseconds and round to 2 decimal
// places and return it as a string
getDisplayMillisecondsFromMicroSeconds(time: bigint): string {
const timeInMilliseconds = Number(time) / 1000;
return timeInMilliseconds.toFixed(2);
}
}
// Declare the custom element
declare global {
interface HTMLElementTagNameMap {
'session-statistics-table': SessionStatisticsTable;
}
}
customElements.define('session-statistics-table', SessionStatisticsTable);