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);