1// Copyright (C) 2018 The Android Open Source Project 2// 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 {Actions} from '../../common/actions'; 16import {TrackState} from '../../common/state'; 17import {checkerboardExcept} from '../../frontend/checkerboard'; 18import {globals} from '../../frontend/globals'; 19import {Track} from '../../frontend/track'; 20import {trackRegistry} from '../../frontend/track_registry'; 21 22import {Config, Data, KIND} from './common'; 23 24// TODO(hjd): De-dupe this from ChromeSliceTrack, CpuSliceTrack and VsyncTrack. 25const MARGIN_TOP = 5; 26const RECT_HEIGHT = 30; 27 28function getCurResolution() { 29 // Truncate the resolution to the closest power of 10. 30 const resolution = globals.frontendLocalState.timeScale.deltaPxToDuration(1); 31 return Math.pow(10, Math.floor(Math.log10(resolution))); 32} 33 34class VsyncTrack extends Track<Config, Data> { 35 static readonly kind = KIND; 36 static create(trackState: TrackState): VsyncTrack { 37 return new VsyncTrack(trackState); 38 } 39 40 private reqPending = false; 41 42 constructor(trackState: TrackState) { 43 super(trackState); 44 } 45 46 reqDataDeferred() { 47 const {visibleWindowTime} = globals.frontendLocalState; 48 const reqStart = visibleWindowTime.start - visibleWindowTime.duration; 49 const reqEnd = visibleWindowTime.end + visibleWindowTime.duration; 50 const reqRes = getCurResolution(); 51 this.reqPending = false; 52 globals.dispatch(Actions.reqTrackData({ 53 trackId: this.trackState.id, 54 start: reqStart, 55 end: reqEnd, 56 resolution: reqRes 57 })); 58 } 59 60 renderCanvas(ctx: CanvasRenderingContext2D): void { 61 const {timeScale, visibleWindowTime} = globals.frontendLocalState; 62 63 const data = this.data(); 64 const inRange = data !== undefined && 65 (visibleWindowTime.start >= data.start && 66 visibleWindowTime.end <= data.end); 67 if (!inRange || data === undefined || 68 data.resolution !== getCurResolution()) { 69 if (!this.reqPending) { 70 this.reqPending = true; 71 setTimeout(() => this.reqDataDeferred(), 50); 72 } 73 } 74 if (data === undefined) return; // Can't possibly draw anything. 75 76 const dataStartPx = timeScale.timeToPx(data.start); 77 const dataEndPx = timeScale.timeToPx(data.end); 78 const visibleStartPx = timeScale.timeToPx(visibleWindowTime.start); 79 const visibleEndPx = timeScale.timeToPx(visibleWindowTime.end); 80 81 checkerboardExcept( 82 ctx, visibleStartPx, visibleEndPx, dataStartPx, dataEndPx); 83 84 const bgColor = '#5E909B'; 85 const fgColor = '#323D48'; 86 87 const startPx = Math.floor(Math.max(dataStartPx, visibleStartPx)); 88 const endPx = Math.floor(Math.min(dataEndPx, visibleEndPx)); 89 90 ctx.fillStyle = bgColor; 91 ctx.fillRect(startPx, MARGIN_TOP, endPx - startPx, RECT_HEIGHT); 92 93 ctx.fillStyle = fgColor; 94 for (let i = 0; i < data.vsyncs.length; i += 2) { 95 const leftPx = Math.floor(timeScale.timeToPx(data.vsyncs[i])); 96 const rightPx = Math.floor(timeScale.timeToPx(data.vsyncs[i + 1])); 97 if (rightPx < startPx) continue; 98 // TODO(hjd): Do some thing better when very zoomed out. 99 if ((rightPx - leftPx) <= 1) continue; 100 if (leftPx > endPx) break; 101 ctx.fillRect(leftPx, MARGIN_TOP, rightPx - leftPx, RECT_HEIGHT); 102 } 103 } 104} 105 106trackRegistry.register(VsyncTrack); 107