| api_resources.rs |
|
12725 |
- |
| batch.rs |
|
53213 |
- |
| border.rs |
|
53303 |
- |
| border_image.rs |
|
13193 |
- |
| box_shadow.rs |
|
22342 |
- |
| bump_allocator.rs |
|
15713 |
- |
| capture.rs |
|
8789 |
- |
| clip.rs |
|
103479 |
- |
| command_buffer.rs |
|
21645 |
- |
| composite.rs |
Types and definitions related to compositing picture cache tiles
and/or OS compositor integration.
|
74422 |
- |
| compositor |
|
|
- |
| debug_colors.rs |
|
14804 |
- |
| debug_font_data.rs |
|
117993 |
- |
| debug_item.rs |
|
709 |
- |
| debugger.rs |
|
17658 |
- |
| device |
|
|
- |
| ellipse.rs |
|
6061 |
- |
| filterdata.rs |
|
7160 |
- |
| frame_allocator.rs |
|
16184 |
- |
| frame_builder.rs |
|
59370 |
- |
| freelist.rs |
A generic backing store for caches.
`FreeList` is a simple vector-backed data structure where each entry in the
vector contains an Option<T>. It maintains an index-based (rather than
pointer-based) free list to efficiently locate the next unused entry. If all
entries are occupied, insertion appends a new element to the vector.
It also supports both strong and weak handle semantics. There is exactly one
(non-Clonable) strong handle per occupied entry, which must be passed by
value into `free()` to release an entry. Strong handles can produce an
unlimited number of (Clonable) weak handles, which are used to perform
lookups which may fail of the entry has been freed. A per-entry epoch ensures
that weak handle lookups properly fail even if the entry has been freed and
reused.
TODO(gw): Add an occupied list head, for fast iteration of the occupied list
to implement retain() style functionality. |
7682 |
- |
| glyph_cache.rs |
|
6815 |
- |
| gpu_types.rs |
|
24516 |
- |
| hit_test.rs |
|
13749 |
- |
| image_source.rs |
This module contains the logic to obtain a primitive's source texture and uv rect.
Currently this is a somewhat involved process because the code grew into having ad-hoc
ways to store this information depending on how the image data is produced. The goal
is for any textured primitive to be able to read from any source (texture cache, render
tasks, etc.) without primitive-specific code. |
4277 |
- |
| image_tiling.rs |
|
27944 |
- |
| intern.rs |
The interning module provides a generic data structure
interning container. It is similar in concept to a
traditional string interning container, but it is
specialized to the WR thread model.
There is an Interner structure, that lives in the
scene builder thread, and a DataStore structure
that lives in the frame builder thread.
Hashing, interning and handle creation is done by
the interner structure during scene building.
Delta changes for the interner are pushed during
a transaction to the frame builder. The frame builder
is then able to access the content of the interned
handles quickly, via array indexing.
Epoch tracking ensures that the garbage collection
step which the interner uses to remove items is
only invoked on items that the frame builder thread
is no longer referencing.
Items in the data store are stored in a traditional
free-list structure, for content access and memory
usage efficiency.
The epoch is incremented each time a scene is
built. The most recently used scene epoch is
stored inside each handle. This is then used for
cache invalidation. |
17146 |
- |
| internal_types.rs |
|
37833 |
- |
| invalidation |
|
|
- |
| lib.rs |
!
A GPU based renderer for the web.
WebRender turns display lists into GPU draw calls. It is the rendering engine of
Firefox, and can also be used standalone.
# Api Structure
[`create_webrender_instance()`](crate::create_webrender_instance) returns a
[`Renderer`] plus a [`RenderApiSender`](crate::render_api::RenderApiSender). The
[`Renderer`] owns the GPU connection and draws frames; the sender is how you talk
to everything else.
[`create_api()`](crate::render_api::RenderApiSender::create_api) gives you a
[`RenderApi`](crate::render_api::RenderApi), which manages resources and
documents. Work is submitted as a
[`Transaction`](crate::render_api::Transaction) — most importantly
[`set_display_list()`](crate::render_api::Transaction::set_display_list), which
takes a [`BuiltDisplayList`](api::BuiltDisplayList) produced by finalizing a
[`DisplayListBuilder`](api::DisplayListBuilder). Display lists nest
[stacking contexts][stacking_contexts]. Completion is reported through the
[`RenderNotifier`](api::RenderNotifier) you passed at init.
# Threads
Work is split across threads, and knowing which thread a piece of code runs on
explains most of the structure here:
- **Scene builder thread** (`scene_builder_thread.rs`, `scene_building.rs`)
turns display lists into a [`BuiltScene`](crate::scene::BuiltScene). Runs
asynchronously; only re-runs when the display list changes.
- **Render backend thread** (`render_backend.rs`, `frame_builder.rs`) turns a
scene plus the current scroll/animation state into a `Frame`. Runs every
frame. This is where most of the interesting logic lives.
- **Render thread** (`renderer/`, `device/`) is the only thread that touches the
GPU, and is also the initial entry point into the crate.
The `renderer` module documentation describes the render/render-backend split in
more detail. Rayon workers and the [`glyph_rasterizer`] are used for parallel
work underneath these.
# Anatomy of a frame
`FrameBuilder::build` in `frame_builder.rs` runs these stages in order. Each has
its own module, and this is the sequence to follow when tracing why something
renders wrongly:
1. **Picture graph passes** (`picture_graph.rs`) walk the picture tree in
dependency order, assign off-screen surfaces (`surface.rs`) and propagate
bounding rects.
2. **Visibility** (`visibility.rs`) culls primitives, resolves clip chains
(`clip.rs`), snaps rects to the pixel grid, and updates picture-cache tile
dependencies (`tile_cache/`, `invalidation/`).
3. **Prepare** (`prepare.rs`) walks each visible primitive by `PrimitiveKind`,
builds its `Pattern` (`pattern/`), requests any render tasks it needs, and
emits draw commands into command buffers (`command_buffer.rs`). Most
primitives go through the quad path (`quad.rs`).
4. **Render task graph** (`render_task_graph.rs`) is finalized: tasks are
assigned to passes and to render target allocations (`render_target.rs`).
5. **Batching** (`batch.rs`) replays the command buffers per pass, grouping
draws into batches keyed by shader and textures.
6. **Compositing** (`composite.rs`) builds the list of picture-cache tiles to
present, either drawn by us or handed to an OS compositor (`compositor/`).
The [`Renderer`] then submits the resulting `Frame`: it uploads resources,
executes the passes in order, and composites.
# Further reading
- `gfx/docs/RenderingOverview.md` — how WebRender fits into Gecko, plus the
picture / spatial / clip / render-task trees. Note it predates the quad and
pattern architecture described above and still describes the retired brush
shaders.
- `gfx/wr/webrender/doc/coordinate-spaces.md` — the spatial tree, and the
local / picture / raster / world / device spaces. Predates the `VisPixel`
visibility space.
- `gfx/wr/webrender/doc/text-rendering.md`, `blob.md`,
`CLIPPING_AND_POSITIONING.md`, `swizzling.md` — subsystem deep dives, in
varying states of currency.
# External dependencies
WebRender depends on [FreeType](https://www.freetype.org/) for font rasterization
on some platforms.
[stacking_contexts]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context
|
8892 |
- |
| lru_cache.rs |
This module implements a least recently used cache structure, which is
used by the texture cache to manage the lifetime of items inside the
texture cache. It has a few special pieces of functionality that the
texture cache requires, but should be usable as a general LRU cache
type if useful in other areas.
The cache is implemented with two types of backing freelists. These allow
random access to the underlying data, while being efficient in both
memory access and allocation patterns.
The "entries" freelist stores the elements being cached (for example, the
CacheEntry structure for the texture cache). These elements are stored
in arbitrary order, reusing empty slots in the freelist where possible.
The "lru_index" freelists store the LRU tracking information. Although the
tracking elements are stored in arbitrary order inside a freelist for
efficiency, they use next/prev links to represent a doubly-linked list,
kept sorted in order of recent use. The next link is also used to store
the current freelist within the array when the element is not occupied.
The LRU cache allows having multiple LRU "partitions". Every entry is tracked
by exactly one partition at any time; all partitions refer to entries in the
shared freelist. Entries can move between partitions, if replace_or_insert is
called with a new partition index for an existing handle.
The partitioning is used by the texture cache so that, for example, allocating
more glyph entries does not cause eviction of image entries (which go into
a different shared texture). If an existing handle's entry is reallocated with
a new size, it might need to move from a shared texture to a standalone
texture; in this case the handle will move to a different LRU partition.
|
23503 |
- |
| pattern |
|
|
- |
| picture.rs |
A picture represents a dynamically rendered image.
# Overview
Pictures consists of:
- A number of primitives that are drawn onto the picture.
- A composite operation describing how to composite this
picture into its parent.
- A configuration describing how to draw the primitives on
this picture (e.g. in screen space or local space).
The tree of pictures are generated during scene building.
Depending on their composite operations pictures can be rendered into
intermediate targets or folded into their parent picture.
## Picture caching
Pictures can be cached to reduce the amount of rasterization happening per
frame.
When picture caching is enabled, the scene is cut into a small number of slices,
typically:
- content slice
- UI slice
- background UI slice which is hidden by the other two slices most of the time.
Each of these slice is made up of fixed-size large tiles of 2048x512 pixels
(or 128x128 for the UI slice).
Tiles can be either cached rasterized content into a texture or "clear tiles"
that contain only a solid color rectangle rendered directly during the composite
pass.
## Invalidation
Each tile keeps track of the elements that affect it, which can be:
- primitives
- clips
- image keys
- opacity bindings
- transforms
These dependency lists are built each frame and compared to the previous frame to
see if the tile changed.
The tile's primitive dependency information is organized in a quadtree, each node
storing an index buffer of tile primitive dependencies.
The union of the invalidated leaves of each quadtree produces a per-tile dirty rect
which defines the scissor rect used when replaying the tile's drawing commands and
can be used for partial present.
## Display List shape
WR will first look for an iframe item in the root stacking context to apply
picture caching to. If that's not found, it will apply to the entire root
stacking context of the display list. Apart from that, the format of the
display list is not important to picture caching. Each time a new scroll root
is encountered, a new picture cache slice will be created. If the display
list contains more than some arbitrary number of slices (currently 8), the
content will all be squashed into a single slice, in order to save GPU memory
and compositing performance.
## Compositor Surfaces
Sometimes, a primitive would prefer to exist as a native compositor surface.
This allows a large and/or regularly changing primitive (such as a video, or
webgl canvas) to be updated each frame without invalidating the content of
tiles, and can provide a significant performance win and battery saving.
Since drawing a primitive as a compositor surface alters the ordering of
primitives in a tile, we use 'overlay tiles' to ensure correctness. If a
tile has a compositor surface, _and_ that tile has primitives that overlap
the compositor surface rect, the tile switches to be drawn in alpha mode.
We rely on only promoting compositor surfaces that are opaque primitives.
With this assumption, the tile(s) that intersect the compositor surface get
a 'cutout' in the rectangle where the compositor surface exists (not the
entire tile), allowing that tile to be drawn as an alpha tile after the
compositor surface.
Tiles are only drawn in overlay mode if there is content that exists on top
of the compositor surface. Otherwise, we can draw the tiles in the normal fast
path before the compositor surface is drawn. Use of the per-tile valid and
dirty rects ensure that we do a minimal amount of per-pixel work here to
blend the overlay tile (this is not always optimal right now, but will be
improved as a follow up). |
137976 |
- |
| picture_composite_mode.rs |
|
54864 |
- |
| picture_graph.rs |
|
6886 |
- |
| picture_textures.rs |
|
12222 |
- |
| prepare.rs |
# Prepare pass
The second frame building traversal of the picture tree. It runs after the
[visibility pass](crate::visibility).
Where visibility decides what is drawn, prepare decides how: it turns each
visible primitive into the render tasks, GPU data and draw commands needed
to render it.
Its outputs are:
- Render tasks and their dependencies in the render task graph.
- GPU buffer data.
- [`PrimitiveCommand`]s pushed into the command buffers of the surfaces and
tiles the primitive is drawn into. `batch.rs` replays these at the
end of frame building to produce the actual draw calls.
## Traversal
[`prepare_picture`] is the entry point. It does a recursive traversal of
the picture and it's visible items.
## Per-primitive work
The bulk of the module is a large match over [`PrimitiveKind`] in
`prepare_prim_for_render`, where each kind:
- Requests the resources it needs, such as texture cache entries (images,
glyphs) or render tasks (rasterized borders, blurred box shadow,cached
gradients, etc.).
- Writes the GPU data for the primitive.
- Push potentially multiple commands to command buffers.
|
54165 |
- |
| prim_store |
|
|
- |
| print_tree.rs |
|
3278 |
- |
| profiler.rs |
# Overlay profiler
## Profiler UI string syntax
Comma-separated list of of tokens with trailing and leading spaces trimmed.
Each tokens can be:
- A counter name with an optional prefix. The name corresponds to the displayed name (see the
counters vector below.
- By default (no prefix) the counter is shown as average + max over half a second.
- With a '#' prefix the counter is shown as a graph.
- With a '*' prefix the counter is shown as a change indicator.
- Some special counters such as GPU time queries have specific visualizations ignoring prefixes.
- A preset name to append the preset to the UI (see PROFILER_PRESETS).
- An empty token to insert a bit of vertical space.
- A '|' token to start a new column.
- A '_' token to start a new row. |
78836 |
- |
| quad.rs |
|
96671 |
- |
| rectangle_occlusion.rs |
A simple occlusion culling algorithm for axis-aligned rectangles.
## Output
Occlusion culling results in two lists of rectangles:
- The opaque list should be rendered first. None of its rectangles overlap so order doesn't matter
within the opaque pass.
- The non-opaque list (or alpha list) which should be rendered in back-to-front order after the opaque pass.
The output has minimal overdraw (no overdraw at all for opaque items and as little as possible for alpha ones).
## Algorithm overview
The occlusion culling algorithm works in front-to-back order, accumulating rectangle in opaque and non-opaque lists.
Each time a rectangle is added, it is first tested against existing opaque rectangles and potentially split into visible
sub-rectangles, or even discarded completely. The front-to-back order ensures that once a rectangle is added it does not
have to be modified again, making the underlying data structure trivial (append-only).
## splitting
Partially visible rectangles are split into up to 4 visible sub-rectangles by each intersecting occluder.
```ascii
+----------------------+ +----------------------+
| rectangle | | |
| | | |
| +-----------+ | +--+-----------+-------+
| |occluder | | --> | |\\\\\\\\\\\| |
| +-----------+ | +--+-----------+-------+
| | | |
+----------------------+ +----------------------+
```
In the example above the rectangle is split into 4 visible parts with the central occluded part left out.
This implementation favors longer horizontal bands instead creating nine-patches to deal with the corners.
The advantage is that it produces less rectangles which is good for the performance of the algorithm and
for SWGL which likes long horizontal spans, however it would cause artifacts if the resulting rectangles
were to be drawn with a non-axis-aligned transformation.
## Performance
The cost of the algorithm grows with the number of opaque rectangle as each new rectangle is tested against
all previously added opaque rectangles.
Note that opaque rectangles can either be added as opaque or non-opaque. This means a trade-off between
overdraw and number of rectangles can be explored to adjust performance: Small opaque rectangles, especially
towards the front of the scene, could be added as non-opaque to avoid causing many splits while adding only
a small amount of overdraw.
This implementation is intended to be used with a small number of (opaque) items. A similar implementation
could use a spatial acceleration structure for opaque rectangles to perform better with a large amount of
occluders.
|
7526 |
- |
| render_api.rs |
|
66092 |
- |
| render_backend.rs |
The high-level module responsible for managing the pipeline and preparing
commands to be issued by the `Renderer`.
See the comment at the top of the `renderer` module for a description of
how these two pieces interact. |
106940 |
- |
| render_backend_pool.rs |
Pool of render-backend threads.
Each pool member owns three threads — a render backend thread and its
companion scene builder and (optional) low-priority scene builder. Windows
are assigned to a member round-robin via [`RenderBackendPool::assign`],
after which a `WindowRegistration` message is sent on the member's api
channel to install per-window state. |
9836 |
- |
| render_target.rs |
|
43367 |
- |
| render_task.rs |
|
104802 |
- |
| render_task_cache.rs |
|
14503 |
- |
| render_task_graph.rs |
This module contains the render task graph.
Code associated with creating specific render tasks is in the render_task
module. |
54292 |
- |
| renderdoc.rs |
On-demand integration with the RenderDoc in-application capture API.
A capture is armed via a `DebugCommand::CaptureRenderDoc` (driven from the
WebRender debugger / wrshell); the next composited frame is then wrapped in a
RenderDoc frame capture and the path of the written `.rdc` is returned.
RenderDoc hooks OpenGL at library-load time, so `librenderdoc` must be loaded
*before* the GL context is created. In practice this means launching the
host process (e.g. Firefox) with `LD_PRELOAD=.../librenderdoc.so`. We resolve
the already-loaded library with `RTLD_NOLOAD` and use the in-app API entry
point; we deliberately do not load a fresh copy, since a late load cannot
install the GL hooks. |
10272 |
- |
| renderer |
|
|
- |
| resource_cache.rs |
|
101075 |
- |
| scene.rs |
|
15072 |
- |
| scene_builder_thread.rs |
|
42785 |
- |
| scene_building.rs |
# Scene building
Scene building is the phase during which display lists, a representation built for
serialization, are turned into a scene, webrender's internal representation that is
suited for rendering frames.
This phase is happening asynchronously on the scene builder thread.
# General algorithm
The important aspects of scene building are:
- Building up primitive lists (much of the cost of scene building goes here).
- Creating pictures for content that needs to be rendered into a surface, be it so that
filters can be applied or for caching purposes.
- Maintaining a temporary stack of stacking contexts to keep track of some of the
drawing states.
- Stitching multiple display lists which reference each other (without cycles) into
a single scene (see build_reference_frame).
- Interning, which detects when some of the retained state stays the same between display
lists.
The scene builder linearly traverses the serialized display list which is naturally
ordered back-to-front, accumulating primitives in the top-most stacking context's
primitive list.
At the end of each stacking context (see pop_stacking_context), its primitive list is
either handed over to a picture if one is created, or it is concatenated into the parent
stacking context's primitive list.
The flow of the algorithm is mostly linear except when handling:
- shadow stacks (see push_shadow and pop_all_shadows),
- backdrop filters (see add_backdrop_filter)
|
176687 |
- |
| screen_capture.rs |
Screen capture infrastructure for the Gecko Profiler and Composition Recorder. |
19837 |
- |
| segment.rs |
|
40784 |
- |
| shutdown_test.rs |
|
13775 |
- |
| space.rs |
Utilities to deal with coordinate spaces. |
33970 |
- |
| spatial_node.rs |
|
48716 |
- |
| spatial_tree.rs |
|
71855 |
- |
| surface.rs |
Contains functionality to help building the render task graph from a series of off-screen
surfaces that are created during the prepare pass, and other surface related types and
helpers. |
46397 |
- |
| svg_filter.rs |
|
89718 |
- |
| telemetry.rs |
|
2740 |
- |
| texture_cache.rs |
|
69885 |
- |
| texture_pack |
|
|
- |
| tile_cache |
|
|
- |
| transform.rs |
|
11130 |
- |
| util.rs |
|
46544 |
- |
| visibility.rs |
# Visibility pass
The first of the two frame building traversals of the picture tree, the
second being the [prepare pass](crate::prepare). It is driven by
`FrameBuilder::build_layer_screen_rects_and_cull_layers`, which calls
[`update_prim_visibility`] once per snapshot picture and once per tile cache
slice. From there the pass walks down the picture tree, pushing and popping
off-screen surfaces as it goes.
For each primitive instance it visits, the pass works out whether the
primitive is drawn this frame and under which clips, and records the answer
in a [`PrimitiveDrawHeader`], pushed into `scratch.primitive.frame.draws`
as each drawn primitive is found.
Later passes read those headers instead of re-deriving the information.
In addition to visibility calculation, this pass performs snapping and
builds clip chain instances.
## Surface bookkeeping
Alongside the per-primitive state, the traversal accumulates the exact
(clipped) local rect of each off-screen surface from the coverage rects of
the primitives drawn into it, and propagates culling rects from parent to
child surfaces. The prepare pass sizes the surfaces' render tasks from those
accumulated rects, so they must be complete before it runs, which is the
main reason visibility is a separate pass.
|
26766 |
- |