From e9edebbbb5d471ba7352423870048189a5c544c2 Mon Sep 17 00:00:00 2001 From: Aitor Moreno Date: Wed, 28 May 2025 09:41:07 +0200 Subject: [PATCH] :books: Add tile rendering documentation (#6568) --- render-wasm/docs/images/tile_rendering.svg | 333 ++++++++++++++++++ .../docs/images/tile_rendering_image.png | Bin 0 -> 7859 bytes ...le_rendering_image_with_bounding_boxes.png | Bin 0 -> 8480 bytes ...ndering_image_with_bounding_boxes_grid.png | Bin 0 -> 9054 bytes render-wasm/docs/tile_rendering.md | 228 ++++++++++++ 5 files changed, 561 insertions(+) create mode 100644 render-wasm/docs/images/tile_rendering.svg create mode 100644 render-wasm/docs/images/tile_rendering_image.png create mode 100644 render-wasm/docs/images/tile_rendering_image_with_bounding_boxes.png create mode 100644 render-wasm/docs/images/tile_rendering_image_with_bounding_boxes_grid.png create mode 100644 render-wasm/docs/tile_rendering.md diff --git a/render-wasm/docs/images/tile_rendering.svg b/render-wasm/docs/images/tile_rendering.svg new file mode 100644 index 0000000000..db9e78a56a --- /dev/null +++ b/render-wasm/docs/images/tile_rendering.svg @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + diff --git a/render-wasm/docs/images/tile_rendering_image.png b/render-wasm/docs/images/tile_rendering_image.png new file mode 100644 index 0000000000000000000000000000000000000000..f8d20e5de31c8e70c243c5a386d390dbaacb898e GIT binary patch literal 7859 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 literal 0 HcmV?d00001 diff --git a/render-wasm/docs/images/tile_rendering_image_with_bounding_boxes.png b/render-wasm/docs/images/tile_rendering_image_with_bounding_boxes.png new file mode 100644 index 0000000000000000000000000000000000000000..95cf151c1eb4935d75d077e392de6a3226eb9e68 GIT binary patch literal 8480 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 LEnXb;y7qqn--O4g literal 0 HcmV?d00001 diff --git a/render-wasm/docs/images/tile_rendering_image_with_bounding_boxes_grid.png b/render-wasm/docs/images/tile_rendering_image_with_bounding_boxes_grid.png new file mode 100644 index 0000000000000000000000000000000000000000..779182640a0fa4272861b95d79607eb4832b21d2 GIT binary patch literal 9054 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 wp#LBK<>3FGm_~nhP$ 💡 We use a `HashMap>` to track which shapes belong to each tile. + +![Landscape bounding boxes and grid](images/tile_rendering_image_with_bounding_boxes_grid.png) + +Once the tiles are determined, we sort them starting from the center of the viewport, using Manhattan distance to prioritize rendering closer tiles first, so the user can see the end result faster. + +### Rendering Step-by-Step + +1. Viewbox updates trigger a re-render, which happens on the initial render, user interactions (such as creating or moving shapes), panning, or zooming. +2. The `TileViewbox` is updated based on the new `Viewbox` (visible area plus margins of interest). +3. The system identifies tiles that are currently visible (`visible_rect`) and tiles just outside the viewport for preloading (`interest_rect`). +4. For each visible tile: + - **If cached**: + - Draw the cached rendered tile directly from `TileTextureCache` to `Surface::Target`. + - **If not cached**: + - Fetch intersecting shapes using `TileHashMap`. + - Render shape layers onto temporary surfaces: + - **Fills** → Shape fills + - **Strokes** → Outlines + - **Shadows** → Visual effects like drop or inner shadows to shapes + - **Current** → Composite tile layer (the final rendered tile before caching) + - **Target** → Final canvas image where the composed tile is drawn; this is the surface ultimately displayed on screen after composing the tile layers. + - Compose and cache the result using `cache_current_tile_texture(tile, image)`. + - Copy the final tile image to `Surface::Target`. + +### Rendering Across Multiple Frames + +To avoid blocking the browser's main thread, tile rendering is distributed across multiple animation frames. This ensures smooth interactivity and responsiveness, even for large canvases or complex documents. + +- Tiles are **sorted by priority** (typically using Manhattan distance to the viewport center). +- A limited number of tiles are rendered per frame based on a time or count budget. +- A limited number of tiles are rendered per animation frame based on either a time budget (to avoid blocking the main thread) or a maximum tile count, typically processing around 5–10 tiles per frame to balance performance and responsiveness. +- A limited number of tiles are rendered per animation frame. After processing every `NODE_BATCH_THRESHOLD` shapes, the system checks if the allotted time budget has been exceeded to decide whether to pause rendering and continue in the next frame. This approach avoids continuous time checks while preventing blocking the main thread. + +- After each batch, control is yielded back to the browser to: + - Allow UI updates + - Handle user input + - Maintain consistent frame rates + +> 💡 This technique is similar to how map web apps or graphics engines progressively load and render content. + +This incremental rendering strategy ensures: +- The most relevant (visible) tiles appear first. +- Remaining tiles are rendered progressively, minimizing perceived latency. +- The user interface remains responsive during rendering operations. + +### Interaction and Updates + +When a user interacts with a shape (creates, moves, or edits a shape): + +- Tiles to be re-rendered are computed using the shape's bounding box. +- `TileHashMap` updates to reflect which shapes are rendered in each tile. +- Affected tiles are invalidated in the cache. +- Only those tiles are re-rendered. + +When zooming or panning: + +- New tiles entering the `visible_rect` are identified. + +> 💡 `visible_rect` stores the current set of tiles that intersect with the viewbox — that is, the exact area visible on screen, without any margin of interest. + +- These tiles are either: + - Pulled from the cache, or + - Rendered from scratch if not already available. + +### Handling Zoom and Scale + +- Tile resolution depends on zoom level (`scale`). +- When zoomed in significantly, higher-resolution tiles are required. +- If the zoom changes beyond a threshold, the cache may be invalidated, and tiles re-rendered at the new scale. + +## Why Cache Tiles? + +Tile caching (via `TileTextureCache`) boosts performance: + +- Prevents unnecessary rendering. +- Only a limited number of tiles are kept in memory (`TEXTURES_CACHE_CAPACITY`). +- Distant tiles are periodically evicted using an LRU (Least Recently Used)-like strategy based on visibility. + +## Scaling and Tile Size Utilities + +Tile size in screen space is constant, but its actual visual size depends on zoom level (`scale`). + +To deal with this, the system uses utility functions: + +- `get_tile_size(scale)`: Gets the logical size of a tile at the current scale. +- `get_tile_rect(tile, scale)`: Gets the rectangular area a tile covers. +- `get_tile_pos(tile, scale)`: Gets the tile’s position in canvas coordinates. + +These allow rendering logic to adapt tile positions/sizes dynamically. + +## Selective Re-rendering + +The system enables: + +- Efficient updates when the viewport changes. +- Targeted re-rendering when a shape changes (only the affected tiles). +- Reduced GPU/CPU work on complex documents. + +## Rendering Pipeline Summary (Per Frame) + +1. **Input** + +Each rendering frame begins with the following inputs: + +- `tree`: A mutable hashmap of all drawable shapes, keyed by UUID. +- `modifiers`: A hashmap of transformation matrices to apply to shapes, keyed by UUID. +- `structure`: A hashmap representing the shape hierarchy and their children. +- `Viewbox`: Defines the current viewport — the visible portion of the canvas, including zoom level and position. +- `timestamp`: A time marker used for animations and time-based updates. + +2. **Compute `TileViewbox`** + - From `Viewbox`, generate visible + interest regions. + +3. **Determine tiles to render** + - Compare tiles to be rendered vs cached ones. + - Detect cache hits and misses. + - Invalidate stale tiles if the viewport changed significantly. + +4. **Render cached tiles** + - Fetch image from `TileTextureCache`. + - Blit to `Surface::Target`. + +5. **Render uncached tiles from scratch** + - Find the shapes intersecting with this tile (`TileHashMap`). + - Render the tile layers on their `skia::Surface` instances, using blending, opacity, masking, etc. when needed. + - Each layer is rendered on a `skia::Surface`. + - Use blending, opacity, masking, etc. + - Store the resulting texture in the cache: + `cache_current_tile_texture(tile, image)` + - Draw the tile to `Surface::Target`. + +6. **Handle user interactions** + - When shapes are modified: + 1. Determine affected tiles. + 2. Invalidate those tiles in the cache. + 3. Re-render them selectively. + - When panning or zooming: + - Detect the visible tiles. + - Fetch them from the cache or render them if needed. + +## Summary of Benefits + +- **Modular pipeline**: It separates surfaces per layer, enabling composite rendering. +- **Avoid unnecessary re-renders**: A cache is used to avoid re-rendering when nothing has changed. +- **Progressive**: Only visible/nearby tiles are drawn. +- **Efficient**: Selective invalidation of cached tiles minimizes GPU/CPU usage on large documents. +- **Scalable with screen siz**: Works well for both small and large canvases due to tile granularity and smart caching. + +## References + +- [Chromium Tile Prioritization Design](https://docs.google.com/document/d/1tkwOlSlXiR320dFufuA_M-RF9L5LxFWmZFg5oW35rZk/edit?tab=t.0) +- [WebGL Best Practices](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices) +- [When Optimisations Work, But for the Wrong Reasons](https://www.youtube.com/watch?v=hf27qsQPRLQ&ab_channel=SimonDev) +- [Life of a Triangle](https://pixeljetstream.blogspot.com/2015/02/life-of-triangle-nvidias-logical.html) +- [A Trip Through the Graphics Pipeline 2011](https://fgiesen.wordpress.com/2011/07/09/a-trip-through-the-graphics-pipeline-2011-index/) \ No newline at end of file