||Types and definitions related to compositing picture cache tiles
and/or OS compositor integration.
|| 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
TODO(gw): Add an occupied list head, for fast iteration of the occupied list
to implement retain() style functionality.
Gamma correction lookup tables.
This is a port of Skia gamma LUT logic into Rust, used by WebRender.
|| Overview of the GPU cache.
The main goal of the GPU cache is to allow on-demand
allocation and construction of GPU resources for the
vertex shaders to consume.
Every item that wants to be stored in the GPU cache
should create a GpuCacheHandle that is used to refer
to a cached GPU resource. Creating a handle is a
cheap operation, that does *not* allocate room in the
On any frame when that data is required, the caller
must request that handle, via ```request```. If the
data is not in the cache, the user provided closure
will be invoked to build the data.
After ```end_frame``` has occurred, callers can
use the ```get_address``` API to get the allocated
address in the GPU cache of a given resource slot
for this frame.
|| 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
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
A GPU based renderer for the web.
It serves as an experimental render backend for [Servo](https://servo.org/),
but it can also be used as such in a standalone application.
# External dependencies
WebRender currently depends on [FreeType](https://www.freetype.org/)
# Api Structure
The main entry point to WebRender is the [`crate::Renderer`].
By calling [`Renderer::new(...)`](crate::Renderer::new) you get a [`Renderer`], as well as
a [`RenderApiSender`](api::RenderApiSender). Your [`Renderer`] is responsible to render the
previously processed frames onto the screen.
By calling [`yourRenderApiSender.create_api()`](api::RenderApiSender::create_api), you'll
get a [`RenderApi`](api::RenderApi) instance, which is responsible for managing resources
and documents. A worker thread is used internally to untie the workload from the application
thread and therefore be able to make better use of multicore systems.
What is referred to as a `frame`, is the current geometry on the screen.
A new Frame is created by calling [`set_display_list()`](api::Transaction::set_display_list)
on the [`RenderApi`](api::RenderApi). When the geometry is processed, the application will be
informed via a [`RenderNotifier`](api::RenderNotifier), a callback which you pass to
More information about [stacking contexts][stacking_contexts].
[`set_display_list()`](api::Transaction::set_display_list) also needs to be supplied with
[`BuiltDisplayList`](api::BuiltDisplayList)s. These are obtained by finalizing a
[`DisplayListBuilder`](api::DisplayListBuilder). These are used to draw your geometry. But it
doesn't only contain trivial geometry, it can also store another
[`StackingContext`](api::StackingContext), as they're nestable.
||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.
|| A picture represents a dynamically rendered image.
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
When picture caching is enabled, the scene is cut into a small number of slices,
- 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
Each tile keeps track of the elements that affect it, which can be:
- image keys
- opacity bindings
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
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).
|| # Prepare pass
TODO: document this!
|| # 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.
|| 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.
|| This module contains the render task graph.
Code associated with creating specific render tasks is in the render_task
|| Screen capture infrastructure for the Gecko Profiler and Composition Recorder.
|| Primitive segmentation
Segmenting is the process of breaking rectangular primitives into smaller rectangular
primitives in order to extract parts that could benefit from a fast paths.
Typically this is used to allow fully opaque segments to be rendered in the opaque
pass. For example when an opaque rectangle has a non-axis-aligned transform applied,
we usually have to apply some anti-aliasing around the edges which requires alpha
blending. By segmenting the edges out of the center of the primitive, we can keep a
large amount of pixels in the opaque pass.
Segmenting also lets us avoids rasterizing parts of clip masks that we know to have
no effect or to be fully masking. For example by segmenting the corners of a rounded
rectangle clip, we can optimize both rendering the mask and the primitive by only
rasterize the corners in the mask and not applying any clipping to the segments of
the primitive that don't overlap the borders.
It is a flexible system in the sense that different sources of segmentation (for
example two rounded rectangle clips) can affect the segmentation, and the possibility
to segment some effects such as specific clip kinds does not necessarily mean the
primitive will actually be segmented.
## Segments and clipping
Segments of a primitive can be either not clipped, fully clipped, or partially clipped.
In the first two case we don't need a clip mask. For each partially masked segments, a
mask is rasterized using a render task. All of the interesting steps happen during frame
- The first step is to determine the segmentation and write the associated GPU data.
See `PrimitiveInstance::build_segments_if_needed` and `write_brush_segment_description`
in `prim_store/mod.rs` which uses the segment builder of this module.
- The second step is to generate the mask render tasks.
See `BrushSegment::update_clip_task` and `RenderTask::new_mask`. For each segment that
needs a mask, the contribution of all clips that affect the segment is added to the
mask's render task.
- Segments are assigned to batches (See `batch.rs`). Segments of a given primitive can
be assigned to different batches.
See also the [`clip` module documentation][clip.rs] for details about how clipping
information is represented.
|| Utilities to deal with coordinate spaces.
||Types and functionality related to picture caching. In future, we'll
move more and more of the existing functionality out of picture.rs
and into here.
|| # Visibility pass
TODO: document what this pass does!