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  PerfRender,
19  Rect,
20  RequestMessage,
21} from './ProcedureWorkerCommon';
22import { TraceRow } from '../../component/trace/base/TraceRow';
23import { ColorUtils } from '../../component/trace/base/ColorUtils';
24import { SpSystemTrace } from '../../component/SpSystemTrace';
25
26export class GpuCounterRender extends PerfRender {
27  renderMainThread(
28    req: {
29      context: CanvasRenderingContext2D,
30      useCache: boolean,
31      type: string,
32      startTime: number,
33      maxValue: number,
34    },
35    row: TraceRow<GpuCounterStruct>
36  ): void {
37    let filter = row.dataListCache;
38    let startTime = req.startTime;
39    let maxValue = req.maxValue;
40    let type = req.type;
41    gpuCounterChart(
42      filter,
43      startTime,
44      type,
45      TraceRow.range?.startNS ?? 0,
46      TraceRow.range?.endNS ?? 0,
47      TraceRow.range?.totalNS ?? 0,
48      maxValue,
49      row.frame,
50      req.useCache || (TraceRow.range?.refresh ?? false)
51    );
52    drawGpuCounter(req, filter, row);
53  }
54
55  render(eBPFRequest: RequestMessage, list: Array<unknown>, filter: Array<unknown>, dataList2: Array<unknown>): void { }
56}
57
58function drawGpuCounter(
59  req: {
60    context: CanvasRenderingContext2D,
61    useCache: boolean,
62    type: string,
63    startTime: number,
64    maxValue: number,
65  },
66  filter: unknown[],
67  row: TraceRow<GpuCounterStruct>
68): void {
69  req.context.beginPath();
70  let find = false;
71  for (let i = 0; i < filter.length; i++) {
72    let it = filter[i];
73    if (
74      //@ts-ignore
75      row.isHover && it.frame &&
76      //@ts-ignore
77      row.hoverX >= it.frame.x &&
78      //@ts-ignore
79      row.hoverX <= it.frame.x + it.frame.width
80    ) {
81      //@ts-ignore
82      GpuCounterStruct.hoverGpuCounterStruct = it;
83      find = true;
84    }
85    //@ts-ignore
86    GpuCounterStruct.draw(req.context, it);
87  }
88  if (!find && row.isHover) {
89    GpuCounterStruct.hoverGpuCounterStruct = undefined;
90  }
91  req.context.closePath();
92}
93
94export function gpuCounterChart(
95  dataList: Array<unknown>,
96  startTime: number,
97  type: string,
98  startNS: number,
99  endNS: number,
100  totalNS: number,
101  maxValue: number,
102  frame: Rect,
103  use: boolean
104): void {
105  setFrameGroup(dataList, startTime, type, startNS, endNS, frame, maxValue);
106}
107
108function setFrameGroup(dataList: Array<unknown>, startTime: number, type: string, startNS: number, endNS: number, frame: Rect, maxValue: number): void {
109  let pns = (endNS - startNS) / frame.width;
110  let y = frame.y;
111  for (let i = 0; i < dataList.length; i++) {
112    let it = dataList[i];
113    //@ts-ignore
114    if ((it.startNS || 0) + (it.dur || 0) - startTime > startNS && (it.startNS || 0) - startTime < endNS) {
115      //@ts-ignore
116      if (!it.frame) {
117        //@ts-ignore
118        it.frame = {};
119        //@ts-ignore
120        it.frame.y = y;
121      }
122      //@ts-ignore
123      it.frame.height = Math.ceil((it.height / maxValue) * 38) || 1;
124      //@ts-ignore
125      it.startTime = startTime;
126      //@ts-ignore
127      it.type = type;
128      GpuCounterStruct.setFrame(it, startTime, pns, startNS, endNS, frame);
129    } else {
130      //@ts-ignore
131      it.frame = null;
132    }
133  }
134}
135
136export function gpuCounterStructOnClick(
137  clickRowType: string,
138  sp: SpSystemTrace,
139  entry?: GpuCounterStruct,
140): Promise<unknown> {
141  return new Promise((resolve, reject) => {
142    if (clickRowType === TraceRow.ROW_TYPE_GPU_COUNTER && (GpuCounterStruct.hoverGpuCounterStruct || entry)) {
143      GpuCounterStruct.selectGpuCounterStruct = entry || GpuCounterStruct.hoverGpuCounterStruct;
144      sp.traceSheetEL?.displayGpuCounterData(GpuCounterStruct.selectGpuCounterStruct!);
145      sp.timerShaftEL?.modifyFlagList(undefined);
146      reject(new Error());
147    } else {
148      resolve(null);
149    }
150  });
151}
152
153export class GpuCounterStruct extends BaseStruct {
154  static hoverGpuCounterStruct: GpuCounterStruct | undefined;
155  static selectGpuCounterStruct: GpuCounterStruct | undefined;
156  startNS: number | undefined;
157  endNS: number | undefined;
158  dur: number | undefined;
159  type: string | undefined;
160  startTime: number | undefined;
161  height: number | undefined;
162  static draw(ctx: CanvasRenderingContext2D, data: GpuCounterStruct): void {
163    if (data.frame) {
164      ctx.fillStyle = ColorUtils.MD_PALETTE[0];
165      ctx.strokeStyle = ColorUtils.MD_PALETTE[0];
166      ctx.fillRect(data.frame.x, 40 - data.frame.height, data.frame.width, data.frame.height);
167      if (data.type === GpuCounterStruct.selectGpuCounterStruct?.type && data.startNS === GpuCounterStruct.selectGpuCounterStruct?.startNS) {
168        ctx.strokeStyle = '#000';
169        ctx.lineWidth = 1;
170        ctx.strokeRect(data.frame.x, 40 - data.frame.height, data.frame.width - 2, data.frame.height);
171      }
172    }
173  }
174
175  static setFrame(
176    eBPFtemNode: unknown,
177    startTime: number,
178    pns: number,
179    startNS: number,
180    endNS: number,
181    frame: unknown
182  ): void {
183    //@ts-ignore
184    if ((eBPFtemNode.startNS - startTime || 0) < startNS) {
185      //@ts-ignore
186      eBPFtemNode.frame.x = 0;
187    } else {
188      //@ts-ignore
189      eBPFtemNode.frame.x = Math.floor((((eBPFtemNode.startNS - startTime) || 0) - startNS) / pns);
190    }
191    //@ts-ignore
192    if ((eBPFtemNode.startNS || 0) + (eBPFtemNode.dur || 0) - startTime > endNS) {
193      //@ts-ignore
194      eBPFtemNode.frame.width = frame.width - eBPFtemNode.frame.x;
195    } else {
196      //@ts-ignore
197      eBPFtemNode.frame.width = Math.ceil(((eBPFtemNode.startNS + eBPFtemNode.dur - startTime) - startNS) / pns - eBPFtemNode.frame.x);
198    }
199    //@ts-ignore
200    if (eBPFtemNode.frame.width < 1) {
201      //@ts-ignore
202      eBPFtemNode.frame.width = 1;
203    }
204  }
205}
206
207export class MaleoonCounterObj {
208  [key: string]: Array<unknown>;
209  gpu_clocks: Array<unknown>;
210  tiler_utilization: Array<unknown>;
211  binning_utilization: Array<unknown>;
212  rendering_utilization: Array<unknown>;
213  compute_utilization: Array<unknown>;
214  drawcall_count: Array<unknown>;
215  vertex_count: Array<unknown>;
216  primitives_count: Array<unknown>;
217  visible_primitives_count: Array<unknown>;
218  compute_invocations_count: Array<unknown>;
219  shader_utilization: Array<unknown>;
220  eu_utilization: Array<unknown>;
221  eu_stall_utilization: Array<unknown>;
222  eu_idle_utilization: Array<unknown>;
223  control_flow_instr_utilization: Array<unknown>;
224  half_float_instr_utilization: Array<unknown>;
225  tu_utilization: Array<unknown>;
226  concurrent_warps: Array<unknown>;
227  instruction_count: Array<unknown>;
228  quads_count: Array<unknown>;
229  texels_count: Array<unknown>;
230  memory_read: Array<unknown>;
231  memory_write: Array<unknown>;
232  memory_traffic: Array<unknown>;
233  constructor() {
234    this.gpu_clocks = [];
235    this.tiler_utilization = [];
236    this.binning_utilization = [];
237    this.rendering_utilization = [];
238    this.compute_utilization = [];
239
240    this.drawcall_count = [];
241    this.vertex_count = [];
242    this.primitives_count = [];
243    this.visible_primitives_count = [];
244    this.compute_invocations_count = [];
245
246    this.shader_utilization = [];
247    this.eu_utilization = [];
248    this.eu_stall_utilization = [];
249    this.eu_idle_utilization = [];
250    this.control_flow_instr_utilization = [];
251    this.half_float_instr_utilization = [];
252    this.tu_utilization = [];
253
254    this.concurrent_warps = [];
255    this.instruction_count = [];
256    this.quads_count = [];
257    this.texels_count = [];
258
259    this.memory_read = [];
260    this.memory_write = [];
261    this.memory_traffic = [];
262  }
263}
264
265export class GpuCounterType {
266  [key: string]: Array<unknown>;
267  'cycle': Array<unknown>;
268  'drawcall': Array<unknown>;
269  'shader_cycle': Array<unknown>;
270  'local_count': Array<unknown>;
271  'local_wr': Array<unknown>;
272  constructor() {
273    this.cycle = [];
274    this.drawcall = [];
275    this.shader_cycle = [];
276    this.local_count = [];
277    this.local_wr = [];
278  }
279}
280