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