perf(canvas): cap retained backing size
This commit is contained in:
parent
054199ac15
commit
7b62c8acca
|
|
@ -9,6 +9,7 @@ import type { RenderLayer } from './pipeline'
|
|||
|
||||
const now = typeof performance !== 'undefined' ? () => performance.now() : () => 0
|
||||
const SCENE_BACKING_SCALE = 3
|
||||
const MAX_SCENE_BACKING_DEVICE_PIXELS = 12_000_000
|
||||
const FRAME_BUDGET_60HZ_MS = 1000 / 60
|
||||
const MIN_SCENE_BACKING_IDLE_FRAMES = 2
|
||||
const MAX_SCENE_BACKING_IDLE_FRAMES = 18
|
||||
|
|
@ -45,10 +46,7 @@ export function updateSceneBackingPreviewState(r: SkiaRenderer, layer: RenderLay
|
|||
if (layer !== 'scene') return
|
||||
const previous = r.lastSceneViewport
|
||||
const viewportChanged =
|
||||
!previous ||
|
||||
previous.panX !== r.panX ||
|
||||
previous.panY !== r.panY ||
|
||||
previous.zoom !== r.zoom
|
||||
!previous || previous.panX !== r.panX || previous.panY !== r.panY || previous.zoom !== r.zoom
|
||||
if (viewportChanged) {
|
||||
const timestamp = now()
|
||||
if (r.sceneBackingLastViewportEventAt > 0) {
|
||||
|
|
@ -85,7 +83,12 @@ function backingScreenCoverageContainsViewport(r: SkiaRenderer): boolean {
|
|||
const scale = r.zoom / backing.zoom
|
||||
const x = r.panX - backing.panX * scale
|
||||
const y = r.panY - backing.panY * scale
|
||||
return x <= 0 && y <= 0 && x + backing.width * scale >= r.viewportWidth && y + backing.height * scale >= r.viewportHeight
|
||||
return (
|
||||
x <= 0 &&
|
||||
y <= 0 &&
|
||||
x + backing.width * scale >= r.viewportWidth &&
|
||||
y + backing.height * scale >= r.viewportHeight
|
||||
)
|
||||
}
|
||||
|
||||
function backingWorldCoverageContainsLiveViewport(r: SkiaRenderer): boolean {
|
||||
|
|
@ -129,12 +132,7 @@ function drawSceneBacking(
|
|||
const backing = r.sceneBacking
|
||||
if (
|
||||
!backing ||
|
||||
!backingCoverageContainsLiveViewport(
|
||||
r,
|
||||
sceneVersion,
|
||||
allowStaleZoom,
|
||||
positionPreviewVersion
|
||||
)
|
||||
!backingCoverageContainsLiveViewport(r, sceneVersion, allowStaleZoom, positionPreviewVersion)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
|
@ -154,9 +152,23 @@ function drawSceneBacking(
|
|||
return true
|
||||
}
|
||||
|
||||
export function sceneBackingScaleForViewport(
|
||||
viewportWidth: number,
|
||||
viewportHeight: number,
|
||||
dpr: number
|
||||
): number {
|
||||
const viewportDevicePixels = Math.max(1, viewportWidth * viewportHeight * dpr * dpr)
|
||||
return clamp(
|
||||
Math.sqrt(MAX_SCENE_BACKING_DEVICE_PIXELS / viewportDevicePixels),
|
||||
1,
|
||||
SCENE_BACKING_SCALE
|
||||
)
|
||||
}
|
||||
|
||||
function sceneBackingGeometry(r: SkiaRenderer) {
|
||||
const marginX = r.viewportWidth * ((SCENE_BACKING_SCALE - 1) / 2)
|
||||
const marginY = r.viewportHeight * ((SCENE_BACKING_SCALE - 1) / 2)
|
||||
const backingScale = sceneBackingScaleForViewport(r.viewportWidth, r.viewportHeight, r.dpr)
|
||||
const marginX = r.viewportWidth * ((backingScale - 1) / 2)
|
||||
const marginY = r.viewportHeight * ((backingScale - 1) / 2)
|
||||
const width = Math.max(1, Math.ceil(r.viewportWidth + marginX * 2))
|
||||
const height = Math.max(1, Math.ceil(r.viewportHeight + marginY * 2))
|
||||
const backingPanX = r.panX + marginX
|
||||
|
|
@ -464,4 +476,3 @@ export function renderSceneBacking(
|
|||
positionPreviewVersion
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
import { expect, mock, test } from 'bun:test'
|
||||
|
||||
import type { Canvas, Image as CKImage, Surface } from 'canvaskit-wasm'
|
||||
|
||||
import type { SkiaRenderer } from '#core/canvas/renderer'
|
||||
import { renderSceneBacking } from '#core/canvas/renderer/retained-backing'
|
||||
import {
|
||||
renderSceneBacking,
|
||||
sceneBackingScaleForViewport
|
||||
} from '#core/canvas/renderer/retained-backing'
|
||||
import type { SceneGraph } from '#core/scene-graph'
|
||||
|
||||
function createRenderer(surfaceFactory: () => Surface | null) {
|
||||
|
|
@ -75,6 +79,12 @@ function createGraph(positionPreviewVersion = 0) {
|
|||
return graph as SceneGraph
|
||||
}
|
||||
|
||||
test('retained scene backing caps large viewport backing allocations', () => {
|
||||
expect(sceneBackingScaleForViewport(400, 300, 1)).toBe(3)
|
||||
expect(sceneBackingScaleForViewport(2560, 1600, 2)).toBe(1)
|
||||
expect(sceneBackingScaleForViewport(2560, 1600, 1)).toBeLessThan(2)
|
||||
})
|
||||
|
||||
test('retained scene backing falls back when CanvasKit cannot create an offscreen surface', () => {
|
||||
const r = createRenderer(() => null)
|
||||
const canvas = createCanvas()
|
||||
|
|
|
|||
Loading…
Reference in a new issue