in web/src/app/timeline/canvas/timeline_renderer.service.ts [397:549]
public onRender(
gl: WebGL2RenderingContext,
canvasSize: CanvasSize,
offsetToFirstItemFromVisibleArea: number,
visibleItemRange: ListRange,
perRowScrollingProperties: PerRowScrollingProperty[],
rowRenderers: Map<ResourceTimeline, TimelineRowWebGLRenderer>,
timeRange: TimeRange,
stickyTimelines: ResourceTimeline[],
selectedTimeline: ResourceTimeline | null,
highlightedTimeline: ResourceTimeline | null,
highlightedByParentSelection: Set<ResourceTimeline>,
logs: LogEntry[],
selectedLog: number,
filteredLog: Set<number>,
highlightLogs: Set<number>,
pixelPerTime: number,
timeOffset: number,
pixelRatio: number,
) {
if (gl.isContextLost()) {
if (!this.initializingGLResources) {
console.warn(
'Detected the webgl context being lost. Reinitializing gl resources',
);
this.refleshGL();
}
return;
}
this.sharedGLResources!.updateViewState(
canvasSize.width * pixelRatio,
canvasSize.height * pixelRatio,
pixelPerTime * pixelRatio,
pixelRatio,
timeOffset - timeRange.begin,
);
// No items to render
if (visibleItemRange.end - visibleItemRange.start === 0) {
gl.disable(gl.SCISSOR_TEST);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.finish();
console.warn('no items to render. Clear screen');
return;
}
const firstItemOffset =
perRowScrollingProperties.length > 0
? perRowScrollingProperties[visibleItemRange.start].offset
: 0;
for (let i = visibleItemRange.start; i < visibleItemRange.end; i++) {
if (perRowScrollingProperties.length <= i) continue;
const row = perRowScrollingProperties[i];
if (!row.source) continue;
const renderer = rowRenderers.get(row.source);
if (!renderer) continue;
// Calculate the draw area for each timelines
const bottom =
canvasSize.height - (row.offset - firstItemOffset) - row.height;
const region: GLRect = {
left: 0 * pixelRatio,
width: canvasSize.width * pixelRatio,
bottom: bottom * pixelRatio,
height: row.height * pixelRatio,
};
renderer.loadGLResources();
renderer.updateInteractiveBuffer(selectedLog, highlightLogs, filteredLog);
renderer.render(
pixelRatio,
region,
row.source === selectedTimeline,
row.source === highlightedTimeline,
highlightedByParentSelection.has(row.source),
);
}
// render sticky timelines
let offset = 0;
for (const timeline of stickyTimelines) {
const row: PerRowScrollingProperty = {
height: TIMELINE_ITEM_HEIGHTS[timeline.layer],
offset: offset,
source: timeline,
};
if (!row.source) continue;
const renderer = rowRenderers.get(row.source);
if (!renderer) continue;
// Calculate the draw area for each timelines
const bottom =
canvasSize.height -
row.offset -
row.height +
offsetToFirstItemFromVisibleArea;
const region: GLRect = {
left: 0 * pixelRatio,
width: canvasSize.width * pixelRatio,
bottom: bottom * pixelRatio,
height: row.height * pixelRatio,
};
renderer.loadGLResources();
renderer.updateInteractiveBuffer(selectedLog, highlightLogs, filteredLog);
renderer.render(
pixelRatio,
region,
row.source === selectedTimeline,
row.source === highlightedTimeline,
highlightedByParentSelection.has(row.source),
);
offset += row.height;
}
if (selectedLog !== -1) {
this.selectedTimeVerticalLineRenderer!.render(
canvasSize,
pixelRatio,
this.sharedGLResources!,
logs[selectedLog].time - timeRange.begin,
4,
[0, 1, 0, 0.9],
);
}
gl.flush();
gl.finish();
// To prevent blocking rendering the timeline currently shown, preloading step is after calling gl.finish()
for (
let i = visibleItemRange.start;
i >=
Math.max(
0,
Math.min(visibleItemRange.start, perRowScrollingProperties.length) -
TimelineRendererService.PRELOAD_GL_RESOURCE_AREA,
);
i--
) {
const row = perRowScrollingProperties[i];
if (!row.source) continue;
rowRenderers.get(row.source)?.loadGLResources();
}
for (
let i = visibleItemRange.end;
i <
Math.min(
perRowScrollingProperties.length,
visibleItemRange.end + TimelineRendererService.PRELOAD_GL_RESOURCE_AREA,
);
i++
) {
const row = perRowScrollingProperties[i];
if (!row.source) continue;
rowRenderers.get(row.source)?.loadGLResources();
}
}