Webrender 1.0
Daosheng Mu
Mozilla
07/26/2016
Introduction
● The rendering engine of Servo
○ Implementations of essentially all features of CSS that Servo supports.
○ Working on enabled by default.
○ Separately from Servo
● Initial commit: September 22, 2015.
● Two main developers: Glenn Watson (lead) and Patrick Walton.
● OpenGL-based renderer
● This is just version 1.0… Still in progress.
Why Webrender?
GPU API modes
Retained mode Immediate mode Tiled-based mode
In 2000s PC GPUs In 2010s mobile GPUsIn 1990s PC GPUs
[In existing APIs] path rendering can result in many state changes per
path…In this case, the API overhead can substantially limit the overall
performance. Our experience…indicates these approaches are often more
GPU-assisted rather than GPU-accelerated…
—Mark Kilgard and Jeff Bolz, NVIDIA
SIGGRAPH Asia 2012
Today web browsers respecify paths every time a web page with path content
is re-rendered assuming re-specifying paths is cheap…When path rendering is
fully GPU-accelerated, a retained model of rendering is more appropriate and
efficient. We believe web browsers should behave more like video games in
this respect to exploit the GPU.
—Mark Kilgard and Jeff Bolz, NVIDIA
SIGGRAPH Asia 2012
Retained vs. Immediate mode
● Framework example: WPF vs. Direct2D
● Immediate mode gives the control of GPU pipeline to developers.
○ If you are good at this, your application would gain more performance. Otherwise...
● Immediate mode doesn’t help the management of scene, state, and batch.
● Retained mode have display lists for managing drawcalls & states. Ex: OpenGL 2.0
--- Advanced Game Programming 3D Mathematics.
Graphics API
“Game engines do scene graph no matter
retained mode or immediate mode API”
“Scene graph == Software retained mode”
Batching
State management
Sorting
etc...
--- Advanced Game Programming 3D Mathematics.
Graphics API
How about Web browser?
CSS DOM
simple scene graph
Batching
State management
Sorting
etc...
GPU synchronization
● Mode transition
● Command buffer
“glFinish​. It will not return, stopping the current CPU thread, until all
rendering commands that have been sent have completed.”
What is Webrender?
● A game engine (renderer) for Web browser
● Retained mode, multithreaded
● Focus on CSS
● Takes a post-layout CSS display list and draws it to the screen as quickly as
possible.
● Webrender supports OpenGL ES 2.1 and OpenGL 3.x.
○ Instance rendering / Loop in shaders
● Webrender could be used as a backend for any sort of 2D graphics that CSS can
describe
How Webrender work?
IOCompositor::
composite
Event
IOCompositor::
composite_specific_target
Servo
Renderer thread
Renderer::update
Renderer::render
publish_frame
build_scene
frame.create
render
frame.build
run
Renderer::new
Create OpenGL device
Create shader / texture
Spawn render_backend thread
webrender_traits
IOCompositor::
set_frame_tree
RenderBackend thread
ApiMsg::
SetRootPipeline
ApiMsg::
SetRootPipeline
Webrender
RendererFrame
draw RendererFrame
Main thread
Steps
1. Add items to display list
2. Scene graph: frame, layer, AABB tree, culling
3. Render
1. Add items to display list
DisplayItem
● The minimum unit of renderable item
● It describes by a visible rect and clip region
● Types:
○ RectangleDisplayItem
○ TextDisplayItem
○ ImageDisplayItem
○ WebGLDisplayItem
○ BorderDisplayItem
○ BoxShadowDisplayItem
○ GradientDisplayItem
DisplayListBuilder
pub enum SpecificDisplayListItem {
DrawList(DrawListInfo),
StackingContext(StackingContextInfo),
Iframe(IframeInfo),
}
○ Store items to a list
○ Finalize
■ Generate a displaylist as Blob
convert_to_webrender
StackingContext
● Stacking context is the three-dimensional conceptualization of HTML elements
along an imaginary z-axis relative to the user who is assumed to be facing the
viewport or the webpage
pub struct StackingContext {
pub servo_id: ServoStackingContextId,
pub scroll_layer_id: Option<ScrollLayerId>,
pub scroll_policy: ScrollPolicy,
pub bounds: Rect<f32>,
pub overflow: Rect<f32>,
pub z_index: i32,
pub display_lists: Vec<DisplayListId>,
pub transform: Matrix4,
pub perspective: Matrix4,
pub establishes_3d_context: bool,
pub mix_blend_mode: MixBlendMode,
pub filters: ItemRange,
pub has_stacking_contexts: bool,
}
StackingContext
- display_list [id]
Scene
- display_list_map(id,
display_list)StackingContext
DisplayItem
● Scene.add_stacking_context
● Scene.add_display_list
● Scene.set_root_stacking_context
Main thread
render_backend
thread
APIMsg::
SetRootStackingContext
Servo Webrender
Scene
● Pipeline_map / display_list_map / stacking_context_map
● Set_root_stacking_context()
○ Remove old display list and stacking_context
○ New a scene pipeline
○ Insert to pipeline_map and remove old one
pub struct ScenePipeline {
pub pipeline_id: PipelineId,
pub epoch: Epoch,
pub background_draw_list: Option<DrawListId>,
pub root_stacking_context_id: StackingContextId,
pub viewport_size: Size2D<f32>,
}
display_list_map
pipeline_id display_list(SpecificDisplayListItem)
pipeline_id display_list(DrawList)
Ex:
pipeline_id display_list(StackingContext)
pipeline_id display_list(Iframe)
pub enum SpecificSceneItem {
DrawList(DrawListId),
StackingContext(StackingContextId, PipelineId),
Iframe(IframeInfo),
}
pub struct SceneDisplayList {
pipeline_id
SceneItem<Vec>
epoch
}
SpecificDisplayListItem is mapped
to SpecificSceneItem
Stored to
stacking_context_map
StackingContextId SceneStackingContext
stacking_context
stacking_context
stacking_context
pub struct SceneStackingContext {
pub pipeline_id: PipelineId,
pub epoch: Epoch,
pub stacking_context: StackingContext,
pub stacking_context_id: StackingContextId,
}
StackingContextId
StackingContextId
StackingContextId
2. Scene graph
Viewport
Render target
Layer
Layer
Layer
AABB
AABB
AABB
● Build_scene -> Do scene graph
● Render -> Generate RenderFrame
Main thread
render_backend
thread
APIMsg::
SetRootPipeline
● Get root stacking_context
● Create render target
● Create layer
Create new Layer
add_items_to_target
Scrollable
stacking
context
Yes
No
Render_backend::
build_scene()
Frame::create() Frame::flatten()
● Add items to render
target
Frame::create
● Create a root layer and render target
● Flatten
○ Try to add to the existing layers as an AABB node or create a new one
■ Determine by whether the same scroll_layer_id or not
impl Layer {
pub fn new(world_origin: Point2D<f32>,
layer_size: Size2D<f32>,
viewport_rect: &Rect<f32>,
viewport_transform: &Matrix4D<f32>,
local_transform: &Matrix4D<f32>,
local_perspective: &Matrix4D<f32>,
pipeline_id: PipelineId,
stacking_context_id: ServoStackingContextId)
Layer
● Own an AABB tree to manage scene items
● Cull via view_port rect
Frame::build
● Cull layer’s AABB nodes
○ Adjust viewport to layer’s local space
○ Recursively check_node_visibility->
intersect(viewport rect, AABB node rect) and
mark is_visible to true
● Update
○ Resource
○ Texture
○ Glyph
Cull layers
via viewport rect
Update
Frame::build
● compile_visible_nodes
○ Thread_pool.scoped
○ Node_compiler uses BatchBuilder to batch draw list
(same texture, color)
(batch.rs:add_rectangle)
● update_batch_cache
○ Because some vertex buffers are modified after
batching, pending them to update
● update_layer_transforms
○ Update child layer’s world transform and viewport
to the world space
compile_visible_nodes
update_batch_cache
update_layer_transform
Frame::build
● compile_visible_nodes
○ Thread_pool.scoped
○ Node_compiler uses BatchBuilder to batch draw list
(same texture, color)
(batch.rs:add_rectangle)
● update_batch_cache
○ Because some vertex buffers are modified after
batching, pending them to update
● update_layer_transforms
○ Update child layer’s world transform and viewport
to the world space
compile_visible_nodes
update_batch_cache
update_layer_transform
thread_pool.scoped(|scope| {
for (_, layer) in layers {
let nodes = &mut layer.aabb_tree.nodes;
for node in nodes {
if node.is_visible && node.compiled_node.is_none() {
scope.execute(move || {
node.compile(resource_cache,
frame_id,
device_pixel_ratio,
stacking_context_info,
draw_list_groups,
pipeline_auxiliary_lists);
});
}
}
}
});
Frame::build
● collect_and_sort_visible_batches
○ Collect visible batches from layers and
transform them to RenderTarget space.
○ Traverse RenderTarget tree to collect
■ CompositeBatch (clear buffer,
transform, set texture commands)
■ DrawListBatch (collect draw calls)
○ Generate a DrawLayer tree
○ Return a RendererFrame
● expire_old_resources
collect_and_sort_visible_batches
expire_old_resources
3. Render
Renderer::update
● Pending shader/texture/batch updates
● Set the Rendererframe from Frame::build() to current frame
Renderer::render
● Draw frame
○ Calculate_layer_viewports
■ Layer_viewports ←- a layer owns a viewport
■ Recursive process the child layer’s viewport
○ Draw_layer recursively for children
■ Bind render target
■ Clear buffer
■ Update shaders/texture cache/batches
■ DrawCommand
● Clear frame buffer
● Batch: combine index buffer → draw_simple_triangles
● CompositeBatch ---> apply filter ---> combine index buffer → draw_simple_triangles
● End frame
○ gl::end_frame()
Render thread
RenderBackend thread
Main thread
Summary
StackingContext &
DisplayList creation
ScenePipeline
creation
AABB tree creation
Add DisplayItem
to layers
AABB nodes culling
Draw list batching
Visible batch collection
RenderFrame publication
RenderTarget
binding
Update resource
DrawCommand
execution
APIMsg::
SetRootPipeline
APIMsg::
SetRootStackingContext
RenderBackend::run()
Renderer::render()
CPU waiting GPU time
Webrender teaches us
● Scene graph
○ Using AABB tree to remove invisible display items effectively.
● Batching
○ Reduce draw calls and state changes to save redundant API calls.
● Delay execution draw commands
○ Avoiding unneeded mode-transition to occur CPU / GPU waiting time.
Thanks for your attention
Question?

Webrender 1.0

