1fb726d48Sopenharmony_ci/*
2fb726d48Sopenharmony_ci * Copyright (C) 2022 Huawei Device Co., Ltd.
3fb726d48Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4fb726d48Sopenharmony_ci * you may not use this file except in compliance with the License.
5fb726d48Sopenharmony_ci * You may obtain a copy of the License at
6fb726d48Sopenharmony_ci *
7fb726d48Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8fb726d48Sopenharmony_ci *
9fb726d48Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10fb726d48Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11fb726d48Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fb726d48Sopenharmony_ci * See the License for the specific language governing permissions and
13fb726d48Sopenharmony_ci * limitations under the License.
14fb726d48Sopenharmony_ci */
15fb726d48Sopenharmony_ciimport { query } from '../../database/SqlLite';
16fb726d48Sopenharmony_ciimport { TraceRow } from '../trace/base/TraceRow';
17fb726d48Sopenharmony_ciimport { FlagsConfig } from '../../component/SpFlags';
18fb726d48Sopenharmony_ciinterface VSyncData {
19fb726d48Sopenharmony_ci  startTime: number;
20fb726d48Sopenharmony_ci  dur: number;
21fb726d48Sopenharmony_ci  value?: number;
22fb726d48Sopenharmony_ci}
23fb726d48Sopenharmony_ci
24fb726d48Sopenharmony_cilet vSyncDataList: VSyncData[] = [];
25fb726d48Sopenharmony_cilet vSyncEnable = false;
26fb726d48Sopenharmony_cilet isSingle = false;
27fb726d48Sopenharmony_ci
28fb726d48Sopenharmony_ciexport function resetVSync(): void {
29fb726d48Sopenharmony_ci  vSyncEnable = false;
30fb726d48Sopenharmony_ci}
31fb726d48Sopenharmony_ci
32fb726d48Sopenharmony_ciexport const querySfVSyncData = (): Promise<Array<VSyncData>> =>
33fb726d48Sopenharmony_ci  query(
34fb726d48Sopenharmony_ci    'querySfVSyncData',
35fb726d48Sopenharmony_ci    `SELECT value, c.ts - tb.start_ts startTime
36fb726d48Sopenharmony_ci     FROM process_measure c,
37fb726d48Sopenharmony_ci          trace_range tb
38fb726d48Sopenharmony_ci     WHERE c.filter_id IN (SELECT process_measure_filter.id AS traceId
39fb726d48Sopenharmony_ci                           FROM process_measure_filter
40fb726d48Sopenharmony_ci                                    JOIN process USING (ipid)
41fb726d48Sopenharmony_ci                           WHERE process.name = ${
42fb726d48Sopenharmony_ci                             `'` +
43fb726d48Sopenharmony_ci                             String.fromCharCode(115, 117, 114, 102, 97, 99, 101, 102, 108, 105, 110, 103, 101, 114) +
44fb726d48Sopenharmony_ci                             `'`
45fb726d48Sopenharmony_ci                           }
46fb726d48Sopenharmony_ci                             AND process_measure_filter.name = ${
47fb726d48Sopenharmony_ci                               `'` + String.fromCharCode(86, 83, 89, 78, 67, 45, 97, 112, 112) + `'`
48fb726d48Sopenharmony_ci                             })`
49fb726d48Sopenharmony_ci  );
50fb726d48Sopenharmony_ci
51fb726d48Sopenharmony_ci  export const querySingleVSyncData = (): Promise<Array<VSyncData>> => {
52fb726d48Sopenharmony_ci    let flagsItem = window.localStorage.getItem(FlagsConfig.FLAGS_CONFIG_KEY);
53fb726d48Sopenharmony_ci    let flagsItemJson = JSON.parse(flagsItem!);
54fb726d48Sopenharmony_ci    let vsyncValue = flagsItemJson.vsyncValue;  
55fb726d48Sopenharmony_ci    let vsyncCondition = '';
56fb726d48Sopenharmony_ci    if (vsyncValue === 'H:VsyncGenerator' || vsyncValue === '') {
57fb726d48Sopenharmony_ci      vsyncCondition = ` AND (callstack.name like 'H:GenerateVsyncCount%'))`;
58fb726d48Sopenharmony_ci    } else {
59fb726d48Sopenharmony_ci      vsyncCondition = ` AND callstack.name like '${vsyncValue}%' )`;
60fb726d48Sopenharmony_ci    }
61fb726d48Sopenharmony_ci  
62fb726d48Sopenharmony_ci    let sql =
63fb726d48Sopenharmony_ci      `SELECT c.ts - tb.start_ts startTime
64fb726d48Sopenharmony_ci     FROM callstack c,
65fb726d48Sopenharmony_ci          trace_range tb
66fb726d48Sopenharmony_ci     WHERE c.id IN (SELECT callstack.id AS trackId
67fb726d48Sopenharmony_ci                    FROM callstack
68fb726d48Sopenharmony_ci                             JOIN process
69fb726d48Sopenharmony_ci                    WHERE process.name = 'render_service'`
70fb726d48Sopenharmony_ci      + vsyncCondition;
71fb726d48Sopenharmony_ci    return query('querySingleVSyncData', sql);
72fb726d48Sopenharmony_ci  }
73fb726d48Sopenharmony_ci
74fb726d48Sopenharmony_ci/**
75fb726d48Sopenharmony_ci * load single vsync data
76fb726d48Sopenharmony_ci */
77fb726d48Sopenharmony_ciexport async function setVSyncData(): Promise<void> {
78fb726d48Sopenharmony_ci  let sfvSyncData = await querySfVSyncData();
79fb726d48Sopenharmony_ci  if (sfvSyncData.length === 0) {
80fb726d48Sopenharmony_ci    sfvSyncData = await querySingleVSyncData();
81fb726d48Sopenharmony_ci    isSingle = true;
82fb726d48Sopenharmony_ci  }
83fb726d48Sopenharmony_ci  sfvSyncData.forEach((it, index, array): void => {
84fb726d48Sopenharmony_ci    if (index < array.length - 1) {
85fb726d48Sopenharmony_ci      it.dur = array[index + 1].startTime - it.startTime;
86fb726d48Sopenharmony_ci    } else {
87fb726d48Sopenharmony_ci      it.dur = window.totalNS - it.startTime;
88fb726d48Sopenharmony_ci    }
89fb726d48Sopenharmony_ci  });
90fb726d48Sopenharmony_ci  vSyncDataList = sfvSyncData;
91fb726d48Sopenharmony_ci}
92fb726d48Sopenharmony_ci
93fb726d48Sopenharmony_ci/**
94fb726d48Sopenharmony_ci * draw chart
95fb726d48Sopenharmony_ci */
96fb726d48Sopenharmony_ciexport function drawVSync(ctx: CanvasRenderingContext2D, width: number, height: number): void {
97fb726d48Sopenharmony_ci  if (!vSyncEnable) {
98fb726d48Sopenharmony_ci    return;
99fb726d48Sopenharmony_ci  }
100fb726d48Sopenharmony_ci  function draw(it: VSyncData): void {
101fb726d48Sopenharmony_ci    let x = ns2x(it.startTime, width);
102fb726d48Sopenharmony_ci    let x2 = ns2x(it.startTime + it.dur, width);
103fb726d48Sopenharmony_ci    ctx.fillRect(x, 0, x2 - x, height);
104fb726d48Sopenharmony_ci  }
105fb726d48Sopenharmony_ci  ctx.beginPath();
106fb726d48Sopenharmony_ci  ctx.fillStyle = '#555555';
107fb726d48Sopenharmony_ci  ctx.lineWidth = 1;
108fb726d48Sopenharmony_ci  ctx.globalAlpha = 0.3;
109fb726d48Sopenharmony_ci  if (isSingle) {
110fb726d48Sopenharmony_ci    // 单框架灰白交替
111fb726d48Sopenharmony_ci    for (let i = 0; i < vSyncDataList.length; i++) {
112fb726d48Sopenharmony_ci      if (i % 2 === 1) {
113fb726d48Sopenharmony_ci        continue;
114fb726d48Sopenharmony_ci      }
115fb726d48Sopenharmony_ci      draw(vSyncDataList[i]);
116fb726d48Sopenharmony_ci    }
117fb726d48Sopenharmony_ci  } else {
118fb726d48Sopenharmony_ci    // 双框架绘制vSync 信号为1的数据为灰
119fb726d48Sopenharmony_ci    vSyncDataList
120fb726d48Sopenharmony_ci      ?.filter((it) => it.value === 1)
121fb726d48Sopenharmony_ci      .forEach((it) => {
122fb726d48Sopenharmony_ci        draw(it);
123fb726d48Sopenharmony_ci      });
124fb726d48Sopenharmony_ci  }
125fb726d48Sopenharmony_ci  ctx.stroke();
126fb726d48Sopenharmony_ci  ctx.globalAlpha = 1.0;
127fb726d48Sopenharmony_ci  ctx.closePath();
128fb726d48Sopenharmony_ci}
129fb726d48Sopenharmony_ci
130fb726d48Sopenharmony_ci/**
131fb726d48Sopenharmony_ci * enable/disable SingleVSync
132fb726d48Sopenharmony_ci */
133fb726d48Sopenharmony_ciexport function enableVSync(press: boolean, ev: KeyboardEvent, handler?: Function): void {
134fb726d48Sopenharmony_ci  if (ev.key.toLocaleLowerCase() === 'v' && !ev.ctrlKey) {
135fb726d48Sopenharmony_ci    window.publish(window.SmartEvent.UI.Loading, { loading: true, text: 'Query VSync' });
136fb726d48Sopenharmony_ci    setVSyncData();
137fb726d48Sopenharmony_ci    window.publish(window.SmartEvent.UI.Loading, { loading: false, text: 'Query VSync' });
138fb726d48Sopenharmony_ci    vSyncEnable = !vSyncEnable;
139fb726d48Sopenharmony_ci    handler?.();
140fb726d48Sopenharmony_ci  }
141fb726d48Sopenharmony_ci}
142fb726d48Sopenharmony_ci
143fb726d48Sopenharmony_ci/**
144fb726d48Sopenharmony_ci * ns to px
145fb726d48Sopenharmony_ci */
146fb726d48Sopenharmony_cifunction ns2x(ns: number, width: number): number {
147fb726d48Sopenharmony_ci  let startNS = TraceRow.range?.startNS || 0;
148fb726d48Sopenharmony_ci  let endNS = TraceRow.range?.endNS || 0;
149fb726d48Sopenharmony_ci  if (endNS === 0) {
150fb726d48Sopenharmony_ci    //@ts-ignore
151fb726d48Sopenharmony_ci    endNS = (window as unknown).totalNS;
152fb726d48Sopenharmony_ci  }
153fb726d48Sopenharmony_ci  let xWidth: number = ((ns - startNS) * width) / (endNS - startNS);
154fb726d48Sopenharmony_ci  if (xWidth < 0) {
155fb726d48Sopenharmony_ci    xWidth = 0;
156fb726d48Sopenharmony_ci  } else if (xWidth > width) {
157fb726d48Sopenharmony_ci    xWidth = width;
158fb726d48Sopenharmony_ci  }
159fb726d48Sopenharmony_ci  return xWidth;
160fb726d48Sopenharmony_ci}
161