• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
15
16import {
17  BaseStruct,
18  drawFlagLine,
19  drawLoading,
20  drawSelection,
21  isFrameContainPoint,
22  ns2x,
23  drawLines,
24  Rect,
25  Render,
26  RequestMessage,
27} from './ProcedureWorkerCommon.js';
28import { TraceRow } from '../../component/trace/base/TraceRow.js';
29
30export class FpsRender extends Render {
31  renderMainThread(
32    req: {
33      context: CanvasRenderingContext2D;
34      useCache: boolean;
35      type: string;
36    },
37    row: TraceRow<FpsStruct>
38  ) {
39    let fpsList = row.dataList;
40    let fpsFilter = row.dataListCache;
41    fps(
42      fpsList,
43      fpsFilter,
44      TraceRow.range!.startNS,
45      TraceRow.range!.endNS,
46      TraceRow.range!.totalNS,
47      row.frame,
48      req.useCache || !TraceRow.range!.refresh
49    );
50    req.context.beginPath();
51    let fpsFind = false;
52    for (let re of fpsFilter) {
53      FpsStruct.draw(req.context, re);
54      if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) {
55        FpsStruct.hoverFpsStruct = re;
56        fpsFind = true;
57      }
58    }
59    if (!fpsFind && row.isHover) FpsStruct.hoverFpsStruct = undefined;
60    req.context.closePath();
61    let maxFps = FpsStruct.maxFps + 'FPS';
62    let textMetrics = req.context.measureText(maxFps);
63    req.context.globalAlpha = 0.8;
64    req.context.fillStyle = '#f0f0f0';
65    req.context.fillRect(0, 5, textMetrics.width + 8, 18);
66    req.context.globalAlpha = 1;
67    req.context.fillStyle = '#333';
68    req.context.textBaseline = 'middle';
69    req.context.fillText(maxFps, 4, 5 + 9);
70  }
71
72  render(fpsRequest: RequestMessage, list: Array<any>, filter: Array<any>) {
73    if (fpsRequest.lazyRefresh) {
74      fps(
75        list,
76        filter,
77        fpsRequest.startNS,
78        fpsRequest.endNS,
79        fpsRequest.totalNS,
80        fpsRequest.frame,
81        fpsRequest.useCache || !fpsRequest.range.refresh
82      );
83    } else {
84      if (!fpsRequest.useCache) {
85        fps(list, filter, fpsRequest.startNS, fpsRequest.endNS, fpsRequest.totalNS, fpsRequest.frame, false);
86      }
87    }
88    if (fpsRequest.canvas) {
89      fpsRequest.context.clearRect(0, 0, fpsRequest.frame.width, fpsRequest.frame.height);
90      let fpsArr = filter;
91      if (fpsArr.length > 0 && !fpsRequest.range.refresh && !fpsRequest.useCache && fpsRequest.lazyRefresh) {
92        drawLoading(
93          fpsRequest.context,
94          fpsRequest.startNS,
95          fpsRequest.endNS,
96          fpsRequest.totalNS,
97          fpsRequest.frame,
98          fpsArr[0].startNS,
99          fpsArr[fpsArr.length - 1].startNS + fpsArr[fpsArr.length - 1].dur
100        );
101      }
102      fpsRequest.context.beginPath();
103      drawLines(fpsRequest.context, fpsRequest.xs, fpsRequest.frame.height, fpsRequest.lineColor);
104      FpsStruct.hoverFpsStruct = undefined;
105      if (fpsRequest.isHover) {
106        for (let re of filter) {
107          if (
108            re.frame &&
109            fpsRequest.hoverX >= re.frame.x &&
110            fpsRequest.hoverX <= re.frame.x + re.frame.width &&
111            fpsRequest.hoverY >= re.frame.y &&
112            fpsRequest.hoverY <= re.frame.y + re.frame.height
113          ) {
114            FpsStruct.hoverFpsStruct = re;
115            break;
116          }
117        }
118      } else {
119        FpsStruct.hoverFpsStruct = fpsRequest.params.hoverFpsStruct;
120      }
121      for (let re of filter) {
122        FpsStruct.draw(fpsRequest.context, re);
123      }
124      drawSelection(fpsRequest.context, fpsRequest.params);
125      fpsRequest.context.closePath();
126      let maxFps = FpsStruct.maxFps + 'FPS';
127      let fpsTextMetrics = fpsRequest.context.measureText(maxFps);
128      fpsRequest.context.globalAlpha = 0.8;
129      fpsRequest.context.fillStyle = '#f0f0f0';
130      fpsRequest.context.fillRect(0, 5, fpsTextMetrics.width + 8, 18);
131      fpsRequest.context.globalAlpha = 1;
132      fpsRequest.context.fillStyle = '#333';
133      fpsRequest.context.textBaseline = 'middle';
134      fpsRequest.context.fillText(maxFps, 4, 5 + 9);
135      drawFlagLine(
136        fpsRequest.context,
137        fpsRequest.flagMoveInfo,
138        fpsRequest.flagSelectedInfo,
139        fpsRequest.startNS,
140        fpsRequest.endNS,
141        fpsRequest.totalNS,
142        fpsRequest.frame,
143        fpsRequest.slicesTime
144      );
145    }
146    // @ts-ignore
147    self.postMessage({
148      id: fpsRequest.id,
149      type: fpsRequest.type,
150      results: fpsRequest.canvas ? undefined : filter,
151      hover: FpsStruct.hoverFpsStruct,
152    });
153  }
154}
155
156export function fps(
157  list: Array<any>,
158  res: Array<any>,
159  startNS: number,
160  endNS: number,
161  totalNS: number,
162  frame: any,
163  use: boolean
164) {
165  if (use && res.length > 0) {
166    res.forEach((it) => FpsStruct.setFrame(it, 5, startNS, endNS, totalNS, frame));
167    return;
168  }
169  FpsStruct.maxFps = 0;
170  res.length = 0;
171  if (list) {
172    for (let i = 0, len = list.length; i < len; i++) {
173      let it = list[i];
174      if ((it.fps || 0) > FpsStruct.maxFps) {
175        FpsStruct.maxFps = it.fps || 0;
176      }
177      if (i === list.length - 1) {
178        it.dur = (endNS || 0) - (it.startNS || 0);
179      } else {
180        it.dur = (list[i + 1].startNS || 0) - (it.startNS || 0);
181      }
182      if ((it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS) {
183        FpsStruct.setFrame(list[i], 5, startNS, endNS, totalNS, frame);
184        if (
185          i > 0 &&
186          (list[i - 1].frame?.x || 0) == (list[i].frame?.x || 0) &&
187          (list[i - 1].frame?.width || 0) == (list[i].frame?.width || 0)
188        ) {
189        } else {
190          res.push(list[i]);
191        }
192      }
193    }
194  }
195}
196
197export class FpsStruct extends BaseStruct {
198  static maxFps: number = 0;
199  static maxFpsName: string = '0 FPS';
200  static hoverFpsStruct: FpsStruct | undefined;
201  static selectFpsStruct: FpsStruct | undefined;
202  fps: number | undefined;
203  startNS: number | undefined = 0;
204  dur: number | undefined; //自补充,数据库没有返回
205
206  static draw(fpsContext: CanvasRenderingContext2D, data: FpsStruct) {
207    if (data.frame) {
208      let width = data.frame.width || 0;
209      fpsContext.fillStyle = '#535da6';
210      fpsContext.strokeStyle = '#535da6';
211      if (data === FpsStruct.hoverFpsStruct) {
212        fpsContext.lineWidth = 1;
213        fpsContext.globalAlpha = 0.6;
214        let drawHeight: number = ((data.fps || 0) * (data.frame.height || 0) * 1.0) / FpsStruct.maxFps;
215        fpsContext.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight);
216        fpsContext.beginPath();
217        fpsContext.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight, 3, 0, 2 * Math.PI, true);
218        fpsContext.fill();
219        fpsContext.globalAlpha = 1.0;
220        fpsContext.stroke();
221        fpsContext.beginPath();
222        fpsContext.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight);
223        fpsContext.lineWidth = 3;
224        fpsContext.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight);
225        fpsContext.stroke();
226      } else {
227        fpsContext.globalAlpha = 0.6;
228        fpsContext.lineWidth = 1;
229        let drawHeight: number = ((data.fps || 0) * (data.frame.height || 0) * 1.0) / FpsStruct.maxFps;
230        fpsContext.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight);
231      }
232    }
233    fpsContext.globalAlpha = 1.0;
234    fpsContext.lineWidth = 1;
235  }
236
237  static setFrame(fpsNode: FpsStruct, padding: number, startNS: number, endNS: number, totalNS: number, frame: Rect) {
238    let x1: number, x2: number;
239    if ((fpsNode.startNS || 0) < startNS) {
240      x1 = 0;
241    } else {
242      x1 = ns2x(fpsNode.startNS || 0, startNS, endNS, totalNS, frame);
243    }
244    if ((fpsNode.startNS || 0) + (fpsNode.dur || 0) > endNS) {
245      x2 = frame.width;
246    } else {
247      x2 = ns2x((fpsNode.startNS || 0) + (fpsNode.dur || 0), startNS, endNS, totalNS, frame);
248    }
249    let getV: number = x2 - x1 <= 1 ? 1 : x2 - x1;
250    let rectangle: Rect = new Rect(
251      Math.floor(x1),
252      Math.ceil(frame.y + padding),
253      Math.ceil(getV),
254      Math.floor(frame.height - padding * 2)
255    );
256    fpsNode.frame = rectangle;
257  }
258}
259
260const textPadding = 2;
261