  • 1.
  • 2.
    Introduction ● The renderingengine of Servo ○ Implementations of essentially all features of CSS that Servo supports. ○ Working on enabled by default. ○ Separately from Servo ● Initial commit: September 22, 2015. ● Two main developers: Glenn Watson (lead) and Patrick Walton. ● OpenGL-based renderer ● This is just version 1.0… Still in progress.
  • 3.
  • 4.
    GPU API modes Retainedmode Immediate mode Tiled-based mode In 2000s PC GPUs In 2010s mobile GPUsIn 1990s PC GPUs
  • 5.
    [In existing APIs]path rendering can result in many state changes per path…In this case, the API overhead can substantially limit the overall performance. Our experience…indicates these approaches are often more GPU-assisted rather than GPU-accelerated… —Mark Kilgard and Jeff Bolz, NVIDIA SIGGRAPH Asia 2012
  • 6.
    Today web browsersrespecify paths every time a web page with path content is re-rendered assuming re-specifying paths is cheap…When path rendering is fully GPU-accelerated, a retained model of rendering is more appropriate and efficient. We believe web browsers should behave more like video games in this respect to exploit the GPU. —Mark Kilgard and Jeff Bolz, NVIDIA SIGGRAPH Asia 2012
  • 7.
    Retained vs. Immediatemode ● Framework example: WPF vs. Direct2D ● Immediate mode gives the control of GPU pipeline to developers. ○ If you are good at this, your application would gain more performance. Otherwise... ● Immediate mode doesn’t help the management of scene, state, and batch. ● Retained mode have display lists for managing drawcalls & states. Ex: OpenGL 2.0
  • 8.
    --- Advanced GameProgramming 3D Mathematics. Graphics API “Game engines do scene graph no matter retained mode or immediate mode API” “Scene graph == Software retained mode” Batching State management Sorting etc...
  • 9.
    --- Advanced GameProgramming 3D Mathematics. Graphics API How about Web browser? CSS DOM simple scene graph Batching State management Sorting etc...
  • 10.
    GPU synchronization ● Modetransition ● Command buffer “glFinish​. It will not return, stopping the current CPU thread, until all rendering commands that have been sent have completed.”
  • 11.
    What is Webrender? ●A game engine (renderer) for Web browser ● Retained mode, multithreaded ● Focus on CSS ● Takes a post-layout CSS display list and draws it to the screen as quickly as possible. ● Webrender supports OpenGL ES 2.1 and OpenGL 3.x. ○ Instance rendering / Loop in shaders ● Webrender could be used as a backend for any sort of 2D graphics that CSS can describe
  • 12.
  • 13.
    IOCompositor:: composite Event IOCompositor:: composite_specific_target Servo Renderer thread Renderer::update Renderer::render publish_frame build_scene frame.create render frame.build run Renderer::new Create OpenGLdevice Create shader / texture Spawn render_backend thread webrender_traits IOCompositor:: set_frame_tree RenderBackend thread ApiMsg:: SetRootPipeline ApiMsg:: SetRootPipeline Webrender RendererFrame draw RendererFrame Main thread
  • 14.
    Steps 1. Add itemsto display list 2. Scene graph: frame, layer, AABB tree, culling 3. Render
  • 15.
    1. Add itemsto display list
  • 16.
    DisplayItem ● The minimumunit of renderable item ● It describes by a visible rect and clip region ● Types: ○ RectangleDisplayItem ○ TextDisplayItem ○ ImageDisplayItem ○ WebGLDisplayItem ○ BorderDisplayItem ○ BoxShadowDisplayItem ○ GradientDisplayItem DisplayListBuilder pub enum SpecificDisplayListItem { DrawList(DrawListInfo), StackingContext(StackingContextInfo), Iframe(IframeInfo), } ○ Store items to a list ○ Finalize ■ Generate a displaylist as Blob convert_to_webrender
  • 17.
    StackingContext ● Stacking contextis the three-dimensional conceptualization of HTML elements along an imaginary z-axis relative to the user who is assumed to be facing the viewport or the webpage pub struct StackingContext { pub servo_id: ServoStackingContextId, pub scroll_layer_id: Option<ScrollLayerId>, pub scroll_policy: ScrollPolicy, pub bounds: Rect<f32>, pub overflow: Rect<f32>, pub z_index: i32, pub display_lists: Vec<DisplayListId>, pub transform: Matrix4, pub perspective: Matrix4, pub establishes_3d_context: bool, pub mix_blend_mode: MixBlendMode, pub filters: ItemRange, pub has_stacking_contexts: bool, }
  • 18.
    StackingContext - display_list [id] Scene -display_list_map(id, display_list)StackingContext DisplayItem
  • 19.
    ● Scene.add_stacking_context ● Scene.add_display_list ●Scene.set_root_stacking_context Main thread render_backend thread APIMsg:: SetRootStackingContext Servo Webrender
  • 20.
    Scene ● Pipeline_map /display_list_map / stacking_context_map ● Set_root_stacking_context() ○ Remove old display list and stacking_context ○ New a scene pipeline ○ Insert to pipeline_map and remove old one pub struct ScenePipeline { pub pipeline_id: PipelineId, pub epoch: Epoch, pub background_draw_list: Option<DrawListId>, pub root_stacking_context_id: StackingContextId, pub viewport_size: Size2D<f32>, }
  • 21.
    display_list_map pipeline_id display_list(SpecificDisplayListItem) pipeline_id display_list(DrawList) Ex: pipeline_iddisplay_list(StackingContext) pipeline_id display_list(Iframe) pub enum SpecificSceneItem { DrawList(DrawListId), StackingContext(StackingContextId, PipelineId), Iframe(IframeInfo), } pub struct SceneDisplayList { pipeline_id SceneItem<Vec> epoch } SpecificDisplayListItem is mapped to SpecificSceneItem Stored to
  • 22.
    stacking_context_map StackingContextId SceneStackingContext stacking_context stacking_context stacking_context pub structSceneStackingContext { pub pipeline_id: PipelineId, pub epoch: Epoch, pub stacking_context: StackingContext, pub stacking_context_id: StackingContextId, } StackingContextId StackingContextId StackingContextId
  • 23.
  • 24.
  • 25.
    ● Build_scene ->Do scene graph ● Render -> Generate RenderFrame Main thread render_backend thread APIMsg:: SetRootPipeline
  • 26.
    ● Get rootstacking_context ● Create render target ● Create layer Create new Layer add_items_to_target Scrollable stacking context Yes No Render_backend:: build_scene() Frame::create() Frame::flatten() ● Add items to render target
  • 27.
    Frame::create ● Create aroot layer and render target ● Flatten ○ Try to add to the existing layers as an AABB node or create a new one ■ Determine by whether the same scroll_layer_id or not impl Layer { pub fn new(world_origin: Point2D<f32>, layer_size: Size2D<f32>, viewport_rect: &Rect<f32>, viewport_transform: &Matrix4D<f32>, local_transform: &Matrix4D<f32>, local_perspective: &Matrix4D<f32>, pipeline_id: PipelineId, stacking_context_id: ServoStackingContextId) Layer ● Own an AABB tree to manage scene items ● Cull via view_port rect
  • 28.
    Frame::build ● Cull layer’sAABB nodes ○ Adjust viewport to layer’s local space ○ Recursively check_node_visibility-> intersect(viewport rect, AABB node rect) and mark is_visible to true ● Update ○ Resource ○ Texture ○ Glyph Cull layers via viewport rect Update
  • 29.
    Frame::build ● compile_visible_nodes ○ Thread_pool.scoped ○Node_compiler uses BatchBuilder to batch draw list (same texture, color) (batch.rs:add_rectangle) ● update_batch_cache ○ Because some vertex buffers are modified after batching, pending them to update ● update_layer_transforms ○ Update child layer’s world transform and viewport to the world space compile_visible_nodes update_batch_cache update_layer_transform
  • 30.
    Frame::build ● compile_visible_nodes ○ Thread_pool.scoped ○Node_compiler uses BatchBuilder to batch draw list (same texture, color) (batch.rs:add_rectangle) ● update_batch_cache ○ Because some vertex buffers are modified after batching, pending them to update ● update_layer_transforms ○ Update child layer’s world transform and viewport to the world space compile_visible_nodes update_batch_cache update_layer_transform thread_pool.scoped(|scope| { for (_, layer) in layers { let nodes = &mut layer.aabb_tree.nodes; for node in nodes { if node.is_visible && node.compiled_node.is_none() { scope.execute(move || { node.compile(resource_cache, frame_id, device_pixel_ratio, stacking_context_info, draw_list_groups, pipeline_auxiliary_lists); }); } } } });
  • 31.
    Frame::build ● collect_and_sort_visible_batches ○ Collectvisible batches from layers and transform them to RenderTarget space. ○ Traverse RenderTarget tree to collect ■ CompositeBatch (clear buffer, transform, set texture commands) ■ DrawListBatch (collect draw calls) ○ Generate a DrawLayer tree ○ Return a RendererFrame ● expire_old_resources collect_and_sort_visible_batches expire_old_resources
  • 32.
  • 33.
    Renderer::update ● Pending shader/texture/batchupdates ● Set the Rendererframe from Frame::build() to current frame
  • 34.
    Renderer::render ● Draw frame ○Calculate_layer_viewports ■ Layer_viewports ←- a layer owns a viewport ■ Recursive process the child layer’s viewport ○ Draw_layer recursively for children ■ Bind render target ■ Clear buffer ■ Update shaders/texture cache/batches ■ DrawCommand ● Clear frame buffer ● Batch: combine index buffer → draw_simple_triangles ● CompositeBatch ---> apply filter ---> combine index buffer → draw_simple_triangles ● End frame ○ gl::end_frame()
  • 35.
    Render thread RenderBackend thread Mainthread Summary StackingContext & DisplayList creation ScenePipeline creation AABB tree creation Add DisplayItem to layers AABB nodes culling Draw list batching Visible batch collection RenderFrame publication RenderTarget binding Update resource DrawCommand execution APIMsg:: SetRootPipeline APIMsg:: SetRootStackingContext
  • 36.
  • 37.
    Webrender teaches us ●Scene graph ○ Using AABB tree to remove invisible display items effectively. ● Batching ○ Reduce draw calls and state changes to save redundant API calls. ● Delay execution draw commands ○ Avoiding unneeded mode-transition to occur CPU / GPU waiting time.
  • 38.
    Thanks for yourattention Question?